@sarj/eslint-plugin 2.7.0 → 2.9.0
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/README.md +135 -1
- package/dist/index.cjs +2035 -223
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +284 -10
- package/dist/index.d.ts +284 -10
- package/dist/index.js +2041 -223
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/rules/enforce-file-structure.ts","../src/rules/no-client-side-data-fetching.ts","../src/rules/no-comment-cruft.ts","../src/rules/no-enum.ts","../src/rules/no-insecure-random-id.ts","../src/rules/no-json-stringify-error.ts","../src/rules/no-log-only-catch.ts","../src/rules/_logging.ts","../src/rules/no-raw-env.ts","../src/rules/no-sentinel-return-on-catch.ts","../src/rules/no-sequential-await.ts","../src/rules/no-string-concat-in-loop.ts","../src/rules/no-unnecessary-use-client.ts","../src/rules/prefer-discriminated-union.ts","../src/rules/prefer-schema-for-api-payload.ts","../src/rules/prefer-semantic-colors.ts","../src/rules/_tailwind.ts","../src/rules/prefer-server-actions.ts","../src/rules/prefer-shadcn.ts","../src/rules/require-assert-never.ts","../src/rules/require-zod-form-validation.ts","../src/rules/zod-naming-convention.ts","../src/rules/no-cors-wildcard-with-credentials.ts","../src/rules/no-silent-promise-catch.ts","../src/rules/_paths.ts","../src/rules/require-fetch-timeout.ts","../src/rules/require-schema-validate-search.ts","../src/rules/no-fat-try-blocks.ts","../src/rules/no-secret-in-log.ts","../src/rules/no-unsafe-cast.ts","../src/rules/prefer-string-literal-union.ts","../src/rules/single-public-export.ts"],"sourcesContent":["import enforceFileStructure from \"./rules/enforce-file-structure.js\";\nimport noClientSideDataFetching from \"./rules/no-client-side-data-fetching.js\";\nimport noCommentCruft from \"./rules/no-comment-cruft.js\";\nimport noEnum from \"./rules/no-enum.js\";\nimport noInsecureRandomId from \"./rules/no-insecure-random-id.js\";\nimport noJsonStringifyError from \"./rules/no-json-stringify-error.js\";\nimport noLogOnlyCatch from \"./rules/no-log-only-catch.js\";\nimport noRawEnv from \"./rules/no-raw-env.js\";\nimport noSentinelReturnOnCatch from \"./rules/no-sentinel-return-on-catch.js\";\nimport noSequentialAwait from \"./rules/no-sequential-await.js\";\nimport noStringConcatInLoop from \"./rules/no-string-concat-in-loop.js\";\nimport noUnnecessaryUseClient from \"./rules/no-unnecessary-use-client.js\";\nimport preferDiscriminatedUnion from \"./rules/prefer-discriminated-union.js\";\nimport preferSchemaForApiPayload from \"./rules/prefer-schema-for-api-payload.js\";\nimport preferSemanticColors from \"./rules/prefer-semantic-colors.js\";\nimport preferServerActions from \"./rules/prefer-server-actions.js\";\nimport preferShadcn from \"./rules/prefer-shadcn.js\";\nimport requireAssertNever from \"./rules/require-assert-never.js\";\nimport requireZodFormValidation from \"./rules/require-zod-form-validation.js\";\nimport zodNamingConvention from \"./rules/zod-naming-convention.js\";\nimport noCorsWildcardWithCredentials from \"./rules/no-cors-wildcard-with-credentials.js\";\nimport noSilentPromiseCatch from \"./rules/no-silent-promise-catch.js\";\nimport requireFetchTimeout from \"./rules/require-fetch-timeout.js\";\nimport requireSchemaValidateSearch from \"./rules/require-schema-validate-search.js\";\nimport noFatTryBlocks from \"./rules/no-fat-try-blocks.js\";\nimport noSecretInLog from \"./rules/no-secret-in-log.js\";\nimport noUnsafeCast from \"./rules/no-unsafe-cast.js\";\nimport preferStringLiteralUnion from \"./rules/prefer-string-literal-union.js\";\nimport singlePublicExport from \"./rules/single-public-export.js\";\n\nconst rules = {\n \"enforce-file-structure\": enforceFileStructure,\n \"no-client-side-data-fetching\": noClientSideDataFetching,\n \"no-comment-cruft\": noCommentCruft,\n \"no-enum\": noEnum,\n \"no-insecure-random-id\": noInsecureRandomId,\n \"no-json-stringify-error\": noJsonStringifyError,\n \"no-log-only-catch\": noLogOnlyCatch,\n \"no-raw-env\": noRawEnv,\n \"no-sentinel-return-on-catch\": noSentinelReturnOnCatch,\n \"no-sequential-await\": noSequentialAwait,\n \"no-string-concat-in-loop\": noStringConcatInLoop,\n \"no-unnecessary-use-client\": noUnnecessaryUseClient,\n \"prefer-discriminated-union\": preferDiscriminatedUnion,\n \"prefer-schema-for-api-payload\": preferSchemaForApiPayload,\n \"prefer-semantic-colors\": preferSemanticColors,\n \"prefer-server-actions\": preferServerActions,\n \"prefer-shadcn\": preferShadcn,\n \"require-assert-never\": requireAssertNever,\n \"require-zod-form-validation\": requireZodFormValidation,\n \"zod-naming-convention\": zodNamingConvention,\n \"no-cors-wildcard-with-credentials\": noCorsWildcardWithCredentials,\n \"no-fat-try-blocks\": noFatTryBlocks,\n \"no-secret-in-log\": noSecretInLog,\n \"no-unsafe-cast\": noUnsafeCast,\n \"prefer-string-literal-union\": preferStringLiteralUnion,\n \"single-public-export\": singlePublicExport,\n \"no-silent-promise-catch\": noSilentPromiseCatch,\n \"require-fetch-timeout\": requireFetchTimeout,\n \"require-schema-validate-search\": requireSchemaValidateSearch,\n};\n\nconst plugin = {\n meta: {\n name: \"@sarj/eslint-plugin\",\n version: \"2.7.0\",\n },\n rules,\n configs: {\n recommended: {\n plugins: [\"@sarj\"],\n rules: {\n \"@sarj/zod-naming-convention\": \"warn\",\n \"@sarj/require-assert-never\": \"error\",\n \"@sarj/require-zod-form-validation\": \"error\",\n \"@sarj/enforce-file-structure\": \"warn\",\n \"@sarj/no-client-side-data-fetching\": \"warn\",\n \"@sarj/prefer-server-actions\": \"warn\",\n \"@sarj/no-unnecessary-use-client\": \"warn\",\n \"@sarj/prefer-schema-for-api-payload\": \"warn\",\n // Distilled from sarj-audit skills — warn in recommended, error in strict.\n \"@sarj/no-sequential-await\": \"warn\",\n \"@sarj/no-sentinel-return-on-catch\": \"warn\",\n \"@sarj/no-log-only-catch\": \"warn\",\n \"@sarj/no-insecure-random-id\": \"warn\",\n \"@sarj/no-json-stringify-error\": \"warn\",\n \"@sarj/no-string-concat-in-loop\": \"warn\",\n \"@sarj/prefer-discriminated-union\": \"warn\",\n \"@sarj/no-comment-cruft\": \"warn\",\n // Frontend / styling — distilled from frontend PR-review mining.\n \"@sarj/prefer-semantic-colors\": \"warn\",\n // Ported from sarj-python-lint (SARJ), corpus-validated FP~0.\n \"@sarj/no-fat-try-blocks\": \"warn\",\n \"@sarj/no-cors-wildcard-with-credentials\": \"warn\",\n \"@sarj/no-secret-in-log\": \"warn\",\n \"@sarj/no-unsafe-cast\": \"warn\",\n \"@sarj/single-public-export\": \"warn\",\n \"@sarj/prefer-string-literal-union\": \"warn\",\n // Mined from 2y of PR review feedback + 5-repo code-smell audit (2026-07).\n \"@sarj/require-fetch-timeout\": \"warn\",\n \"@sarj/no-silent-promise-catch\": \"warn\",\n \"@sarj/require-schema-validate-search\": \"warn\",\n },\n },\n strict: {\n plugins: [\"@sarj\"],\n rules: {\n \"@sarj/zod-naming-convention\": \"error\",\n \"@sarj/require-assert-never\": \"error\",\n \"@sarj/require-zod-form-validation\": \"error\",\n \"@sarj/enforce-file-structure\": \"error\",\n \"@sarj/no-raw-env\": \"error\",\n \"@sarj/prefer-shadcn\": \"error\",\n \"@sarj/no-enum\": \"error\",\n \"@sarj/no-client-side-data-fetching\": \"error\",\n \"@sarj/prefer-server-actions\": \"error\",\n \"@sarj/no-unnecessary-use-client\": \"error\",\n \"@sarj/prefer-schema-for-api-payload\": \"error\",\n // Distilled from sarj-audit skills.\n \"@sarj/no-sequential-await\": \"error\",\n \"@sarj/no-sentinel-return-on-catch\": \"error\",\n \"@sarj/no-log-only-catch\": \"error\",\n \"@sarj/no-insecure-random-id\": \"error\",\n \"@sarj/no-json-stringify-error\": \"error\",\n \"@sarj/no-string-concat-in-loop\": \"error\",\n \"@sarj/prefer-discriminated-union\": \"error\",\n \"@sarj/no-comment-cruft\": \"error\",\n // Frontend / styling — distilled from frontend PR-review mining. Stylistic,\n // no autofix → warn (rollout should prove the FP rate before raising it).\n \"@sarj/prefer-semantic-colors\": \"warn\",\n // Ported from sarj-python-lint (SARJ), corpus-validated FP~0.\n \"@sarj/no-fat-try-blocks\": \"error\",\n \"@sarj/no-cors-wildcard-with-credentials\": \"error\",\n \"@sarj/no-secret-in-log\": \"error\",\n \"@sarj/no-unsafe-cast\": \"warn\",\n \"@sarj/single-public-export\": \"error\",\n // High-volume/stylistic — warn until rollout proves FP rate.\n \"@sarj/prefer-string-literal-union\": \"warn\",\n // Mined from 2y of PR review feedback + 5-repo code-smell audit (2026-07).\n \"@sarj/require-fetch-timeout\": \"error\",\n \"@sarj/no-silent-promise-catch\": \"error\",\n \"@sarj/require-schema-validate-search\": \"error\",\n },\n },\n },\n};\n\nexport default plugin;\nexport { rules };\n","import { ESLintUtils, type TSESTree, AST_NODE_TYPES } from \"@typescript-eslint/utils\";\n\ntype MessageIds = \"importsFirst\" | \"useServerDirective\";\ntype Options = readonly [];\n\ntype StatementKind = \"import\" | \"reexport\" | \"body\";\n\n/**\n * Classify a top-level statement by WHAT it introduces, not by the presence of\n * the `export` keyword.\n *\n * - `import ...` → \"import\"\n * - `export ... from`, `export * from`, → \"reexport\"\n * `export { a, b }` (local names)\n * - everything else, INCLUDING every → \"body\"\n * exported declaration/function\n *\n * Bucketing exported statements as \"body\" is the whole point: an exported\n * `interface`/`type`/`enum`/`class`/value-`const` is a declaration and an\n * exported `function` (or `export default <fn>`) is a function — both live in\n * the same body as their non-exported equivalents. That lets the dominant\n * step-down layout (public API first, private helpers below) pass instead of\n * forcing every `export`-prefixed statement into a terminal \"exports\" section.\n *\n * Re-exports are their own neutral group: a generated `_namespaces` barrel that\n * interleaves `import * as X` / `export { X }` must not be flagged, so\n * re-exports never trigger and are allowed anywhere in the file.\n */\nconst classifyStatement = (\n statement: TSESTree.ProgramStatement,\n): StatementKind => {\n switch (statement.type) {\n case AST_NODE_TYPES.ImportDeclaration:\n return \"import\";\n case AST_NODE_TYPES.ExportAllDeclaration:\n return \"reexport\";\n case AST_NODE_TYPES.ExportNamedDeclaration:\n // `export { a } from './x'` / `export { a, b }` re-export names without\n // declaring anything; only `export <decl>` introduces a body statement.\n return statement.declaration === null ? \"reexport\" : \"body\";\n default:\n return \"body\";\n }\n};\n\nconst isStringDirective = (statement: TSESTree.ProgramStatement): boolean =>\n statement.type === AST_NODE_TYPES.ExpressionStatement &&\n statement.expression.type === AST_NODE_TYPES.Literal &&\n typeof statement.expression.value === \"string\" &&\n statement.expression.value.startsWith(\"use \");\n\nconst isUseServerDirective = (\n statement: TSESTree.ProgramStatement,\n): boolean => {\n if (statement.type !== AST_NODE_TYPES.ExpressionStatement) return false;\n const expr = statement.expression;\n if (expr.type !== AST_NODE_TYPES.Literal) return false;\n return expr.value === \"use server\";\n};\n\nexport default ESLintUtils.RuleCreator(\n (name) =>\n `https://github.com/sarj-ai/linting/blob/main/packages/typescript/src/rules/${name}.ts`,\n)<Options, MessageIds>({\n name: \"enforce-file-structure\",\n meta: {\n type: \"suggestion\",\n docs: {\n description:\n \"Require `import` statements to come first, then allow step-down ordering (public API first, private helpers below) for the rest of the file. Exported statements are classified by WHAT they export — an exported interface is a declaration, an exported function is a function — so a public exported function followed by a private helper, or an exported interface among declarations, is allowed. Re-exports (`export { … } from`, `export *`, `export { … }`) are a neutral group, so generated namespace barrels pass. When a module contains a `use server` directive, it must be the first statement in the file.\",\n },\n schema: [],\n messages: {\n importsFirst:\n \"File structure violation: import statements must come before other declarations\",\n useServerDirective:\n \"A 'use server' directive must be the first statement in the file\",\n },\n },\n defaultOptions: [],\n create(context) {\n return {\n Program(node: TSESTree.Program): void {\n const body = node.body;\n\n const misplacedUseServer = body.find(\n (statement, index) => index > 0 && isUseServerDirective(statement),\n );\n if (misplacedUseServer !== undefined) {\n context.report({\n node: misplacedUseServer,\n messageId: \"useServerDirective\",\n });\n }\n\n let seenBody = false;\n\n for (const statement of body) {\n if (isStringDirective(statement)) continue;\n\n switch (classifyStatement(statement)) {\n case \"reexport\":\n continue;\n case \"body\":\n seenBody = true;\n continue;\n case \"import\":\n if (seenBody) {\n context.report({\n node: statement,\n messageId: \"importsFirst\",\n });\n }\n continue;\n }\n }\n },\n };\n },\n});\n","/**\n * @fileoverview Disallow data fetching inside `useEffect` / `useLayoutEffect`.\n *\n * Anti-pattern:\n *\n * useEffect(() => { fetch('/data').then(setData); }, []);\n *\n * Causes a client-side waterfall (render → effect → fetch → re-render),\n * forfeits server-side caching, and produces layout shift. In Next.js App\n * Router, prefer:\n * - a React Server Component that fetches at render time, or\n * - a Server Action invoked from a form / onClick handler, or\n * - client-side caching libraries like SWR or React Query.\n *\n * Detection covers:\n * - `fetch(...)` (default + when explicit `method: \"GET\"`)\n * - `axios.<method>(...)` for actual HTTP verbs only:\n * get / post / put / delete / patch / request / head / options\n * (i.e. NOT `axios.create` / `axios.defaults`)\n * - `ky.<method>(...)` / `superagent.<method>(...)` (same verbs)\n * - bare `axios(...)` / `ky(...)` calls (when treated as a GET)\n *\n * Analytics / telemetry endpoints whose URL has a whole path segment of\n * `track` / `log` / `ping` / `event` / ... are intentionally exempt because\n * they aren't render-blocking data fetches. (Matched per-segment, so\n * `/api/login`, `/blog`, `/api/events`, `/catalog`, `/api/shipping` are NOT\n * exempt.)\n *\n * References:\n * - https://nextjs.org/docs/app/building-your-application/data-fetching\n * - https://react.dev/reference/react/useEffect#fetching-data-with-effects\n */\n\nimport {\n AST_NODE_TYPES,\n ESLintUtils,\n type TSESTree,\n} from \"@typescript-eslint/utils\";\n\ntype MessageIds = \"noClientFetch\";\ntype Options = readonly [];\n\nconst FETCH_LIBS: ReadonlySet<string> = new Set([\"axios\", \"ky\", \"superagent\"]);\n\n// Real HTTP verbs only. Explicitly excludes `create`, `defaults`,\n// `interceptors`, `isAxiosError`, etc.\nconst HTTP_METHOD_NAMES: ReadonlySet<string> = new Set([\n \"get\",\n \"post\",\n \"put\",\n \"delete\",\n \"patch\",\n \"request\",\n \"head\",\n \"options\",\n]);\n\n// Matched against whole path SEGMENTS (split on `/` and `.`), never as raw\n// substrings — otherwise `/api/login` (\"log\"), `/blog` (\"log\"), `/api/events`\n// (\"event\"), `/catalog` (\"log\"), and `/api/shipping` (\"ping\") would be wrongly\n// exempted.\nconst ANALYTICS_SEGMENTS: ReadonlySet<string> = new Set([\n \"analytics\",\n \"telemetry\",\n \"track\",\n \"log\",\n \"ping\",\n \"beacon\",\n \"metrics\",\n \"event\",\n]);\n\nfunction isEffectHookCall(node: TSESTree.CallExpression): boolean {\n const callee = node.callee;\n\n // useEffect(...) / useLayoutEffect(...)\n if (callee.type === AST_NODE_TYPES.Identifier) {\n return callee.name === \"useEffect\" || callee.name === \"useLayoutEffect\";\n }\n\n // React.useEffect(...) / React.useLayoutEffect(...)\n if (\n callee.type === AST_NODE_TYPES.MemberExpression &&\n !callee.computed &&\n callee.object.type === AST_NODE_TYPES.Identifier &&\n callee.object.name === \"React\" &&\n callee.property.type === AST_NODE_TYPES.Identifier\n ) {\n return (\n callee.property.name === \"useEffect\" ||\n callee.property.name === \"useLayoutEffect\"\n );\n }\n\n return false;\n}\n\n/**\n * Reads the `method` property of an options object passed to `fetch` / `axios`.\n * Returns the uppercased method name, or `null` if not statically determinable.\n */\nfunction readMethodProperty(\n optionsArg: TSESTree.Node | undefined,\n): string | null {\n if (!optionsArg || optionsArg.type !== AST_NODE_TYPES.ObjectExpression) {\n return null;\n }\n for (const prop of optionsArg.properties) {\n if (prop.type !== AST_NODE_TYPES.Property) continue;\n if (prop.computed) continue;\n const key = prop.key;\n const matchesMethodKey =\n (key.type === AST_NODE_TYPES.Identifier && key.name === \"method\") ||\n (key.type === AST_NODE_TYPES.Literal && key.value === \"method\");\n if (!matchesMethodKey) continue;\n if (\n prop.value.type === AST_NODE_TYPES.Literal &&\n typeof prop.value.value === \"string\"\n ) {\n return prop.value.value.toUpperCase();\n }\n return null;\n }\n return null;\n}\n\nfunction isFetchCall(node: TSESTree.CallExpression): boolean {\n const callee = node.callee;\n\n // fetch(url, options?)\n if (\n callee.type === AST_NODE_TYPES.Identifier &&\n callee.name === \"fetch\"\n ) {\n const method = readMethodProperty(node.arguments[1]);\n if (method !== null && method !== \"GET\") {\n return false;\n }\n return true;\n }\n\n // axios.get(...), ky.post(...), superagent.delete(...), ...\n if (\n callee.type === AST_NODE_TYPES.MemberExpression &&\n !callee.computed &&\n callee.object.type === AST_NODE_TYPES.Identifier &&\n FETCH_LIBS.has(callee.object.name) &&\n callee.property.type === AST_NODE_TYPES.Identifier\n ) {\n // Only flag actual HTTP method calls — NOT `axios.create`, `axios.defaults`,\n // `axios.interceptors`, `axios.isAxiosError`, etc.\n return HTTP_METHOD_NAMES.has(callee.property.name);\n }\n\n // axios(config) / ky(config) — treat as request unless method is explicitly non-GET.\n if (\n callee.type === AST_NODE_TYPES.Identifier &&\n (callee.name === \"axios\" || callee.name === \"ky\")\n ) {\n const firstArg = node.arguments[0];\n const secondArg = node.arguments[1];\n let configArg: TSESTree.Node | undefined;\n if (firstArg?.type === AST_NODE_TYPES.ObjectExpression) {\n configArg = firstArg;\n } else if (secondArg?.type === AST_NODE_TYPES.ObjectExpression) {\n configArg = secondArg;\n }\n const method = readMethodProperty(configArg);\n if (method !== null && method !== \"GET\") {\n return false;\n }\n return true;\n }\n\n return false;\n}\n\nfunction extractUrlString(node: TSESTree.CallExpression): string {\n const firstArg = node.arguments[0];\n if (!firstArg) return \"\";\n\n if (\n firstArg.type === AST_NODE_TYPES.Literal &&\n typeof firstArg.value === \"string\"\n ) {\n return firstArg.value;\n }\n if (firstArg.type === AST_NODE_TYPES.TemplateLiteral) {\n return firstArg.quasis.map((q) => q.value.cooked).join(\"\");\n }\n if (firstArg.type === AST_NODE_TYPES.Identifier) {\n return firstArg.name;\n }\n return \"\";\n}\n\nfunction isAnalyticsCall(node: TSESTree.CallExpression): boolean {\n const url = extractUrlString(node).toLowerCase();\n if (url === \"\") return false;\n // Split into path segments and file-extension parts; exempt only when a\n // WHOLE segment is a known analytics keyword.\n return url\n .split(/[/.]/)\n .some((segment) => ANALYTICS_SEGMENTS.has(segment));\n}\n\nexport default ESLintUtils.RuleCreator(\n (name) =>\n `https://github.com/sarj-ai/linting/blob/main/packages/typescript/src/rules/${name}.ts`,\n)<Options, MessageIds>({\n name: \"no-client-side-data-fetching\",\n meta: {\n type: \"problem\",\n docs: {\n description:\n \"Disallow data fetching inside `useEffect` / `useLayoutEffect`; prefer React Server Components, Server Actions, or a client-side cache (SWR / React Query).\",\n },\n schema: [],\n messages: {\n noClientFetch:\n \"Avoid direct data fetching inside useEffect / useLayoutEffect. This causes waterfalls and layout shifts. Prefer React Server Components, Server Actions, or client-side caching libraries like SWR or React Query.\",\n },\n },\n defaultOptions: [],\n create(context) {\n let effectDepth = 0;\n return {\n CallExpression(node: TSESTree.CallExpression): void {\n if (isEffectHookCall(node)) {\n effectDepth += 1;\n return;\n }\n if (effectDepth === 0) return;\n if (!isFetchCall(node)) return;\n if (isAnalyticsCall(node)) return;\n context.report({ node, messageId: \"noClientFetch\" });\n },\n \"CallExpression:exit\"(node: TSESTree.CallExpression): void {\n if (isEffectHookCall(node)) {\n effectDepth -= 1;\n }\n },\n };\n },\n});\n","/**\n * @fileoverview Flag comment cruft — commented-out code, section banners,\n * leading file-header comment preambles, and redundant narration (step markers\n * like \"First, …\" and self-admitted meta-commentary like \"for now\" / \"temporary\n * hack\"). Code carries the *what*; comments are reserved for the *why*. The\n * fuzzier \"this comment restates the next line\" judgment stays in review (a\n * substring-corroboration heuristic was too false-positive-prone on real code).\n * JSDoc (`/** ... *\\/`) is never flagged, and directive comments (`eslint-`,\n * `@ts-`, `prettier-`, `biome-`, `c8`, `<reference`, `TODO`, `FIXME`) are ignored.\n */\n\nimport { ESLintUtils, type TSESTree } from \"@typescript-eslint/utils\";\n\ntype MessageIds =\n | \"commentedOutCode\"\n | \"sectionBanner\"\n | \"fileHeaderPreamble\"\n | \"redundantNarration\";\ntype Options = readonly [];\n\nconst LEADING_PREAMBLE_MIN = 4;\n\n// Step-narration lead-ins (\"First, …\", \"Then, …\", \"Finally, …\", \"Step 2:\"). A\n// trailing comma/colon is required so English adverbs (\"finally the invariant\n// holds\") aren't mistaken for an enumeration marker.\nconst STEP_NARRATION_RE =\n /^(?:first(?:ly)?|second(?:ly)?|third(?:ly)?|then|next|after(?:wards| that)?|finally|lastly|now)\\s*[,:]\\s*\\S|^step\\s+\\d+\\b/i;\n\n// Self-admitted meta-commentary — the \"why later\", not the why. `TODO`/`FIXME`/\n// `HACK`/`XXX` are handled as directives (kept, with an owner, per convention).\nconst META_COMMENTARY_RE =\n /\\b(?:for now|keeping (?:it|this) simple|could be (?:refactored|improved|cleaned up|simplified)|refactor(?:ed|ing)? (?:later|this)|not sure (?:if|whether|why|how)|quick[- ](?:and[- ]dirty|fix)|(?:a |bit of a )?hacky|is a hack|temporary (?:solution|workaround|fix|hack)|revisit (?:this|later|below)|clean (?:this|it) up|not ideal|placeholder for now)\\b/i;\n\n\nconst DIRECTIVE_RE =\n /^(eslint\\b|eslint-|@ts-|prettier-ignore|prettier\\b|biome-|c8\\b|v8\\b|istanbul\\b|@type\\b|@vite|webpack|<reference|<amd|global\\b|noinspection|todo\\b|fixme\\b|hack\\b|xxx\\b)/i;\n\nconst LICENSE_RE =\n /copyright|licen[cs]ed?|spdx|permission is hereby granted|all rights reserved/i;\n\nconst BANNER_FULL_RE = /^[\\s\\-=*#~_+.]{4,}$/;\n// `={4,}` not `={3,}`: `===` is TS strict-equality and appears in prose comments.\nconst BANNER_RUN_RE = /={4,}|-{4,}|#{4,}|\\*{4,}|~{4,}/;\nconst REGION_RE = /^#?(?:end)?region\\b/i;\n\nconst CODE_KEYWORD_RE =\n /^(import |export |const |let |var |function\\b|class |interface |type \\w|enum |return\\b|throw |await |async |if\\s*\\(|for\\s*\\(|while\\s*\\(|switch\\s*\\(|new |console\\.)/;\nconst CODE_TAIL_RE = /[;{}()]\\s*$|=>\\s*$|,\\s*$/;\n// LHS must be a real identifier (not a number literal — `0=Monday` in prose is\n// not an assignment) and `=` must not be `==`/`===`/`=>` (comparison/arrow).\n// The assignment branch additionally requires a code-tail — the line must end\n// with `;`, `)`, `}` or `]` — so plain prose like `count = number of items`\n// (which has no code-tail) is not mistaken for commented-out code.\nconst CALL_OR_ASSIGN_RE =\n /^[A-Za-z_$][\\w.$[\\]]*\\s*(?:=(?![=>])|\\+=|-=|\\*=)\\s*\\S.*[;)}\\]]\\s*$|^[A-Za-z_$][\\w.$]*\\([^)]*\\)\\s*;?\\s*$/;\n\n// Placeholders that only appear in grammar productions / desugaring examples,\n// never in real code: `%sent%`, `[opt]`, a standalone `<FunctionBody>`, `…` / `...`.\nconst PSEUDOCODE_RE = /%\\w+%|\\[opt\\]|(?:^|\\s)<[A-Za-z]\\w*>|…|\\.\\.\\./;\n\n// A triple-slash `///` directive keeps its third `/` after ESLint strips the\n// leading `//`, so strip 1–2 leading slashes (not exactly two) for `<reference`.\nfunction stripCommentMarker(line: string): string {\n return line.replace(/^\\s*\\/{1,2}/, \"\").replace(/^\\s*\\*+/, \"\").trim();\n}\n\nfunction isDirective(text: string): boolean {\n return DIRECTIVE_RE.test(text.trim());\n}\n\nfunction isBanner(text: string): boolean {\n const t = text.trim();\n if (!t) return false;\n return BANNER_FULL_RE.test(t) || BANNER_RUN_RE.test(t) || REGION_RE.test(t);\n}\n\nfunction looksLikeCode(text: string): boolean {\n const t = text.trim();\n if (!t) return false;\n if (CODE_KEYWORD_RE.test(t) && CODE_TAIL_RE.test(t)) return true;\n return CALL_OR_ASSIGN_RE.test(t);\n}\n\nfunction hasPseudocode(text: string): boolean {\n return PSEUDOCODE_RE.test(text);\n}\n\n// A prose lead-in preceding a code-shaped line marks that line as an\n// illustration (`// For example:`, a grammar production `FunctionExpression:`),\n// not commented-out code.\nfunction isProse(text: string): boolean {\n const t = text.trim();\n if (!t) return false;\n if (t.endsWith(\":\")) return true;\n if (\n /[.!?]$/.test(t) &&\n /\\s/.test(t) &&\n /[a-z]/.test(t) &&\n !looksLikeCode(t) &&\n t.split(/\\s+/).length >= 3\n ) {\n return true;\n }\n return false;\n}\n\n/**\n * Whether a single-line comment merely narrates the code rather than explaining\n * the *why*. Three deterministic shapes: step narration (\"First, …\"), self-\n * admitted meta-commentary (\"keeping it simple\"), and a restatement of the very\n * next statement — a narration-verb opener corroborated by a shared token with\n * the following code line (`// create the user` above `const user = createUser()`).\n */\nfunction isRedundantNarration(body: string): boolean {\n const t = body.trim();\n if (!t || looksLikeCode(t) || hasPseudocode(t)) return false;\n if (STEP_NARRATION_RE.test(t)) return true;\n if (META_COMMENTARY_RE.test(t)) return true;\n return false;\n}\n\nfunction hasCommentedOutCode(\n texts: readonly string[],\n precedingProse: boolean,\n): boolean {\n for (let i = 0; i < texts.length; i++) {\n const line = texts[i];\n if (line === undefined || !looksLikeCode(line) || hasPseudocode(line)) {\n continue;\n }\n const prev = i > 0 ? texts[i - 1] : undefined;\n if (prev !== undefined ? isProse(prev) : precedingProse) continue;\n return true;\n }\n return false;\n}\n\nexport default ESLintUtils.RuleCreator(\n (name) =>\n `https://github.com/sarj-ai/standards/blob/main/packages/typescript/src/rules/${name}.ts`,\n)<Options, MessageIds>({\n name: \"no-comment-cruft\",\n meta: {\n type: \"suggestion\",\n docs: {\n description:\n \"Flag commented-out code, section-banner comments, and leading file-header comment preambles.\",\n },\n schema: [],\n messages: {\n commentedOutCode:\n \"Commented-out code — delete it; git history remembers.\",\n sectionBanner:\n \"Section-banner / region comment — structure code with functions, not ASCII rules.\",\n fileHeaderPreamble:\n \"File-header comment preamble — use a brief doc comment for the why, not a block of `//` lines.\",\n redundantNarration:\n \"Comment narrates the code — delete it or say *why*, not *what*. Code is self-documenting.\",\n },\n },\n defaultOptions: [],\n create(context) {\n const sourceCode = context.sourceCode;\n\n function isStandalone(comment: TSESTree.Comment): boolean {\n const before = sourceCode.getTokenBefore(comment, {\n includeComments: false,\n });\n return !before || before.loc.end.line < comment.loc.start.line;\n }\n\n function isJsDoc(comment: TSESTree.Comment): boolean {\n return comment.type === \"Block\" && /^\\*/.test(comment.value);\n }\n\n function reportLeadingPreamble(\n comments: readonly TSESTree.Comment[],\n firstCodeLine: number,\n ): void {\n const leading: TSESTree.Comment[] = [];\n let prevLine: number | null = null;\n for (const comment of comments) {\n if (comment.type !== \"Line\") break;\n if (comment.loc.start.line >= firstCodeLine) break;\n if (!isStandalone(comment)) break;\n const body = stripCommentMarker(comment.value);\n if (isDirective(body) || body.startsWith(\"!\")) continue;\n if (prevLine !== null && comment.loc.start.line !== prevLine + 1) break;\n leading.push(comment);\n prevLine = comment.loc.start.line;\n }\n const first = leading[0];\n if (first === undefined || leading.length < LEADING_PREAMBLE_MIN) return;\n const isLicense = leading.some((c) =>\n LICENSE_RE.test(stripCommentMarker(c.value)),\n );\n if (!isLicense) {\n context.report({ node: first, messageId: \"fileHeaderPreamble\" });\n }\n }\n\n return {\n Program(): void {\n const comments = sourceCode.getAllComments();\n const firstCodeLine =\n sourceCode.ast.tokens[0]?.loc.start.line ?? Number.MAX_SAFE_INTEGER;\n\n for (let i = 0; i < comments.length; i++) {\n const comment = comments[i];\n if (comment === undefined) continue;\n if (isJsDoc(comment) || !isStandalone(comment)) continue;\n if (LICENSE_RE.test(comment.value)) continue;\n const texts = comment.value\n .split(\"\\n\")\n .map(stripCommentMarker)\n .filter((l) => l.length > 0 && !isDirective(l));\n if (texts.some(isBanner)) {\n context.report({ node: comment, messageId: \"sectionBanner\" });\n continue;\n }\n const prev = comments[i - 1];\n const precedingProse =\n prev !== undefined &&\n prev.type === \"Line\" &&\n prev.loc.end.line === comment.loc.start.line - 1 &&\n isProse(stripCommentMarker(prev.value));\n if (hasCommentedOutCode(texts, precedingProse)) {\n context.report({ node: comment, messageId: \"commentedOutCode\" });\n continue;\n }\n // Narration only for single-line comments (a multi-line block is\n // usually a real doc). The next non-blank source line is the code the\n // comment sits above.\n if (comment.type === \"Line\" && texts.length === 1) {\n const body = texts[0];\n if (body !== undefined && isRedundantNarration(body)) {\n context.report({ node: comment, messageId: \"redundantNarration\" });\n }\n }\n }\n\n reportLeadingPreamble(comments, firstCodeLine);\n },\n };\n },\n});\n","/**\n * @fileoverview Disallow TypeScript `enum` declarations. Use string-literal\n * union types (e.g. `type Status = \"active\" | \"inactive\"`) or `as const`\n * objects instead — enums generate runtime code, have unintuitive numeric\n * defaults, and don't tree-shake cleanly.\n *\n * Generated files can opt out either by living under a path matched by\n * `ignoreFiles` (default: `**\\/generated/**`, `**\\/*.gen.ts`, `**\\/*.generated.ts`)\n * or by including a `@generated` marker comment near the top of the file.\n */\n\nimport { ESLintUtils, type TSESTree } from \"@typescript-eslint/utils\";\n\ntype MessageIds = \"noEnum\";\ntype Options = readonly [\n {\n ignoreFiles?: readonly string[];\n }?,\n];\n\nconst DEFAULT_IGNORE_PATTERNS: readonly RegExp[] = [\n /[\\\\/]generated[\\\\/]/,\n /\\.gen\\.tsx?$/,\n /\\.generated\\.tsx?$/,\n];\n\nfunction matchesAnyPattern(\n filename: string,\n patterns: readonly string[],\n): boolean {\n for (const pattern of patterns) {\n // Convert minimatch-ish globs to regex: ** -> .*, * -> [^/\\\\]*\n const regexSource = pattern\n .replace(/[.+^${}()|[\\]\\\\]/g, \"\\\\$&\")\n .replace(/\\*\\*/g, \"::DOUBLESTAR::\")\n .replace(/\\*/g, \"[^/\\\\\\\\]*\")\n .replace(/::DOUBLESTAR::/g, \".*\");\n if (new RegExp(`^${regexSource}$`).test(filename)) {\n return true;\n }\n }\n return false;\n}\n\nfunction hasGeneratedMarker(sourceText: string): boolean {\n // Look only in the first 1KB to keep this cheap.\n const head = sourceText.slice(0, 1024);\n return /@generated\\b/.test(head);\n}\n\nexport default ESLintUtils.RuleCreator(\n (name) =>\n `https://github.com/sarj-ai/linting/blob/main/packages/typescript/src/rules/${name}.ts`,\n)<Options, MessageIds>({\n name: \"no-enum\",\n meta: {\n type: \"suggestion\",\n docs: {\n description:\n \"Disallow TypeScript `enum`; use string-literal unions or `as const` objects instead.\",\n },\n schema: [\n {\n type: \"object\",\n additionalProperties: false,\n properties: {\n ignoreFiles: {\n type: \"array\",\n items: { type: \"string\" },\n },\n },\n },\n ],\n messages: {\n noEnum:\n 'Enums are discouraged. Use a string-literal union (e.g. `type Status = \"active\" | \"inactive\"`) or an `as const` object instead.',\n },\n },\n defaultOptions: [{}],\n create(context, [optionsArg]) {\n const options = optionsArg ?? {};\n const ignoreFiles = options.ignoreFiles ?? [];\n const filename = context.filename;\n const sourceText = context.sourceCode.getText();\n\n const isIgnoredByDefault = DEFAULT_IGNORE_PATTERNS.some((re) =>\n re.test(filename),\n );\n const isIgnoredByOption =\n ignoreFiles.length > 0 && matchesAnyPattern(filename, ignoreFiles);\n const isGenerated = hasGeneratedMarker(sourceText);\n\n if (isIgnoredByDefault || isIgnoredByOption || isGenerated) {\n return {};\n }\n\n return {\n TSEnumDeclaration(node: TSESTree.TSEnumDeclaration): void {\n context.report({\n node,\n messageId: \"noEnum\",\n });\n },\n };\n },\n});\n","/**\n * @fileoverview Disallow using `Math.random()` to generate identifiers,\n * tokens, keys, or other security-sensitive values. `Math.random()` is not\n * cryptographically secure and is predictable — using it for tokens/secrets\n * can lead to collisions and trivially guessable values. Prefer\n * `crypto.randomUUID()` or `crypto.getRandomValues(...)` instead.\n *\n * Precision matters here: the rule runs at `error` in the `strict` config, so a\n * false positive blocks a real PR. Large open-source sweeps (VS Code, NestJS,\n * Next.js) showed the bare `id`/`key`/`session` substring heuristic firing on a\n * flood of NON-security correlation/ephemeral ids — temp-file suffixes, HMR\n * session numbers, dev request/execution/trace ids, in-process RPC handles.\n * None of those are security tokens. So the rule now requires a STRONG security\n * signal, and actively exempts names that read as ephemeral/correlation ids or\n * random values concatenated into a filename/path/DOM id.\n *\n * The rule flags a `Math.random()` call when, and only when:\n * 1. Its enclosing binding/property NAME carries a strong security signal\n * (`token`, `secret`, `apiKey`, `csrf`, `password`, `nonce`, `salt`,\n * `uuid`, `authId`) — even a `sessionToken` counts because of `token`; or\n * 2. Its result is fed into a `.toString(36)` chain (the classic insecure\n * random-id idiom, e.g. `Math.random().toString(36).slice(2)`) AND the\n * value is not an exempt ephemeral/correlation id or path fragment.\n *\n * It does NOT flag when the enclosing name signals a non-security\n * correlation/ephemeral id (`temp`, `tmp`, `cache`, `correlation`, `request`,\n * `req`, `trace`, `execution`, `dev`, `hmr`, `mock`, `test`, `perf`, `marker`),\n * nor when the random value is concatenated into a filename/path/DOM id. A\n * strong security name still wins over these exemptions.\n *\n * Bare `Math.random()` used for non-identifier purposes (jitter, sampling,\n * rolls, etc.) is NOT flagged, and neither is the bare `id`/`key`/`session`\n * substring on its own — we err toward suppressing ambiguous correlation ids.\n *\n * KNOWN GAP (false-negative): an arithmetic expression between `Math.random()`\n * and `.toString(36)` breaks the member-chain walk, e.g.\n * `(Math.random() * 1e9).toString(36)`. The intervening `BinaryExpression`\n * means `Math.random()` is no longer the object end of the `.toString` chain,\n * so trigger 2 does not fire. Such code is only caught if its binding/property\n * name looks security-like (trigger 1). See the documented test case.\n */\n\nimport { ESLintUtils, type TSESTree } from \"@typescript-eslint/utils\";\n\ntype MessageIds = \"insecureRandomId\";\ntype Options = readonly [];\n\nconst STRONG_SECURITY_PATTERN =\n /token|secret|csrf|password|passwd|apikey|api[-_]?key|nonce|salt|uuid|authid/i;\n\nconst NON_SECURITY_ID_PATTERN =\n /temp|tmp|cache|correlation|request|req|trace|execution|dev|hmr|mock|test|perf|marker/i;\n\n/** Matches a static string fragment that reads as a path or DOM-id context. */\nconst PATH_OR_DOM_MARKER = /[\\\\/#]|\\.[A-Za-z0-9]/;\n\n/**\n * Returns true if `node` is a `Math.random()` CallExpression.\n */\nfunction isMathRandomCall(node: TSESTree.Node): node is TSESTree.CallExpression {\n if (node.type !== \"CallExpression\") {\n return false;\n }\n const callee = node.callee;\n if (callee.type !== \"MemberExpression\" || callee.computed) {\n return false;\n }\n const { object, property } = callee;\n return (\n object.type === \"Identifier\" &&\n object.name === \"Math\" &&\n property.type === \"Identifier\" &&\n property.name === \"random\"\n );\n}\n\n/**\n * Climbs the member/call chain in which `node` is the object/callee end, and\n * returns the outermost value node of that chain. For\n * `Math.random().toString(36).slice(2)` this returns the `.slice(2)` call —\n * i.e. the value that actually gets assigned/concatenated.\n */\nfunction climbValueChain(node: TSESTree.Node): TSESTree.Node {\n let current: TSESTree.Node = node;\n let parent = current.parent;\n\n while (parent) {\n if (\n parent.type === \"MemberExpression\" &&\n parent.object === current &&\n !parent.computed\n ) {\n current = parent;\n parent = current.parent;\n continue;\n }\n if (parent.type === \"CallExpression\" && parent.callee === current) {\n current = parent;\n parent = current.parent;\n continue;\n }\n break;\n }\n\n return current;\n}\n\n/**\n * Returns true if `node` (a `Math.random()` call) is the base of a member\n * chain that calls `.toString(36)` somewhere above it, e.g.\n * `Math.random().toString(36)` or `Math.random().toString(36).slice(2)`.\n */\nfunction isPartOfToString36Chain(node: TSESTree.Node): boolean {\n let current: TSESTree.Node = node;\n let parent = current.parent;\n\n while (parent) {\n if (\n parent.type === \"MemberExpression\" &&\n parent.object === current &&\n !parent.computed &&\n parent.property.type === \"Identifier\" &&\n parent.property.name === \"toString\"\n ) {\n const grandparent = parent.parent;\n if (\n grandparent &&\n grandparent.type === \"CallExpression\" &&\n grandparent.callee === parent\n ) {\n const firstArg = grandparent.arguments[0];\n if (firstArg && firstArg.type === \"Literal\" && firstArg.value === 36) {\n return true;\n }\n }\n }\n\n if (parent.type === \"MemberExpression\" && parent.object === current) {\n current = parent;\n parent = current.parent;\n continue;\n }\n if (parent.type === \"CallExpression\" && parent.callee === current) {\n current = parent;\n parent = current.parent;\n continue;\n }\n break;\n }\n\n return false;\n}\n\n/**\n * Walks up from `node` to find the name of the nearest enclosing binding\n * (VariableDeclarator id) or property (Property / PropertyDefinition key),\n * and returns it. Passes through string concatenation and template literals so\n * that `const tempPath = base + Math.random()...` resolves to `tempPath`.\n * Returns `undefined` if no such name is found before leaving the enclosing\n * initializer/value context.\n */\nfunction findEnclosingName(node: TSESTree.Node): string | undefined {\n let current: TSESTree.Node = node;\n let parent = current.parent;\n\n while (parent) {\n if (parent.type === \"VariableDeclarator\" && parent.init === current) {\n if (parent.id.type === \"Identifier\") {\n return parent.id.name;\n }\n return undefined;\n }\n\n if (parent.type === \"Property\" && parent.value === current) {\n const key = parent.key;\n if (!parent.computed && key.type === \"Identifier\") {\n return key.name;\n }\n if (key.type === \"Literal\" && typeof key.value === \"string\") {\n return key.value;\n }\n return undefined;\n }\n\n if (parent.type === \"PropertyDefinition\" && parent.value === current) {\n const key = parent.key;\n if (!parent.computed && key.type === \"Identifier\") {\n return key.name;\n }\n if (key.type === \"Literal\" && typeof key.value === \"string\") {\n return key.value;\n }\n return undefined;\n }\n\n if (\n parent.type === \"FunctionDeclaration\" ||\n parent.type === \"FunctionExpression\" ||\n parent.type === \"ArrowFunctionExpression\" ||\n parent.type === \"BlockStatement\" ||\n parent.type === \"ReturnStatement\" ||\n parent.type === \"ExpressionStatement\"\n ) {\n return undefined;\n }\n\n current = parent;\n parent = current.parent;\n }\n\n return undefined;\n}\n\n/**\n * Collects the static string fragments of a `+` concatenation / template\n * literal subtree into `out`.\n */\nfunction collectStaticStringParts(\n node: TSESTree.Node,\n out: string[],\n): void {\n if (node.type === \"Literal\" && typeof node.value === \"string\") {\n out.push(node.value);\n return;\n }\n if (node.type === \"TemplateLiteral\") {\n for (const quasi of node.quasis) {\n out.push(quasi.value.cooked ?? quasi.value.raw);\n }\n return;\n }\n if (node.type === \"BinaryExpression\" && node.operator === \"+\") {\n collectStaticStringParts(node.left, out);\n collectStaticStringParts(node.right, out);\n }\n}\n\n/**\n * Returns true if the random value is concatenated into a string whose static\n * parts read as a filename/path/DOM id (contain a slash, backslash, `#`, or a\n * `.ext`-style fragment).\n */\nfunction isConcatenatedIntoPathOrDomId(node: TSESTree.Node): boolean {\n const valueNode = climbValueChain(node);\n\n let current: TSESTree.Node = valueNode;\n let parent = current.parent;\n let top: TSESTree.Node | undefined;\n\n while (parent) {\n if (\n parent.type === \"BinaryExpression\" &&\n parent.operator === \"+\" &&\n (parent.left === current || parent.right === current)\n ) {\n top = parent;\n current = parent;\n parent = current.parent;\n continue;\n }\n if (parent.type === \"TemplateLiteral\") {\n top = parent;\n current = parent;\n parent = current.parent;\n continue;\n }\n break;\n }\n\n if (!top) {\n return false;\n }\n\n const parts: string[] = [];\n collectStaticStringParts(top, parts);\n return parts.some((part) => PATH_OR_DOM_MARKER.test(part));\n}\n\nexport default ESLintUtils.RuleCreator(\n (name) =>\n `https://github.com/sarj-ai/linting/blob/main/packages/typescript/src/rules/${name}.ts`,\n)<Options, MessageIds>({\n name: \"no-insecure-random-id\",\n meta: {\n type: \"problem\",\n docs: {\n description:\n \"Disallow using `Math.random()` to generate identifiers, tokens, or secrets; use `crypto.randomUUID()` or `crypto.getRandomValues(...)` instead.\",\n },\n schema: [],\n messages: {\n insecureRandomId:\n \"`Math.random()` is not cryptographically secure and is predictable; do not use it to generate IDs, tokens, or secrets. Use `crypto.randomUUID()` or `crypto.getRandomValues(...)` instead.\",\n },\n },\n defaultOptions: [],\n create(context) {\n return {\n CallExpression(node: TSESTree.CallExpression): void {\n if (!isMathRandomCall(node)) {\n return;\n }\n\n const name = findEnclosingName(node);\n\n // A strong security name always fires — even a `sessionToken` or a name\n // that also happens to contain a correlation-id word.\n if (name !== undefined && STRONG_SECURITY_PATTERN.test(name)) {\n context.report({ node, messageId: \"insecureRandomId\" });\n return;\n }\n\n // Ephemeral / correlation ids (temp files, HMR sessions, dev request\n // ids, ...) are not security-sensitive — suppress, including the\n // `.toString(36)` idiom used to shape them.\n if (name !== undefined && NON_SECURITY_ID_PATTERN.test(name)) {\n return;\n }\n\n // A random value concatenated into a filename/path/DOM id is not a\n // security token.\n if (isConcatenatedIntoPathOrDomId(node)) {\n return;\n }\n\n // The classic insecure random-id idiom.\n if (isPartOfToString36Chain(node)) {\n context.report({ node, messageId: \"insecureRandomId\" });\n }\n },\n };\n },\n});\n","/**\n * @fileoverview Disallow `JSON.stringify(err)` on a (heuristically detected)\n * Error value. `JSON.stringify` on an Error produces `\"{}\"` because the\n * `message` and `stack` properties are non-enumerable, silently throwing away\n * the very information you were trying to log.\n *\n * This is a purely syntactic rule (no type information). It flags\n * `JSON.stringify(x)` when the first argument is either:\n * 1. an Identifier that is the binding of an enclosing `catch (x)` clause, or\n * matches the conventional error-name pattern /^(e|err|error|ex|exc)$/i, OR\n * 2. a member expression denoting an error value (`err.cause`, `this.lastError`) —\n * an error-suggesting property name, or an error-named base whose property is\n * not a plain string accessor (`.message` / `.stack` / `.name`).\n *\n * It suppresses the report inside the non-error branch of an `x instanceof Error`\n * guard (`x instanceof Error ? x : JSON.stringify(x)`), where stringifying the\n * non-Error fallback is exactly correct.\n *\n * Object literals and arbitrary identifiers (`JSON.stringify(user)`) are not flagged.\n */\n\nimport { ESLintUtils, type TSESTree } from \"@typescript-eslint/utils\";\nimport type { Scope, SourceCode } from \"@typescript-eslint/utils/ts-eslint\";\n\ntype MessageIds = \"noJsonStringifyError\";\ntype Options = readonly [];\n\nconst ERROR_NAME_PATTERN = /^(e|err|error|ex|exc)$/i;\n\n/** Property names whose value is itself an error object (unsafe to stringify). */\nconst ERROR_PROP_PATTERN = /^(cause|lastError|error|err|exception|originalError|innerError)$/i;\n\n/** Property names whose value is a plain string — the recommended escape hatch. */\nconst SAFE_STRING_PROPS: ReadonlySet<string> = new Set([\"message\", \"stack\", \"name\"]);\n\n/**\n * Walk up the scope chain looking for a `catch` clause whose binding matches\n * `name`. We rely on the scope analysis provided by the parser rather than\n * type information, keeping the rule type-free.\n */\nfunction isCatchBinding(scope: Scope.Scope, name: string): boolean {\n let current: Scope.Scope | null = scope;\n while (current) {\n const variable = current.set.get(name);\n if (variable) {\n for (const def of variable.defs) {\n if (def.type === \"CatchClause\") {\n return true;\n }\n }\n }\n current = current.upper;\n }\n return false;\n}\n\n/**\n * True if a member-expression argument (`err.cause`, `this.lastError`) denotes an\n * Error value: an error-suggesting property name, or an error-suggesting base whose\n * property is not a known string accessor (`.message` / `.stack` / `.name`).\n */\nfunction memberSuggestsError(\n member: TSESTree.MemberExpression,\n scope: Scope.Scope,\n): boolean {\n const propName =\n !member.computed && member.property.type === \"Identifier\" ? member.property.name : null;\n\n if (propName !== null && ERROR_PROP_PATTERN.test(propName)) {\n return true;\n }\n\n const base = member.object;\n const baseSuggestsError =\n base.type === \"Identifier\" &&\n (ERROR_NAME_PATTERN.test(base.name) || isCatchBinding(scope, base.name));\n if (baseSuggestsError) {\n return propName === null || !SAFE_STRING_PROPS.has(propName.toLowerCase());\n }\n\n return false;\n}\n\n/** The subject `x` of an `x instanceof Error` test, or null. */\nfunction instanceofErrorSubject(\n test: TSESTree.Expression,\n): TSESTree.Expression | null {\n if (\n test.type === \"BinaryExpression\" &&\n test.operator === \"instanceof\" &&\n test.right.type === \"Identifier\" &&\n test.right.name === \"Error\"\n ) {\n return test.left;\n }\n return null;\n}\n\n/** Names of a user-defined type-guard predicate: `isErrorLike`, `isError`, `hasErrorShape`. */\nconst TYPE_GUARD_PATTERN = /^(is|has)[A-Z]/;\n\n/** The narrowed subject `x` of a user-defined type-guard call `isFoo(x)`, or null. */\nfunction typeGuardSubject(\n test: TSESTree.Expression,\n): TSESTree.Expression | null {\n const arg = test.type === \"CallExpression\" ? test.arguments[0] : undefined;\n if (\n test.type === \"CallExpression\" &&\n test.callee.type === \"Identifier\" &&\n TYPE_GUARD_PATTERN.test(test.callee.name) &&\n test.arguments.length === 1 &&\n arg !== undefined &&\n arg.type !== \"SpreadElement\"\n ) {\n return arg;\n }\n return null;\n}\n\n/**\n * The subject `x` of a positive error-narrowing test — `x instanceof Error` or a\n * user-defined guard `isErrorLike(x)`. In both, the value IS the error in the\n * truthy branch, so `JSON.stringify(x)` belongs in the falsy (alternate) branch.\n */\nfunction positiveErrorSubject(\n test: TSESTree.Expression,\n): TSESTree.Expression | null {\n return instanceofErrorSubject(test) ?? typeGuardSubject(test);\n}\n\n/** The subject `x` of a negated error-narrowing test — `!(x instanceof Error)` / `!isErrorLike(x)`. */\nfunction negatedInstanceofErrorSubject(\n test: TSESTree.Expression,\n): TSESTree.Expression | null {\n if (test.type === \"UnaryExpression\" && test.operator === \"!\") {\n return positiveErrorSubject(test.argument);\n }\n return null;\n}\n\n/** Whether a branch statement unconditionally exits (its last statement returns/throws). */\nfunction branchTerminates(branch: TSESTree.Statement): boolean {\n const body = branch.type === \"BlockStatement\" ? branch.body : [branch];\n const last = body[body.length - 1];\n return (\n last !== undefined &&\n (last.type === \"ReturnStatement\" || last.type === \"ThrowStatement\")\n );\n}\n\n/**\n * True if an earlier guard `if (isErrorLike(arg)) return …` (or `instanceof Error`)\n * in an enclosing block narrows `argExpr` away from the error case before `node`,\n * so by the time `JSON.stringify(arg)` runs the value is the non-Error fallback.\n */\nfunction isNarrowedByEarlyReturn(\n node: TSESTree.Node,\n argExpr: TSESTree.Expression,\n sourceCode: Readonly<SourceCode>,\n): boolean {\n const argText = sourceCode.getText(argExpr);\n let current: TSESTree.Node | undefined = node.parent;\n while (current) {\n if (current.type === \"BlockStatement\" || current.type === \"Program\") {\n for (const stmt of current.body) {\n if (stmt.range[0] >= node.range[0]) {\n break;\n }\n if (\n stmt.type === \"IfStatement\" &&\n stmt.alternate === null &&\n branchTerminates(stmt.consequent)\n ) {\n const subject = positiveErrorSubject(stmt.test);\n if (subject && sourceCode.getText(subject) === argText) {\n return true;\n }\n }\n }\n }\n current = current.parent;\n }\n return false;\n}\n\nfunction nodeWithin(node: TSESTree.Node, container: TSESTree.Node | null): boolean {\n return (\n container !== null &&\n node.range[0] >= container.range[0] &&\n node.range[1] <= container.range[1]\n );\n}\n\n/**\n * True if `node` sits in the NON-error branch of an `argExpr instanceof Error`\n * guard — the branch where `argExpr` is provably not an Error, so stringifying it\n * is the correct fallback. Handles both the ternary and `if`/`else` shapes,\n * including the negated `!(x instanceof Error)` form.\n */\nfunction isGuardedByInstanceofError(\n node: TSESTree.Node,\n argExpr: TSESTree.Expression,\n sourceCode: Readonly<SourceCode>,\n): boolean {\n const argText = sourceCode.getText(argExpr);\n const sameSubject = (subject: TSESTree.Expression): boolean =>\n sourceCode.getText(subject) === argText;\n\n let current: TSESTree.Node | undefined = node.parent;\n while (current) {\n if (current.type === \"ConditionalExpression\") {\n const subject = positiveErrorSubject(current.test);\n if (subject && sameSubject(subject) && nodeWithin(node, current.alternate)) {\n return true;\n }\n const negated = negatedInstanceofErrorSubject(current.test);\n if (negated && sameSubject(negated) && nodeWithin(node, current.consequent)) {\n return true;\n }\n } else if (current.type === \"IfStatement\") {\n const subject = positiveErrorSubject(current.test);\n if (subject && sameSubject(subject) && nodeWithin(node, current.alternate)) {\n return true;\n }\n const negated = negatedInstanceofErrorSubject(current.test);\n if (negated && sameSubject(negated) && nodeWithin(node, current.consequent)) {\n return true;\n }\n }\n current = current.parent;\n }\n return false;\n}\n\nfunction isJsonStringify(callee: TSESTree.Expression): boolean {\n return (\n callee.type === \"MemberExpression\" &&\n !callee.computed &&\n callee.object.type === \"Identifier\" &&\n callee.object.name === \"JSON\" &&\n callee.property.type === \"Identifier\" &&\n callee.property.name === \"stringify\"\n );\n}\n\nexport default ESLintUtils.RuleCreator(\n (name) =>\n `https://github.com/sarj-ai/linting/blob/main/packages/typescript/src/rules/${name}.ts`,\n)<Options, MessageIds>({\n name: \"no-json-stringify-error\",\n meta: {\n type: \"problem\",\n docs: {\n description:\n \"Disallow `JSON.stringify` on an Error value; it yields `{}` because `message`/`stack` are non-enumerable.\",\n },\n schema: [],\n messages: {\n noJsonStringifyError:\n \"`JSON.stringify` on an Error yields `{}` because `message`/`stack` are non-enumerable. Log `err.message` / `err.stack`, or use a proper error serializer.\",\n },\n },\n defaultOptions: [],\n create(context) {\n return {\n CallExpression(node: TSESTree.CallExpression): void {\n if (!isJsonStringify(node.callee)) {\n return;\n }\n\n const firstArg = node.arguments[0];\n if (!firstArg) {\n return;\n }\n\n const scope = context.sourceCode.getScope(firstArg);\n\n let suggestsError: boolean;\n if (firstArg.type === \"Identifier\") {\n suggestsError =\n ERROR_NAME_PATTERN.test(firstArg.name) || isCatchBinding(scope, firstArg.name);\n } else if (firstArg.type === \"MemberExpression\") {\n suggestsError = memberSuggestsError(firstArg, scope);\n } else {\n return;\n }\n\n if (!suggestsError) {\n return;\n }\n\n if (\n isGuardedByInstanceofError(node, firstArg, context.sourceCode) ||\n isNarrowedByEarlyReturn(node, firstArg, context.sourceCode)\n ) {\n return;\n }\n\n context.report({\n node,\n messageId: \"noJsonStringifyError\",\n });\n },\n };\n },\n});\n","/**\n * @fileoverview Disallow `catch` clauses that only log (via `console.*` or a\n * logger receiver such as `logger.warn(...)` / `Log.error(...)`) and then\n * swallow the error. A catch that logs and falls through — with no `throw`, no\n * `return`, and no real recovery — hides failures: the program keeps running in\n * a broken state while the only signal is a log line that is easy to miss.\n * Either rethrow the error or handle it for real.\n *\n * This rule is deliberately conservative and fires in exactly two shapes:\n * - `noLogOnlyCatch`: the catch body is non-empty and *every* statement is a\n * logging call (`console.*` or a call on a logger-named receiver). Any other\n * statement (a `throw`, a `return`, a fallback assignment, a non-logging\n * call, etc.) means the catch is doing something and is left alone.\n * - `emptyCatch`: the catch body is genuinely empty AND carries no comment.\n * A comment-only catch (`catch { /* ignore, safe because … *\\/ }`) is treated\n * as an intentional, documented ignore and is exempt.\n *\n * A previous version fired the \"logging then swallowing\" message on empty and\n * comment-only catches that contained no logging call at all — the vast majority\n * of real-world hits — which was factually wrong. The two distinct message ids\n * keep each diagnostic accurate.\n *\n * Test files opt out by default (filenames containing `.test.`, `.spec.`, or a\n * `__tests__/` path segment) since swallow-and-log is common and acceptable in\n * test scaffolding.\n */\n\nimport { ESLintUtils, type TSESTree } from \"@typescript-eslint/utils\";\n\nimport { isLoggingCall } from \"./_logging.js\";\n\ntype MessageIds = \"noLogOnlyCatch\" | \"emptyCatch\";\ntype Options = readonly [];\n\nconst DEFAULT_IGNORE_PATTERNS: readonly RegExp[] = [\n /\\.test\\./,\n /\\.spec\\./,\n /[\\\\/]__tests__[\\\\/]/,\n];\n\n/** True when a statement is exactly a bare logging call, e.g. `console.error(err);` or `logger.warn(err);`. */\nfunction isLoggingCallStatement(statement: TSESTree.Statement): boolean {\n if (statement.type !== \"ExpressionStatement\") {\n return false;\n }\n return isLoggingCall(statement.expression);\n}\n\nexport default ESLintUtils.RuleCreator(\n (name) =>\n `https://github.com/sarj-ai/linting/blob/main/packages/typescript/src/rules/${name}.ts`,\n)<Options, MessageIds>({\n name: \"no-log-only-catch\",\n meta: {\n type: \"problem\",\n docs: {\n description:\n \"Disallow `catch` clauses that only log (or silently do nothing) and then swallow the error; rethrow or handle it instead.\",\n },\n schema: [],\n messages: {\n noLogOnlyCatch:\n \"Logging then swallowing the error hides failures. Rethrow the error or handle it for real.\",\n emptyCatch:\n \"Empty catch silently swallows the error. Rethrow it, handle it, or add a comment explaining why it is safe to ignore.\",\n },\n },\n defaultOptions: [],\n create(context) {\n const filename = context.filename;\n\n const isIgnoredByDefault = DEFAULT_IGNORE_PATTERNS.some((re) =>\n re.test(filename),\n );\n\n if (isIgnoredByDefault) {\n return {};\n }\n\n return {\n CatchClause(node: TSESTree.CatchClause): void {\n const statements = node.body.body;\n\n if (statements.length === 0) {\n // A comment inside the block documents an intentional ignore; only a\n // truly empty catch is an unexplained silent swallow.\n if (context.sourceCode.getCommentsInside(node.body).length > 0) {\n return;\n }\n context.report({ node, messageId: \"emptyCatch\" });\n return;\n }\n\n const everyStatementIsLogging = statements.every((statement) =>\n isLoggingCallStatement(statement),\n );\n\n if (everyStatementIsLogging) {\n context.report({ node, messageId: \"noLogOnlyCatch\" });\n }\n },\n };\n },\n});\n","/**\n * @fileoverview Shared helpers for recognising logging / error-reporting calls.\n * Used by `no-log-only-catch` and `no-sentinel-return-on-catch` so both rules\n * agree on what counts as \"the error was logged/reported\" before deciding a\n * catch silently swallows it. The logger-name and log-method sets mirror\n * `no-secret-in-log.ts`.\n */\n\nimport { type TSESTree } from \"@typescript-eslint/utils\";\n\nexport const LOG_METHODS: ReadonlySet<string> = new Set([\n \"debug\",\n \"info\",\n \"warn\",\n \"warning\",\n \"error\",\n \"exception\",\n \"critical\",\n \"trace\",\n \"log\",\n \"fatal\",\n \"success\",\n]);\n\nexport const LOGGER_NAMES: ReadonlySet<string> = new Set([\n \"logger\",\n \"log\",\n \"logging\",\n \"loguru\",\n \"console\",\n \"_logger\",\n \"_log\",\n]);\n\n/**\n * Names of free functions / methods that report an error to a handler or sink,\n * e.g. `onUnexpectedError`, `reportError`, `captureException`, `logError`. Kept\n * broad on purpose: pairing this with \"takes the caught binding\" is what makes\n * it precise.\n */\nexport const REPORT_NAME_RE = /error|report|capture|log|trace|warn/i;\n\n/**\n * True when `expr` resolves to a logger receiver — a bare logger identifier\n * (`logger`, `log`, `console`, `Log`) or a member chain ending in one\n * (`this.logger`, `svc.log`).\n */\nexport function isLoggerReceiver(\n expr: TSESTree.Expression | TSESTree.PrivateIdentifier,\n): boolean {\n switch (expr.type) {\n case \"Identifier\":\n return LOGGER_NAMES.has(expr.name.toLowerCase());\n case \"MemberExpression\": {\n const { property, object } = expr;\n if (\n !expr.computed &&\n property.type === \"Identifier\" &&\n LOGGER_NAMES.has(property.name.toLowerCase())\n ) {\n return true;\n }\n return isLoggerReceiver(object);\n }\n default:\n return false;\n }\n}\n\n/**\n * True when `expr` is a logging call: `console.error(...)`, `logger.warn(...)`,\n * `Log.error(...)`, `this.logger.info(...)`, etc. Requires a non-computed log\n * method on a logger receiver.\n */\nexport function isLoggingCall(expr: TSESTree.Expression): boolean {\n if (expr.type !== \"CallExpression\") {\n return false;\n }\n const callee = expr.callee;\n if (\n callee.type !== \"MemberExpression\" ||\n callee.computed ||\n callee.property.type !== \"Identifier\"\n ) {\n return false;\n }\n if (!LOG_METHODS.has(callee.property.name.toLowerCase())) {\n return false;\n }\n return isLoggerReceiver(callee.object);\n}\n\n/** The static callee name of a call (free function or method), or null. */\nexport function calleeName(callee: TSESTree.Node): string | null {\n if (callee.type === \"Identifier\") {\n return callee.name;\n }\n if (\n callee.type === \"MemberExpression\" &&\n !callee.computed &&\n callee.property.type === \"Identifier\"\n ) {\n return callee.property.name;\n }\n return null;\n}\n","/**\n * @fileoverview Disallow direct `process.env` access. Force all env reads\n * through a Zod-validated env module so configuration is typed and validated\n * at startup.\n */\n\nimport { ESLintUtils, type TSESTree } from \"@typescript-eslint/utils\";\n\ntype MessageIds = \"noRawEnv\";\ntype Options = readonly [];\n\n/** True for the `process.env` member node (dotted or as the base of `process.env[key]`). */\nfunction isProcessEnv(node: TSESTree.MemberExpression): boolean {\n return (\n !node.computed &&\n node.object.type === \"Identifier\" &&\n node.object.name === \"process\" &&\n node.property.type === \"Identifier\" &&\n node.property.name === \"env\"\n );\n}\n\n/** True for the `import.meta.env` member node (dotted or as the base of `import.meta.env[key]`). */\nfunction isImportMetaEnv(node: TSESTree.MemberExpression): boolean {\n return (\n !node.computed &&\n node.property.type === \"Identifier\" &&\n node.property.name === \"env\" &&\n node.object.type === \"MetaProperty\" &&\n node.object.meta.name === \"import\" &&\n node.object.property.name === \"meta\"\n );\n}\n\n// Build-time constants that bundlers (webpack/Vite) statically replace — there is\n// no runtime env value to route through the validated layer, so they are exempt.\nconst BUILD_TIME_CONSTANTS: ReadonlySet<string> = new Set([\n \"NODE_ENV\",\n \"MODE\",\n \"DEV\",\n \"PROD\",\n \"SSR\",\n]);\n\n/** True when `node` is the base of a build-time-constant access like `process.env.NODE_ENV`. */\nfunction isBuildTimeConstantAccess(node: TSESTree.MemberExpression): boolean {\n const parent = node.parent;\n return (\n parent.type === \"MemberExpression\" &&\n parent.object === node &&\n !parent.computed &&\n parent.property.type === \"Identifier\" &&\n BUILD_TIME_CONSTANTS.has(parent.property.name)\n );\n}\n\nexport default ESLintUtils.RuleCreator(\n (name) =>\n `https://github.com/sarj-ai/linting/blob/main/packages/typescript/src/rules/${name}.ts`,\n)<Options, MessageIds>({\n name: \"no-raw-env\",\n meta: {\n type: \"problem\",\n docs: {\n description:\n \"Disallow direct `process.env` access; use a Zod-validated env module instead.\",\n },\n schema: [],\n messages: {\n noRawEnv:\n \"Do not read from `process.env` directly. Import the Zod-validated env module instead so values are typed and validated at startup.\",\n },\n },\n defaultOptions: [],\n create(context) {\n return {\n MemberExpression(node: TSESTree.MemberExpression): void {\n if (\n (isProcessEnv(node) || isImportMetaEnv(node)) &&\n !isBuildTimeConstantAccess(node)\n ) {\n context.report({\n node,\n messageId: \"noRawEnv\",\n });\n }\n },\n };\n },\n});\n","/**\n * @fileoverview Disallow silently swallowing an error in a `catch` clause by\n * returning a \"sentinel\" empty value as the final/only statement.\n *\n * A `catch` block whose last statement is `return null` / `return undefined` /\n * `return false` / `return []` / `return {}` (and which never `throw`s) discards\n * the caught error entirely. Downstream callers can't distinguish a genuine\n * empty result from a failure, which is a frequent source of silent data loss\n * and broken idempotency decisions.\n *\n * This rule is deliberately conservative — it prefers false negatives over\n * false positives. It does NOT flag:\n * - catch blocks that `throw`/rethrow anywhere in their body,\n * - returns of a computed/meaningful value (calls, identifiers, member\n * expressions, non-empty literals),\n * - `return 0` / `return \"\"`, which are often legitimate results,\n * - catches that LOG or REPORT the caught error before the sentinel return —\n * a `console.*`/logger call, or an error-reporting call that takes the\n * caught binding (`onUnexpectedError(err)`). Here the sentinel is a\n * deliberate degraded return, not a silent swallow.\n * - the typed-optional / safe-parse / predicate shape: the try body returns a\n * parse-style call that throws on bad input (`JSON.parse(x)`, `new RegExp`),\n * or the enclosing function returns the same sentinel kind on a normal path\n * (a boolean predicate, a `T | undefined` accessor). Here the sentinel is\n * the declared contract.\n */\n\nimport {\n ESLintUtils,\n type TSESTree,\n AST_NODE_TYPES,\n} from \"@typescript-eslint/utils\";\n\nimport {\n isLoggingCall,\n calleeName,\n REPORT_NAME_RE,\n} from \"./_logging.js\";\n\ntype MessageIds = \"noSentinelReturn\";\ntype Options = readonly [];\n\ntype SentinelKind = \"nullish\" | \"boolean\" | \"array\" | \"object\" | \"string\";\n\n/** The sentinel \"kind\" of a returned expression, or null if not a sentinel. */\nfunction sentinelKind(arg: TSESTree.Expression | null): SentinelKind | null {\n if (arg === null) {\n return null;\n }\n if (arg.type === AST_NODE_TYPES.Literal) {\n if (arg.value === null) {\n return \"nullish\";\n }\n if (typeof arg.value === \"boolean\") {\n return \"boolean\";\n }\n if (typeof arg.value === \"string\") {\n return \"string\";\n }\n return null;\n }\n if (arg.type === AST_NODE_TYPES.Identifier && arg.name === \"undefined\") {\n return \"nullish\";\n }\n if (arg.type === AST_NODE_TYPES.ArrayExpression) {\n return \"array\";\n }\n if (arg.type === AST_NODE_TYPES.ObjectExpression) {\n return \"object\";\n }\n return null;\n}\n\n/** Whether a returned expression is one of the swallowing sentinels we flag. */\nfunction isSentinelArgument(arg: TSESTree.Expression | null): boolean {\n if (arg === null) {\n return false;\n }\n if (arg.type === AST_NODE_TYPES.Literal && arg.value === null) {\n return true;\n }\n if (arg.type === AST_NODE_TYPES.Literal && arg.value === false) {\n return true;\n }\n if (arg.type === AST_NODE_TYPES.Identifier && arg.name === \"undefined\") {\n return true;\n }\n if (arg.type === AST_NODE_TYPES.ArrayExpression && arg.elements.length === 0) {\n return true;\n }\n if (\n arg.type === AST_NODE_TYPES.ObjectExpression &&\n arg.properties.length === 0\n ) {\n return true;\n }\n return false;\n}\n\nfunction isFunctionNode(node: TSESTree.Node): boolean {\n return (\n node.type === AST_NODE_TYPES.FunctionDeclaration ||\n node.type === AST_NODE_TYPES.FunctionExpression ||\n node.type === AST_NODE_TYPES.ArrowFunctionExpression\n );\n}\n\nfunction isNode(value: unknown): value is TSESTree.Node {\n return (\n typeof value === \"object\" &&\n value !== null &&\n typeof (value as { type?: unknown }).type === \"string\"\n );\n}\n\n/**\n * Walk `node`'s subtree applying `visit`, but do not descend into nested\n * function scopes — their statements don't run synchronously for the current\n * catch. Stops early once `visit` returns true.\n */\nfunction walkWithinScope(\n node: TSESTree.Node,\n visit: (current: TSESTree.Node) => boolean,\n): boolean {\n let found = false;\n\n const recurse = (current: TSESTree.Node): void => {\n if (found) {\n return;\n }\n if (visit(current)) {\n found = true;\n return;\n }\n if (isFunctionNode(current)) {\n return;\n }\n for (const key of Object.keys(current)) {\n if (key === \"parent\") {\n continue;\n }\n const value = (current as unknown as Record<string, unknown>)[key];\n if (Array.isArray(value)) {\n for (const child of value) {\n if (isNode(child)) {\n recurse(child);\n }\n }\n } else if (isNode(value)) {\n recurse(value);\n }\n }\n };\n\n recurse(node);\n return found;\n}\n\n/** Does this subtree throw (ignoring nested function scopes)? */\nfunction containsThrow(node: TSESTree.Node): boolean {\n return walkWithinScope(\n node,\n (current) => current.type === AST_NODE_TYPES.ThrowStatement,\n );\n}\n\n/** Are any of a call's arguments exactly the caught-error binding identifier? */\nfunction argsIncludeBinding(\n args: readonly TSESTree.CallExpressionArgument[],\n caughtName: string | null,\n): boolean {\n if (caughtName === null) {\n return false;\n }\n return args.some(\n (arg) => arg.type === AST_NODE_TYPES.Identifier && arg.name === caughtName,\n );\n}\n\n/**\n * Does the catch body log or report the caught error before the sentinel\n * return? Either a logging call (`console.*` / logger receiver), or an\n * error-reporting call whose name matches `REPORT_NAME_RE` and that takes the\n * caught binding (`onUnexpectedError(err)`).\n */\nfunction logsOrReportsError(\n catchBody: TSESTree.BlockStatement,\n caughtName: string | null,\n): boolean {\n return walkWithinScope(catchBody, (current) => {\n if (current.type !== AST_NODE_TYPES.CallExpression) {\n return false;\n }\n if (isLoggingCall(current)) {\n return true;\n }\n const name = calleeName(current.callee);\n return (\n name !== null &&\n REPORT_NAME_RE.test(name) &&\n argsIncludeBinding(current.arguments, caughtName)\n );\n });\n}\n\n/** The try block guarded by this catch. */\nfunction tryBlockOf(catchNode: TSESTree.CatchClause): TSESTree.BlockStatement {\n return catchNode.parent.block;\n}\n\n/**\n * True when a return argument is a parse-style call that throws on bad input,\n * so returning a sentinel on failure is the declared \"safe-parse\" contract:\n * `JSON.parse(x)`, `YAML.parse(x)`, `new RegExp(x)`, `new URL(x)`.\n */\nfunction isSafeParseExpression(arg: TSESTree.Expression | null): boolean {\n if (arg === null) {\n return false;\n }\n if (\n arg.type === AST_NODE_TYPES.CallExpression &&\n arg.callee.type === AST_NODE_TYPES.MemberExpression &&\n !arg.callee.computed &&\n arg.callee.property.type === AST_NODE_TYPES.Identifier &&\n arg.callee.property.name === \"parse\"\n ) {\n return true;\n }\n if (\n arg.type === AST_NODE_TYPES.NewExpression &&\n arg.callee.type === AST_NODE_TYPES.Identifier\n ) {\n return arg.callee.name === \"RegExp\" || arg.callee.name === \"URL\";\n }\n return false;\n}\n\n/** Does the try body return a safe-parse-style expression? */\nfunction tryReturnsSafeParse(catchNode: TSESTree.CatchClause): boolean {\n return walkWithinScope(\n tryBlockOf(catchNode),\n (current) =>\n current.type === AST_NODE_TYPES.ReturnStatement &&\n isSafeParseExpression(current.argument),\n );\n}\n\n/** The nearest enclosing function body, or null. */\nfunction enclosingFunctionBody(\n node: TSESTree.Node,\n): TSESTree.BlockStatement | null {\n let current: TSESTree.Node | undefined | null = node.parent;\n while (current !== undefined && current !== null) {\n if (\n isFunctionNode(current) &&\n \"body\" in current &&\n isNode(current.body) &&\n current.body.type === AST_NODE_TYPES.BlockStatement\n ) {\n return current.body;\n }\n current = current.parent;\n }\n return null;\n}\n\n/**\n * True when the enclosing function returns the same sentinel kind on a normal\n * (non-catch) path — a boolean predicate, a `T | undefined` accessor, etc. —\n * so the catch sentinel is the declared contract, not a swallow. Returns inside\n * the flagged catch itself are excluded.\n */\nfunction functionReturnsSameSentinelKindElsewhere(\n catchNode: TSESTree.CatchClause,\n kind: SentinelKind,\n): boolean {\n const functionBody = enclosingFunctionBody(catchNode);\n if (functionBody === null) {\n return false;\n }\n return walkWithinScope(functionBody, (current) => {\n if (current.type !== AST_NODE_TYPES.ReturnStatement) {\n return false;\n }\n if (isWithin(current, catchNode.body)) {\n return false;\n }\n return sentinelKind(current.argument) === kind;\n });\n}\n\n/** Is `node` inside `ancestor`'s subtree? */\nfunction isWithin(node: TSESTree.Node, ancestor: TSESTree.Node): boolean {\n let current: TSESTree.Node | undefined | null = node;\n while (current !== undefined && current !== null) {\n if (current === ancestor) {\n return true;\n }\n current = current.parent;\n }\n return false;\n}\n\nexport default ESLintUtils.RuleCreator(\n (name) =>\n `https://github.com/sarj-ai/linting/blob/main/packages/typescript/src/rules/${name}.ts`,\n)<Options, MessageIds>({\n name: \"no-sentinel-return-on-catch\",\n meta: {\n type: \"problem\",\n docs: {\n description:\n \"Disallow swallowing a caught error by returning an empty sentinel (`null`, `undefined`, `false`, `[]`, `{}`) as the final statement of a `catch` block, unless the error is logged/reported or the sentinel is the declared safe-parse/predicate contract.\",\n },\n schema: [],\n messages: {\n noSentinelReturn:\n \"This `catch` block swallows the error by returning an empty sentinel without logging it. Rethrow it, log/report it, or return a typed Result.\",\n },\n },\n defaultOptions: [],\n create(context) {\n return {\n CatchClause(node: TSESTree.CatchClause): void {\n const body = node.body.body;\n if (body.length === 0) {\n return;\n }\n\n const last = body[body.length - 1];\n if (last === undefined || last.type !== AST_NODE_TYPES.ReturnStatement) {\n return;\n }\n\n if (!isSentinelArgument(last.argument)) {\n return;\n }\n\n if (containsThrow(node.body)) {\n return;\n }\n\n const caughtName =\n node.param?.type === AST_NODE_TYPES.Identifier\n ? node.param.name\n : null;\n\n if (logsOrReportsError(node.body, caughtName)) {\n return;\n }\n\n if (tryReturnsSafeParse(node)) {\n return;\n }\n\n const kind = sentinelKind(last.argument);\n if (\n kind !== null &&\n functionReturnsSameSentinelKindElsewhere(node, kind)\n ) {\n return;\n }\n\n context.report({\n node: last,\n messageId: \"noSentinelReturn\",\n });\n },\n };\n },\n});\n","/**\n * @fileoverview Disallow `await` expressions located directly inside the body\n * of a `for` / `for-of` / `for-in` / `while` loop (or an async `.forEach` /\n * `.map` / `.filter` callback) within the same function scope. Awaiting serially\n * inside a loop serializes I/O that is often better expressed as\n * `await Promise.all(xs.map(async (x) => ...))`, letting the operations run\n * concurrently.\n *\n * This rule is intentionally conservative — it prefers a false negative over a\n * false positive:\n * - `for await...of` is NOT flagged (async iteration is the correct tool).\n * - awaits inside a function/arrow defined within the loop are NOT flagged\n * (they belong to a different function scope).\n * - awaits not inside any loop are NOT flagged.\n *\n * Real-world sweeps (VS Code, NestJS, Next.js) surfaced whole classes of loops\n * where serial awaits are REQUIRED and `Promise.all` would change semantics.\n * Those are suppressed here:\n * (a) the loop short-circuits or retries — its body (this scope) contains a\n * `return` / `break` / `continue`;\n * (b) the awaited value threads through the iteration — `x = await f(x)`,\n * `content = await p(content)` (the assignment target is read inside the\n * awaited expression);\n * (c) the await is a timer yield — `await new Promise((r) => setTimeout(r))`;\n * (d) the iterable's name/derivation signals ordering — `*Sorted*`,\n * `.reverse()`, lifecycle `hooks`, pipeline `stages`, etc.\n * The genuinely parallelizable shape — independent awaits whose results are\n * collected or discarded without a cross-iteration dependency or early exit —\n * still fires.\n *\n * At most one report is emitted per offending loop / callback.\n */\n\nimport { ESLintUtils, type TSESTree } from \"@typescript-eslint/utils\";\n\ntype MessageIds = \"noSequentialAwait\";\ntype Options = readonly [];\n\n/**\n * Array iteration methods whose async callback with an `await` inside is the\n * classic serial-await footgun (`.forEach` ignores the returned promise\n * entirely; a discarded `.map` / `.filter` floats its promises).\n */\nconst ARRAY_ITERATION_METHODS = new Set<string>([\"forEach\", \"map\", \"filter\"]);\n\n/**\n * Text on the iterable (its identifier name or derivation) that signals an\n * ORDERED sequence whose elements must be processed one-after-another —\n * lifecycle hooks, sorted / reversed lists, pipeline stages. Awaiting serially\n * over such a sequence is the contract, so the report is suppressed. Broad by\n * design: the rule prefers a false negative to a false positive.\n */\nconst SEQUENTIAL_ITERABLE_HINT =\n /sort|reverse|ordered|sequence|hook|middleware|pipeline|\\bstage|\\bstep|\\bphase|migration|chain|buffer|stream|teleport|chunk|\\bqueue|drain/i;\n\n/**\n * Node types that introduce a new function scope. We never descend across one\n * of these when looking for awaits belonging to a loop, because an `await`\n * inside a nested function/arrow is awaited by *that* function, not by the loop.\n */\nfunction isFunctionLike(node: TSESTree.Node): boolean {\n return (\n node.type === \"FunctionDeclaration\" ||\n node.type === \"FunctionExpression\" ||\n node.type === \"ArrowFunctionExpression\"\n );\n}\n\ntype LoopNode =\n | TSESTree.ForStatement\n | TSESTree.ForOfStatement\n | TSESTree.ForInStatement\n | TSESTree.WhileStatement\n | TSESTree.DoWhileStatement;\n\n/**\n * Statement node types that introduce a nested loop. When scanning a loop's\n * body we must NOT descend into another loop — that inner loop's awaits belong\n * to it and are reported when the inner loop is visited. This keeps reporting\n * at one-per-loop and avoids double-flagging an outer loop for an await that\n * only appears inside a nested loop.\n */\nfunction isLoop(node: TSESTree.Node): boolean {\n return (\n node.type === \"ForStatement\" ||\n node.type === \"ForOfStatement\" ||\n node.type === \"ForInStatement\" ||\n node.type === \"WhileStatement\" ||\n node.type === \"DoWhileStatement\"\n );\n}\n\nfunction isNode(value: unknown): value is TSESTree.Node {\n return (\n typeof value === \"object\" &&\n value !== null &&\n typeof (value as { type?: unknown }).type === \"string\"\n );\n}\n\n/**\n * Visits `root` and its descendants, calling `visit` on each, without crossing\n * into a nested function scope or descending into a nested loop — the same\n * ownership boundaries the rule uses to decide which awaits belong to a loop.\n */\nfunction visitScope(\n root: TSESTree.Node,\n visit: (node: TSESTree.Node) => void,\n): void {\n visit(root);\n for (const key of Object.keys(root) as (keyof TSESTree.Node)[]) {\n if (key === \"parent\") {\n continue;\n }\n const value = root[key];\n const children = Array.isArray(value) ? value : [value];\n for (const child of children) {\n if (isNode(child) && !isFunctionLike(child) && !isLoop(child)) {\n visitScope(child, visit);\n }\n }\n }\n}\n\nfunction collectAwaits(root: TSESTree.Node): TSESTree.AwaitExpression[] {\n const awaits: TSESTree.AwaitExpression[] = [];\n visitScope(root, (node) => {\n if (node.type === \"AwaitExpression\") {\n awaits.push(node);\n }\n });\n return awaits;\n}\n\n/**\n * Guard (a): the scope contains a `return` / `break` / `continue`, marking a\n * retry / short-circuit / early-exit loop whose serial awaits are intentional.\n */\nfunction hasEarlyExit(root: TSESTree.Node): boolean {\n let found = false;\n visitScope(root, (node) => {\n if (\n node.type === \"ReturnStatement\" ||\n node.type === \"BreakStatement\" ||\n node.type === \"ContinueStatement\"\n ) {\n found = true;\n }\n });\n return found;\n}\n\n/**\n * Guard (c): `await new Promise(...)` — a deliberate event-loop / timer yield,\n * not parallelizable I/O.\n */\nconst TIMER_HELPER_RE = /^(sleep|timeout|delay|wait|pause|tick)$/i;\n\nfunction calleeName(callee: TSESTree.Node): string | null {\n if (callee.type === \"Identifier\") return callee.name;\n if (\n callee.type === \"MemberExpression\" &&\n !callee.computed &&\n callee.property.type === \"Identifier\"\n ) {\n return callee.property.name;\n }\n return null;\n}\n\nfunction isTimerYield(node: TSESTree.AwaitExpression): boolean {\n const arg = node.argument;\n // `await new Promise((r) => setTimeout(r))` — the canonical event-loop yield.\n if (\n arg.type === \"NewExpression\" &&\n arg.callee.type === \"Identifier\" &&\n arg.callee.name === \"Promise\"\n ) {\n return true;\n }\n // `await sleep(ms)` / `await delay()` / `await this.wait()` — a poll/throttle\n // yield in a `while` loop, deliberately serial.\n if (arg.type === \"CallExpression\") {\n const name = calleeName(arg.callee);\n return name !== null && TIMER_HELPER_RE.test(name);\n }\n return false;\n}\n\nconst QUEUE_DRAIN_METHODS = /^(shift|pop|dequeue|next|poll)$/;\n\n/**\n * Guard: `await queue.shift()` / `await this.stack.pop()` — draining a mutable\n * receiver one element at a time. Each call consumes the shared queue, so the\n * iterations are order-dependent and cannot be parallelized.\n */\nfunction isQueueDrain(node: TSESTree.AwaitExpression): boolean {\n const arg = node.argument;\n return (\n arg.type === \"CallExpression\" &&\n arg.callee.type === \"MemberExpression\" &&\n !arg.callee.computed &&\n arg.callee.property.type === \"Identifier\" &&\n QUEUE_DRAIN_METHODS.test(arg.callee.property.name)\n );\n}\n\nfunction referencesName(root: TSESTree.Node, name: string): boolean {\n let found = false;\n visitScope(root, (node) => {\n if (node.type === \"Identifier\" && node.name === name) {\n found = true;\n }\n });\n return found;\n}\n\n/**\n * Guard (b): the awaited value is threaded into the next iteration — the await\n * is the RHS of `target = await ...` / `const target = await ...` and `target`\n * is read inside the awaited expression (`x = await f(x)`,\n * `content = await p(content)`). Parallelizing would break the data dependency.\n */\nfunction isThreadedAccumulator(node: TSESTree.AwaitExpression): boolean {\n const parent = node.parent;\n let target: string | null = null;\n if (\n parent.type === \"AssignmentExpression\" &&\n parent.operator === \"=\" &&\n parent.right === node &&\n parent.left.type === \"Identifier\"\n ) {\n target = parent.left.name;\n } else if (\n parent.type === \"VariableDeclarator\" &&\n parent.init === node &&\n parent.id.type === \"Identifier\"\n ) {\n target = parent.id.name;\n }\n if (target === null) {\n return false;\n }\n return referencesName(node.argument, target);\n}\n\n/**\n * Decides whether a set of awaits owned by a loop/callback is worth reporting.\n * Suppressed when the loop short-circuits (a) or iterates an ordered sequence\n * (d); otherwise reported if AT LEAST ONE await is genuinely parallelizable —\n * i.e. not a timer yield (c) and not a threaded accumulator (b).\n */\nfunction shouldReport(\n awaits: readonly TSESTree.AwaitExpression[],\n earlyExit: boolean,\n iterableText: string | null,\n): boolean {\n if (awaits.length === 0) {\n return false;\n }\n if (earlyExit) {\n return false;\n }\n if (iterableText !== null && SEQUENTIAL_ITERABLE_HINT.test(iterableText)) {\n return false;\n }\n return awaits.some(\n (node) =>\n !isTimerYield(node) &&\n !isThreadedAccumulator(node) &&\n !isQueueDrain(node),\n );\n}\n\nexport default ESLintUtils.RuleCreator(\n (name) =>\n `https://github.com/sarj-ai/linting/blob/main/packages/typescript/src/rules/${name}.ts`,\n)<Options, MessageIds>({\n name: \"no-sequential-await\",\n meta: {\n type: \"problem\",\n docs: {\n description:\n \"Disallow serial `await` inside a loop; use `await Promise.all(...)` to run the operations concurrently.\",\n },\n schema: [],\n messages: {\n noSequentialAwait:\n \"Avoid `await` inside a loop — it serializes I/O. Collect the promises and `await Promise.all(xs.map(async (x) => ...))` instead.\",\n },\n },\n defaultOptions: [],\n create(context) {\n /**\n * The parts of a loop where an await \"belonging to this loop\" can live: the\n * body, plus the C-style `for` init/test/update or the for-of/for-in\n * iterable or the while/do-while test. A part that is itself a nested loop\n * is owned by that loop and checked when it is visited.\n */\n function loopParts(node: LoopNode): (TSESTree.Node | null)[] {\n // Only parts that run PER ITERATION can serialize awaits. The C-`for`\n // init and the for-of/for-in iterable are evaluated ONCE, so an `await`\n // there (`for (const x of await Promise.allSettled(...))`) is a single\n // await, not a loop-serialized one — exclude them.\n if (node.type === \"ForStatement\") {\n return [node.body, node.test, node.update];\n }\n if (node.type === \"ForOfStatement\" || node.type === \"ForInStatement\") {\n return [node.body];\n }\n return [node.body, node.test];\n }\n\n function iterableTextOf(node: LoopNode): string | null {\n if (node.type === \"ForOfStatement\" || node.type === \"ForInStatement\") {\n return context.sourceCode.getText(node.right);\n }\n return null;\n }\n\n function checkLoop(node: LoopNode): void {\n const awaits: TSESTree.AwaitExpression[] = [];\n let earlyExit = false;\n for (const part of loopParts(node)) {\n if (part === null || isLoop(part)) {\n continue;\n }\n awaits.push(...collectAwaits(part));\n if (!earlyExit && hasEarlyExit(part)) {\n earlyExit = true;\n }\n }\n if (shouldReport(awaits, earlyExit, iterableTextOf(node))) {\n context.report({ node, messageId: \"noSequentialAwait\" });\n }\n }\n\n return {\n ForStatement: checkLoop,\n ForInStatement: checkLoop,\n WhileStatement: checkLoop,\n DoWhileStatement: checkLoop,\n ForOfStatement(node: TSESTree.ForOfStatement): void {\n // `for await...of` is correct async iteration — never flag it.\n if (node.await) {\n return;\n }\n checkLoop(node);\n },\n CallExpression(node: TSESTree.CallExpression): void {\n const callee = node.callee;\n if (callee.type !== \"MemberExpression\" || callee.computed) {\n return;\n }\n if (\n callee.property.type !== \"Identifier\" ||\n !ARRAY_ITERATION_METHODS.has(callee.property.name)\n ) {\n return;\n }\n const callback = node.arguments[0];\n if (\n callback === undefined ||\n !isFunctionLike(callback) ||\n !(\"async\" in callback && callback.async)\n ) {\n return;\n }\n // A discarded `.map` / `.filter` (statement position) floats its\n // promises just like `.forEach`; when its result is kept\n // (`Promise.all(...)`, an assignment, a `return`) the awaits are\n // consumed correctly, so only flag `.forEach` or a bare-statement call.\n if (\n callee.property.name !== \"forEach\" &&\n node.parent.type !== \"ExpressionStatement\"\n ) {\n return;\n }\n const awaits = collectAwaits(callback.body);\n const earlyExit = hasEarlyExit(callback.body);\n const iterableText = context.sourceCode.getText(callee.object);\n if (shouldReport(awaits, earlyExit, iterableText)) {\n context.report({ node, messageId: \"noSequentialAwait\" });\n }\n },\n };\n },\n});\n","/**\n * @fileoverview Disallow string accumulation via `+=` inside a loop, which is\n * the classic O(n^2) string-building antipattern: each `+=` rebuilds the whole\n * string. Push the parts onto an array and `arr.join(\"\")` after the loop\n * instead.\n *\n * This is a purely SYNTACTIC rule — it uses scope analysis (not the type\n * service) to confirm the left-hand side was declared with a string-literal\n * initializer (`let s = \"\"`, `= \"...\"`, or a template literal). It is\n * deliberately conservative: when the initializer type cannot be determined\n * (no initializer, a non-literal expression, a parameter, etc.) the `+=` is\n * NOT flagged. This mirrors the Python rule SARJ002.\n *\n * Both the compound `s += x` and the equivalent longhand `s = s + x` (a plain\n * `=` assignment whose RHS is a `+` `BinaryExpression` with the target as one\n * operand) are detected — they have identical O(n^2) behavior. A plain\n * `s = x + y` (target absent from the RHS) is NOT flagged.\n */\n\nimport { ESLintUtils, type TSESTree } from \"@typescript-eslint/utils\";\nimport type { Scope } from \"@typescript-eslint/utils/ts-eslint\";\n\ntype MessageIds = \"noStringConcatInLoop\";\ntype Options = readonly [];\n\nconst LOOP_NODE_TYPES = new Set<string>([\n \"ForStatement\",\n \"ForOfStatement\",\n \"ForInStatement\",\n \"WhileStatement\",\n \"DoWhileStatement\",\n]);\n\n/**\n * Returns true if the given expression node is a string-producing literal:\n * a string `Literal` (`\"\"`, `\"...\"`, `'...'`) or a `TemplateLiteral`.\n */\nfunction isStringLiteralInit(node: TSESTree.Expression | null): boolean {\n if (node === null) {\n return false;\n }\n if (node.type === \"TemplateLiteral\") {\n return true;\n }\n if (node.type === \"Literal\") {\n return typeof node.value === \"string\";\n }\n return false;\n}\n\n/**\n * Walk the chain of enclosing scopes to find the variable definition for the\n * given identifier name. Returns the resolved `Variable`, or `undefined` if it\n * cannot be found (e.g. an undeclared global or an out-of-scope reference).\n */\nfunction findVariable(\n scope: Scope.Scope,\n name: string,\n): Scope.Variable | undefined {\n let current: Scope.Scope | null = scope;\n while (current !== null) {\n const variable = current.variables.find((v) => v.name === name);\n if (variable !== undefined) {\n return variable;\n }\n current = current.upper;\n }\n return undefined;\n}\n\n/**\n * Returns true if the variable was declared with a string-literal initializer.\n * Conservative: if the variable has no single string-initialized declarator\n * (no init, non-literal init, multiple conflicting declarators), returns false.\n */\nfunction isStringInitializedVariable(variable: Scope.Variable): boolean {\n // A variable can technically have multiple declarators (e.g. via `var`\n // hoisting / redeclaration). Only treat it as string-initialized when there\n // is exactly one declarator and it has a string-literal initializer.\n if (variable.defs.length !== 1) {\n return false;\n }\n const def = variable.defs[0];\n if (def === undefined || def.type !== \"Variable\") {\n // Parameters, function names, imports, etc. — type unknown, don't flag.\n return false;\n }\n const declarator = def.node;\n if (declarator.type !== \"VariableDeclarator\") {\n return false;\n }\n return isStringLiteralInit(declarator.init);\n}\n\n/**\n * Returns true if `target` appears as a direct operand of a `+` expression\n * (following left-associative `+` chains, e.g. `s + a + b`). Used to recognize\n * the longhand `s = s + <...>` reassignment, which has the same O(n^2) cost as\n * `s += <...>`. A non-`+` operand (`foo.s`, `s.slice()`, `x + y`) does not match.\n */\nfunction isConcatOperand(\n node: TSESTree.Expression | TSESTree.PrivateIdentifier,\n target: string,\n): boolean {\n if (node.type === \"Identifier\") {\n return node.name === target;\n }\n if (node.type === \"BinaryExpression\" && node.operator === \"+\") {\n return (\n isConcatOperand(node.left, target) || isConcatOperand(node.right, target)\n );\n }\n return false;\n}\n\n/**\n * Returns true if `rhs` is a `+` `BinaryExpression` in which `target` appears as\n * an operand — the reassignment shape `s = s + x` / `s = x + s` / `s = s + a + b`.\n */\nfunction isConcatOntoTarget(\n rhs: TSESTree.Expression,\n target: string,\n): boolean {\n if (rhs.type !== \"BinaryExpression\" || rhs.operator !== \"+\") {\n return false;\n }\n return isConcatOperand(rhs.left, target) || isConcatOperand(rhs.right, target);\n}\n\n/**\n * Returns true if `node` is contained within the body of a loop statement.\n * Walks ancestors and, for each loop, ensures the node is inside the loop's\n * BODY (not its test/init/update clauses, which run a bounded number of times\n * relative to the body and aren't the antipattern we target).\n */\nfunction isInsideLoopBody(node: TSESTree.Node): boolean {\n let child: TSESTree.Node = node;\n let parent = node.parent;\n while (parent !== undefined && parent !== null) {\n if (LOOP_NODE_TYPES.has(parent.type)) {\n // `body` is the property that holds the looped statements for every\n // loop variant we care about.\n const loop = parent as\n | TSESTree.ForStatement\n | TSESTree.ForOfStatement\n | TSESTree.ForInStatement\n | TSESTree.WhileStatement\n | TSESTree.DoWhileStatement;\n if (loop.body === child) {\n return true;\n }\n }\n child = parent;\n parent = parent.parent;\n }\n return false;\n}\n\nexport default ESLintUtils.RuleCreator(\n (name) =>\n `https://github.com/sarj-ai/linting/blob/main/packages/typescript/src/rules/${name}.ts`,\n)<Options, MessageIds>({\n name: \"no-string-concat-in-loop\",\n meta: {\n type: \"suggestion\",\n docs: {\n description:\n \"Disallow O(n^2) string building via `+=` on a string variable inside a loop; push parts to an array and `join` instead.\",\n },\n schema: [],\n messages: {\n noStringConcatInLoop:\n \"Avoid building a string with `+=` inside a loop — this is O(n^2). Push the parts onto an array and use `arr.join(\\\"\\\")` after the loop.\",\n },\n },\n defaultOptions: [],\n create(context) {\n return {\n AssignmentExpression(node: TSESTree.AssignmentExpression): void {\n // The LHS must be a plain variable reference.\n if (node.left.type !== \"Identifier\") {\n return;\n }\n // Accept both the compound `s += x` and the longhand `s = s + x`; any\n // other operator/shape (`s = x + y`, `s -= x`, ...) is not accumulation.\n const isAccumulation =\n node.operator === \"+=\" ||\n (node.operator === \"=\" &&\n isConcatOntoTarget(node.right, node.left.name));\n if (!isAccumulation) {\n return;\n }\n // Must occur inside a loop body, else it's a one-shot append.\n if (!isInsideLoopBody(node)) {\n return;\n }\n\n const scope = context.sourceCode.getScope(node);\n const variable = findVariable(scope, node.left.name);\n // Conservative: can't resolve the declaration -> don't flag.\n if (variable === undefined) {\n return;\n }\n // Only flag when we can confirm the LHS was string-initialized; a\n // numeric initializer (or anything non-string) is intentionally\n // excluded to avoid false positives.\n if (!isStringInitializedVariable(variable)) {\n return;\n }\n\n context.report({\n node,\n messageId: \"noStringConcatInLoop\",\n });\n },\n };\n },\n});\n","/**\n * @fileoverview Flag `'use client'` files with no hooks or event handlers.\n *\n * If a file is marked `'use client'` but contains no hook calls\n * (`useState`/`useEffect`/etc.), no JSX event handlers (`onClick`,\n * `onChange`, etc.), no browser globals, no client-only imports, and no\n * other client-side indicators (classes, re-exports), the directive is\n * likely unnecessary and the file could be a React Server Component —\n * improving cold-start, bundle size, and SEO.\n *\n * False-positive watch: components that only use client-side context\n * (e.g. theme providers) without hooks or events still need `'use client'`.\n *\n * References:\n * - https://nextjs.org/docs/app/building-your-application/rendering/client-components\n */\n\nimport {\n AST_NODE_TYPES,\n ESLintUtils,\n type TSESTree,\n} from \"@typescript-eslint/utils\";\nimport type { RuleContext, Scope } from \"@typescript-eslint/utils/ts-eslint\";\n\ntype MessageIds = \"unnecessaryUseClient\";\ntype Options = readonly [];\n\nconst HOOK_REGEX = /^use([A-Z]|$)/;\nconst EVENT_PROP_REGEX = /^on[A-Z]/;\nconst ERROR_FILE_REGEX = /\\b(?:global-)?error\\.[jt]sx?$/;\n\nconst BROWSER_GLOBALS: ReadonlySet<string> = new Set([\n \"window\",\n \"document\",\n \"navigator\",\n \"localStorage\",\n \"sessionStorage\",\n \"location\",\n \"history\",\n \"screen\",\n \"requestAnimationFrame\",\n \"cancelAnimationFrame\",\n \"CustomEvent\",\n \"Event\",\n \"MouseEvent\",\n \"KeyboardEvent\",\n \"TouchEvent\",\n]);\n\nconst CLIENT_ONLY_PACKAGES_REGEX =\n /^(?:@radix-ui\\/|framer-motion|react-dom|react-day-picker|@floating-ui\\/|react-select|react-toastify|react-hook-form|recharts|react-dropzone|react-slick|react-swipeable|react-resizable|react-draggable|react-beautiful-dnd|@hello-pangea\\/dnd|react-virtualized|react-window|@tanstack\\/react-table|@tanstack\\/react-query|react-redux|recoil|jotai|zustand|@tippyjs\\/react|react-color|react-datepicker|next-themes|react-helmet|react-helmet-async|styled-components|@emotion\\/)/;\n\ntype Ctx = Readonly<RuleContext<MessageIds, Options>>;\n\nconst isUseClientDirective = (\n node: TSESTree.Statement,\n): node is TSESTree.ExpressionStatement => {\n return (\n node.type === AST_NODE_TYPES.ExpressionStatement &&\n node.expression.type === AST_NODE_TYPES.Literal &&\n node.expression.value === \"use client\"\n );\n};\n\nconst isGlobalReference = (\n node: TSESTree.Identifier,\n context: Ctx,\n): boolean => {\n if (!BROWSER_GLOBALS.has(node.name)) return false;\n\n const parent = node.parent;\n if (parent !== undefined) {\n // `obj.window` — `window` is a property name, not a global reference.\n if (\n parent.type === AST_NODE_TYPES.MemberExpression &&\n parent.property === node &&\n !parent.computed\n ) {\n return false;\n }\n // `{ window: ... }` — property key, not a global reference.\n if (\n parent.type === AST_NODE_TYPES.Property &&\n parent.key === node &&\n !parent.computed\n ) {\n return false;\n }\n // Type annotations / type-only positions are not runtime references.\n if (parent.type.startsWith(\"TS\")) {\n return false;\n }\n }\n\n // If there's a local binding for this name anywhere up the chain, it's not\n // a reference to the browser global.\n let scope: Scope.Scope | null = context.sourceCode.getScope(node);\n while (scope !== null) {\n const variable = scope.set.get(node.name);\n if (variable !== undefined && variable.defs.length > 0) {\n return false;\n }\n scope = scope.upper;\n }\n\n return true;\n};\n\nexport default ESLintUtils.RuleCreator(\n (name) =>\n `https://github.com/sarj-ai/linting/blob/main/packages/typescript/src/rules/${name}.ts`,\n)<Options, MessageIds>({\n name: \"no-unnecessary-use-client\",\n meta: {\n type: \"suggestion\",\n docs: {\n description:\n \"Flag `'use client'` files with no hooks or event handlers — they could be RSC.\",\n },\n schema: [],\n messages: {\n unnecessaryUseClient:\n \"'use client' directive but no hooks (use*), JSX event handlers (on*), browser globals, or client-only imports found. Consider removing the directive and serving as a React Server Component.\",\n },\n },\n defaultOptions: [],\n create(context) {\n const filename = context.filename;\n if (ERROR_FILE_REGEX.test(filename)) {\n return {};\n }\n\n let directiveNode: TSESTree.ExpressionStatement | null = null;\n let hasClientIndicator = false;\n\n const markIfHookOrContext = (\n callee: TSESTree.CallExpression[\"callee\"],\n ): void => {\n if (callee.type === AST_NODE_TYPES.Identifier) {\n if (HOOK_REGEX.test(callee.name) || callee.name === \"createContext\") {\n hasClientIndicator = true;\n }\n return;\n }\n if (\n callee.type === AST_NODE_TYPES.MemberExpression &&\n callee.property.type === AST_NODE_TYPES.Identifier\n ) {\n const name = callee.property.name;\n if (HOOK_REGEX.test(name) || name === \"createContext\") {\n hasClientIndicator = true;\n }\n }\n };\n\n return {\n Program(node): void {\n for (const stmt of node.body) {\n // Directives must be the first statements; once we see a non-\n // ExpressionStatement, stop scanning.\n if (stmt.type !== AST_NODE_TYPES.ExpressionStatement) break;\n if (isUseClientDirective(stmt)) {\n directiveNode = stmt;\n break;\n }\n }\n },\n CallExpression(node): void {\n // The `Program` visitor (entered first) has already determined whether\n // this file has a `'use client'` directive. If it doesn't, the result\n // can't change — skip all of the per-node indicator work, including the\n // hot scope-resolution in the `Identifier` visitor below.\n if (directiveNode === null) return;\n markIfHookOrContext(node.callee);\n },\n JSXAttribute(node): void {\n if (directiveNode === null) return;\n if (\n node.name.type === AST_NODE_TYPES.JSXIdentifier &&\n EVENT_PROP_REGEX.test(node.name.name)\n ) {\n hasClientIndicator = true;\n }\n },\n ImportDeclaration(node): void {\n if (directiveNode === null) return;\n if (\n typeof node.source.value === \"string\" &&\n CLIENT_ONLY_PACKAGES_REGEX.test(node.source.value)\n ) {\n hasClientIndicator = true;\n }\n },\n ExportNamedDeclaration(node): void {\n if (directiveNode === null) return;\n if (node.source !== null) {\n hasClientIndicator = true;\n }\n },\n ExportAllDeclaration(node): void {\n if (directiveNode === null) return;\n if (node.source !== null) {\n hasClientIndicator = true;\n }\n },\n ClassDeclaration(): void {\n if (directiveNode === null) return;\n hasClientIndicator = true;\n },\n ClassExpression(): void {\n if (directiveNode === null) return;\n hasClientIndicator = true;\n },\n Identifier(node): void {\n if (directiveNode === null) return;\n if (isGlobalReference(node, context)) {\n hasClientIndicator = true;\n }\n },\n \"Program:exit\"(): void {\n if (directiveNode !== null && !hasClientIndicator) {\n context.report({\n node: directiveNode,\n messageId: \"unnecessaryUseClient\",\n });\n }\n },\n };\n },\n});\n","/**\n * @fileoverview Flag object types that model mutually-exclusive states with a\n * boolean status flag plus many optional members. A shape like\n * `{ success: boolean; data?: T; error?: E; code?: number }` encodes \"success\n * vs. error\" implicitly and lets illegal states (e.g. `success: true` with an\n * `error`) be representable.\n *\n * Such shapes should be modelled as a discriminated union, e.g.\n * `{ ok: true; data: T } | { ok: false; error: E }`, so the compiler enforces\n * that exactly one branch's fields are present.\n *\n * This is the TypeScript mirror of the Python rule SARJ005.\n */\n\nimport { ESLintUtils, type TSESTree } from \"@typescript-eslint/utils\";\nimport { AST_NODE_TYPES } from \"@typescript-eslint/utils\";\n\ntype MessageIds = \"preferDiscriminatedUnion\";\ntype Options = readonly [];\n\n/**\n * Boolean-typed member names that read as a success/error status discriminant.\n */\nconst STATUS_MEMBER_NAMES: ReadonlySet<string> = new Set([\n \"success\",\n \"ok\",\n \"error\",\n \"failed\",\n \"isError\",\n]);\n\nconst MIN_OPTIONAL_MEMBERS = 2;\n\n/**\n * Returns the property key name for a member if it is a plain identifier or\n * string-literal property signature, otherwise `null`.\n */\nfunction getMemberName(member: TSESTree.TypeElement): string | null {\n if (member.type !== AST_NODE_TYPES.TSPropertySignature) {\n return null;\n }\n const { key } = member;\n if (key.type === AST_NODE_TYPES.Identifier) {\n return key.name;\n }\n if (key.type === AST_NODE_TYPES.Literal && typeof key.value === \"string\") {\n return key.value;\n }\n return null;\n}\n\n/**\n * Whether a property signature is annotated with `boolean`.\n */\nfunction isBooleanTyped(member: TSESTree.TSPropertySignature): boolean {\n return (\n member.typeAnnotation?.typeAnnotation.type ===\n AST_NODE_TYPES.TSBooleanKeyword\n );\n}\n\n/**\n * Returns true when the object type literal has BOTH a boolean-typed status\n * member AND at least `MIN_OPTIONAL_MEMBERS` optional members.\n */\nfunction looksLikeMutuallyExclusiveState(\n typeLiteral: TSESTree.TSTypeLiteral,\n): boolean {\n let hasStatusBoolean = false;\n let optionalCount = 0;\n\n for (const member of typeLiteral.members) {\n if (member.type !== AST_NODE_TYPES.TSPropertySignature) {\n continue;\n }\n\n if (member.optional) {\n optionalCount += 1;\n }\n\n const name = getMemberName(member);\n if (\n name !== null &&\n STATUS_MEMBER_NAMES.has(name) &&\n isBooleanTyped(member)\n ) {\n hasStatusBoolean = true;\n }\n }\n\n return hasStatusBoolean && optionalCount >= MIN_OPTIONAL_MEMBERS;\n}\n\nexport default ESLintUtils.RuleCreator(\n (name) =>\n `https://github.com/sarj-ai/linting/blob/main/packages/typescript/src/rules/${name}.ts`,\n)<Options, MessageIds>({\n name: \"prefer-discriminated-union\",\n meta: {\n type: \"suggestion\",\n docs: {\n description:\n \"Flag object types with a boolean status flag and many optionals; model them as a discriminated union instead.\",\n },\n schema: [],\n messages: {\n preferDiscriminatedUnion:\n \"This object type uses a boolean status flag alongside several optional fields, which lets illegal states be representable. Model it as a `z.discriminatedUnion` / discriminated union (e.g. `{ ok: true; data: T } | { ok: false; error: E }`) to make illegal states unrepresentable.\",\n },\n },\n defaultOptions: [],\n create(context) {\n function checkTypeLiteral(\n typeLiteral: TSESTree.TSTypeLiteral,\n reportNode: TSESTree.Node,\n ): void {\n if (looksLikeMutuallyExclusiveState(typeLiteral)) {\n context.report({\n node: reportNode,\n messageId: \"preferDiscriminatedUnion\",\n });\n }\n }\n\n return {\n TSInterfaceDeclaration(\n node: TSESTree.TSInterfaceDeclaration,\n ): void {\n // An interface body is structurally an object type literal; reuse the\n // same membership analysis by treating its `body.body` as members.\n const synthetic: TSESTree.TSTypeLiteral = {\n ...node.body,\n type: AST_NODE_TYPES.TSTypeLiteral,\n members: node.body.body,\n } as TSESTree.TSTypeLiteral;\n checkTypeLiteral(synthetic, node);\n },\n \"TSTypeAliasDeclaration > TSTypeLiteral\"(\n node: TSESTree.TSTypeLiteral,\n ): void {\n checkTypeLiteral(node, node.parent);\n },\n };\n },\n});\n","/**\n * @fileoverview Don't access `response.json()` fields without a Zod parse first.\n *\n * Pattern flagged:\n * const data = await response.json();\n * doSomething(data.foo); // <-- unvalidated property access\n *\n * Encouraged:\n * const data = MySchema.parse(await response.json());\n * doSomething(data.foo); // typed + validated\n *\n * Heuristic:\n * - Track variables initialized to `await someCall.json()` using ESLint's scope manager.\n * - Untrack if reassigned to anything other than another raw `json()` call.\n * - Untrack when passed to a user-defined type-guard predicate — a call whose\n * callee name matches `/^is[A-Z]/`, or any call used in an `if`/`?:` test\n * position (`if (guard(body)) { … body.foo … }`). Hand-written guards validate\n * the payload just as a Zod `.parse()` does.\n * - Flag MemberExpression reads and destructuring off tracked variables.\n * - `.parse()` / `.safeParse()` chained directly on the json call are legit\n * and never produce a tracked binding in the first place.\n *\n * References:\n * - https://zod.dev/?id=parse\n * - https://www.totaltypescript.com/parse-don-t-validate\n */\n\nimport {\n AST_NODE_TYPES,\n ESLintUtils,\n type TSESTree,\n} from \"@typescript-eslint/utils\";\nimport type { RuleContext, Scope } from \"@typescript-eslint/utils/ts-eslint\";\n\ntype MessageIds = \"unparsedJsonAccess\";\ntype Options = readonly [];\n\ntype Ctx = Readonly<RuleContext<MessageIds, Options>>;\n\n/**\n * Peel TypeScript wrapper nodes that don't affect the underlying value\n * (`as Foo`, `<Foo>x`, `x!`, `x satisfies Foo`, parentheses, optional chain\n * wrappers). Returns the inner expression we actually care about.\n */\nconst unwrap = (\n node: TSESTree.Node | null | undefined,\n): TSESTree.Node | null => {\n let current: TSESTree.Node | null | undefined = node;\n while (current !== null && current !== undefined) {\n if (\n current.type === AST_NODE_TYPES.TSAsExpression ||\n current.type === AST_NODE_TYPES.TSTypeAssertion ||\n current.type === AST_NODE_TYPES.TSNonNullExpression ||\n current.type === AST_NODE_TYPES.TSSatisfiesExpression\n ) {\n current = current.expression;\n } else if (current.type === AST_NODE_TYPES.ChainExpression) {\n current = current.expression;\n } else {\n break;\n }\n }\n return current ?? null;\n};\n\n/**\n * Returns true if the expression is (optionally awaited) `<x>.json()`.\n */\nconst isJsonCall = (\n node: TSESTree.Node | null | undefined,\n): boolean => {\n let current = unwrap(node);\n if (current === null) return false;\n if (current.type === AST_NODE_TYPES.AwaitExpression) {\n current = unwrap(current.argument);\n }\n if (current === null || current.type !== AST_NODE_TYPES.CallExpression) {\n return false;\n }\n const callee = unwrap(current.callee);\n if (callee === null || callee.type !== AST_NODE_TYPES.MemberExpression) {\n return false;\n }\n const property = unwrap(callee.property);\n return (\n property !== null &&\n property.type === AST_NODE_TYPES.Identifier &&\n property.name === \"json\"\n );\n};\n\nconst findVariable = (\n scope: Scope.Scope | null,\n name: string,\n): Scope.Variable | null => {\n let current: Scope.Scope | null = scope;\n while (current !== null) {\n const variable = current.set.get(name);\n if (variable !== undefined) return variable;\n current = current.upper;\n }\n return null;\n};\n\n/** User-defined type-guard predicate names, e.g. `isProtectedResourceMetadata`. */\nconst GUARD_NAME_RE = /^is[A-Z]/;\n\n/**\n * True when a call sits in a boolean-test position (`if`/`while`/`for`/`?:`),\n * seen through `!`, `&&`/`||`, and optional-chaining wrappers — i.e. it narrows.\n */\nconst isGuardTestPosition = (node: TSESTree.Node): boolean => {\n let current: TSESTree.Node = node;\n let parent: TSESTree.Node | null | undefined = current.parent;\n while (parent !== undefined && parent !== null) {\n switch (parent.type) {\n case AST_NODE_TYPES.UnaryExpression:\n case AST_NODE_TYPES.LogicalExpression:\n case AST_NODE_TYPES.ChainExpression:\n current = parent;\n parent = parent.parent;\n continue;\n case AST_NODE_TYPES.IfStatement:\n case AST_NODE_TYPES.ConditionalExpression:\n case AST_NODE_TYPES.WhileStatement:\n case AST_NODE_TYPES.DoWhileStatement:\n case AST_NODE_TYPES.ForStatement:\n return parent.test === current;\n default:\n return false;\n }\n }\n return false;\n};\n\nconst isUnvalidatedVariableRef = (\n node: TSESTree.Node | null | undefined,\n scope: Scope.Scope,\n tracked: ReadonlySet<Scope.Variable>,\n): boolean => {\n const unwrapped = unwrap(node);\n if (unwrapped === null || unwrapped.type !== AST_NODE_TYPES.Identifier) {\n return false;\n }\n const variable = findVariable(scope, unwrapped.name);\n return variable !== null && tracked.has(variable);\n};\n\nexport default ESLintUtils.RuleCreator(\n (name) =>\n `https://github.com/sarj-ai/linting/blob/main/packages/typescript/src/rules/${name}.ts`,\n)<Options, MessageIds>({\n name: \"prefer-schema-for-api-payload\",\n meta: {\n type: \"problem\",\n docs: {\n description:\n \"Require Zod (or similar) schema validation on `response.json()` before property access.\",\n },\n schema: [],\n messages: {\n unparsedJsonAccess:\n \"Property access on the result of `response.json()` without a schema parse. Pipe through `XSchema.parse(...)` (Zod) before reading fields.\",\n },\n },\n defaultOptions: [],\n create(context: Ctx) {\n const unvalidatedVariables = new Set<Scope.Variable>();\n\n const trackInitializer = (\n declarator: TSESTree.VariableDeclarator,\n ): void => {\n if (!isJsonCall(declarator.init)) return;\n const declaredVars = context.sourceCode.getDeclaredVariables(declarator);\n const variable = declaredVars[0];\n if (variable !== undefined) {\n unvalidatedVariables.add(variable);\n }\n };\n\n return {\n VariableDeclarator(node): void {\n const scope = context.sourceCode.getScope(node);\n\n if (node.id.type === AST_NODE_TYPES.Identifier) {\n trackInitializer(node);\n return;\n }\n\n if (\n node.id.type === AST_NODE_TYPES.ObjectPattern ||\n node.id.type === AST_NODE_TYPES.ArrayPattern\n ) {\n if (isJsonCall(node.init)) {\n context.report({ node: node.id, messageId: \"unparsedJsonAccess\" });\n return;\n }\n if (\n isUnvalidatedVariableRef(node.init, scope, unvalidatedVariables)\n ) {\n context.report({ node: node.id, messageId: \"unparsedJsonAccess\" });\n }\n }\n },\n AssignmentExpression(node): void {\n const scope = context.sourceCode.getScope(node);\n\n if (node.left.type === AST_NODE_TYPES.Identifier) {\n const variable = findVariable(scope, node.left.name);\n if (variable === null) return;\n if (isJsonCall(node.right)) {\n unvalidatedVariables.add(variable);\n } else {\n // Reassigned to a parse call or something else: drop tracking.\n unvalidatedVariables.delete(variable);\n }\n return;\n }\n\n if (\n node.left.type === AST_NODE_TYPES.ObjectPattern ||\n node.left.type === AST_NODE_TYPES.ArrayPattern\n ) {\n if (isJsonCall(node.right)) {\n context.report({\n node: node.left,\n messageId: \"unparsedJsonAccess\",\n });\n return;\n }\n if (\n isUnvalidatedVariableRef(node.right, scope, unvalidatedVariables)\n ) {\n context.report({\n node: node.left,\n messageId: \"unparsedJsonAccess\",\n });\n }\n }\n },\n CallExpression(node): void {\n if (node.callee.type !== AST_NODE_TYPES.Identifier) return;\n if (!GUARD_NAME_RE.test(node.callee.name) && !isGuardTestPosition(node)) {\n return;\n }\n const scope = context.sourceCode.getScope(node);\n for (const arg of node.arguments) {\n if (arg.type === AST_NODE_TYPES.SpreadElement) continue;\n const unwrapped = unwrap(arg);\n if (unwrapped === null || unwrapped.type !== AST_NODE_TYPES.Identifier) {\n continue;\n }\n const variable = findVariable(scope, unwrapped.name);\n if (variable !== null) unvalidatedVariables.delete(variable);\n }\n },\n MemberExpression(node): void {\n const scope = context.sourceCode.getScope(node);\n const obj = unwrap(node.object);\n\n if (isJsonCall(obj)) {\n // Direct `.foo` access on `(await r.json()).foo` is always bad,\n // unless the parent call is a `.parse()`/`.safeParse()` — in which\n // case it's a validation, not an unvalidated read.\n const parent = node.parent;\n if (\n parent.type === AST_NODE_TYPES.CallExpression &&\n parent.callee === node &&\n node.property.type === AST_NODE_TYPES.Identifier &&\n (node.property.name === \"parse\" ||\n node.property.name === \"safeParse\")\n ) {\n return;\n }\n context.report({ node, messageId: \"unparsedJsonAccess\" });\n return;\n }\n\n if (\n obj !== null &&\n obj.type === AST_NODE_TYPES.Identifier &&\n isUnvalidatedVariableRef(obj, scope, unvalidatedVariables)\n ) {\n context.report({ node, messageId: \"unparsedJsonAccess\" });\n const variable = findVariable(scope, obj.name);\n if (variable !== null) {\n unvalidatedVariables.delete(variable);\n }\n }\n },\n };\n },\n});\n","/**\n * @fileoverview Enforce design-system semantic color tokens over raw Tailwind\n * palette classes and hardcoded color values.\n *\n * Scoped to genuine className positions to avoid false positives on non-class\n * strings (Tailwind `safelist`, `toHaveClass(...)` test assertions, prose, color\n * maps): JSX `className`, the args of `cn()`/`clsx()`/`cva()`/`tv()`/`cx()`/\n * `twMerge()` (recursing into cva variant objects), and `*class*`-named\n * variables/object properties. Plus inline color literals on JSX `style`/`fill`/\n * `stroke`.\n *\n * Flags:\n * - raw palette classes: `text-red-500`, `bg-slate-200/50`\n * - arbitrary color values: `bg-[#fff]`, `text-[rgb(...)]`, `ring-[oklch(...)]`\n * - inline color literals: `style={{ color: \"#111827\" }}`, `fill=\"#000\"`\n *\n * Allowed: semantic tokens (`bg-primary`, `text-muted-foreground`, `bg-chart-1`),\n * `white`/`black` (the `bg-black/50` overlay idiom rarely has a token), `var(--…)`,\n * `currentColor`, and non-color arbitraries (`w-[437px]`, `grid-cols-[auto_1fr]`).\n *\n * SVG drawing data is exempt on `fill`/`stroke`/`color` attributes: any value inside\n * a `<mask>`/`<clipPath>`/`<defs>`/`<pattern>`/`<linearGradient>`/`<radialGradient>`\n * (masking breaks without literal `#fff`/`#000`), the neutral literals\n * (`#fff`/`#000`/`transparent`/`none`/`currentColor`/`inherit`), and `*.stories.*`\n * files (Storybook fixtures) never fire. Real component styling — `className` and\n * inline `style={{ … }}` objects — still fires on hardcoded colors.\n *\n * No autofix — use a semantic token, or for charts / standalone pages / 3rd-party\n * config add `// eslint-disable-next-line @sarj/prefer-semantic-colors -- <reason>`.\n */\n\nimport { AST_NODE_TYPES, ESLintUtils, type TSESTree } from \"@typescript-eslint/utils\";\n\nimport { classTokens, tailwindBase } from \"./_tailwind.js\";\n\ntype MessageIds = \"rawPalette\" | \"arbitraryColor\" | \"inlineColor\";\ntype Options = readonly [];\n\nconst COLOR_PREFIXES =\n \"text|bg|border(?:-[trblxyse])?|ring(?:-offset)?|fill|stroke|from|via|to|divide|decoration|placeholder|accent|caret|shadow|outline\";\nconst PALETTE =\n \"red|orange|amber|yellow|lime|green|emerald|teal|cyan|sky|blue|indigo|violet|purple|fuchsia|pink|rose|slate|gray|zinc|neutral|stone\";\nconst COLOR_FN = \"rgba?|hsla?|hwb|oklch|oklab|lab|lch|color\";\n\nconst RAW_PALETTE_RE = new RegExp(`^(?:${COLOR_PREFIXES})-(?:${PALETTE})-\\\\d{2,3}(?:/\\\\d{1,3})?$`);\nconst ARBITRARY_COLOR_RE = new RegExp(\n `^(?:${COLOR_PREFIXES})-\\\\[(?:#[0-9a-fA-F]{3,8}|(?:${COLOR_FN})\\\\([^\\\\]]*\\\\))\\\\]$`,\n \"i\",\n);\n\n/** Call expressions whose string args are className fragments. */\nconst CLASS_FNS = new Set<string>([\"cn\", \"clsx\", \"cva\", \"tv\", \"cx\", \"twMerge\", \"classnames\", \"classNames\"]);\nconst CLASS_NAME_RE = /class/i;\n\n/** CSS color-bearing properties, in their JSX (camelCase) and SVG-attribute forms. */\nconst STYLE_COLOR_PROPS = new Set<string>([\n \"color\",\n \"background\",\n \"backgroundColor\",\n \"borderColor\",\n \"borderTopColor\",\n \"borderRightColor\",\n \"borderBottomColor\",\n \"borderLeftColor\",\n \"outlineColor\",\n \"caretColor\",\n \"textDecorationColor\",\n \"columnRuleColor\",\n \"fill\",\n \"stroke\",\n \"stopColor\",\n \"floodColor\",\n \"lightingColor\",\n]);\nconst RAW_COLOR_VALUE_RE = new RegExp(`#[0-9a-fA-F]{3,8}\\\\b|\\\\b(?:${COLOR_FN})\\\\s*\\\\(`, \"i\");\n\nconst STORIES_FILE_RE = /\\.stories\\.[cm]?[jt]sx?$/i;\n\n/** SVG container elements whose children carry structural (not UI-token) colors. */\nconst SVG_DEFS_CONTAINERS = new Set<string>([\n \"mask\",\n \"clipPath\",\n \"defs\",\n \"pattern\",\n \"linearGradient\",\n \"radialGradient\",\n]);\n\n/** Neutral fill/stroke literals that are SVG drawing data, never a UI token. */\nconst SVG_EXEMPT_COLOR_VALUES = new Set<string>([\n \"#fff\",\n \"#ffffff\",\n \"#000\",\n \"#000000\",\n \"transparent\",\n \"none\",\n \"currentcolor\",\n \"inherit\",\n]);\n\n// A `fill`/`stroke` literal anywhere inside an `<svg>` subtree is drawing data\n// (icon/illustration artwork), not a reusable UI token — the color is inherent to\n// the graphic. Exempt any descendant of `<svg>` (which subsumes the defs\n// containers `<mask>`/`<clipPath>`/`<defs>`/`<pattern>`/gradients).\nconst isInsideSvg = (node: TSESTree.Node): boolean => {\n let current: TSESTree.Node | null | undefined = node.parent;\n while (current !== undefined && current !== null) {\n if (\n current.type === AST_NODE_TYPES.JSXElement &&\n current.openingElement.name.type === AST_NODE_TYPES.JSXIdentifier &&\n (current.openingElement.name.name === \"svg\" ||\n SVG_DEFS_CONTAINERS.has(current.openingElement.name.name))\n ) {\n return true;\n }\n current = current.parent;\n }\n return false;\n};\n\nconst propName = (key: TSESTree.Property[\"key\"]): string | null => {\n if (key.type === AST_NODE_TYPES.Identifier) return key.name;\n if (key.type === AST_NODE_TYPES.Literal && typeof key.value === \"string\") return key.value;\n return null;\n};\n\nexport default ESLintUtils.RuleCreator(\n (name) =>\n `https://github.com/sarj-ai/standards/blob/main/packages/typescript/src/rules/${name}.ts`,\n)<Options, MessageIds>({\n name: \"prefer-semantic-colors\",\n meta: {\n type: \"suggestion\",\n docs: {\n description:\n \"Enforce design-system semantic color tokens (bg-primary, text-destructive, …) over raw Tailwind palette classes (text-red-500), arbitrary color values (bg-[#fff]), and inline color literals.\",\n },\n schema: [],\n messages: {\n rawPalette:\n \"Raw palette class '{{class}}' — use a semantic token (e.g. text-foreground, bg-primary, text-destructive, bg-muted).\",\n arbitraryColor:\n \"Hardcoded color '{{class}}' — use a semantic token, or var(--…). For charts/brand add an eslint-disable with a reason.\",\n inlineColor:\n \"Hardcoded color '{{value}}' — use a semantic token / CSS variable. For charts/standalone pages add an eslint-disable with a reason.\",\n },\n },\n defaultOptions: [],\n create(context) {\n if (STORIES_FILE_RE.test(context.filename)) return {};\n\n const reportClasses = (value: string, node: TSESTree.Node): void => {\n for (const token of classTokens(value)) {\n const base = tailwindBase(token);\n if (RAW_PALETTE_RE.test(base)) {\n context.report({ node, messageId: \"rawPalette\", data: { class: token } });\n } else if (ARBITRARY_COLOR_RE.test(base)) {\n context.report({ node, messageId: \"arbitraryColor\", data: { class: token } });\n }\n }\n };\n\n // Walk a node that holds className fragments: strings, templates, arrays, cva\n // variant objects, and conditionals. CallExpressions are handled separately, so\n // they're not recursed here (avoids double-reporting cn()/cva() args).\n const checkClassNode = (node: TSESTree.Node | null): void => {\n if (node === null) return;\n switch (node.type) {\n case AST_NODE_TYPES.Literal:\n if (typeof node.value === \"string\") reportClasses(node.value, node);\n break;\n case AST_NODE_TYPES.TemplateLiteral:\n for (const quasi of node.quasis) reportClasses(quasi.value.cooked ?? \"\", quasi);\n break;\n case AST_NODE_TYPES.ArrayExpression:\n for (const element of node.elements) {\n if (element !== null && element.type !== AST_NODE_TYPES.SpreadElement) checkClassNode(element);\n }\n break;\n case AST_NODE_TYPES.ObjectExpression:\n for (const property of node.properties) {\n if (property.type === AST_NODE_TYPES.Property) checkClassNode(property.value);\n }\n break;\n case AST_NODE_TYPES.ConditionalExpression:\n checkClassNode(node.consequent);\n checkClassNode(node.alternate);\n break;\n case AST_NODE_TYPES.LogicalExpression:\n checkClassNode(node.right);\n break;\n default:\n break;\n }\n };\n\n const checkColorValueNode = (node: TSESTree.Node): void => {\n if (\n node.type === AST_NODE_TYPES.Literal &&\n typeof node.value === \"string\" &&\n RAW_COLOR_VALUE_RE.test(node.value)\n ) {\n context.report({ node, messageId: \"inlineColor\", data: { value: node.value } });\n }\n };\n\n return {\n \"JSXAttribute[name.name='className']\"(node: TSESTree.JSXAttribute): void {\n if (node.value === null) return;\n if (node.value.type === AST_NODE_TYPES.Literal) checkClassNode(node.value);\n else if (node.value.type === AST_NODE_TYPES.JSXExpressionContainer) {\n if (node.value.expression.type !== AST_NODE_TYPES.JSXEmptyExpression) {\n checkClassNode(node.value.expression);\n }\n }\n },\n CallExpression(node: TSESTree.CallExpression): void {\n if (node.callee.type === AST_NODE_TYPES.Identifier && CLASS_FNS.has(node.callee.name)) {\n for (const arg of node.arguments) {\n if (arg.type !== AST_NODE_TYPES.SpreadElement) checkClassNode(arg);\n }\n }\n },\n VariableDeclarator(node: TSESTree.VariableDeclarator): void {\n if (node.id.type === AST_NODE_TYPES.Identifier && CLASS_NAME_RE.test(node.id.name)) {\n checkClassNode(node.init);\n }\n },\n Property(node: TSESTree.Property): void {\n const name = propName(node.key);\n if (name !== null && CLASS_NAME_RE.test(name)) checkClassNode(node.value);\n },\n // SVG presentation attributes: <path fill=\"#7c3aed\" stroke=\"#7c3aed\" />.\n // Neutral drawing literals and anything inside an SVG defs container are\n // structural, not UI tokens, so they never fire.\n \"JSXAttribute[name.name=/^(fill|stroke|color)$/]\"(node: TSESTree.JSXAttribute): void {\n if (node.value?.type !== AST_NODE_TYPES.Literal) return;\n if (\n typeof node.value.value === \"string\" &&\n SVG_EXEMPT_COLOR_VALUES.has(node.value.value.toLowerCase())\n ) {\n return;\n }\n if (isInsideSvg(node)) return;\n checkColorValueNode(node.value);\n },\n // Inline style objects: style={{ color: \"#111827\", backgroundColor: \"#fff\" }}\n \"JSXAttribute[name.name='style'] ObjectExpression > Property\"(node: TSESTree.Property): void {\n const name = propName(node.key);\n if (name !== null && STYLE_COLOR_PROPS.has(name)) checkColorValueNode(node.value);\n },\n };\n },\n});\n","/**\n * @fileoverview Shared helpers for the Tailwind-className rules. className values\n * are reachable as plain string `Literal`s (attribute values, `cn()`/`clsx()`/\n * `cva()`/`tv()` args, and className-holding constants) and as the static quasis of\n * `TemplateLiteral`s — so the rules visit both node types and run these helpers.\n */\n\n/**\n * Strip Tailwind variant prefixes (`hover:`, `dark:`, `focus-visible:`, …) and a\n * leading `!` important marker, leaving the bare utility (`bg-red-500`). Variants are\n * `[a-z0-9-]+:` runs at the start; bracketed arbitrary values never start a token, so\n * a `:` inside `[url(http://…)]` is not mistaken for a variant separator.\n */\nexport const tailwindBase = (token: string): string =>\n token.replace(/^(?:[a-z0-9-]+:)+/i, \"\").replace(/^!/, \"\");\n\n/** Split a className string into its non-empty class tokens. */\nexport const classTokens = (value: string): readonly string[] =>\n value.split(/\\s+/).filter(Boolean);\n","/**\n * @fileoverview Prefer Next.js Server Actions over /api/* mutations.\n *\n * Flags mutations against internal `/api/*` URLs (POST/PUT/DELETE/PATCH) via\n * `fetch`, axios-style helpers, or direct axios/request calls. GET requests\n * and external URLs are ignored. Tests, scripts, and Next.js route handlers\n * are skipped because Server Actions don't apply there.\n *\n * The member branch (`api.post('/api/x')`) intentionally skips calls that pass\n * a function argument (e.g. `router.post('/api/x', handler)`) so Express-style\n * route *definitions* aren't mistaken for client-side mutations.\n *\n * References:\n * - https://nextjs.org/docs/app/building-your-application/data-fetching/server-actions-and-mutations\n */\n\nimport { ESLintUtils, type TSESTree } from \"@typescript-eslint/utils\";\nimport type { RuleContext, Scope } from \"@typescript-eslint/utils/ts-eslint\";\n\ntype MessageIds = \"preferServerAction\";\ntype Options = readonly [];\n\nconst MUTATION_METHODS = new Set([\"POST\", \"PUT\", \"DELETE\", \"PATCH\"]);\nconst AXIOS_MUTATION_METHODS = new Set([\"post\", \"put\", \"delete\", \"patch\"]);\n\nconst SKIP_FILE_REGEX =\n /(?:\\.test\\.[jt]sx?$|\\.spec\\.[jt]sx?$|\\/tests?\\/|\\/__tests__\\/|\\/scripts?\\/|\\/app\\/api\\/.*\\/route\\.[jt]sx?$|\\/pages\\/api\\/)/;\n\ntype Ctx = Readonly<RuleContext<MessageIds, Options>>;\n\nfunction getScope(\n context: Ctx,\n node: TSESTree.Node,\n): Scope.Scope {\n return context.sourceCode.getScope(node);\n}\n\n/**\n * Walk up the scope chain looking for a variable declared with a single\n * initializer; if found, return the initializer expression so we can analyze\n * it. Falls back to the original node when resolution is not possible.\n */\nfunction resolveNode(\n node: TSESTree.Node | null | undefined,\n context: Ctx,\n): TSESTree.Node | null {\n if (!node) return null;\n if (node.type !== \"Identifier\") return node;\n\n let scope: Scope.Scope | null = getScope(context, node);\n while (scope) {\n const variable = scope.set.get(node.name);\n if (variable && variable.defs.length === 1) {\n const def = variable.defs[0];\n if (def && def.type === \"Variable\") {\n const declarator = def.node;\n if (\n declarator.type === \"VariableDeclarator\" &&\n declarator.init\n ) {\n return declarator.init;\n }\n }\n }\n scope = scope.upper;\n }\n return node;\n}\n\nfunction isApiUrl(\n node: TSESTree.Node | null | undefined,\n context: Ctx,\n): boolean {\n const resolved = resolveNode(node, context);\n if (!resolved) return false;\n\n if (resolved.type === \"Literal\" && typeof resolved.value === \"string\") {\n return resolved.value.startsWith(\"/api/\");\n }\n if (resolved.type === \"TemplateLiteral\") {\n const firstQuasi = resolved.quasis[0];\n const cooked = firstQuasi?.value.cooked;\n return typeof cooked === \"string\" && cooked.startsWith(\"/api/\");\n }\n if (resolved.type === \"BinaryExpression\" && resolved.operator === \"+\") {\n return isApiUrl(resolved.left, context);\n }\n return false;\n}\n\nfunction isMutationMethod(\n node: TSESTree.Node | null | undefined,\n context: Ctx,\n): boolean {\n const resolved = resolveNode(node, context);\n if (!resolved) return false;\n\n if (resolved.type === \"Literal\" && typeof resolved.value === \"string\") {\n return MUTATION_METHODS.has(resolved.value.toUpperCase());\n }\n\n if (\n resolved.type === \"TemplateLiteral\" &&\n resolved.expressions.length === 0\n ) {\n const val = resolved.quasis.map((q) => q.value.cooked).join(\"\");\n return MUTATION_METHODS.has(val.toUpperCase());\n }\n\n if (resolved.type === \"ConditionalExpression\") {\n return (\n isMutationMethod(resolved.consequent, context) ||\n isMutationMethod(resolved.alternate, context)\n );\n }\n\n if (resolved.type === \"LogicalExpression\" && resolved.operator === \"||\") {\n return (\n isMutationMethod(resolved.left, context) ||\n isMutationMethod(resolved.right, context)\n );\n }\n\n return false;\n}\n\nfunction getPropertyNode(\n objNode: TSESTree.Node | null | undefined,\n propName: string,\n): TSESTree.Node | null {\n if (!objNode || objNode.type !== \"ObjectExpression\") return null;\n for (const prop of objNode.properties) {\n if (prop.type !== \"Property\") continue;\n let keyName: string | null = null;\n if (prop.key.type === \"Identifier\" && !prop.computed) {\n keyName = prop.key.name;\n } else if (\n prop.key.type === \"Literal\" &&\n typeof prop.key.value === \"string\"\n ) {\n keyName = prop.key.value;\n }\n if (keyName === propName) {\n // Skip destructuring patterns — they're not valid as config values.\n if (\n prop.value.type === \"AssignmentPattern\" ||\n prop.value.type === \"ArrayPattern\" ||\n prop.value.type === \"ObjectPattern\"\n ) {\n return null;\n }\n return prop.value;\n }\n }\n return null;\n}\n\nexport default ESLintUtils.RuleCreator(\n (name) =>\n `https://github.com/sarj-ai/linting/blob/main/packages/typescript/src/rules/${name}.ts`,\n)<Options, MessageIds>({\n name: \"prefer-server-actions\",\n meta: {\n type: \"suggestion\",\n docs: {\n description: \"Prefer Next.js Server Actions over /api/* mutations.\",\n },\n schema: [],\n messages: {\n preferServerAction:\n \"Mutation against /api/* — prefer a Next.js Server Action for type-safety and to avoid the JSON round-trip.\",\n },\n },\n defaultOptions: [],\n create(context) {\n const filename = context.filename;\n if (SKIP_FILE_REGEX.test(filename)) {\n return {};\n }\n\n return {\n CallExpression(node) {\n let isMutation = false;\n\n // 1. Standard fetch('/api/orders', { method: 'POST' })\n if (\n node.callee.type === \"Identifier\" &&\n node.callee.name === \"fetch\"\n ) {\n const urlArg = node.arguments[0];\n if (urlArg && urlArg.type !== \"SpreadElement\" && isApiUrl(urlArg, context)) {\n const initArg = node.arguments[1];\n if (initArg && initArg.type !== \"SpreadElement\") {\n const resolvedInit = resolveNode(initArg, context);\n const methodNode = getPropertyNode(resolvedInit, \"method\");\n if (methodNode && isMutationMethod(methodNode, context)) {\n isMutation = true;\n }\n }\n }\n }\n // 2. Custom wrappers or Axios: api.post('/api/orders') or axios.put('/api/orders')\n else if (\n node.callee.type === \"MemberExpression\" &&\n node.callee.property.type === \"Identifier\" &&\n !node.callee.computed\n ) {\n const methodName = node.callee.property.name.toLowerCase();\n if (AXIOS_MUTATION_METHODS.has(methodName)) {\n const urlArg = node.arguments[0];\n // Skip Express-style route definitions like\n // `router.post('/api/x', handler)`: a function argument means this\n // is registering a handler, not issuing a client mutation.\n const hasHandlerArg = node.arguments.some(\n (arg) =>\n arg.type === \"ArrowFunctionExpression\" ||\n arg.type === \"FunctionExpression\",\n );\n if (\n urlArg &&\n urlArg.type !== \"SpreadElement\" &&\n !hasHandlerArg &&\n isApiUrl(urlArg, context)\n ) {\n isMutation = true;\n }\n }\n }\n // 3. Direct axios/request call: axios({ method: 'post', url: '/api/orders' })\n else if (\n node.callee.type === \"Identifier\" &&\n (node.callee.name === \"axios\" || node.callee.name === \"request\")\n ) {\n const firstArg = node.arguments[0];\n if (firstArg && firstArg.type !== \"SpreadElement\") {\n const configArg = resolveNode(firstArg, context);\n if (configArg && configArg.type === \"ObjectExpression\") {\n const urlNode = getPropertyNode(configArg, \"url\");\n const methodNode = getPropertyNode(configArg, \"method\");\n if (\n urlNode &&\n isApiUrl(urlNode, context) &&\n methodNode &&\n isMutationMethod(methodNode, context)\n ) {\n isMutation = true;\n }\n }\n }\n }\n\n if (isMutation) {\n context.report({ node, messageId: \"preferServerAction\" });\n }\n },\n };\n },\n});\n","/**\n * @fileoverview Prefer shadcn/ui form primitives over their native HTML\n * counterparts. Limited to form/dialog elements — `<button>` and `<table>`\n * have been removed from the forbid list because they produced 100% false\n * positives during bulbul validation (icon buttons, layout tables).\n *\n * `<input>` is resolved by its `type`: a bare `<input type=\"checkbox\">` maps to\n * `<Checkbox>`, `radio` → `<RadioGroup>`, `range` → `<Slider>`, and the text-like\n * types (or no type) → `<Input>`. `type=\"hidden\"` is skipped (no shadcn primitive),\n * and a dynamic `type={…}` falls back to the generic `<Input>` rather than asserting\n * a wrong primitive.\n */\n\nimport {\n AST_NODE_TYPES,\n ESLintUtils,\n type TSESTree,\n} from \"@typescript-eslint/utils\";\n\ntype MessageIds = \"preferShadcn\";\ntype Options = readonly [];\n\nconst REPLACEMENTS: Readonly<Record<string, string>> = {\n select: \"Select\",\n textarea: \"Textarea\",\n dialog: \"Dialog\",\n};\n\n/** `<input type>` → shadcn primitive. Absent types (and text-likes) fall to Input. */\nconst INPUT_TYPE_REPLACEMENTS: Readonly<Record<string, string>> = {\n checkbox: \"Checkbox\",\n radio: \"RadioGroup\",\n range: \"Slider\",\n};\n\n/** `<input type>` values with no shadcn equivalent — never reported. */\nconst SKIPPED_INPUT_TYPES = new Set<string>([\"hidden\"]);\n\nconst kebabCase = (component: string): string =>\n component.replace(/([a-z0-9])([A-Z])/g, \"$1-$2\").toLowerCase();\n\nconst literalTypeAttr = (\n node: TSESTree.JSXOpeningElement,\n): { readonly kind: \"literal\"; readonly value: string } | { readonly kind: \"dynamic\" } | null => {\n for (const attribute of node.attributes) {\n if (\n attribute.type !== AST_NODE_TYPES.JSXAttribute ||\n attribute.name.type !== AST_NODE_TYPES.JSXIdentifier ||\n attribute.name.name !== \"type\"\n ) {\n continue;\n }\n if (attribute.value?.type === AST_NODE_TYPES.Literal && typeof attribute.value.value === \"string\") {\n return { kind: \"literal\", value: attribute.value.value.toLowerCase() };\n }\n return { kind: \"dynamic\" };\n }\n return null;\n};\n\n/** Resolve an `<input>` to its shadcn primitive, or null to skip it entirely. */\nconst resolveInputReplacement = (node: TSESTree.JSXOpeningElement): string | null => {\n const typeAttr = literalTypeAttr(node);\n if (typeAttr === null || typeAttr.kind === \"dynamic\") return \"Input\";\n if (SKIPPED_INPUT_TYPES.has(typeAttr.value)) return null;\n return INPUT_TYPE_REPLACEMENTS[typeAttr.value] ?? \"Input\";\n};\n\nexport default ESLintUtils.RuleCreator(\n (name) =>\n `https://github.com/sarj-ai/linting/blob/main/packages/typescript/src/rules/${name}.ts`,\n)<Options, MessageIds>({\n name: \"prefer-shadcn\",\n meta: {\n type: \"suggestion\",\n docs: {\n description:\n \"Prefer shadcn/ui form primitives over native `<input>`, `<select>`, `<textarea>`, and `<dialog>` elements.\",\n },\n schema: [],\n messages: {\n preferShadcn:\n \"Use the shadcn <{{replacement}}> component from @/components/ui/{{lowercase}} instead of native <{{element}}>.\",\n },\n },\n defaultOptions: [],\n create(context) {\n return {\n JSXOpeningElement(node: TSESTree.JSXOpeningElement): void {\n // Only lowercase JSXIdentifier names represent native HTML elements.\n // Member expressions (`Foo.Bar`) and namespaces (`svg:path`) are skipped.\n if (node.name.type !== \"JSXIdentifier\") {\n return;\n }\n\n const elementName = node.name.name;\n const replacement =\n elementName === \"input\" ? resolveInputReplacement(node) : REPLACEMENTS[elementName];\n\n if (replacement === undefined || replacement === null) {\n return;\n }\n\n context.report({\n node,\n messageId: \"preferShadcn\",\n data: {\n element: elementName,\n replacement,\n lowercase: kebabCase(replacement),\n },\n });\n },\n };\n },\n});\n","import {\n ESLintUtils,\n type TSESLint,\n type TSESTree,\n AST_NODE_TYPES,\n} from \"@typescript-eslint/utils\";\n\ntype MessageIds = \"missingAssertNever\";\ntype Options = readonly [];\n\n/**\n * Matches a call to `assertNever(...)` — either the bare identifier form\n * (`assertNever(x)`) or a namespaced member form (`utils.assertNever(x)`).\n */\nconst isAssertNeverCall = (expression: TSESTree.Expression): boolean => {\n if (expression.type !== AST_NODE_TYPES.CallExpression) return false;\n const callee = expression.callee;\n if (callee.type === AST_NODE_TYPES.Identifier) {\n return callee.name === \"assertNever\";\n }\n if (\n callee.type === AST_NODE_TYPES.MemberExpression &&\n !callee.computed &&\n callee.property.type === AST_NODE_TYPES.Identifier\n ) {\n return callee.property.name === \"assertNever\";\n }\n return false;\n};\n\nconst statementContainsAssertNever = (\n statement: TSESTree.Statement,\n): boolean => {\n if (statement.type === AST_NODE_TYPES.ExpressionStatement) {\n return isAssertNeverCall(statement.expression);\n }\n if (statement.type === AST_NODE_TYPES.ThrowStatement) {\n return isAssertNeverCall(statement.argument);\n }\n if (statement.type === AST_NODE_TYPES.ReturnStatement) {\n return (\n statement.argument !== null && isAssertNeverCall(statement.argument)\n );\n }\n // Recurse into block-scoped default bodies like `default: { ... }`\n if (statement.type === AST_NODE_TYPES.BlockStatement) {\n return statement.body.some(statementContainsAssertNever);\n }\n return false;\n};\n\n/**\n * Returns true if the statement performs some runtime work. An empty statement\n * or an empty block does nothing; everything else (`return`, `throw`, `break`,\n * a function call, an `if`, ...) is treated as legitimate runtime handling of\n * the default case.\n */\nconst isRuntimeHandlingStatement = (statement: TSESTree.Statement): boolean => {\n if (statement.type === AST_NODE_TYPES.EmptyStatement) return false;\n if (statement.type === AST_NODE_TYPES.BlockStatement) {\n return statement.body.some(isRuntimeHandlingStatement);\n }\n return true;\n};\n\n/**\n * A `default` clause with an empty body that is followed by another `case`\n * falls through into that case, which does the real work (e.g.\n * `default: case Single: handle();`). There is nothing to assert here.\n */\nconst isFallthroughDefault = (\n node: TSESTree.SwitchStatement,\n defaultIndex: number,\n): boolean => {\n const defaultCase = node.cases[defaultIndex];\n return (\n defaultCase !== undefined &&\n defaultCase.consequent.length === 0 &&\n defaultIndex < node.cases.length - 1\n );\n};\n\n/**\n * A `default` clause is a deliberate, documented no-op when its body is empty\n * (or an empty block) but carries a comment — e.g. `default: // do nothing`.\n * We can't distinguish a config-string switch from an exhaustive union switch\n * without type info, so a written-out intent to do nothing is honoured;\n * injecting `assertNever` there would throw at runtime. A bare empty default\n * with no comment is still flagged.\n */\nconst isCommentOnlyNoopDefault = (\n defaultCase: TSESTree.SwitchCase,\n sourceCode: Readonly<TSESLint.SourceCode>,\n): boolean => {\n if (defaultCase.consequent.length === 0) {\n const defaultToken = sourceCode.getFirstToken(defaultCase);\n const colonToken = defaultToken\n ? sourceCode.getTokenAfter(defaultToken)\n : null;\n return (\n colonToken !== null && sourceCode.getCommentsAfter(colonToken).length > 0\n );\n }\n const only = defaultCase.consequent[0];\n if (\n only !== undefined &&\n defaultCase.consequent.length === 1 &&\n only.type === AST_NODE_TYPES.BlockStatement &&\n only.body.length === 0\n ) {\n return sourceCode.getCommentsInside(only).length > 0;\n }\n return false;\n};\n\nexport default ESLintUtils.RuleCreator(\n (name) =>\n `https://github.com/sarj-ai/linting/blob/main/packages/typescript/src/rules/${name}.ts`,\n)<Options, MessageIds>({\n name: \"require-assert-never\",\n meta: {\n type: \"problem\",\n docs: {\n description:\n \"Require an exhaustive-style switch whose `default` case does no runtime work to call `assertNever(_)` so that discriminated unions are exhaustively checked at compile time. Switches with a legitimate runtime default (a reducer's `return state`, an HTTP-status `return fallback()`, a `break`, a `throw`, etc.) are left alone.\",\n },\n schema: [],\n messages: {\n missingAssertNever:\n \"Empty switch `default` case — add runtime handling or call `assertNever()` so the discriminated union is exhaustively checked at compile time.\",\n },\n },\n defaultOptions: [],\n create(context) {\n return {\n SwitchStatement(node: TSESTree.SwitchStatement): void {\n const defaultIndex = node.cases.findIndex(\n (caseNode) => caseNode.test === null,\n );\n // No `default` at all is fine — we don't demand exhaustiveness of every\n // switch, only of those that opted into a (no-op) default.\n if (defaultIndex === -1) return;\n const defaultCase = node.cases[defaultIndex];\n if (defaultCase === undefined) return;\n\n // An explicit `assertNever(...)` is the canonical exhaustiveness check.\n if (defaultCase.consequent.some(statementContainsAssertNever)) return;\n\n // A default that does real runtime work (return a fallback, break,\n // throw, log, ...) is legitimate — don't demand assertNever there.\n if (defaultCase.consequent.some(isRuntimeHandlingStatement)) return;\n\n // A fallthrough default hands control to a following case, which does\n // the work — there is nothing to assert.\n if (isFallthroughDefault(node, defaultIndex)) return;\n\n // A deliberate, comment-documented no-op default is honoured; we can't\n // prove the discriminant is a union without type info, and injecting\n // assertNever would throw at runtime on a config-string switch.\n if (isCommentOnlyNoopDefault(defaultCase, context.sourceCode)) return;\n\n // Otherwise the default is a bare, undocumented no-op: flag it.\n context.report({\n node: defaultCase,\n messageId: \"missingAssertNever\",\n });\n },\n };\n },\n});\n","import { ESLintUtils, type TSESTree, AST_NODE_TYPES } from \"@typescript-eslint/utils\";\nimport type { RuleContext, Scope } from \"@typescript-eslint/utils/ts-eslint\";\n\ntype MessageIds = \"missingZodValidation\";\ntype Options = readonly [];\n\ntype Ctx = Readonly<RuleContext<MessageIds, Options>>;\n\n// A receiver name that looks like a Zod schema: ends in `Schema`, or uses the\n// `Z<Capital>` house convention (e.g. `ZUser`), or the bare `z` builder.\nconst ZOD_SCHEMA_NAME_RE = /Schema$|^Z[A-Z]/;\n\n/**\n * Walk down a (possibly chained) receiver expression and decide whether it\n * originates from something that looks like a Zod schema — the bare `z` builder\n * (`z.object({...}).parse(...)`), a `Schema`-suffixed identifier\n * (`userSchema.parse(...)`), or a `Z`-prefixed identifier (`ZUser.parse(...)`).\n * Non-Zod receivers like `JSON` / `Date` are intentionally rejected.\n */\nconst looksLikeZodSchema = (node: TSESTree.Node): boolean => {\n let current: TSESTree.Node = node;\n while (true) {\n if (current.type === AST_NODE_TYPES.Identifier) {\n return current.name === \"z\" || ZOD_SCHEMA_NAME_RE.test(current.name);\n }\n if (current.type === AST_NODE_TYPES.CallExpression) {\n current = current.callee;\n continue;\n }\n if (current.type === AST_NODE_TYPES.MemberExpression) {\n current = current.object;\n continue;\n }\n return false;\n }\n};\n\n/**\n * Matches a Zod validation call: `<ZodSchema>.parse(...)` or\n * `<ZodSchema>.safeParse(...)`. Keys off the *receiver* looking like a Zod\n * schema rather than the method name alone, so `JSON.parse(...)` /\n * `Date.parse(...)` are NOT treated as validation.\n */\nconst isZodParseCall = (node: TSESTree.Node): boolean => {\n if (node.type !== AST_NODE_TYPES.CallExpression) return false;\n const callee = node.callee;\n if (callee.type !== AST_NODE_TYPES.MemberExpression) return false;\n if (callee.computed) return false;\n if (callee.property.type !== AST_NODE_TYPES.Identifier) return false;\n const method = callee.property.name;\n if (method !== \"parse\" && method !== \"safeParse\") return false;\n return looksLikeZodSchema(callee.object);\n};\n\n/**\n * Matches an (optionally awaited) `<x>.formData()` call — the canonical way a\n * `FormData` object is obtained from a `Request` / `Response`.\n */\nconst isFormDataMethodCall = (node: TSESTree.Node): boolean => {\n let current: TSESTree.Node = node;\n if (current.type === AST_NODE_TYPES.AwaitExpression) {\n current = current.argument;\n }\n if (current.type !== AST_NODE_TYPES.CallExpression) return false;\n const callee = current.callee;\n return (\n callee.type === AST_NODE_TYPES.MemberExpression &&\n !callee.computed &&\n callee.property.type === AST_NODE_TYPES.Identifier &&\n callee.property.name === \"formData\"\n );\n};\n\nexport default ESLintUtils.RuleCreator(\n (name) =>\n `https://github.com/sarj-ai/linting/blob/main/packages/typescript/src/rules/${name}.ts`,\n)<Options, MessageIds>({\n name: \"require-zod-form-validation\",\n meta: {\n type: \"problem\",\n docs: {\n description:\n \"Require Zod validation (`Schema.parse(...)` / `Schema.safeParse(...)`) when reading values out of a `FormData` object.\",\n },\n schema: [],\n messages: {\n missingZodValidation:\n \"FormData parsing must use Zod schema validation (e.g., Schema.parse() / Schema.safeParse())\",\n },\n },\n defaultOptions: [],\n create(context: Ctx) {\n // A receiver is a FormData source if its name reads like form data, or if\n // it is a binding initialized from a `.formData()` call.\n const isFormSourceIdentifier = (node: TSESTree.Node): boolean => {\n if (node.type !== AST_NODE_TYPES.Identifier) return false;\n if (/formdata/i.test(node.name)) return true;\n\n let scope: Scope.Scope | null = context.sourceCode.getScope(node);\n while (scope !== null) {\n const variable = scope.set.get(node.name);\n if (variable !== undefined && variable.defs.length === 1) {\n const def = variable.defs[0];\n if (\n def !== undefined &&\n def.type === \"Variable\" &&\n def.node.type === AST_NODE_TYPES.VariableDeclarator &&\n def.node.init !== null\n ) {\n return isFormDataMethodCall(def.node.init);\n }\n return false;\n }\n scope = scope.upper;\n }\n return false;\n };\n\n const isFormDataGetCall = (node: TSESTree.CallExpression): boolean => {\n const callee = node.callee;\n if (callee.type !== AST_NODE_TYPES.MemberExpression) return false;\n if (\n callee.property.type !== AST_NODE_TYPES.Identifier ||\n callee.property.name !== \"get\"\n ) {\n return false;\n }\n return isFormSourceIdentifier(callee.object);\n };\n\n return {\n CallExpression(node: TSESTree.CallExpression): void {\n if (!isFormDataGetCall(node)) return;\n\n // Walk up the parent chain to find a surrounding Zod `.parse(...)` /\n // `.safeParse(...)` call. `.parent` is `null` at the Program root, so we\n // must guard for both null and undefined.\n let parent: TSESTree.Node | null | undefined = node.parent;\n while (parent !== null && parent !== undefined) {\n if (isZodParseCall(parent)) return;\n parent = parent.parent;\n }\n\n context.report({\n node,\n messageId: \"missingZodValidation\",\n });\n },\n };\n },\n});\n","/**\n * @fileoverview Enforce the `Z`-prefix naming convention for Zod schemas\n * (`ZUser = z.object({...})`).\n *\n * NOTE on audit backing: this is an intentional org-wide convention, not a\n * direct mapping of `readability-and-naming.md` (which governs property-name\n * casing, not schema-variable prefixes). The `Z` prefix lets schemas and their\n * inferred types share a base name (`ZUser` / `type User = z.infer<typeof\n * ZUser>`) without collision. Kept as-is by design.\n */\n\nimport { ESLintUtils, type TSESTree, AST_NODE_TYPES } from \"@typescript-eslint/utils\";\n\ntype MessageIds = \"zPrefix\";\ntype Options = readonly [];\n\n/**\n * Walks down a (possibly chained) callee like `z.object().extend().refine()` and\n * returns `true` if the chain originates from a bare `z` identifier — i.e. the\n * outermost MemberExpression on the chain has `z` as its receiver.\n */\nconst calleeChainStartsWithZ = (node: TSESTree.Node): boolean => {\n let current: TSESTree.Node = node;\n\n while (current.type === AST_NODE_TYPES.MemberExpression) {\n const receiver: TSESTree.Node = current.object;\n if (receiver.type === AST_NODE_TYPES.Identifier && receiver.name === \"z\") {\n return true;\n }\n if (receiver.type === AST_NODE_TYPES.CallExpression) {\n current = receiver.callee;\n continue;\n }\n return false;\n }\n\n return false;\n};\n\nexport default ESLintUtils.RuleCreator(\n (name) =>\n `https://github.com/sarj-ai/linting/blob/main/packages/typescript/src/rules/${name}.ts`,\n)<Options, MessageIds>({\n name: \"zod-naming-convention\",\n meta: {\n type: \"suggestion\",\n docs: {\n description:\n \"Enforce Zod schemas to be named with a Z prefix (e.g. `ZUser = z.object({...})`).\",\n },\n schema: [],\n messages: {\n zPrefix: \"Zod schema names should start with Z\",\n },\n },\n defaultOptions: [],\n create(context) {\n return {\n VariableDeclarator(node: TSESTree.VariableDeclarator): void {\n const init = node.init;\n if (init === null || init === undefined) return;\n if (init.type !== AST_NODE_TYPES.CallExpression) return;\n\n const callee = init.callee;\n if (callee.type !== AST_NODE_TYPES.MemberExpression) return;\n\n if (!calleeChainStartsWithZ(callee)) return;\n\n if (node.id.type !== AST_NODE_TYPES.Identifier) return;\n const variableName = node.id.name;\n if (variableName.startsWith(\"Z\")) return;\n\n context.report({\n node: node.id,\n messageId: \"zPrefix\",\n });\n },\n };\n },\n});\n","/**\n * @fileoverview TS port of Python SARJ028\n * (`no-cors-wildcard-with-credentials`). Flags CORS configuration that reflects\n * ANY origin (`\"*\"`) while ALSO allowing credentials. The browser treats\n * `Access-Control-Allow-Origin: *` together with\n * `Access-Control-Allow-Credentials: true` as a directive to reflect the\n * request's Origin and expose authenticated (cookie/session) responses — which\n * lets any website read them cross-origin. That is a credential-theft surface.\n *\n * Two shapes are detected, and BOTH the wildcard origin and credentials=true\n * must co-occur before the rule fires (a `\"*\"` origin without credentials, or\n * credentials with a specific origin, is safe and is NOT reported):\n *\n * 1. A `cors(...)` / `new Cors(...)` call whose options `ObjectExpression`\n * has `credentials: true` AND an `origin` property whose value subtree\n * contains a `\"*\"` string literal anywhere — the bare `\"*\"`, the `[\"*\"]`\n * array, or a `flag ? origins : \"*\"` conditional branch. Reported at the\n * call.\n *\n * 2. Manual header setting where, within the SAME function (or module) scope,\n * `Access-Control-Allow-Origin` is set to `\"*\"` AND\n * `Access-Control-Allow-Credentials` is set to `\"true\"` — via\n * `res.setHeader(...)`, `headers.set(...)` / `.append(...)` (covers\n * `NextResponse` header objects), or a single object literal\n * `{ \"Access-Control-Allow-Origin\": \"*\", \"Access-Control-Allow-Credentials\": \"true\" }`.\n * Header-name matching is case-insensitive. The object-literal form is\n * reported at the object; the split `setHeader`/`set` form is reported at\n * the wildcard-origin call.\n *\n * References:\n * - https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#credentialed_requests_and_wildcards\n */\n\nimport { ESLintUtils, type TSESTree } from \"@typescript-eslint/utils\";\n\ntype MessageIds = \"corsWildcardWithCredentials\";\ntype Options = readonly [];\n\nconst ACAO_HEADER = \"access-control-allow-origin\";\nconst ACAC_HEADER = \"access-control-allow-credentials\";\nconst HEADER_SET_METHODS = new Set([\"setheader\", \"set\", \"append\"]);\n\n/**\n * True only for the boolean literal `true` (not `1`, not a truthy expression).\n */\nfunction isTrueLiteral(node: TSESTree.Node): boolean {\n return node.type === \"Literal\" && node.value === true;\n}\n\n/**\n * True if `node` is a string literal whose value equals `\"true\"`\n * (case-insensitive), or the boolean literal `true`. Header values are strings,\n * but some frameworks coerce a boolean, so both are accepted.\n */\nfunction isCredentialsTrueValue(node: TSESTree.Node): boolean {\n if (node.type === \"Literal\") {\n if (node.value === true) {\n return true;\n }\n if (typeof node.value === \"string\") {\n return node.value.trim().toLowerCase() === \"true\";\n }\n }\n return false;\n}\n\n/**\n * True if `node` is the string literal `\"*\"`.\n */\nfunction isStarLiteral(node: TSESTree.Node): boolean {\n return node.type === \"Literal\" && node.value === \"*\";\n}\n\n/**\n * True if a `\"*\"` string literal appears anywhere in `node`'s subtree. Walking\n * the whole subtree catches `\"*\"`, `[\"*\"]`, and the `flag ? origins : \"*\"`\n * conditional branch. A dynamic `origin: someVar` has no `\"*\"` literal, so it\n * does not fire.\n */\nfunction subtreeContainsStarLiteral(node: TSESTree.Node): boolean {\n if (isStarLiteral(node)) {\n return true;\n }\n for (const key of Object.keys(node)) {\n if (key === \"parent\" || key === \"loc\" || key === \"range\") {\n continue;\n }\n const value = (node as unknown as Record<string, unknown>)[key];\n if (Array.isArray(value)) {\n for (const child of value) {\n if (isNode(child) && subtreeContainsStarLiteral(child)) {\n return true;\n }\n }\n } else if (isNode(value) && subtreeContainsStarLiteral(value)) {\n return true;\n }\n }\n return false;\n}\n\nfunction isNode(value: unknown): value is TSESTree.Node {\n return (\n typeof value === \"object\" &&\n value !== null &&\n typeof (value as { type?: unknown }).type === \"string\"\n );\n}\n\n/**\n * Returns the (non-computed) string name of a property key, or `undefined`.\n */\nfunction propertyKeyName(prop: TSESTree.Property): string | undefined {\n if (prop.computed) {\n return undefined;\n }\n const key = prop.key;\n if (key.type === \"Identifier\") {\n return key.name;\n }\n if (key.type === \"Literal\" && typeof key.value === \"string\") {\n return key.value;\n }\n return undefined;\n}\n\n/**\n * Extracts the callee's terminal identifier name for a call/new expression\n * (`cors` for `cors(...)` and `app.cors(...)`, `Cors` for `new Cors(...)`).\n */\nfunction calleeName(\n node: TSESTree.CallExpression | TSESTree.NewExpression,\n): string | undefined {\n const callee = node.callee;\n if (callee.type === \"Identifier\") {\n return callee.name;\n }\n if (\n callee.type === \"MemberExpression\" &&\n !callee.computed &&\n callee.property.type === \"Identifier\"\n ) {\n return callee.property.name;\n }\n return undefined;\n}\n\n/**\n * Detects the `cors({ origin: \"*\", credentials: true })` shape. Returns true\n * when the callee is `cors` / `Cors` and the first ObjectExpression argument\n * has `credentials: true` AND an `origin` whose subtree contains `\"*\"`.\n */\nfunction isCorsWildcardCredentialsCall(\n node: TSESTree.CallExpression | TSESTree.NewExpression,\n): boolean {\n const name = calleeName(node);\n if (name === undefined || name.toLowerCase() !== \"cors\") {\n return false;\n }\n const options = node.arguments.find(\n (arg): arg is TSESTree.ObjectExpression => arg.type === \"ObjectExpression\",\n );\n if (options === undefined) {\n return false;\n }\n let hasCredentials = false;\n let hasWildcardOrigin = false;\n for (const prop of options.properties) {\n if (prop.type !== \"Property\") {\n continue;\n }\n const key = propertyKeyName(prop);\n if (key === \"credentials\" && isTrueLiteral(prop.value)) {\n hasCredentials = true;\n } else if (key === \"origin\" && subtreeContainsStarLiteral(prop.value)) {\n hasWildcardOrigin = true;\n }\n }\n return hasCredentials && hasWildcardOrigin;\n}\n\n/**\n * True if the ObjectExpression is a header map setting BOTH\n * `Access-Control-Allow-Origin: \"*\"` and\n * `Access-Control-Allow-Credentials: \"true\"` (case-insensitive keys).\n */\nfunction isWildcardCredentialsHeaderObject(\n node: TSESTree.ObjectExpression,\n): boolean {\n let wildcardOrigin = false;\n let credentialsTrue = false;\n for (const prop of node.properties) {\n if (prop.type !== \"Property\") {\n continue;\n }\n const key = propertyKeyName(prop);\n if (key === undefined) {\n continue;\n }\n const header = key.toLowerCase();\n if (header === ACAO_HEADER && isStarLiteral(prop.value)) {\n wildcardOrigin = true;\n } else if (header === ACAC_HEADER && isCredentialsTrueValue(prop.value)) {\n credentialsTrue = true;\n }\n }\n return wildcardOrigin && credentialsTrue;\n}\n\ntype HeaderSetKind = \"origin\" | \"credentials\";\n\n/**\n * Classifies a `x.setHeader(name, value)` / `x.set(name, value)` /\n * `x.append(name, value)` call as an ACAO-wildcard set, an ACAC-true set, or\n * neither.\n */\nfunction classifyHeaderSetCall(\n node: TSESTree.CallExpression,\n): HeaderSetKind | undefined {\n const callee = node.callee;\n if (\n callee.type !== \"MemberExpression\" ||\n callee.computed ||\n callee.property.type !== \"Identifier\" ||\n !HEADER_SET_METHODS.has(callee.property.name.toLowerCase())\n ) {\n return undefined;\n }\n const [nameArg, valueArg] = node.arguments;\n if (\n nameArg === undefined ||\n valueArg === undefined ||\n nameArg.type !== \"Literal\" ||\n typeof nameArg.value !== \"string\"\n ) {\n return undefined;\n }\n const header = nameArg.value.toLowerCase();\n if (header === ACAO_HEADER && isStarLiteral(valueArg)) {\n return \"origin\";\n }\n if (header === ACAC_HEADER && isCredentialsTrueValue(valueArg)) {\n return \"credentials\";\n }\n return undefined;\n}\n\n/**\n * Nearest enclosing function node, or `undefined` for module scope. Used to\n * group split `setHeader`/`set` header assignments so a wildcard origin and a\n * credentials=true set only pair up when they live in the same scope.\n */\nfunction enclosingScope(node: TSESTree.Node): TSESTree.Node | undefined {\n let current: TSESTree.Node | undefined = node.parent;\n while (current) {\n if (\n current.type === \"FunctionDeclaration\" ||\n current.type === \"FunctionExpression\" ||\n current.type === \"ArrowFunctionExpression\"\n ) {\n return current;\n }\n current = current.parent;\n }\n return undefined;\n}\n\ninterface ScopeHeaderSets {\n originNodes: TSESTree.CallExpression[];\n credentialsNodes: TSESTree.CallExpression[];\n}\n\nexport default ESLintUtils.RuleCreator(\n (name) =>\n `https://github.com/sarj-ai/linting/blob/main/packages/typescript/src/rules/${name}.ts`,\n)<Options, MessageIds>({\n name: \"no-cors-wildcard-with-credentials\",\n meta: {\n type: \"problem\",\n docs: {\n description:\n 'Disallow CORS that reflects any Origin (`\"*\"`) while allowing credentials; any site could then read authenticated responses. Enumerate explicit trusted origins instead.',\n },\n schema: [],\n messages: {\n corsWildcardWithCredentials:\n 'CORS reflects any Origin (`\"*\"`) while allowing credentials — any site can read authenticated responses. Enumerate explicit trusted origins instead of using `\"*\"` with credentials.',\n },\n },\n defaultOptions: [],\n create(context) {\n const scopeHeaderSets = new Map<TSESTree.Node | \"module\", ScopeHeaderSets>();\n\n function recordHeaderSet(\n node: TSESTree.CallExpression,\n kind: HeaderSetKind,\n ): void {\n const key = enclosingScope(node) ?? \"module\";\n let entry = scopeHeaderSets.get(key);\n if (entry === undefined) {\n entry = { originNodes: [], credentialsNodes: [] };\n scopeHeaderSets.set(key, entry);\n }\n if (kind === \"origin\") {\n entry.originNodes.push(node);\n } else {\n entry.credentialsNodes.push(node);\n }\n }\n\n return {\n NewExpression(node: TSESTree.NewExpression): void {\n if (isCorsWildcardCredentialsCall(node)) {\n context.report({ node, messageId: \"corsWildcardWithCredentials\" });\n }\n },\n CallExpression(node: TSESTree.CallExpression): void {\n if (isCorsWildcardCredentialsCall(node)) {\n context.report({ node, messageId: \"corsWildcardWithCredentials\" });\n return;\n }\n const kind = classifyHeaderSetCall(node);\n if (kind !== undefined) {\n recordHeaderSet(node, kind);\n }\n },\n ObjectExpression(node: TSESTree.ObjectExpression): void {\n if (isWildcardCredentialsHeaderObject(node)) {\n context.report({ node, messageId: \"corsWildcardWithCredentials\" });\n }\n },\n \"Program:exit\"(): void {\n for (const { originNodes, credentialsNodes } of scopeHeaderSets.values()) {\n if (originNodes.length > 0 && credentialsNodes.length > 0) {\n for (const node of originNodes) {\n context.report({\n node,\n messageId: \"corsWildcardWithCredentials\",\n });\n }\n }\n }\n },\n };\n },\n});\n","/**\n * @fileoverview Flag `.catch()` handlers that silently swallow the rejection:\n * `promise.catch(() => null)` and friends. These are the promise-chain twin of\n * the empty-`catch`-block anti-pattern already covered by the try/catch rules —\n * the failure vanishes with no log, no metric, no rethrow, and the caller\n * receives a sentinel it usually cannot distinguish from a real value.\n *\n * Only handlers that provably do nothing are flagged: an arrow/function whose\n * entire body is a bare literal (`null`, `undefined`, a number, a string, a\n * boolean), an empty object/array literal, an empty block, or a block that\n * only `return`s one of those. A handler that references its error parameter\n * or calls anything (logging, metrics, rethrow) is never flagged.\n *\n * Two corpus-driven exemptions (5-repo sweep, 2026-07: 11/35 raw hits — 31% —\n * were these deliberate idioms):\n * - `res.json().catch(() => ({}))` / `res.text().catch(() => '')` — the\n * body-parse-fallback idiom while composing error diagnostics; the parse\n * failure itself is not the signal being handled.\n * - Test files (`.test.` / `.spec.` / `__tests__/`), where silencing a\n * promise is routine unhandled-rejection suppression.\n */\n\nimport { AST_NODE_TYPES, ESLintUtils, type TSESTree } from \"@typescript-eslint/utils\";\n\nimport { isTestFile } from \"./_paths.js\";\n\ntype MessageIds = \"silentCatch\";\ntype Options = readonly [];\n\n/** True for `x.json()` / `x.text()` — the receiver of a body-parse-fallback catch. */\nfunction isBodyParseCall(node: TSESTree.Expression): boolean {\n return (\n node.type === AST_NODE_TYPES.CallExpression &&\n node.arguments.length === 0 &&\n node.callee.type === AST_NODE_TYPES.MemberExpression &&\n !node.callee.computed &&\n node.callee.property.type === AST_NODE_TYPES.Identifier &&\n (node.callee.property.name === \"json\" ||\n node.callee.property.name === \"text\")\n );\n}\n\n/** True for expressions that provably discard the error: bare literals,\n * `undefined`, empty object/array literals. */\nfunction isSilentExpression(node: TSESTree.Expression): boolean {\n switch (node.type) {\n case AST_NODE_TYPES.Literal:\n // null / number / string / boolean literals (regex literals excluded —\n // nobody writes `.catch(() => /x/)` and they are not sentinel values).\n return !(\"regex\" in node);\n case AST_NODE_TYPES.Identifier:\n return node.name === \"undefined\";\n case AST_NODE_TYPES.UnaryExpression:\n // `void 0` — the other spelling of undefined.\n return (\n node.operator === \"void\" &&\n node.argument.type === AST_NODE_TYPES.Literal\n );\n case AST_NODE_TYPES.ObjectExpression:\n return node.properties.length === 0;\n case AST_NODE_TYPES.ArrayExpression:\n return node.elements.length === 0;\n case AST_NODE_TYPES.TSAsExpression:\n // `.catch(() => null as Foo | null)` is still silent.\n return isSilentExpression(node.expression);\n default:\n return false;\n }\n}\n\n/** True when the handler's whole body provably does nothing with the error. */\nfunction isSilentHandler(\n handler: TSESTree.ArrowFunctionExpression | TSESTree.FunctionExpression,\n): boolean {\n const body = handler.body;\n\n if (body.type !== AST_NODE_TYPES.BlockStatement) {\n // Arrow expression body: `.catch(() => null)`\n return isSilentExpression(body);\n }\n\n if (body.body.length === 0) {\n // `.catch(() => {})` / `.catch(function () {})`\n return true;\n }\n\n if (body.body.length === 1) {\n const only = body.body[0];\n if (only !== undefined && only.type === AST_NODE_TYPES.ReturnStatement) {\n // `.catch(() => { return null; })`\n return only.argument === null || isSilentExpression(only.argument);\n }\n }\n\n return false;\n}\n\nexport default ESLintUtils.RuleCreator(\n (name) =>\n `https://github.com/sarj-ai/linting/blob/main/packages/typescript/src/rules/${name}.ts`,\n)<Options, MessageIds>({\n name: \"no-silent-promise-catch\",\n meta: {\n type: \"problem\",\n docs: {\n description:\n \"Disallow `.catch()` handlers that silently swallow the rejection (e.g. `.catch(() => null)`); log, rethrow, or handle the error.\",\n },\n schema: [],\n messages: {\n silentCatch:\n \"This `.catch()` swallows the rejection without logging, rethrowing, or handling it — failures become invisible and callers get an indistinguishable sentinel. Log the error (and only then map to a fallback), or let it propagate.\",\n },\n },\n defaultOptions: [],\n create(context) {\n if (isTestFile(context.filename)) {\n return {};\n }\n\n return {\n CallExpression(node: TSESTree.CallExpression): void {\n if (\n node.callee.type !== AST_NODE_TYPES.MemberExpression ||\n node.callee.computed ||\n node.callee.property.type !== AST_NODE_TYPES.Identifier ||\n node.callee.property.name !== \"catch\"\n ) {\n return;\n }\n\n if (isBodyParseCall(node.callee.object)) {\n return;\n }\n\n if (node.arguments.length !== 1) {\n return;\n }\n const handler = node.arguments[0];\n if (\n handler === undefined ||\n (handler.type !== AST_NODE_TYPES.ArrowFunctionExpression &&\n handler.type !== AST_NODE_TYPES.FunctionExpression)\n ) {\n return;\n }\n\n if (isSilentHandler(handler)) {\n // Anchor on the CallExpression, not the handler: when the handler\n // sits on a later line than the call (multi-line `.catch(`), a\n // handler-anchored report escapes an `eslint-disable-next-line`\n // above the call AND marks that directive as unused.\n context.report({ node, messageId: \"silentCatch\" });\n }\n },\n };\n },\n});\n","/**\n * @fileoverview Shared filename predicates for rules that exempt whole file\n * categories. One definition (mirroring the Python `_paths.py` extraction) so\n * the per-rule test-file regexes cannot drift apart again.\n */\n\nconst TEST_FILE_RE = /(\\.(test|spec)\\.)|([\\\\/]__tests__[\\\\/])/;\n\nconst SCRIPT_FILE_RE = /([\\\\/]scripts[\\\\/])|(\\.mjs$)/;\n\n/** True for test files: `*.test.*`, `*.spec.*`, or anything under `__tests__/`. */\nexport function isTestFile(filename: string): boolean {\n return TEST_FILE_RE.test(filename);\n}\n\n/**\n * True for one-off tooling files: anything under a `scripts/` directory or a\n * `*.mjs` file. Dev scripts run interactively and die with the terminal, so\n * production-hardening rules (e.g. fetch timeouts) do not apply there.\n */\nexport function isScriptFile(filename: string): boolean {\n return SCRIPT_FILE_RE.test(filename);\n}\n","/**\n * @fileoverview Require an abort `signal` on global `fetch()` calls. A fetch\n * without a timeout hangs forever when the upstream stalls, tying up the\n * request (or worker) with it. Pass `AbortSignal.timeout(ms)` — or a signal\n * from an `AbortController` — in the init object.\n *\n * Scope is deliberately narrow to keep false positives near zero:\n * - Only calls that resolve to the *global* `fetch` are checked: bare\n * `fetch(...)` (unless a local binding — import, parameter, variable —\n * shadows it) plus the explicit global spellings `globalThis.fetch(...)`,\n * `window.fetch(...)`, and `self.fetch(...)`. Other member calls like\n * Cloudflare Workers service bindings (`env.MY_SERVICE.fetch(...)`) or\n * custom clients (`client.fetch(...)`) are skipped.\n * - A call is flagged only when the init argument is absent, or is an\n * object literal that provably lacks `signal` (no spread, no `signal`\n * key). Anything dynamic (an identifier, a call result, a spread) is\n * assumed to carry a signal.\n * - Single-argument calls whose argument is not a string/template literal\n * are skipped: `fetch(request)` / `fetch(c.req.raw.clone())` are proxy\n * passthroughs (Workers idiom) where the inbound Request governs the\n * lifetime and attaching a fresh signal is impossible or wrong.\n * - Test files and one-off tooling (`scripts/**`, `*.mjs`) are skipped —\n * dev scripts die with the terminal, so hang-hardening is noise there.\n *\n * Wrapper modules that centralize timeout handling can be exempted via the\n * `allowIn` glob-pattern option.\n */\n\nimport {\n AST_NODE_TYPES,\n ASTUtils,\n ESLintUtils,\n type TSESTree,\n} from \"@typescript-eslint/utils\";\n\nimport { isScriptFile, isTestFile } from \"./_paths.js\";\n\ntype MessageIds = \"missingSignal\";\ntype Options = readonly [\n {\n allowIn?: readonly string[];\n }?,\n];\n\n/** The explicit-global receivers of `<obj>.fetch(...)`. */\nconst GLOBAL_OBJECTS: ReadonlySet<string> = new Set([\n \"globalThis\",\n \"window\",\n \"self\",\n]);\n\nfunction matchesAnyPattern(\n filename: string,\n patterns: readonly string[],\n): boolean {\n for (const pattern of patterns) {\n // Convert minimatch-ish globs to regex: ** -> .*, * -> [^/\\\\]*\n const regexSource = pattern\n .replace(/[.+^${}()|[\\]\\\\]/g, \"\\\\$&\")\n .replace(/\\*\\*/g, \"::DOUBLESTAR::\")\n .replace(/\\*/g, \"[^/\\\\\\\\]*\")\n .replace(/::DOUBLESTAR::/g, \".*\");\n if (new RegExp(`^${regexSource}$`).test(filename)) {\n return true;\n }\n }\n return false;\n}\n\n/**\n * True when the init argument provably lacks an abort signal: it is an object\n * literal with no `signal` property and no spread element. Any other shape\n * (identifier, call, spread, conditional, ...) may carry a signal, so it is\n * treated as safe.\n */\nfunction initProvablyLacksSignal(init: TSESTree.CallExpressionArgument): boolean {\n if (init.type !== AST_NODE_TYPES.ObjectExpression) {\n return false;\n }\n for (const prop of init.properties) {\n if (prop.type === AST_NODE_TYPES.SpreadElement) {\n return false;\n }\n if (\n (prop.key.type === AST_NODE_TYPES.Identifier &&\n prop.key.name === \"signal\") ||\n (prop.key.type === AST_NODE_TYPES.Literal && prop.key.value === \"signal\")\n ) {\n return false;\n }\n // A computed key could be \"signal\" at runtime; assume it is.\n if (prop.computed) {\n return false;\n }\n }\n return true;\n}\n\n/** True for a string or template literal — a URL spelled inline. */\nfunction isStringish(node: TSESTree.CallExpressionArgument): boolean {\n return (\n (node.type === AST_NODE_TYPES.Literal && typeof node.value === \"string\") ||\n node.type === AST_NODE_TYPES.TemplateLiteral\n );\n}\n\nexport default ESLintUtils.RuleCreator(\n (name) =>\n `https://github.com/sarj-ai/linting/blob/main/packages/typescript/src/rules/${name}.ts`,\n)<Options, MessageIds>({\n name: \"require-fetch-timeout\",\n meta: {\n type: \"problem\",\n docs: {\n description:\n \"Require an abort `signal` (e.g. `AbortSignal.timeout(ms)`) on global `fetch()` calls so stalled upstreams cannot hang the caller forever.\",\n },\n schema: [\n {\n type: \"object\",\n additionalProperties: false,\n properties: {\n allowIn: {\n description:\n \"Glob patterns for wrapper modules exempt from the rule. Matched against the ABSOLUTE file path, so anchor with a `**/` prefix (e.g. `**/http-client.ts`).\",\n type: \"array\",\n items: { type: \"string\" },\n },\n },\n },\n ],\n messages: {\n missingSignal:\n \"This `fetch()` has no abort `signal` — a stalled upstream will hang it forever. Pass `{ signal: AbortSignal.timeout(ms) }` or a signal from an AbortController.\",\n },\n },\n defaultOptions: [{}],\n create(context, [optionsArg]) {\n if (isTestFile(context.filename) || isScriptFile(context.filename)) {\n return {};\n }\n const allowIn = optionsArg?.allowIn ?? [];\n if (allowIn.length > 0 && matchesAnyPattern(context.filename, allowIn)) {\n return {};\n }\n\n /** True when `identifier` resolves to the global (no local binding shadows it). */\n function resolvesToGlobal(identifier: TSESTree.Identifier): boolean {\n const scope = context.sourceCode.getScope(identifier);\n const variable = ASTUtils.findVariable(scope, identifier.name);\n // Unresolved → implicit global. Resolved with zero defs → declared\n // global (languageOptions.globals). Any def is a local shadow.\n return variable === null || variable.defs.length === 0;\n }\n\n /** True for `fetch(...)` / `globalThis.fetch(...)` / `window.fetch(...)` /\n * `self.fetch(...)` where the receiver resolves to the global scope. */\n function isGlobalFetchCall(callee: TSESTree.Expression): boolean {\n if (callee.type === AST_NODE_TYPES.Identifier) {\n return callee.name === \"fetch\" && resolvesToGlobal(callee);\n }\n return (\n callee.type === AST_NODE_TYPES.MemberExpression &&\n !callee.computed &&\n callee.property.type === AST_NODE_TYPES.Identifier &&\n callee.property.name === \"fetch\" &&\n callee.object.type === AST_NODE_TYPES.Identifier &&\n GLOBAL_OBJECTS.has(callee.object.name) &&\n resolvesToGlobal(callee.object)\n );\n }\n\n return {\n CallExpression(node: TSESTree.CallExpression): void {\n if (!isGlobalFetchCall(node.callee)) {\n return;\n }\n\n // Proxy passthrough: a lone non-string argument is a Request (or\n // equivalent) being forwarded — the inbound request owns the\n // lifetime, and a fresh signal cannot be attached without an init.\n const [first, init] = node.arguments;\n if (node.arguments.length === 1 && first !== undefined && !isStringish(first)) {\n return;\n }\n\n if (init === undefined || initProvablyLacksSignal(init)) {\n context.report({ node, messageId: \"missingSignal\" });\n }\n },\n };\n },\n});\n","/**\n * @fileoverview Flag TanStack Router `validateSearch` implementations that\n * hand-roll \"validation\" with `as` casts. A cast asserts a shape without\n * checking it, so malformed query params flow into the app typed as clean\n * data. Use a schema validator (e.g. `zodValidator(searchSchema)` from\n * `@tanstack/zod-adapter`, or `searchSchema.parse`) so the search params are\n * actually validated at runtime.\n *\n * Deliberately narrow: only fires on a property literally named\n * `validateSearch` whose value is a function containing at least one cast —\n * `as` form or angle-bracket `<T>x` form (`as const` exempt: it narrows\n * rather than lies). Two exemptions:\n * - Casts that feed a validator are fine: an argument (transitively) of a\n * call whose callee property is `parse` / `safeParse` / `decode` — e.g.\n * the rule's own recommended remedy\n * `validateSearch: (s) => schema.parse(s as Record<string, unknown>)` —\n * is validated at runtime regardless of the cast.\n * - Test files, where route stubs are fixtures rather than real routes.\n */\n\nimport { AST_NODE_TYPES, ESLintUtils, type TSESTree } from \"@typescript-eslint/utils\";\n\nimport { isTestFile } from \"./_paths.js\";\n\ntype MessageIds = \"castInValidateSearch\";\ntype Options = readonly [];\n\n/** Callee property names whose calls validate their input at runtime. */\nconst VALIDATOR_METHODS: ReadonlySet<string> = new Set([\n \"parse\",\n \"safeParse\",\n \"decode\",\n]);\n\nfunction isConstTypeAnnotation(typeAnnotation: TSESTree.TypeNode): boolean {\n return (\n typeAnnotation.type === AST_NODE_TYPES.TSTypeReference &&\n typeAnnotation.typeName.type === AST_NODE_TYPES.Identifier &&\n typeAnnotation.typeName.name === \"const\"\n );\n}\n\n/** True for a call whose callee property is a runtime validator (`schema.parse(...)`). */\nfunction isValidatorCall(node: TSESTree.CallExpression): boolean {\n return (\n node.callee.type === AST_NODE_TYPES.MemberExpression &&\n !node.callee.computed &&\n node.callee.property.type === AST_NODE_TYPES.Identifier &&\n VALIDATOR_METHODS.has(node.callee.property.name)\n );\n}\n\n/**\n * Depth-first search for the first offending cast under `node`: a non-`const`\n * TSAsExpression or TSTypeAssertion that is not (transitively) an argument of\n * a validator call. `insideValidatorArg` is threaded through the descent so a\n * cast feeding `schema.parse(...)` is exempt however deeply it nests.\n */\nfunction findCastExpression(\n node: TSESTree.Node,\n insideValidatorArg: boolean,\n): TSESTree.TSAsExpression | TSESTree.TSTypeAssertion | null {\n if (\n (node.type === AST_NODE_TYPES.TSAsExpression ||\n node.type === AST_NODE_TYPES.TSTypeAssertion) &&\n !isConstTypeAnnotation(node.typeAnnotation) &&\n !insideValidatorArg\n ) {\n return node;\n }\n\n if (\n node.type === AST_NODE_TYPES.CallExpression &&\n isValidatorCall(node)\n ) {\n // The callee itself is still in scope; only the arguments are validated.\n const inCallee = findCastExpression(node.callee, insideValidatorArg);\n if (inCallee !== null) {\n return inCallee;\n }\n for (const arg of node.arguments) {\n const found = findCastExpression(arg, true);\n if (found !== null) {\n return found;\n }\n }\n return null;\n }\n\n for (const key of Object.keys(node)) {\n if (key === \"parent\") {\n continue;\n }\n const value = (node as unknown as Record<string, unknown>)[key];\n const children = Array.isArray(value) ? value : [value];\n for (const child of children) {\n if (\n child !== null &&\n typeof child === \"object\" &&\n \"type\" in child &&\n typeof (child as { type: unknown }).type === \"string\"\n ) {\n const found = findCastExpression(\n child as TSESTree.Node,\n insideValidatorArg,\n );\n if (found !== null) {\n return found;\n }\n }\n }\n }\n return null;\n}\n\nexport default ESLintUtils.RuleCreator(\n (name) =>\n `https://github.com/sarj-ai/linting/blob/main/packages/typescript/src/rules/${name}.ts`,\n)<Options, MessageIds>({\n name: \"require-schema-validate-search\",\n meta: {\n type: \"problem\",\n docs: {\n description:\n \"Disallow `as` casts inside hand-rolled `validateSearch` functions; use a schema validator (e.g. zodValidator) so search params are validated at runtime.\",\n },\n schema: [],\n messages: {\n castInValidateSearch:\n \"This `validateSearch` asserts the search-param shape with `as` instead of validating it — malformed query params flow through typed as clean data. Use a schema validator (e.g. `zodValidator(searchSchema)` or `searchSchema.parse`) instead of casting.\",\n },\n },\n defaultOptions: [],\n create(context) {\n if (isTestFile(context.filename)) {\n return {};\n }\n\n return {\n Property(node: TSESTree.Property): void {\n const isValidateSearchKey =\n (!node.computed &&\n node.key.type === AST_NODE_TYPES.Identifier &&\n node.key.name === \"validateSearch\") ||\n (node.key.type === AST_NODE_TYPES.Literal &&\n node.key.value === \"validateSearch\");\n if (!isValidateSearchKey) {\n return;\n }\n\n if (\n node.value.type !== AST_NODE_TYPES.ArrowFunctionExpression &&\n node.value.type !== AST_NODE_TYPES.FunctionExpression\n ) {\n return;\n }\n\n const cast = findCastExpression(node.value.body, false);\n if (cast !== null) {\n context.report({ node: cast, messageId: \"castInValidateSearch\" });\n }\n },\n };\n },\n});\n","/**\n * @fileoverview Disallow `try` blocks whose body contains more than three\n * top-level statements that can throw (TS port of Python's SARJ007).\n *\n * A fat `try` body obscures which statement is actually expected to throw and\n * widens the blast radius of the `catch` handler: unrelated failures get caught\n * (and often swallowed or mis-reported) by a handler written for a different\n * operation. Keep the `try` skinny — isolate the throwing statement(s) and move\n * the non-throwing setup and follow-up work outside.\n *\n * Only top-level statements that can *throw* are counted. What counts, and the\n * guards that keep the count aligned with intent (tuned against ~5.6k real TS\n * files to drive false positives to ~zero):\n *\n * - An `await` always counts — awaiting a promise is the canonical throwing\n * operation in async TS. A statement with an `await` in its same-scope\n * subtree counts.\n * - A synchronous call / `new` whose value is *used* (assigned, returned,\n * branched on, or passed as an argument) counts — e.g. `const x = parse(s)`,\n * `return build(x)`, `if (!validate(x))`.\n * - A bare fire-and-forget call statement with no `await` does NOT count. In\n * idiomatic TS these are side effects — React state setters (`setOpen(false)`),\n * toasts (`toast.error(...)`), `router.refresh()`, logging, optional\n * callbacks (`onSuccess?.()`). They are the post-success UI work that\n * naturally trails the one awaited action; counting them flagged nearly\n * every event handler.\n * - Pure, non-throwing array / string / `Map` / `Object` / `Math` / `JSON`\n * helpers (`.map`, `.filter`, `.push`, `.get`, `.join`, `Object.keys`, ...)\n * do NOT count — they are data plumbing, not the operation being guarded.\n * - Calls inside a nested function / arrow body do not run when the `try`\n * executes, so they are not counted (same-scope walk).\n *\n * Two structural exemptions match the Python rule:\n *\n * - A `finally` clause is a deliberate cleanup contract that couples the body\n * to the handler — exempt.\n * - A `catch` handler guaranteed to re-throw (its body's last statement is a\n * `throw`) makes the wide body uniform error-context wrapping, not an\n * over-broad swallow — exempt.\n */\n\nimport {\n ESLintUtils,\n type TSESTree,\n AST_NODE_TYPES,\n} from \"@typescript-eslint/utils\";\n\ntype MessageIds = \"fatTryBlock\";\ntype Options = readonly [];\n\nconst MAX_TRY_BODY_STATEMENTS = 3;\n\nconst NESTED_FUNCTION_TYPES = new Set<AST_NODE_TYPES>([\n AST_NODE_TYPES.FunctionDeclaration,\n AST_NODE_TYPES.FunctionExpression,\n AST_NODE_TYPES.ArrowFunctionExpression,\n]);\n\n/** Non-throwing member methods — array / string / Map / Set data plumbing. */\nconst PURE_METHODS = new Set<string>([\n \"map\", \"filter\", \"forEach\", \"reduce\", \"reduceRight\", \"find\", \"findIndex\",\n \"findLast\", \"findLastIndex\", \"some\", \"every\", \"push\", \"pop\", \"shift\",\n \"unshift\", \"slice\", \"splice\", \"concat\", \"flat\", \"flatMap\", \"join\", \"reverse\",\n \"sort\", \"fill\", \"includes\", \"indexOf\", \"lastIndexOf\", \"at\", \"keys\", \"values\",\n \"entries\", \"has\", \"get\", \"set\", \"add\", \"delete\", \"clear\", \"toString\",\n \"toLocaleString\", \"valueOf\", \"charAt\", \"charCodeAt\", \"codePointAt\", \"split\",\n \"padStart\", \"padEnd\", \"repeat\", \"trim\", \"trimStart\", \"trimEnd\", \"toUpperCase\",\n \"toLowerCase\", \"toFixed\", \"toPrecision\", \"startsWith\", \"endsWith\",\n]);\n\n/** Non-throwing global namespaces called as `X.method(...)`. */\nconst PURE_NAMESPACES = new Set<string>([\n \"Object\", \"Array\", \"Math\", \"JSON\", \"Number\", \"String\", \"Boolean\", \"console\",\n]);\n\n/** Constructors that do not throw on construction. */\nconst PURE_CONSTRUCTORS = new Set<string>([\n \"Map\", \"Set\", \"WeakMap\", \"WeakSet\", \"Date\", \"Error\", \"TypeError\",\n \"RangeError\", \"Array\", \"Object\", \"Headers\", \"URLSearchParams\", \"FormData\",\n \"TextEncoder\", \"TextDecoder\", \"Blob\", \"ReadableStream\", \"WritableStream\",\n \"TransformStream\", \"Response\", \"AbortController\",\n]);\n\nfunction isNode(value: unknown): value is TSESTree.Node {\n return (\n typeof value === \"object\" &&\n value !== null &&\n typeof (value as { type?: unknown }).type === \"string\"\n );\n}\n\n/** A call whose value is a known pure, non-throwing helper. */\nfunction isPureCall(node: TSESTree.CallExpression): boolean {\n const callee = node.callee;\n if (callee.type !== AST_NODE_TYPES.MemberExpression) {\n return false;\n }\n const property = callee.property;\n if (property.type !== AST_NODE_TYPES.Identifier) {\n return false;\n }\n if (\n callee.object.type === AST_NODE_TYPES.Identifier &&\n PURE_NAMESPACES.has(callee.object.name)\n ) {\n return true;\n }\n return PURE_METHODS.has(property.name);\n}\n\nfunction isPureNew(node: TSESTree.NewExpression): boolean {\n return (\n node.callee.type === AST_NODE_TYPES.Identifier &&\n PURE_CONSTRUCTORS.has(node.callee.name)\n );\n}\n\n/**\n * Walk `stmt`'s same-scope subtree (not descending into nested function/arrow\n * bodies) until `predicate` matches a node.\n */\nfunction subtreeMatches(\n stmt: TSESTree.Node,\n predicate: (node: TSESTree.Node) => boolean,\n): boolean {\n let found = false;\n\n const visit = (current: TSESTree.Node): void => {\n if (found) {\n return;\n }\n if (predicate(current)) {\n found = true;\n return;\n }\n for (const key of Object.keys(current)) {\n if (key === \"parent\") {\n continue;\n }\n if (NESTED_FUNCTION_TYPES.has(current.type) && key === \"body\") {\n continue;\n }\n const value = (current as unknown as Record<string, unknown>)[key];\n if (Array.isArray(value)) {\n for (const child of value) {\n if (isNode(child)) {\n visit(child);\n }\n }\n } else if (isNode(value)) {\n visit(value);\n }\n if (found) {\n return;\n }\n }\n };\n\n visit(stmt);\n return found;\n}\n\nconst hasAwait = (stmt: TSESTree.Statement): boolean =>\n subtreeMatches(stmt, (n) => n.type === AST_NODE_TYPES.AwaitExpression);\n\nconst hasThrowingCallOrNew = (stmt: TSESTree.Statement): boolean =>\n subtreeMatches(\n stmt,\n (n) =>\n (n.type === AST_NODE_TYPES.CallExpression && !isPureCall(n)) ||\n (n.type === AST_NODE_TYPES.NewExpression && !isPureNew(n)),\n );\n\n/** Unwrap `await` / optional-chain / non-null wrappers to the core expression. */\nfunction unwrap(expr: TSESTree.Expression): TSESTree.Expression {\n let current = expr;\n while (\n current.type === AST_NODE_TYPES.ChainExpression ||\n current.type === AST_NODE_TYPES.TSNonNullExpression\n ) {\n current = current.expression;\n }\n return current;\n}\n\n/**\n * Whether a top-level try-body statement can plausibly throw when the `try`\n * runs. See the file overview for the guards; the key ones are: `await` always\n * counts, and a bare fire-and-forget call statement (no `await`) does not.\n */\nfunction canThrow(stmt: TSESTree.Statement): boolean {\n if (hasAwait(stmt)) {\n return true;\n }\n if (\n stmt.type === AST_NODE_TYPES.ExpressionStatement &&\n unwrap(stmt.expression).type === AST_NODE_TYPES.CallExpression\n ) {\n return false;\n }\n return hasThrowingCallOrNew(stmt);\n}\n\n/**\n * Conservative: is the `catch` handler guaranteed to re-throw? True when a\n * handler is present and its body's last statement is a `throw`.\n */\nfunction handlerRethrows(handler: TSESTree.CatchClause | null): boolean {\n if (handler === null) {\n return false;\n }\n const body = handler.body.body;\n const last = body[body.length - 1];\n return last !== undefined && last.type === AST_NODE_TYPES.ThrowStatement;\n}\n\nexport default ESLintUtils.RuleCreator(\n (name) =>\n `https://github.com/sarj-ai/standards/blob/main/packages/typescript/src/rules/${name}.ts`,\n)<Options, MessageIds>({\n name: \"no-fat-try-blocks\",\n meta: {\n type: \"problem\",\n docs: {\n description:\n \"Disallow `try` blocks with more than three top-level statements that can throw — isolate the throwing statement and move non-throwing work outside.\",\n },\n schema: [],\n messages: {\n fatTryBlock:\n \"This `try` block has {{count}} statements that can throw (max {{max}}). Isolate the throwing statement(s); move non-throwing work outside the `try`.\",\n },\n },\n defaultOptions: [],\n create(context) {\n const sourceCode = context.sourceCode;\n\n return {\n TryStatement(node: TSESTree.TryStatement): void {\n if (node.finalizer !== null) {\n return;\n }\n if (handlerRethrows(node.handler)) {\n return;\n }\n\n const count = node.block.body.filter(canThrow).length;\n if (count <= MAX_TRY_BODY_STATEMENTS) {\n return;\n }\n\n const tryKeyword = sourceCode.getFirstToken(node);\n context.report({\n node: tryKeyword ?? node,\n messageId: \"fatTryBlock\",\n data: { count, max: MAX_TRY_BODY_STATEMENTS },\n });\n },\n };\n },\n});\n","/**\n * @fileoverview TS port of SARJ012 (`no-secret-in-log`). Passing a secret value\n * (token, password, api key, jwt, credential, signature, ...) to a logging call\n * leaks it into log sinks — files, stdout, log aggregators — where it persists\n * far beyond its intended lifetime and is readable by anyone with log access.\n * Prefer redaction (`tokenPrefix: token.slice(0, 6)`) or omission.\n *\n * We fire on a logging call (`logger.info(...)`, `log.error(...)`, loguru/bind\n * builder chains, etc.) that passes a secret-named value either as a property of\n * an object argument (`logger.error(\"msg\", { token, apiKey })`) or as a bare\n * secret-named positional identifier (`logger.info(\"x\", password)`).\n *\n * The secret-name predicate matches a secret word only as a WHOLE token (after\n * snake_case / camelCase splitting) and disqualifies identifiers whose trailing\n * token is a counter / row-id / flag marker (`tokenCount`, `apiKeyId`,\n * `passwordEnabled`), so metadata *about* a secret is not mistaken for the\n * secret itself. Redaction markers (prefix/mask/hash/redact/tag) are exempt.\n *\n * References:\n * - https://owasp.org/www-community/vulnerabilities/Information_exposure_through_log_files\n */\n\nimport { ESLintUtils, type TSESTree } from \"@typescript-eslint/utils\";\n\ntype MessageIds = \"noSecretInLog\";\ntype Options = readonly [];\n\nconst LOG_METHODS: ReadonlySet<string> = new Set([\n \"debug\",\n \"info\",\n \"warn\",\n \"warning\",\n \"error\",\n \"exception\",\n \"critical\",\n \"trace\",\n \"log\",\n \"fatal\",\n \"success\",\n]);\n\nconst LOGGER_NAMES: ReadonlySet<string> = new Set([\n \"logger\",\n \"log\",\n \"logging\",\n \"loguru\",\n \"console\",\n \"_logger\",\n \"_log\",\n]);\n\nconst LOGGER_FACTORIES: ReadonlySet<string> = new Set([\"getlogger\", \"get_logger\"]);\n\nconst SECRET_WORDS: ReadonlySet<string> = new Set([\n \"token\",\n \"secret\",\n \"password\",\n \"passwd\",\n \"jwt\",\n \"secrets\",\n \"passwords\",\n \"credential\",\n \"credentials\",\n \"authorization\",\n \"signature\",\n \"hmac\",\n \"digest\",\n \"hash\",\n \"apikey\",\n]);\n\nconst INNOCUOUS_WORDS: ReadonlySet<string> = new Set([\n \"count\",\n \"counts\",\n \"budget\",\n \"limit\",\n \"limits\",\n \"id\",\n \"ids\",\n \"enabled\",\n \"disabled\",\n \"flag\",\n \"flags\",\n \"present\",\n \"set\",\n \"unset\",\n \"configured\",\n \"missing\",\n \"required\",\n \"valid\",\n \"invalid\",\n \"exists\",\n \"type\",\n \"types\",\n \"name\",\n \"names\",\n \"label\",\n \"labels\",\n \"title\",\n \"expiry\",\n \"expiration\",\n \"expires\",\n \"ttl\",\n \"version\",\n \"versions\",\n \"policy\",\n \"rotation\",\n \"arn\",\n \"path\",\n \"paths\",\n \"issuer\",\n \"audience\",\n \"strength\",\n \"manager\",\n \"service\",\n \"services\",\n \"repository\",\n \"provider\",\n \"providers\",\n \"store\",\n \"factory\",\n \"handler\",\n \"controller\",\n \"bucket\",\n \"url\",\n \"uri\",\n \"endpoint\",\n \"endpoints\",\n \"scope\",\n \"scopes\",\n \"event\",\n \"events\",\n \"format\",\n \"at\",\n \"len\",\n \"length\",\n]);\n\nconst REDACTION_RE = /prefix|suffix|redact|mask|hash|hint|_len|length/i;\nconst WHOLE_TOKEN_REDACTION_MARKERS: ReadonlySet<string> = new Set([\"tag\"]);\n\nconst CAMEL_RE = /[A-Z]+(?=[A-Z][a-z])|[A-Z]?[a-z]+|[A-Z]+|\\d+/g;\nconst SEGMENT_RE = /[^A-Za-z0-9]+/;\n\n/**\n * Ordered lowercase tokens from snake_case + camelCase decomposition. Also\n * yields each whole snake/kebab segment lowercased, so a pathological mixed-case\n * word still surfaces its intended form.\n */\nfunction tokenize(identifier: string): string[] {\n const tokens: string[] = [];\n for (const segment of identifier.split(SEGMENT_RE)) {\n if (!segment) {\n continue;\n }\n tokens.push(segment.toLowerCase());\n for (const part of segment.match(CAMEL_RE) ?? []) {\n tokens.push(part.toLowerCase());\n }\n }\n return tokens;\n}\n\n/** True if `api` is immediately followed by `key` (the split form of `api_key`). */\nfunction hasApiKey(tokens: readonly string[]): boolean {\n for (let i = 0; i + 1 < tokens.length; i++) {\n if (tokens[i] === \"api\" && tokens[i + 1] === \"key\") {\n return true;\n }\n }\n return false;\n}\n\n/** True if `identifier` names raw secret material (a credential, not metadata). */\nfunction isSecretName(identifier: string): boolean {\n const tokens = tokenize(identifier);\n const last = tokens.at(-1);\n if (last !== undefined && INNOCUOUS_WORDS.has(last)) {\n return false;\n }\n if (tokens.some((tok) => SECRET_WORDS.has(tok))) {\n return true;\n }\n return hasApiKey(tokens);\n}\n\n/** True if the name names a raw secret and is not a redacted derivative. */\nfunction isSecretKeyword(name: string): boolean {\n if (REDACTION_RE.test(name)) {\n return false;\n }\n if (tokenize(name).some((tok) => WHOLE_TOKEN_REDACTION_MARKERS.has(tok))) {\n return false;\n }\n return isSecretName(name);\n}\n\n/**\n * True if `expr` evaluates to a logger. Resolves the whole receiver chain so\n * adapter/builder/factory calls are caught: `logger.bind(...).info(...)`,\n * `logging.getLogger(name).info(...)`, `this.logger.error(...)`.\n */\nfunction isLoggerExpr(expr: TSESTree.Expression | TSESTree.PrivateIdentifier): boolean {\n switch (expr.type) {\n case \"Identifier\":\n return LOGGER_NAMES.has(expr.name.toLowerCase());\n case \"MemberExpression\": {\n const { property, object } = expr;\n if (!expr.computed && property.type === \"Identifier\") {\n const lowered = property.name.toLowerCase();\n if (LOGGER_NAMES.has(lowered) || LOGGER_FACTORIES.has(lowered)) {\n return true;\n }\n }\n return isLoggerExpr(object);\n }\n case \"CallExpression\": {\n const callee = expr.callee;\n if (\n callee.type === \"MemberExpression\" &&\n !callee.computed &&\n callee.property.type === \"Identifier\" &&\n LOGGER_FACTORIES.has(callee.property.name.toLowerCase())\n ) {\n return true;\n }\n if (callee.type !== \"Super\") {\n return isLoggerExpr(callee);\n }\n return false;\n }\n default:\n return false;\n }\n}\n\n/**\n * True if `prop`'s value is the raw secret rather than a redacted/derived form.\n * Shorthand (`{ token }`), a bare identifier (`{ apiKey: theKey }`), or a plain\n * member access (`{ apiKey: config.apiKey }`) all carry the secret verbatim. A\n * call (`token.slice(0, 6)`, `mask(token)`), template literal, ternary, concat,\n * or literal placeholder (`\"***\"`) is already redacted — logging it is safe.\n */\nfunction isRawSecretValue(prop: TSESTree.Property): boolean {\n if (prop.shorthand) {\n return true;\n }\n return prop.value.type === \"Identifier\" || prop.value.type === \"MemberExpression\";\n}\n\n/** The static string name of an object-property key, or null when not statically named. */\nfunction propertyKeyName(prop: TSESTree.Property): string | null {\n if (prop.computed) {\n return null;\n }\n if (prop.key.type === \"Identifier\") {\n return prop.key.name;\n }\n if (prop.key.type === \"Literal\" && typeof prop.key.value === \"string\") {\n return prop.key.value;\n }\n return null;\n}\n\nexport default ESLintUtils.RuleCreator(\n (name) =>\n `https://github.com/sarj-ai/standards/blob/main/packages/typescript/src/rules/${name}.ts`,\n)<Options, MessageIds>({\n name: \"no-secret-in-log\",\n meta: {\n type: \"problem\",\n docs: {\n description:\n \"Disallow passing a secret-named value to a logging call; it leaks to log sinks. Redact or omit it.\",\n },\n schema: [],\n messages: {\n noSecretInLog:\n \"Secret `{{name}}` passed to a logging call leaks it to log sinks. Redact (e.g. `{{name}}Prefix: {{name}}.slice(0, 6)`) or omit it.\",\n },\n },\n defaultOptions: [],\n create(context) {\n return {\n CallExpression(node: TSESTree.CallExpression): void {\n const callee = node.callee;\n if (\n callee.type !== \"MemberExpression\" ||\n callee.computed ||\n callee.property.type !== \"Identifier\" ||\n !LOG_METHODS.has(callee.property.name)\n ) {\n return;\n }\n if (!isLoggerExpr(callee.object)) {\n return;\n }\n\n for (const arg of node.arguments) {\n if (arg.type === \"Identifier\") {\n if (isSecretKeyword(arg.name)) {\n context.report({\n node: arg,\n messageId: \"noSecretInLog\",\n data: { name: arg.name },\n });\n }\n continue;\n }\n if (arg.type === \"MemberExpression\") {\n if (\n !arg.computed &&\n arg.property.type === \"Identifier\" &&\n isSecretKeyword(arg.property.name)\n ) {\n context.report({\n node: arg,\n messageId: \"noSecretInLog\",\n data: { name: arg.property.name },\n });\n }\n continue;\n }\n if (arg.type === \"ObjectExpression\") {\n for (const prop of arg.properties) {\n if (prop.type !== \"Property\") {\n continue;\n }\n const keyName = propertyKeyName(prop);\n if (keyName !== null && isSecretKeyword(keyName) && isRawSecretValue(prop)) {\n context.report({\n node: prop,\n messageId: \"noSecretInLog\",\n data: { name: keyName },\n });\n }\n }\n }\n }\n },\n };\n },\n});\n","/**\n * @fileoverview Flag type-safety escape hatches that fully disable checking:\n * 1. `x as any` (and the `<any>x` assertion form) — silences every downstream\n * error on the value.\n * 2. `x as unknown as T` double-casts — assert through `unknown`/`any` to reach\n * an unrelated type, bypassing the compiler's structural check.\n *\n * `as const` is exempt — it narrows rather than widens and is the prescribed\n * pattern for literal inference.\n */\n\nimport { ESLintUtils, type TSESTree } from \"@typescript-eslint/utils\";\nimport { AST_NODE_TYPES } from \"@typescript-eslint/utils\";\n\ntype MessageIds = \"asAny\" | \"doubleCast\";\n\nfunction isAnyAnnotation(node: TSESTree.TypeNode): boolean {\n return node.type === AST_NODE_TYPES.TSAnyKeyword;\n}\n\nfunction isConstAssertion(typeAnnotation: TSESTree.TypeNode): boolean {\n return (\n typeAnnotation.type === AST_NODE_TYPES.TSTypeReference &&\n typeAnnotation.typeName.type === AST_NODE_TYPES.Identifier &&\n typeAnnotation.typeName.name === \"const\"\n );\n}\n\nexport default ESLintUtils.RuleCreator(\n (name) =>\n `https://github.com/sarj-ai/linting/blob/main/packages/typescript/src/rules/${name}.ts`,\n)<[], MessageIds>({\n name: \"no-unsafe-cast\",\n meta: {\n type: \"problem\",\n docs: {\n description:\n \"Disallow `as any`/`<any>` casts and `as unknown as T` double-casts, which fully disable type checking.\",\n },\n schema: [],\n messages: {\n asAny:\n \"`as any` disables type checking on this value. Narrow with a type guard, model the shape, or cast to a specific type instead.\",\n doubleCast:\n \"`as unknown as T` double-cast bypasses the compiler's structural check. Prefer a runtime validator (e.g. a zod schema) or an accurate type at the boundary.\",\n },\n },\n defaultOptions: [],\n create(context) {\n function checkAssertion(\n node: TSESTree.TSAsExpression | TSESTree.TSTypeAssertion,\n ): void {\n if (isConstAssertion(node.typeAnnotation)) {\n return;\n }\n\n if (isAnyAnnotation(node.typeAnnotation)) {\n context.report({ node, messageId: \"asAny\" });\n return;\n }\n\n const inner = node.expression;\n if (\n inner.type === AST_NODE_TYPES.TSAsExpression ||\n inner.type === AST_NODE_TYPES.TSTypeAssertion\n ) {\n context.report({ node, messageId: \"doubleCast\" });\n }\n }\n\n return {\n TSAsExpression: checkAssertion,\n TSTypeAssertion: checkAssertion,\n };\n },\n});\n","/**\n * @fileoverview Flag raw `string` used where a closed enumeration is clearly\n * intended, and comparison clusters against a fixed set of string literals.\n * The prescribed replacement is a string-literal union type\n * (`type Status = \"active\" | \"inactive\"`) — NOT a `StrEnum`/`enum`, since the\n * companion `no-enum` rule bans TypeScript enums.\n *\n * This is the TypeScript analog of the Python rule SARJ006 (prefer-str-enum).\n * It fires on two shapes:\n *\n * 1. **Choice-like field** — a `TSPropertySignature` (interface / type literal)\n * or class `PropertyDefinition` whose key's last word is one of the\n * high-precision CHOICE tokens (`status`, `state`, `kind`, `role`,\n * `priority`, `severity`, `direction`, `tier`, `stage`, `type`, `mode`,\n * `level`) and whose type annotation is the bare `string` keyword. Because\n * open-set API DTO fields (`status: string` from an untyped backend) are the\n * dominant false positive, a bare field fires ONLY when CORROBORATED by a\n * sibling string-literal-union member in the SAME interface / class / object\n * type. A file-wide comparison cluster on the field's name is deliberately\n * NOT used to corroborate: it flags unrelated same-named fields (DB-row casts\n * like `as Array<{ status: string }>`, passthrough DTOs). The closed-set fact\n * is still surfaced — as a `comparisonCluster` diagnostic at the comparison\n * site, which is the actionable location.\n *\n * 2. **Comparison cluster** — within one function scope, the same identifier or\n * member expression compared (`===` / `!==` / `==` / `!=`, or a `switch`)\n * against 2+ distinct short lowercase string literals (each matching\n * `^[a-z][a-z0-9_-]{0,30}$`). One diagnostic per cluster. This shape is\n * type-aware: it fires ONLY when the compared operand's resolved type is the\n * general `string` type. An operand already typed as a string-literal union\n * (`CallStatus = \"a\" | \"b\"`, a discriminated-union tag) is the target state\n * and is suppressed — a syntactic rule can't see through a named/imported\n * union, so without type information this shape is inert (the choice-field\n * shape still runs).\n *\n * `Literal`-union types (`type X = \"a\" | \"b\"`) are the target state and never\n * fire. Generated files (`*.gen.ts`, `**\\/generated/**`, `*.d.ts`, or a\n * `@generated` marker) opt out.\n */\n\nimport {\n ESLintUtils,\n type TSESTree,\n type ParserServicesWithTypeInformation,\n AST_NODE_TYPES,\n} from \"@typescript-eslint/utils\";\nimport * as ts from \"typescript\";\n\ntype MessageIds = \"bareChoiceField\" | \"comparisonCluster\";\ntype Options = readonly [];\n\nconst CHOICE_TOKENS: ReadonlySet<string> = new Set([\n \"status\",\n \"state\",\n \"kind\",\n \"role\",\n \"priority\",\n \"severity\",\n \"direction\",\n \"tier\",\n \"stage\",\n \"type\",\n \"mode\",\n \"level\",\n]);\n\nconst LOWER_TOKEN_RE = /^[a-z][a-z0-9_-]{0,30}$/;\nconst MIN_CLUSTER_SIZE = 2;\n\nconst BOOLEANISH: ReadonlySet<string> = new Set([\"true\", \"false\"]);\n\n/**\n * An enum-shaped token worth a string-literal union: a short lowercase word of\n * 2+ chars that isn't a boolean-string. Single characters (`'a'`), file\n * paths/URLs/i18n keys (contain `/`, `:`, `.`), and `'true'`/`'false'` are NOT\n * closed-enum members — comparing against them is a flag/path/boolean guard.\n */\nfunction isEnumToken(lit: string): boolean {\n return LOWER_TOKEN_RE.test(lit) && lit.length >= 2 && !BOOLEANISH.has(lit);\n}\n\nconst IGNORE_PATTERNS: readonly RegExp[] = [\n /[\\\\/]generated[\\\\/]/,\n /\\.gen\\.tsx?$/,\n /\\.generated\\.tsx?$/,\n /\\.d\\.ts$/,\n];\n\nfunction isIgnoredFile(filename: string, sourceText: string): boolean {\n if (IGNORE_PATTERNS.some((re) => re.test(filename))) {\n return true;\n }\n return /@generated\\b/.test(sourceText.slice(0, 1024));\n}\n\n/**\n * The trailing word of a camelCase / snake_case identifier, lowercased.\n * `callStatus` -> `status`, `user_role` -> `role`, `estate` -> `estate`.\n */\nfunction lastWord(name: string): string {\n const words = name\n .replace(/([a-z0-9])([A-Z])/g, \"$1 $2\")\n .split(/[_\\s]+/)\n .filter((w) => w.length > 0);\n const last = words[words.length - 1] ?? name;\n return last.toLowerCase();\n}\n\nfunction isChoiceLikeName(name: string): boolean {\n return CHOICE_TOKENS.has(lastWord(name));\n}\n\nfunction keyName(\n key: TSESTree.PropertyDefinition[\"key\"] | TSESTree.PropertyName,\n): string | null {\n if (key.type === AST_NODE_TYPES.Identifier) {\n return key.name;\n }\n if (key.type === AST_NODE_TYPES.Literal && typeof key.value === \"string\") {\n return key.value;\n }\n return null;\n}\n\nfunction isStringLiteralMember(t: TSESTree.TypeNode): boolean {\n return (\n t.type === AST_NODE_TYPES.TSLiteralType &&\n t.literal.type === AST_NODE_TYPES.Literal &&\n typeof t.literal.value === \"string\"\n );\n}\n\n/** Whether a type node is a union of 2+ string-literal types. */\nfunction isStringLiteralUnion(node: TSESTree.TypeNode | undefined): boolean {\n if (node?.type !== AST_NODE_TYPES.TSUnionType) {\n return false;\n }\n return node.types.filter(isStringLiteralMember).length >= MIN_CLUSTER_SIZE;\n}\n\n/**\n * Whether a resolved TS type includes the general `string` type — as opposed to\n * being (a union of) string-literal types. `CallStatus = \"a\" | \"b\"` has no\n * general-string member and is already the target state; a raw `string` (or\n * `string | undefined`) does, and a comparison cluster on it should become a\n * union. Requires type information; the comparison-cluster path is inert\n * without it.\n */\nfunction typeHasRawString(type: ts.Type): boolean {\n const parts = type.isUnion() ? type.types : [type];\n return parts.some((t) => (t.flags & ts.TypeFlags.String) !== 0);\n}\n\nfunction isExternalSourceFile(sf: ts.SourceFile | undefined): boolean {\n if (sf === undefined) {\n return false;\n }\n return sf.isDeclarationFile || sf.fileName.includes(\"/node_modules/\");\n}\n\nfunction symbolIsExternallyDeclared(sym: ts.Symbol | undefined): boolean {\n return (\n sym?.declarations?.some((d) => isExternalSourceFile(d.getSourceFile())) ??\n false\n );\n}\n\n/**\n * The iterable expression a destructuring binding element draws its value from,\n * e.g. `Object.entries(x)` for `key` in `for (const [key] of Object.entries(x))`\n * or the RHS of `const { a } = rhs`.\n */\nfunction bindingSourceExpression(\n decl: ts.BindingElement,\n): ts.Expression | undefined {\n let node: ts.Node = decl.parent;\n while (\n !ts.isForOfStatement(node) &&\n !(ts.isVariableDeclaration(node) && node.initializer !== undefined)\n ) {\n if (node.parent === undefined) {\n return undefined;\n }\n node = node.parent;\n }\n return ts.isForOfStatement(node) ? node.expression : node.initializer;\n}\n\n/** A stable key for a plain identifier or non-computed member chain, else null. */\nfunction refKey(node: TSESTree.Node): string | null {\n if (node.type === AST_NODE_TYPES.Identifier) {\n return node.name;\n }\n if (node.type === AST_NODE_TYPES.MemberExpression && !node.computed) {\n const inner = refKey(node.object);\n if (inner === null || node.property.type !== AST_NODE_TYPES.Identifier) {\n return null;\n }\n return `${inner}.${node.property.name}`;\n }\n return null;\n}\n\nfunction strLiteral(node: TSESTree.Node): string | null {\n if (node.type === AST_NODE_TYPES.Literal && typeof node.value === \"string\") {\n return node.value;\n }\n return null;\n}\n\ninterface ClusterEntry {\n node: TSESTree.Node;\n literals: Set<string>;\n allTokens: boolean;\n}\n\ninterface Scope {\n clusters: Map<string, ClusterEntry>;\n}\n\ninterface CollectedProperty {\n name: string;\n container: TSESTree.Node;\n node: TSESTree.Node;\n}\n\nexport default ESLintUtils.RuleCreator(\n (name) =>\n `https://github.com/sarj-ai/linting/blob/main/packages/typescript/src/rules/${name}.ts`,\n)<Options, MessageIds>({\n name: \"prefer-string-literal-union\",\n meta: {\n type: \"suggestion\",\n docs: {\n description:\n \"Flag raw `string` choice fields and string-literal comparison clusters; prefer a string-literal union type.\",\n },\n schema: [],\n messages: {\n bareChoiceField:\n '`{{name}}: string` looks like a choice field — prefer a string-literal union type (e.g. `type X = \"a\" | \"b\"`). Enums are banned by `no-enum`; use a union.',\n comparisonCluster:\n '`{{key}}` is compared against a closed set of string literals — define a string-literal union type (e.g. `type X = \"a\" | \"b\"`).',\n },\n },\n defaultOptions: [],\n create(context) {\n const filename = context.filename;\n const sourceText = context.sourceCode.getText();\n if (isIgnoredFile(filename, sourceText)) {\n return {};\n }\n\n let services: ParserServicesWithTypeInformation | null;\n try {\n services = ESLintUtils.getParserServices(context);\n } catch {\n services = null;\n }\n\n const scopeStack: Scope[] = [];\n const validClusters: TSESTree.Node[] = [];\n const bareChoiceProps: CollectedProperty[] = [];\n const containersWithUnion = new Set<TSESTree.Node>();\n\n function operandIsRawString(node: TSESTree.Node): boolean {\n if (services === null) {\n return false;\n }\n return typeHasRawString(services.getTypeAtLocation(node));\n }\n\n /**\n * Whether the compared value provably originates from a type we don't own —\n * a property of a `.d.ts` / node_modules type (DOM `getComputedStyle().overflowY`,\n * `Task.status` from another package), the return of such a method\n * (`URLSearchParams.get()`, `str.toLowerCase()`), or a destructuring of one\n * (`Object.entries()` keys). A string-literal union is not an available fix\n * for these, so the cluster shape must not flag them.\n */\n function originIsExternal(node: ts.Node | undefined, depth: number): boolean {\n if (node === undefined || services === null || depth > 6) {\n return false;\n }\n const checker = services.program.getTypeChecker();\n if (\n ts.isParenthesizedExpression(node) ||\n ts.isNonNullExpression(node) ||\n ts.isAsExpression(node)\n ) {\n return originIsExternal(node.expression, depth + 1);\n }\n if (ts.isPropertyAccessExpression(node)) {\n return symbolIsExternallyDeclared(checker.getSymbolAtLocation(node.name));\n }\n if (ts.isCallExpression(node)) {\n return originIsExternal(node.expression, depth + 1);\n }\n if (ts.isIdentifier(node)) {\n const decl = checker.getSymbolAtLocation(node)?.valueDeclaration;\n if (decl === undefined) {\n return false;\n }\n if (ts.isVariableDeclaration(decl) && decl.initializer !== undefined) {\n return originIsExternal(decl.initializer, depth + 1);\n }\n if (ts.isBindingElement(decl)) {\n return originIsExternal(bindingSourceExpression(decl), depth + 1);\n }\n }\n return false;\n }\n\n function operandIsFlaggable(node: TSESTree.Node): boolean {\n return (\n operandIsRawString(node) &&\n !originIsExternal(services?.esTreeNodeToTSNodeMap.get(node), 0)\n );\n }\n\n function pushScope(): void {\n scopeStack.push({ clusters: new Map() });\n }\n\n function popScope(): void {\n const scope = scopeStack.pop();\n if (scope === undefined) {\n return;\n }\n for (const entry of scope.clusters.values()) {\n if (entry.allTokens && entry.literals.size >= MIN_CLUSTER_SIZE) {\n validClusters.push(entry.node);\n }\n }\n }\n\n function accumulate(\n key: string,\n literals: string[],\n node: TSESTree.Node,\n ): void {\n const scope = scopeStack[scopeStack.length - 1];\n if (scope === undefined) {\n return;\n }\n const allTokens = literals.every((lit) => isEnumToken(lit));\n const existing = scope.clusters.get(key);\n if (existing === undefined) {\n scope.clusters.set(key, {\n node,\n literals: new Set(literals),\n allTokens,\n });\n return;\n }\n for (const lit of literals) {\n existing.literals.add(lit);\n }\n existing.allTokens = existing.allTokens && allTokens;\n }\n\n function collectProperty(\n key: TSESTree.PropertyDefinition[\"key\"] | TSESTree.PropertyName,\n typeNode: TSESTree.TypeNode | undefined,\n container: TSESTree.Node,\n node: TSESTree.Node,\n ): void {\n if (isStringLiteralUnion(typeNode)) {\n containersWithUnion.add(container);\n return;\n }\n if (typeNode?.type !== AST_NODE_TYPES.TSStringKeyword) {\n return;\n }\n const name = keyName(key);\n if (name === null || !isChoiceLikeName(name)) {\n return;\n }\n bareChoiceProps.push({ name, container, node });\n }\n\n return {\n FunctionDeclaration: pushScope,\n \"FunctionDeclaration:exit\": popScope,\n FunctionExpression: pushScope,\n \"FunctionExpression:exit\": popScope,\n ArrowFunctionExpression: pushScope,\n \"ArrowFunctionExpression:exit\": popScope,\n\n BinaryExpression(node: TSESTree.BinaryExpression): void {\n if (\n node.operator !== \"===\" &&\n node.operator !== \"!==\" &&\n node.operator !== \"==\" &&\n node.operator !== \"!=\"\n ) {\n return;\n }\n const leftKey = refKey(node.left);\n const rightLit = strLiteral(node.right);\n const rightKey = refKey(node.right);\n const leftLit = strLiteral(node.left);\n if (leftKey !== null && rightLit !== null) {\n if (operandIsFlaggable(node.left)) {\n accumulate(leftKey, [rightLit], node);\n }\n } else if (rightKey !== null && leftLit !== null) {\n if (operandIsFlaggable(node.right)) {\n accumulate(rightKey, [leftLit], node);\n }\n }\n },\n\n SwitchStatement(node: TSESTree.SwitchStatement): void {\n const key = refKey(node.discriminant);\n if (key === null || !operandIsFlaggable(node.discriminant)) {\n return;\n }\n const literals: string[] = [];\n for (const c of node.cases) {\n if (c.test !== null) {\n const lit = strLiteral(c.test);\n if (lit !== null) {\n literals.push(lit);\n }\n }\n }\n if (literals.length > 0) {\n accumulate(key, literals, node);\n }\n },\n\n TSPropertySignature(node: TSESTree.TSPropertySignature): void {\n collectProperty(\n node.key,\n node.typeAnnotation?.typeAnnotation,\n node.parent,\n node,\n );\n },\n\n PropertyDefinition(node: TSESTree.PropertyDefinition): void {\n collectProperty(\n node.key,\n node.typeAnnotation?.typeAnnotation,\n node.parent,\n node,\n );\n },\n\n \"Program:exit\"(): void {\n for (const clusterNode of validClusters) {\n context.report({\n node: clusterNode,\n messageId: \"comparisonCluster\",\n data: { key: refKeyText(clusterNode) },\n });\n }\n for (const prop of bareChoiceProps) {\n if (containersWithUnion.has(prop.container)) {\n context.report({\n node: prop.node,\n messageId: \"bareChoiceField\",\n data: { name: prop.name },\n });\n }\n }\n },\n };\n\n function refKeyText(node: TSESTree.Node): string {\n if (node.type === AST_NODE_TYPES.BinaryExpression) {\n return refKey(node.left) ?? refKey(node.right) ?? \"value\";\n }\n if (node.type === AST_NODE_TYPES.SwitchStatement) {\n return refKey(node.discriminant) ?? \"value\";\n }\n return \"value\";\n }\n },\n});\n","/**\n * @fileoverview Flag a junk-drawer module stem that has a single public export.\n * TS port of Python SARJ022. Fires ONLY when BOTH hold:\n *\n * (a) the file's basename stem is a generic \"junk-drawer\" name that describes\n * no responsibility (`utils`, `helpers`, `types`, `models`, ...), AND\n * (b) the module has exactly one public export, and that export is a named\n * function / class / function-const, so the rename target is unambiguous.\n *\n * When both hold, the sole export's name is the information-rich replacement for\n * the meaningless stem (`utils.ts` exporting `snakeCaseText` -> `snake-case-text.ts`).\n *\n * A junk-drawer stem carries no domain to lose, so replacing it with the export\n * name is strictly an improvement; an informative stem (`pagination.ts`) names a\n * domain broader than its one current export and is deliberately never flagged.\n */\n\nimport { ESLintUtils, type TSESTree, AST_NODE_TYPES } from \"@typescript-eslint/utils\";\n\ntype MessageIds = \"renameJunkDrawer\";\ntype Options = readonly [];\n\n// Generic module stems that describe no responsibility. `index` is deliberately\n// excluded: barrel files legitimately re-export many symbols under that name.\nconst JUNK_DRAWER_STEMS = new Set([\n \"util\",\n \"utils\",\n \"helper\",\n \"helpers\",\n \"common\",\n \"constant\",\n \"constants\",\n \"type\",\n \"types\",\n \"model\",\n \"models\",\n \"shared\",\n \"misc\",\n]);\n\n// Exports whose name is an idiomatic ecosystem convention that lives in a\n// junk-drawer bucket by design — flagging them fights the convention and the\n// bucket is expected to grow. `cn` is the shadcn/ui tailwind-merge className\n// helper that scaffolds into `lib/utils.ts`; renaming to `cn.ts` breaks every\n// `import { cn } from \"@/lib/utils\"`.\nconst CONVENTIONAL_BUCKET_EXPORTS = new Set([\"cn\"]);\n\n// Multi-word acronyms whose accepted kebab-case is a single token rather than a\n// letter-by-letter split (`OAuth` -> `oauth`, not `o-auth`).\nconst ACRONYM_OVERRIDES: ReadonlyArray<readonly [RegExp, string]> = [\n [/OAuth/g, \"Oauth\"],\n [/GraphQL/g, \"Graphql\"],\n [/gRPC/g, \"Grpc\"],\n];\n\n// Split on camelCase boundaries while keeping runs of capitals (acronyms)\n// together: `HTTPServer` -> `HTTP` + `Server`, `JWTHandler` -> `JWT` + `Handler`.\nconst CAMEL_BOUNDARY_RE = /(?<=[a-z0-9])(?=[A-Z])|(?<=[A-Z])(?=[A-Z][a-z])/g;\n\nconst TEST_FILE_RE = /\\.(test|spec)\\.[cm]?[jt]sx?$/i;\nconst SCRIPT_EXT_RE = /\\.[cm]?[jt]sx?$/i;\n\ninterface ExportSummary {\n readonly names: number;\n readonly hasReExport: boolean;\n readonly candidate: { name: string; node: TSESTree.Node } | null;\n}\n\nconst basename = (filename: string): string =>\n filename.split(/[/\\\\]/).pop() ?? filename;\n\nconst stemOf = (base: string): string => base.replace(SCRIPT_EXT_RE, \"\");\n\nconst kebabCase = (name: string): string => {\n let normalized = name;\n for (const [pattern, replacement] of ACRONYM_OVERRIDES) {\n normalized = normalized.replace(pattern, replacement);\n }\n return normalized.replace(CAMEL_BOUNDARY_RE, \"-\").toLowerCase();\n};\n\nconst isFunctionExpression = (node: TSESTree.Expression | null): boolean =>\n node !== null &&\n (node.type === AST_NODE_TYPES.ArrowFunctionExpression ||\n node.type === AST_NODE_TYPES.FunctionExpression);\n\n// A `const foo = () => {}` is a rename candidate; a value const (`const MAX = 5`)\n// is not — renaming a file after a bare constant loses more than it gains.\nconst functionConstName = (\n decl: TSESTree.VariableDeclaration,\n): string | null => {\n if (decl.declarations.length !== 1) return null;\n const [declarator] = decl.declarations;\n if (declarator === undefined) return null;\n if (declarator.id.type !== AST_NODE_TYPES.Identifier) return null;\n if (!isFunctionExpression(declarator.init)) return null;\n return declarator.id.name;\n};\n\nconst summarizeExports = (body: readonly TSESTree.ProgramStatement[]): ExportSummary => {\n let names = 0;\n let hasReExport = false;\n let candidate: { name: string; node: TSESTree.Node } | null = null;\n\n const addCandidate = (name: string, node: TSESTree.Node): void => {\n names += 1;\n candidate = { name, node };\n };\n\n for (const statement of body) {\n switch (statement.type) {\n case AST_NODE_TYPES.ExportAllDeclaration:\n hasReExport = true;\n break;\n case AST_NODE_TYPES.ExportDefaultDeclaration: {\n names += 1;\n const decl = statement.declaration;\n if (\n decl.type === AST_NODE_TYPES.FunctionDeclaration &&\n decl.id !== null\n ) {\n candidate = { name: decl.id.name, node: statement };\n } else if (\n decl.type === AST_NODE_TYPES.ClassDeclaration &&\n decl.id !== null\n ) {\n candidate = { name: decl.id.name, node: statement };\n }\n break;\n }\n case AST_NODE_TYPES.ExportNamedDeclaration: {\n if (statement.source !== null) {\n hasReExport = true;\n break;\n }\n const decl = statement.declaration;\n if (decl === null) {\n names += statement.specifiers.length;\n break;\n }\n switch (decl.type) {\n case AST_NODE_TYPES.FunctionDeclaration:\n if (decl.id !== null) addCandidate(decl.id.name, statement);\n else names += 1;\n break;\n case AST_NODE_TYPES.ClassDeclaration:\n if (decl.id !== null) addCandidate(decl.id.name, statement);\n else names += 1;\n break;\n case AST_NODE_TYPES.VariableDeclaration: {\n const fnName = functionConstName(decl);\n if (fnName !== null && decl.declarations.length === 1) {\n addCandidate(fnName, statement);\n } else {\n names += decl.declarations.length;\n }\n break;\n }\n default:\n names += 1;\n }\n break;\n }\n default:\n break;\n }\n }\n\n return { names, hasReExport, candidate };\n};\n\nexport default ESLintUtils.RuleCreator(\n (name) =>\n `https://github.com/sarj-ai/standards/blob/main/packages/typescript/src/rules/${name}.ts`,\n)<Options, MessageIds>({\n name: \"single-public-export\",\n meta: {\n type: \"suggestion\",\n docs: {\n description:\n \"A junk-drawer module stem (`utils`, `helpers`, `types`, ...) with a single public function/class/const export should be renamed after that export.\",\n },\n schema: [],\n messages: {\n renameJunkDrawer:\n \"Module stem `{{stem}}` is a generic junk-drawer name; its sole public export is `{{name}}` — rename the file to `{{expected}}.ts` to describe its responsibility.\",\n },\n },\n defaultOptions: [],\n create(context) {\n const base = basename(context.filename);\n\n if (base.endsWith(\".d.ts\")) return {};\n if (TEST_FILE_RE.test(base)) return {};\n\n const stem = stemOf(base);\n if (!JUNK_DRAWER_STEMS.has(stem.toLowerCase())) return {};\n\n return {\n Program(node: TSESTree.Program): void {\n const { names, hasReExport, candidate } = summarizeExports(node.body);\n if (hasReExport) return;\n if (names !== 1 || candidate === null) return;\n if (CONVENTIONAL_BUCKET_EXPORTS.has(candidate.name)) return;\n\n const expected = kebabCase(candidate.name);\n if (stem === expected) return;\n\n context.report({\n node: candidate.node,\n messageId: \"renameJunkDrawer\",\n data: { stem, name: candidate.name, expected },\n });\n },\n };\n },\n});\n"],"mappings":"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","names":["import_utils","import_utils","import_utils","import_utils","import_utils","propName","import_utils","import_utils","DEFAULT_IGNORE_PATTERNS","import_utils","import_utils","import_utils","isNode","calleeName","import_utils","import_utils","import_utils","import_utils","findVariable","import_utils","import_utils","propName","keyName","import_utils","import_utils","import_utils","import_utils","import_utils","isNode","calleeName","import_utils","import_utils","matchesAnyPattern","import_utils","import_utils","isNode","unwrap","import_utils","LOG_METHODS","LOGGER_NAMES","propertyKeyName","keyName","import_utils","import_utils","import_utils","TEST_FILE_RE","kebabCase"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/rules/enforce-file-structure.ts","../src/rules/no-client-side-data-fetching.ts","../src/rules/no-comment-cruft.ts","../src/rules/no-enum.ts","../src/rules/no-insecure-random-id.ts","../src/rules/no-json-stringify-error.ts","../src/rules/no-log-only-catch.ts","../src/rules/_logging.ts","../src/rules/no-raw-env.ts","../src/rules/no-sentinel-return-on-catch.ts","../src/rules/no-sequential-await.ts","../src/rules/no-string-concat-in-loop.ts","../src/rules/no-unnecessary-use-client.ts","../src/rules/prefer-discriminated-union.ts","../src/rules/prefer-schema-for-api-payload.ts","../src/rules/prefer-semantic-colors.ts","../src/rules/_tailwind.ts","../src/rules/prefer-server-actions.ts","../src/rules/prefer-shadcn.ts","../src/rules/require-assert-never.ts","../src/rules/require-zod-form-validation.ts","../src/rules/_zod.ts","../src/rules/zod-naming-convention.ts","../src/rules/no-cors-wildcard-with-credentials.ts","../src/rules/no-silent-promise-catch.ts","../src/rules/_paths.ts","../src/rules/require-fetch-timeout.ts","../src/rules/require-schema-validate-search.ts","../src/rules/no-fat-try-blocks.ts","../src/rules/no-secret-in-log.ts","../src/rules/_secret_names.ts","../src/rules/no-unsafe-cast.ts","../src/rules/prefer-string-literal-union.ts","../src/rules/single-public-export.ts","../src/rules/no-offset-pagination.ts","../src/rules/_sql.ts","../src/rules/no-positional-tuple-return.ts","../src/rules/no-repeated-string-literal.ts","../src/rules/no-select-star.ts","../src/rules/no-sleep-in-test-body.ts","../src/rules/prefer-constant-time-secret-compare.ts","../src/rules/store-insert-requires-on-conflict.ts","../src/rules/no-dynamic-sql.ts","../src/rules/no-raw-fetch-outside-clients.ts","../src/rules/no-storage-in-stateless-modules.ts","../src/rules/no-zod-native-enum.ts","../src/rules/prefer-module-level-constant.ts"],"sourcesContent":["import enforceFileStructure from \"./rules/enforce-file-structure.js\";\nimport noClientSideDataFetching from \"./rules/no-client-side-data-fetching.js\";\nimport noCommentCruft from \"./rules/no-comment-cruft.js\";\nimport noEnum from \"./rules/no-enum.js\";\nimport noInsecureRandomId from \"./rules/no-insecure-random-id.js\";\nimport noJsonStringifyError from \"./rules/no-json-stringify-error.js\";\nimport noLogOnlyCatch from \"./rules/no-log-only-catch.js\";\nimport noRawEnv from \"./rules/no-raw-env.js\";\nimport noSentinelReturnOnCatch from \"./rules/no-sentinel-return-on-catch.js\";\nimport noSequentialAwait from \"./rules/no-sequential-await.js\";\nimport noStringConcatInLoop from \"./rules/no-string-concat-in-loop.js\";\nimport noUnnecessaryUseClient from \"./rules/no-unnecessary-use-client.js\";\nimport preferDiscriminatedUnion from \"./rules/prefer-discriminated-union.js\";\nimport preferSchemaForApiPayload from \"./rules/prefer-schema-for-api-payload.js\";\nimport preferSemanticColors from \"./rules/prefer-semantic-colors.js\";\nimport preferServerActions from \"./rules/prefer-server-actions.js\";\nimport preferShadcn from \"./rules/prefer-shadcn.js\";\nimport requireAssertNever from \"./rules/require-assert-never.js\";\nimport requireZodFormValidation from \"./rules/require-zod-form-validation.js\";\nimport zodNamingConvention from \"./rules/zod-naming-convention.js\";\nimport noCorsWildcardWithCredentials from \"./rules/no-cors-wildcard-with-credentials.js\";\nimport noSilentPromiseCatch from \"./rules/no-silent-promise-catch.js\";\nimport requireFetchTimeout from \"./rules/require-fetch-timeout.js\";\nimport requireSchemaValidateSearch from \"./rules/require-schema-validate-search.js\";\nimport noFatTryBlocks from \"./rules/no-fat-try-blocks.js\";\nimport noSecretInLog from \"./rules/no-secret-in-log.js\";\nimport noUnsafeCast from \"./rules/no-unsafe-cast.js\";\nimport preferStringLiteralUnion from \"./rules/prefer-string-literal-union.js\";\nimport singlePublicExport from \"./rules/single-public-export.js\";\nimport noOffsetPagination from \"./rules/no-offset-pagination.js\";\nimport noPositionalTupleReturn from \"./rules/no-positional-tuple-return.js\";\nimport noRepeatedStringLiteral from \"./rules/no-repeated-string-literal.js\";\nimport noSelectStar from \"./rules/no-select-star.js\";\nimport noSleepInTestBody from \"./rules/no-sleep-in-test-body.js\";\nimport preferConstantTimeSecretCompare from \"./rules/prefer-constant-time-secret-compare.js\";\nimport storeInsertRequiresOnConflict from \"./rules/store-insert-requires-on-conflict.js\";\nimport noDynamicSql from \"./rules/no-dynamic-sql.js\";\nimport noRawFetchOutsideClients from \"./rules/no-raw-fetch-outside-clients.js\";\nimport noStorageInStatelessModules from \"./rules/no-storage-in-stateless-modules.js\";\nimport noZodNativeEnum from \"./rules/no-zod-native-enum.js\";\nimport preferModuleLevelConstant from \"./rules/prefer-module-level-constant.js\";\n\nconst rules = {\n \"enforce-file-structure\": enforceFileStructure,\n \"no-client-side-data-fetching\": noClientSideDataFetching,\n \"no-comment-cruft\": noCommentCruft,\n \"no-enum\": noEnum,\n \"no-insecure-random-id\": noInsecureRandomId,\n \"no-json-stringify-error\": noJsonStringifyError,\n \"no-log-only-catch\": noLogOnlyCatch,\n \"no-raw-env\": noRawEnv,\n \"no-sentinel-return-on-catch\": noSentinelReturnOnCatch,\n \"no-sequential-await\": noSequentialAwait,\n \"no-string-concat-in-loop\": noStringConcatInLoop,\n \"no-unnecessary-use-client\": noUnnecessaryUseClient,\n \"prefer-discriminated-union\": preferDiscriminatedUnion,\n \"prefer-schema-for-api-payload\": preferSchemaForApiPayload,\n \"prefer-semantic-colors\": preferSemanticColors,\n \"prefer-server-actions\": preferServerActions,\n \"prefer-shadcn\": preferShadcn,\n \"require-assert-never\": requireAssertNever,\n \"require-zod-form-validation\": requireZodFormValidation,\n \"zod-naming-convention\": zodNamingConvention,\n \"no-cors-wildcard-with-credentials\": noCorsWildcardWithCredentials,\n \"no-fat-try-blocks\": noFatTryBlocks,\n \"no-secret-in-log\": noSecretInLog,\n \"no-unsafe-cast\": noUnsafeCast,\n \"prefer-string-literal-union\": preferStringLiteralUnion,\n \"single-public-export\": singlePublicExport,\n \"no-silent-promise-catch\": noSilentPromiseCatch,\n \"require-fetch-timeout\": requireFetchTimeout,\n \"require-schema-validate-search\": requireSchemaValidateSearch,\n \"no-offset-pagination\": noOffsetPagination,\n \"no-positional-tuple-return\": noPositionalTupleReturn,\n \"no-repeated-string-literal\": noRepeatedStringLiteral,\n \"no-select-star\": noSelectStar,\n \"no-sleep-in-test-body\": noSleepInTestBody,\n \"prefer-constant-time-secret-compare\": preferConstantTimeSecretCompare,\n \"store-insert-requires-on-conflict\": storeInsertRequiresOnConflict,\n \"no-dynamic-sql\": noDynamicSql,\n \"no-raw-fetch-outside-clients\": noRawFetchOutsideClients,\n \"no-storage-in-stateless-modules\": noStorageInStatelessModules,\n \"no-zod-native-enum\": noZodNativeEnum,\n \"prefer-module-level-constant\": preferModuleLevelConstant,\n};\n\nconst plugin = {\n meta: {\n name: \"@sarj/eslint-plugin\",\n version: \"2.9.0\",\n },\n rules,\n configs: {\n recommended: {\n plugins: [\"@sarj\"],\n rules: {\n \"@sarj/zod-naming-convention\": \"warn\",\n \"@sarj/require-assert-never\": \"error\",\n \"@sarj/require-zod-form-validation\": \"error\",\n \"@sarj/enforce-file-structure\": \"warn\",\n \"@sarj/no-client-side-data-fetching\": \"warn\",\n \"@sarj/prefer-server-actions\": \"warn\",\n \"@sarj/no-unnecessary-use-client\": \"warn\",\n \"@sarj/prefer-schema-for-api-payload\": \"warn\",\n // Distilled from sarj-audit skills — warn in recommended, error in strict.\n \"@sarj/no-sequential-await\": \"warn\",\n \"@sarj/no-sentinel-return-on-catch\": \"warn\",\n \"@sarj/no-log-only-catch\": \"warn\",\n \"@sarj/no-insecure-random-id\": \"warn\",\n \"@sarj/no-json-stringify-error\": \"warn\",\n \"@sarj/no-string-concat-in-loop\": \"warn\",\n \"@sarj/prefer-discriminated-union\": \"warn\",\n \"@sarj/no-comment-cruft\": \"warn\",\n // Frontend / styling — distilled from frontend PR-review mining.\n \"@sarj/prefer-semantic-colors\": \"warn\",\n // Ported from sarj-python-lint (SARJ), corpus-validated FP~0.\n \"@sarj/no-fat-try-blocks\": \"warn\",\n \"@sarj/no-cors-wildcard-with-credentials\": \"warn\",\n \"@sarj/no-secret-in-log\": \"warn\",\n \"@sarj/no-unsafe-cast\": \"warn\",\n \"@sarj/single-public-export\": \"warn\",\n \"@sarj/prefer-string-literal-union\": \"warn\",\n // Mined from 2y of PR review feedback + 5-repo code-smell audit (2026-07).\n \"@sarj/require-fetch-timeout\": \"warn\",\n \"@sarj/no-silent-promise-catch\": \"warn\",\n \"@sarj/require-schema-validate-search\": \"warn\",\n // Second SARJ port wave — the TS/Python parity gap. Each targets a\n // defect class seen in production Workers code: timing-leaky secret\n // compares, non-idempotent store writes under queue redelivery,\n // O(N) pagination, implicit row contracts, flaky timed tests.\n \"@sarj/prefer-constant-time-secret-compare\": \"error\",\n \"@sarj/store-insert-requires-on-conflict\": \"warn\",\n \"@sarj/no-offset-pagination\": \"warn\",\n \"@sarj/no-select-star\": \"warn\",\n \"@sarj/no-sleep-in-test-body\": \"warn\",\n \"@sarj/no-repeated-string-literal\": \"warn\",\n \"@sarj/no-positional-tuple-return\": \"warn\",\n // Injection guard — low FP, applies to any repo touching SQL.\n \"@sarj/no-dynamic-sql\": \"warn\",\n // Mined from two years of PR review (SARJ-928). Schema-layer sibling of\n // `no-enum`; autofixable for inline string-literal objects.\n \"@sarj/no-zod-native-enum\": \"warn\",\n // Mined from two years of PR review — the single most frequent uncovered\n // theme (~37 PRs). Measured 17 hits / 1085 real TS files, all true\n // positives, so it is safe to run everywhere.\n \"@sarj/prefer-module-level-constant\": \"warn\",\n },\n },\n strict: {\n plugins: [\"@sarj\"],\n rules: {\n \"@sarj/zod-naming-convention\": \"error\",\n \"@sarj/require-assert-never\": \"error\",\n \"@sarj/require-zod-form-validation\": \"error\",\n \"@sarj/enforce-file-structure\": \"error\",\n \"@sarj/no-raw-env\": \"error\",\n \"@sarj/prefer-shadcn\": \"error\",\n \"@sarj/no-enum\": \"error\",\n \"@sarj/no-client-side-data-fetching\": \"error\",\n \"@sarj/prefer-server-actions\": \"error\",\n \"@sarj/no-unnecessary-use-client\": \"error\",\n \"@sarj/prefer-schema-for-api-payload\": \"error\",\n // Distilled from sarj-audit skills.\n \"@sarj/no-sequential-await\": \"error\",\n \"@sarj/no-sentinel-return-on-catch\": \"error\",\n \"@sarj/no-log-only-catch\": \"error\",\n \"@sarj/no-insecure-random-id\": \"error\",\n \"@sarj/no-json-stringify-error\": \"error\",\n \"@sarj/no-string-concat-in-loop\": \"error\",\n \"@sarj/prefer-discriminated-union\": \"error\",\n \"@sarj/no-comment-cruft\": \"error\",\n // Frontend / styling — distilled from frontend PR-review mining. Stylistic,\n // no autofix → warn (rollout should prove the FP rate before raising it).\n \"@sarj/prefer-semantic-colors\": \"warn\",\n // Ported from sarj-python-lint (SARJ), corpus-validated FP~0.\n \"@sarj/no-fat-try-blocks\": \"error\",\n \"@sarj/no-cors-wildcard-with-credentials\": \"error\",\n \"@sarj/no-secret-in-log\": \"error\",\n \"@sarj/no-unsafe-cast\": \"warn\",\n \"@sarj/single-public-export\": \"error\",\n // High-volume/stylistic — warn until rollout proves FP rate.\n \"@sarj/prefer-string-literal-union\": \"warn\",\n // Mined from 2y of PR review feedback + 5-repo code-smell audit (2026-07).\n \"@sarj/require-fetch-timeout\": \"error\",\n \"@sarj/no-silent-promise-catch\": \"error\",\n \"@sarj/require-schema-validate-search\": \"error\",\n // Second SARJ port wave — the TS/Python parity gap.\n \"@sarj/prefer-constant-time-secret-compare\": \"error\",\n \"@sarj/store-insert-requires-on-conflict\": \"error\",\n \"@sarj/no-offset-pagination\": \"error\",\n \"@sarj/no-select-star\": \"error\",\n \"@sarj/no-sleep-in-test-body\": \"error\",\n \"@sarj/no-repeated-string-literal\": \"error\",\n // API-shape advice rather than a runtime defect — a corpus sweep found its\n // only hits are parser `[value, cursor]` returns, which are conventional.\n // Warn even in strict until a rollout justifies more.\n \"@sarj/no-positional-tuple-return\": \"warn\",\n \"@sarj/no-dynamic-sql\": \"error\",\n // Architectural: both need per-repo config to be meaningful, so they\n // are strict-only. `no-storage-in-stateless-modules` is a no-op until\n // its `modules` option names the directories a team declared stateless;\n // `no-raw-fetch-outside-clients` defaults to the `clients/` convention\n // and takes an `allow` list for repos that lay their client layer out\n // differently.\n \"@sarj/no-raw-fetch-outside-clients\": \"error\",\n \"@sarj/no-storage-in-stateless-modules\": \"error\",\n // Mined from two years of PR review (SARJ-928).\n \"@sarj/no-zod-native-enum\": \"error\",\n \"@sarj/prefer-module-level-constant\": \"error\",\n },\n },\n },\n};\n\nexport default plugin;\nexport { rules };\n","import { ESLintUtils, type TSESTree, AST_NODE_TYPES } from \"@typescript-eslint/utils\";\n\ntype MessageIds = \"importsFirst\" | \"useServerDirective\";\ntype Options = readonly [];\n\ntype StatementKind = \"import\" | \"reexport\" | \"body\";\n\n/**\n * Classify a top-level statement by WHAT it introduces, not by the presence of\n * the `export` keyword.\n *\n * - `import ...` → \"import\"\n * - `export ... from`, `export * from`, → \"reexport\"\n * `export { a, b }` (local names)\n * - everything else, INCLUDING every → \"body\"\n * exported declaration/function\n *\n * Bucketing exported statements as \"body\" is the whole point: an exported\n * `interface`/`type`/`enum`/`class`/value-`const` is a declaration and an\n * exported `function` (or `export default <fn>`) is a function — both live in\n * the same body as their non-exported equivalents. That lets the dominant\n * step-down layout (public API first, private helpers below) pass instead of\n * forcing every `export`-prefixed statement into a terminal \"exports\" section.\n *\n * Re-exports are their own neutral group: a generated `_namespaces` barrel that\n * interleaves `import * as X` / `export { X }` must not be flagged, so\n * re-exports never trigger and are allowed anywhere in the file.\n */\nconst classifyStatement = (\n statement: TSESTree.ProgramStatement,\n): StatementKind => {\n switch (statement.type) {\n case AST_NODE_TYPES.ImportDeclaration:\n return \"import\";\n case AST_NODE_TYPES.ExportAllDeclaration:\n return \"reexport\";\n case AST_NODE_TYPES.ExportNamedDeclaration:\n // `export { a } from './x'` / `export { a, b }` re-export names without\n // declaring anything; only `export <decl>` introduces a body statement.\n return statement.declaration === null ? \"reexport\" : \"body\";\n default:\n return \"body\";\n }\n};\n\nconst isStringDirective = (statement: TSESTree.ProgramStatement): boolean =>\n statement.type === AST_NODE_TYPES.ExpressionStatement &&\n statement.expression.type === AST_NODE_TYPES.Literal &&\n typeof statement.expression.value === \"string\" &&\n statement.expression.value.startsWith(\"use \");\n\nconst isUseServerDirective = (\n statement: TSESTree.ProgramStatement,\n): boolean => {\n if (statement.type !== AST_NODE_TYPES.ExpressionStatement) return false;\n const expr = statement.expression;\n if (expr.type !== AST_NODE_TYPES.Literal) return false;\n return expr.value === \"use server\";\n};\n\nexport default ESLintUtils.RuleCreator(\n (name) =>\n `https://github.com/sarj-ai/linting/blob/main/packages/typescript/src/rules/${name}.ts`,\n)<Options, MessageIds>({\n name: \"enforce-file-structure\",\n meta: {\n type: \"suggestion\",\n docs: {\n description:\n \"Require `import` statements to come first, then allow step-down ordering (public API first, private helpers below) for the rest of the file. Exported statements are classified by WHAT they export — an exported interface is a declaration, an exported function is a function — so a public exported function followed by a private helper, or an exported interface among declarations, is allowed. Re-exports (`export { … } from`, `export *`, `export { … }`) are a neutral group, so generated namespace barrels pass. When a module contains a `use server` directive, it must be the first statement in the file.\",\n },\n schema: [],\n messages: {\n importsFirst:\n \"File structure violation: import statements must come before other declarations\",\n useServerDirective:\n \"A 'use server' directive must be the first statement in the file\",\n },\n },\n defaultOptions: [],\n create(context) {\n return {\n Program(node: TSESTree.Program): void {\n const body = node.body;\n\n const misplacedUseServer = body.find(\n (statement, index) => index > 0 && isUseServerDirective(statement),\n );\n if (misplacedUseServer !== undefined) {\n context.report({\n node: misplacedUseServer,\n messageId: \"useServerDirective\",\n });\n }\n\n let seenBody = false;\n\n for (const statement of body) {\n if (isStringDirective(statement)) continue;\n\n switch (classifyStatement(statement)) {\n case \"reexport\":\n continue;\n case \"body\":\n seenBody = true;\n continue;\n case \"import\":\n if (seenBody) {\n context.report({\n node: statement,\n messageId: \"importsFirst\",\n });\n }\n continue;\n }\n }\n },\n };\n },\n});\n","/**\n * @fileoverview Disallow data fetching inside `useEffect` / `useLayoutEffect`.\n *\n * Anti-pattern:\n *\n * useEffect(() => { fetch('/data').then(setData); }, []);\n *\n * Causes a client-side waterfall (render → effect → fetch → re-render),\n * forfeits server-side caching, and produces layout shift. In Next.js App\n * Router, prefer:\n * - a React Server Component that fetches at render time, or\n * - a Server Action invoked from a form / onClick handler, or\n * - client-side caching libraries like SWR or React Query.\n *\n * Detection covers:\n * - `fetch(...)` (default + when explicit `method: \"GET\"`)\n * - `axios.<method>(...)` for actual HTTP verbs only:\n * get / post / put / delete / patch / request / head / options\n * (i.e. NOT `axios.create` / `axios.defaults`)\n * - `ky.<method>(...)` / `superagent.<method>(...)` (same verbs)\n * - bare `axios(...)` / `ky(...)` calls (when treated as a GET)\n *\n * Analytics / telemetry endpoints whose URL has a whole path segment of\n * `track` / `log` / `ping` / `event` / ... are intentionally exempt because\n * they aren't render-blocking data fetches. (Matched per-segment, so\n * `/api/login`, `/blog`, `/api/events`, `/catalog`, `/api/shipping` are NOT\n * exempt.)\n *\n * References:\n * - https://nextjs.org/docs/app/building-your-application/data-fetching\n * - https://react.dev/reference/react/useEffect#fetching-data-with-effects\n */\n\nimport {\n AST_NODE_TYPES,\n ESLintUtils,\n type TSESTree,\n} from \"@typescript-eslint/utils\";\n\ntype MessageIds = \"noClientFetch\";\ntype Options = readonly [];\n\nconst FETCH_LIBS: ReadonlySet<string> = new Set([\"axios\", \"ky\", \"superagent\"]);\n\n// Real HTTP verbs only. Explicitly excludes `create`, `defaults`,\n// `interceptors`, `isAxiosError`, etc.\nconst HTTP_METHOD_NAMES: ReadonlySet<string> = new Set([\n \"get\",\n \"post\",\n \"put\",\n \"delete\",\n \"patch\",\n \"request\",\n \"head\",\n \"options\",\n]);\n\n// Matched against whole path SEGMENTS (split on `/` and `.`), never as raw\n// substrings — otherwise `/api/login` (\"log\"), `/blog` (\"log\"), `/api/events`\n// (\"event\"), `/catalog` (\"log\"), and `/api/shipping` (\"ping\") would be wrongly\n// exempted.\nconst ANALYTICS_SEGMENTS: ReadonlySet<string> = new Set([\n \"analytics\",\n \"telemetry\",\n \"track\",\n \"log\",\n \"ping\",\n \"beacon\",\n \"metrics\",\n \"event\",\n]);\n\nfunction isEffectHookCall(node: TSESTree.CallExpression): boolean {\n const callee = node.callee;\n\n // useEffect(...) / useLayoutEffect(...)\n if (callee.type === AST_NODE_TYPES.Identifier) {\n return callee.name === \"useEffect\" || callee.name === \"useLayoutEffect\";\n }\n\n // React.useEffect(...) / React.useLayoutEffect(...)\n if (\n callee.type === AST_NODE_TYPES.MemberExpression &&\n !callee.computed &&\n callee.object.type === AST_NODE_TYPES.Identifier &&\n callee.object.name === \"React\" &&\n callee.property.type === AST_NODE_TYPES.Identifier\n ) {\n return (\n callee.property.name === \"useEffect\" ||\n callee.property.name === \"useLayoutEffect\"\n );\n }\n\n return false;\n}\n\n/**\n * Reads the `method` property of an options object passed to `fetch` / `axios`.\n * Returns the uppercased method name, or `null` if not statically determinable.\n */\nfunction readMethodProperty(\n optionsArg: TSESTree.Node | undefined,\n): string | null {\n if (!optionsArg || optionsArg.type !== AST_NODE_TYPES.ObjectExpression) {\n return null;\n }\n for (const prop of optionsArg.properties) {\n if (prop.type !== AST_NODE_TYPES.Property) continue;\n if (prop.computed) continue;\n const key = prop.key;\n const matchesMethodKey =\n (key.type === AST_NODE_TYPES.Identifier && key.name === \"method\") ||\n (key.type === AST_NODE_TYPES.Literal && key.value === \"method\");\n if (!matchesMethodKey) continue;\n if (\n prop.value.type === AST_NODE_TYPES.Literal &&\n typeof prop.value.value === \"string\"\n ) {\n return prop.value.value.toUpperCase();\n }\n return null;\n }\n return null;\n}\n\nfunction isFetchCall(node: TSESTree.CallExpression): boolean {\n const callee = node.callee;\n\n // fetch(url, options?)\n if (\n callee.type === AST_NODE_TYPES.Identifier &&\n callee.name === \"fetch\"\n ) {\n const method = readMethodProperty(node.arguments[1]);\n if (method !== null && method !== \"GET\") {\n return false;\n }\n return true;\n }\n\n // axios.get(...), ky.post(...), superagent.delete(...), ...\n if (\n callee.type === AST_NODE_TYPES.MemberExpression &&\n !callee.computed &&\n callee.object.type === AST_NODE_TYPES.Identifier &&\n FETCH_LIBS.has(callee.object.name) &&\n callee.property.type === AST_NODE_TYPES.Identifier\n ) {\n // Only flag actual HTTP method calls — NOT `axios.create`, `axios.defaults`,\n // `axios.interceptors`, `axios.isAxiosError`, etc.\n return HTTP_METHOD_NAMES.has(callee.property.name);\n }\n\n // axios(config) / ky(config) — treat as request unless method is explicitly non-GET.\n if (\n callee.type === AST_NODE_TYPES.Identifier &&\n (callee.name === \"axios\" || callee.name === \"ky\")\n ) {\n const firstArg = node.arguments[0];\n const secondArg = node.arguments[1];\n let configArg: TSESTree.Node | undefined;\n if (firstArg?.type === AST_NODE_TYPES.ObjectExpression) {\n configArg = firstArg;\n } else if (secondArg?.type === AST_NODE_TYPES.ObjectExpression) {\n configArg = secondArg;\n }\n const method = readMethodProperty(configArg);\n if (method !== null && method !== \"GET\") {\n return false;\n }\n return true;\n }\n\n return false;\n}\n\nfunction extractUrlString(node: TSESTree.CallExpression): string {\n const firstArg = node.arguments[0];\n if (!firstArg) return \"\";\n\n if (\n firstArg.type === AST_NODE_TYPES.Literal &&\n typeof firstArg.value === \"string\"\n ) {\n return firstArg.value;\n }\n if (firstArg.type === AST_NODE_TYPES.TemplateLiteral) {\n return firstArg.quasis.map((q) => q.value.cooked).join(\"\");\n }\n if (firstArg.type === AST_NODE_TYPES.Identifier) {\n return firstArg.name;\n }\n return \"\";\n}\n\nfunction isAnalyticsCall(node: TSESTree.CallExpression): boolean {\n const url = extractUrlString(node).toLowerCase();\n if (url === \"\") return false;\n // Split into path segments and file-extension parts; exempt only when a\n // WHOLE segment is a known analytics keyword.\n return url\n .split(/[/.]/)\n .some((segment) => ANALYTICS_SEGMENTS.has(segment));\n}\n\nexport default ESLintUtils.RuleCreator(\n (name) =>\n `https://github.com/sarj-ai/linting/blob/main/packages/typescript/src/rules/${name}.ts`,\n)<Options, MessageIds>({\n name: \"no-client-side-data-fetching\",\n meta: {\n type: \"problem\",\n docs: {\n description:\n \"Disallow data fetching inside `useEffect` / `useLayoutEffect`; prefer React Server Components, Server Actions, or a client-side cache (SWR / React Query).\",\n },\n schema: [],\n messages: {\n noClientFetch:\n \"Avoid direct data fetching inside useEffect / useLayoutEffect. This causes waterfalls and layout shifts. Prefer React Server Components, Server Actions, or client-side caching libraries like SWR or React Query.\",\n },\n },\n defaultOptions: [],\n create(context) {\n let effectDepth = 0;\n return {\n CallExpression(node: TSESTree.CallExpression): void {\n if (isEffectHookCall(node)) {\n effectDepth += 1;\n return;\n }\n if (effectDepth === 0) return;\n if (!isFetchCall(node)) return;\n if (isAnalyticsCall(node)) return;\n context.report({ node, messageId: \"noClientFetch\" });\n },\n \"CallExpression:exit\"(node: TSESTree.CallExpression): void {\n if (isEffectHookCall(node)) {\n effectDepth -= 1;\n }\n },\n };\n },\n});\n","/**\n * @fileoverview Flag comment cruft — commented-out code, section banners,\n * leading file-header comment preambles, and redundant narration (step markers\n * like \"First, …\" and self-admitted meta-commentary like \"for now\" / \"temporary\n * hack\"). Code carries the *what*; comments are reserved for the *why*. The\n * fuzzier \"this comment restates the next line\" judgment stays in review (a\n * substring-corroboration heuristic was too false-positive-prone on real code).\n * JSDoc (`/** ... *\\/`) is never flagged, and directive comments (`eslint-`,\n * `@ts-`, `prettier-`, `biome-`, `c8`, `<reference`, `TODO`, `FIXME`) are ignored.\n *\n * `fileHeaderPreamble` requires the preamble to contain NO prose sentence. The\n * original \"4+ consecutive `//` lines before the first code\" test penalised\n * syntax rather than content: on a real 42k-LOC codebase, 11 of 15 hits were the\n * repo's BEST documentation — module headers explaining a stateless idempotency\n * substrate, one citing RFC 9562 §5.7 — which is precisely the \"brief doc\n * comment for the why\" this rule's own message asks for. Exactly one hit was\n * genuine (an ASCII banner, already covered by `sectionBanner`). What survives\n * is the content-free preamble: a stack of bare labels/fragments with nothing\n * explained. A prose header should be a JSDoc block for tooling reasons, but\n * that is a formatting preference, not cruft, and this rule does not litigate it.\n */\n\nimport { ESLintUtils, type TSESTree } from \"@typescript-eslint/utils\";\n\ntype MessageIds =\n | \"commentedOutCode\"\n | \"sectionBanner\"\n | \"fileHeaderPreamble\"\n | \"redundantNarration\";\ntype Options = readonly [];\n\nconst LEADING_PREAMBLE_MIN = 4;\n\n// Step-narration lead-ins (\"First, …\", \"Then, …\", \"Finally, …\", \"Step 2:\"). A\n// trailing comma/colon is required so English adverbs (\"finally the invariant\n// holds\") aren't mistaken for an enumeration marker.\nconst STEP_NARRATION_RE =\n /^(?:first(?:ly)?|second(?:ly)?|third(?:ly)?|then|next|after(?:wards| that)?|finally|lastly|now)\\s*[,:]\\s*\\S|^step\\s+\\d+\\b/i;\n\n// Self-admitted meta-commentary — the \"why later\", not the why. `TODO`/`FIXME`/\n// `HACK`/`XXX` are handled as directives (kept, with an owner, per convention).\nconst META_COMMENTARY_RE =\n /\\b(?:for now|keeping (?:it|this) simple|could be (?:refactored|improved|cleaned up|simplified)|refactor(?:ed|ing)? (?:later|this)|not sure (?:if|whether|why|how)|quick[- ](?:and[- ]dirty|fix)|(?:a |bit of a )?hacky|is a hack|temporary (?:solution|workaround|fix|hack)|revisit (?:this|later|below)|clean (?:this|it) up|not ideal|placeholder for now)\\b/i;\n\n\nconst DIRECTIVE_RE =\n /^(eslint\\b|eslint-|@ts-|prettier-ignore|prettier\\b|biome-|c8\\b|v8\\b|istanbul\\b|@type\\b|@vite|webpack|<reference|<amd|global\\b|noinspection|todo\\b|fixme\\b|hack\\b|xxx\\b)/i;\n\nconst LICENSE_RE =\n /copyright|licen[cs]ed?|spdx|permission is hereby granted|all rights reserved/i;\n\nconst BANNER_FULL_RE = /^[\\s\\-=*#~_+.]{4,}$/;\n// `={4,}` not `={3,}`: `===` is TS strict-equality and appears in prose comments.\nconst BANNER_RUN_RE = /={4,}|-{4,}|#{4,}|\\*{4,}|~{4,}/;\nconst REGION_RE = /^#?(?:end)?region\\b/i;\n\nconst CODE_KEYWORD_RE =\n /^(import |export |const |let |var |function\\b|class |interface |type \\w|enum |return\\b|throw |await |async |if\\s*\\(|for\\s*\\(|while\\s*\\(|switch\\s*\\(|new |console\\.)/;\nconst CODE_TAIL_RE = /[;{}()]\\s*$|=>\\s*$|,\\s*$/;\n// LHS must be a real identifier (not a number literal — `0=Monday` in prose is\n// not an assignment) and `=` must not be `==`/`===`/`=>` (comparison/arrow).\n// The assignment branch additionally requires a code-tail — the line must end\n// with `;`, `)`, `}` or `]` — so plain prose like `count = number of items`\n// (which has no code-tail) is not mistaken for commented-out code.\nconst CALL_OR_ASSIGN_RE =\n /^[A-Za-z_$][\\w.$[\\]]*\\s*(?:=(?![=>])|\\+=|-=|\\*=)\\s*\\S.*[;)}\\]]\\s*$|^[A-Za-z_$][\\w.$]*\\([^)]*\\)\\s*;?\\s*$/;\n\n// Placeholders that only appear in grammar productions / desugaring examples,\n// never in real code: `%sent%`, `[opt]`, a standalone `<FunctionBody>`, `…` / `...`.\nconst PSEUDOCODE_RE = /%\\w+%|\\[opt\\]|(?:^|\\s)<[A-Za-z]\\w*>|…|\\.\\.\\./;\n\n// A triple-slash `///` directive keeps its third `/` after ESLint strips the\n// leading `//`, so strip 1–2 leading slashes (not exactly two) for `<reference`.\nfunction stripCommentMarker(line: string): string {\n return line.replace(/^\\s*\\/{1,2}/, \"\").replace(/^\\s*\\*+/, \"\").trim();\n}\n\nfunction isDirective(text: string): boolean {\n return DIRECTIVE_RE.test(text.trim());\n}\n\nfunction isBanner(text: string): boolean {\n const t = text.trim();\n if (!t) return false;\n return BANNER_FULL_RE.test(t) || BANNER_RUN_RE.test(t) || REGION_RE.test(t);\n}\n\nfunction looksLikeCode(text: string): boolean {\n const t = text.trim();\n if (!t) return false;\n if (CODE_KEYWORD_RE.test(t) && CODE_TAIL_RE.test(t)) return true;\n return CALL_OR_ASSIGN_RE.test(t);\n}\n\nfunction hasPseudocode(text: string): boolean {\n return PSEUDOCODE_RE.test(text);\n}\n\n// A prose lead-in preceding a code-shaped line marks that line as an\n// illustration (`// For example:`, a grammar production `FunctionExpression:`),\n// not commented-out code.\nfunction isProse(text: string): boolean {\n const t = text.trim();\n if (!t) return false;\n if (t.endsWith(\":\")) return true;\n if (\n /[.!?]$/.test(t) &&\n /\\s/.test(t) &&\n /[a-z]/.test(t) &&\n !looksLikeCode(t) &&\n t.split(/\\s+/).length >= 3\n ) {\n return true;\n }\n return false;\n}\n\n/**\n * Whether a single-line comment merely narrates the code rather than explaining\n * the *why*. Three deterministic shapes: step narration (\"First, …\"), self-\n * admitted meta-commentary (\"keeping it simple\"), and a restatement of the very\n * next statement — a narration-verb opener corroborated by a shared token with\n * the following code line (`// create the user` above `const user = createUser()`).\n */\nfunction isRedundantNarration(body: string): boolean {\n const t = body.trim();\n if (!t || looksLikeCode(t) || hasPseudocode(t)) return false;\n if (STEP_NARRATION_RE.test(t)) return true;\n if (META_COMMENTARY_RE.test(t)) return true;\n return false;\n}\n\nfunction hasCommentedOutCode(\n texts: readonly string[],\n precedingProse: boolean,\n): boolean {\n for (let i = 0; i < texts.length; i++) {\n const line = texts[i];\n if (line === undefined || !looksLikeCode(line) || hasPseudocode(line)) {\n continue;\n }\n const prev = i > 0 ? texts[i - 1] : undefined;\n if (prev !== undefined ? isProse(prev) : precedingProse) continue;\n return true;\n }\n return false;\n}\n\nexport default ESLintUtils.RuleCreator(\n (name) =>\n `https://github.com/sarj-ai/standards/blob/main/packages/typescript/src/rules/${name}.ts`,\n)<Options, MessageIds>({\n name: \"no-comment-cruft\",\n meta: {\n type: \"suggestion\",\n docs: {\n description:\n \"Flag commented-out code, section-banner comments, and leading file-header comment preambles.\",\n },\n schema: [],\n messages: {\n commentedOutCode:\n \"Commented-out code — delete it; git history remembers.\",\n sectionBanner:\n \"Section-banner / region comment — structure code with functions, not ASCII rules.\",\n fileHeaderPreamble:\n \"File-header comment preamble — use a brief doc comment for the why, not a block of `//` lines.\",\n redundantNarration:\n \"Comment narrates the code — delete it or say *why*, not *what*. Code is self-documenting.\",\n },\n },\n defaultOptions: [],\n create(context) {\n const sourceCode = context.sourceCode;\n\n function isStandalone(comment: TSESTree.Comment): boolean {\n const before = sourceCode.getTokenBefore(comment, {\n includeComments: false,\n });\n return !before || before.loc.end.line < comment.loc.start.line;\n }\n\n function isJsDoc(comment: TSESTree.Comment): boolean {\n return comment.type === \"Block\" && /^\\*/.test(comment.value);\n }\n\n function reportLeadingPreamble(\n comments: readonly TSESTree.Comment[],\n firstCodeLine: number,\n ): void {\n const leading: TSESTree.Comment[] = [];\n let prevLine: number | null = null;\n for (const comment of comments) {\n if (comment.type !== \"Line\") break;\n if (comment.loc.start.line >= firstCodeLine) break;\n if (!isStandalone(comment)) break;\n const body = stripCommentMarker(comment.value);\n if (isDirective(body) || body.startsWith(\"!\")) continue;\n if (prevLine !== null && comment.loc.start.line !== prevLine + 1) break;\n leading.push(comment);\n prevLine = comment.loc.start.line;\n }\n const first = leading[0];\n if (first === undefined || leading.length < LEADING_PREAMBLE_MIN) return;\n const bodies = leading.map((c) => stripCommentMarker(c.value));\n if (bodies.some((body) => LICENSE_RE.test(body))) return;\n // A preamble carrying at least one prose sentence is documentation — the\n // \"why\" the rule wants — regardless of which comment syntax carries it.\n if (bodies.some((body) => isProse(body))) return;\n context.report({ node: first, messageId: \"fileHeaderPreamble\" });\n }\n\n return {\n Program(): void {\n const comments = sourceCode.getAllComments();\n const firstCodeLine =\n sourceCode.ast.tokens[0]?.loc.start.line ?? Number.MAX_SAFE_INTEGER;\n\n for (let i = 0; i < comments.length; i++) {\n const comment = comments[i];\n if (comment === undefined) continue;\n if (isJsDoc(comment) || !isStandalone(comment)) continue;\n if (LICENSE_RE.test(comment.value)) continue;\n const texts = comment.value\n .split(\"\\n\")\n .map(stripCommentMarker)\n .filter((l) => l.length > 0 && !isDirective(l));\n if (texts.some(isBanner)) {\n context.report({ node: comment, messageId: \"sectionBanner\" });\n continue;\n }\n const prev = comments[i - 1];\n const precedingProse =\n prev !== undefined &&\n prev.type === \"Line\" &&\n prev.loc.end.line === comment.loc.start.line - 1 &&\n isProse(stripCommentMarker(prev.value));\n if (hasCommentedOutCode(texts, precedingProse)) {\n context.report({ node: comment, messageId: \"commentedOutCode\" });\n continue;\n }\n // Narration only for single-line comments (a multi-line block is\n // usually a real doc). The next non-blank source line is the code the\n // comment sits above.\n if (comment.type === \"Line\" && texts.length === 1) {\n const body = texts[0];\n if (body !== undefined && isRedundantNarration(body)) {\n context.report({ node: comment, messageId: \"redundantNarration\" });\n }\n }\n }\n\n reportLeadingPreamble(comments, firstCodeLine);\n },\n };\n },\n});\n","/**\n * @fileoverview Disallow TypeScript `enum` declarations. Use string-literal\n * union types (e.g. `type Status = \"active\" | \"inactive\"`) or `as const`\n * objects instead — enums generate runtime code, have unintuitive numeric\n * defaults, and don't tree-shake cleanly.\n *\n * Generated files can opt out either by living under a path matched by\n * `ignoreFiles` (default: `**\\/generated/**`, `**\\/*.gen.ts`, `**\\/*.generated.ts`)\n * or by including a `@generated` marker comment near the top of the file.\n */\n\nimport { ESLintUtils, type TSESTree } from \"@typescript-eslint/utils\";\n\ntype MessageIds = \"noEnum\";\ntype Options = readonly [\n {\n ignoreFiles?: readonly string[];\n }?,\n];\n\nconst DEFAULT_IGNORE_PATTERNS: readonly RegExp[] = [\n /[\\\\/]generated[\\\\/]/,\n /\\.gen\\.tsx?$/,\n /\\.generated\\.tsx?$/,\n];\n\nfunction matchesAnyPattern(\n filename: string,\n patterns: readonly string[],\n): boolean {\n for (const pattern of patterns) {\n // Convert minimatch-ish globs to regex: ** -> .*, * -> [^/\\\\]*\n const regexSource = pattern\n .replace(/[.+^${}()|[\\]\\\\]/g, \"\\\\$&\")\n .replace(/\\*\\*/g, \"::DOUBLESTAR::\")\n .replace(/\\*/g, \"[^/\\\\\\\\]*\")\n .replace(/::DOUBLESTAR::/g, \".*\");\n if (new RegExp(`^${regexSource}$`).test(filename)) {\n return true;\n }\n }\n return false;\n}\n\nfunction hasGeneratedMarker(sourceText: string): boolean {\n // Look only in the first 1KB to keep this cheap.\n const head = sourceText.slice(0, 1024);\n return /@generated\\b/.test(head);\n}\n\nexport default ESLintUtils.RuleCreator(\n (name) =>\n `https://github.com/sarj-ai/linting/blob/main/packages/typescript/src/rules/${name}.ts`,\n)<Options, MessageIds>({\n name: \"no-enum\",\n meta: {\n type: \"suggestion\",\n docs: {\n description:\n \"Disallow TypeScript `enum`; use string-literal unions or `as const` objects instead.\",\n },\n schema: [\n {\n type: \"object\",\n additionalProperties: false,\n properties: {\n ignoreFiles: {\n type: \"array\",\n items: { type: \"string\" },\n },\n },\n },\n ],\n messages: {\n noEnum:\n 'Enums are discouraged. Use a string-literal union (e.g. `type Status = \"active\" | \"inactive\"`) or an `as const` object instead.',\n },\n },\n defaultOptions: [{}],\n create(context, [optionsArg]) {\n const options = optionsArg ?? {};\n const ignoreFiles = options.ignoreFiles ?? [];\n const filename = context.filename;\n const sourceText = context.sourceCode.getText();\n\n const isIgnoredByDefault = DEFAULT_IGNORE_PATTERNS.some((re) =>\n re.test(filename),\n );\n const isIgnoredByOption =\n ignoreFiles.length > 0 && matchesAnyPattern(filename, ignoreFiles);\n const isGenerated = hasGeneratedMarker(sourceText);\n\n if (isIgnoredByDefault || isIgnoredByOption || isGenerated) {\n return {};\n }\n\n return {\n TSEnumDeclaration(node: TSESTree.TSEnumDeclaration): void {\n context.report({\n node,\n messageId: \"noEnum\",\n });\n },\n };\n },\n});\n","/**\n * @fileoverview Disallow using `Math.random()` to generate identifiers,\n * tokens, keys, or other security-sensitive values. `Math.random()` is not\n * cryptographically secure and is predictable — using it for tokens/secrets\n * can lead to collisions and trivially guessable values. Prefer\n * `crypto.randomUUID()` or `crypto.getRandomValues(...)` instead.\n *\n * Precision matters here: the rule runs at `error` in the `strict` config, so a\n * false positive blocks a real PR. Large open-source sweeps (VS Code, NestJS,\n * Next.js) showed the bare `id`/`key`/`session` substring heuristic firing on a\n * flood of NON-security correlation/ephemeral ids — temp-file suffixes, HMR\n * session numbers, dev request/execution/trace ids, in-process RPC handles.\n * None of those are security tokens. So the rule now requires a STRONG security\n * signal, and actively exempts names that read as ephemeral/correlation ids or\n * random values concatenated into a filename/path/DOM id.\n *\n * The rule flags a `Math.random()` call when, and only when:\n * 1. Its enclosing binding/property NAME carries a strong security signal\n * (`token`, `secret`, `apiKey`, `csrf`, `password`, `nonce`, `salt`,\n * `uuid`, `authId`) — even a `sessionToken` counts because of `token`; or\n * 2. Its result is fed into a `.toString(36)` chain (the classic insecure\n * random-id idiom, e.g. `Math.random().toString(36).slice(2)`) AND the\n * value is not an exempt ephemeral/correlation id or path fragment.\n *\n * It does NOT flag when the enclosing name signals a non-security\n * correlation/ephemeral id (`temp`, `tmp`, `cache`, `correlation`, `request`,\n * `req`, `trace`, `execution`, `dev`, `hmr`, `mock`, `test`, `perf`, `marker`),\n * nor when the random value is concatenated into a filename/path/DOM id. A\n * strong security name still wins over these exemptions.\n *\n * Bare `Math.random()` used for non-identifier purposes (jitter, sampling,\n * rolls, etc.) is NOT flagged, and neither is the bare `id`/`key`/`session`\n * substring on its own — we err toward suppressing ambiguous correlation ids.\n *\n * KNOWN GAP (false-negative): an arithmetic expression between `Math.random()`\n * and `.toString(36)` breaks the member-chain walk, e.g.\n * `(Math.random() * 1e9).toString(36)`. The intervening `BinaryExpression`\n * means `Math.random()` is no longer the object end of the `.toString` chain,\n * so trigger 2 does not fire. Such code is only caught if its binding/property\n * name looks security-like (trigger 1). See the documented test case.\n */\n\nimport { ESLintUtils, type TSESTree } from \"@typescript-eslint/utils\";\n\ntype MessageIds = \"insecureRandomId\";\ntype Options = readonly [];\n\nconst STRONG_SECURITY_PATTERN =\n /token|secret|csrf|password|passwd|apikey|api[-_]?key|nonce|salt|uuid|authid/i;\n\nconst NON_SECURITY_ID_PATTERN =\n /temp|tmp|cache|correlation|request|req|trace|execution|dev|hmr|mock|test|perf|marker/i;\n\n/** Matches a static string fragment that reads as a path or DOM-id context. */\nconst PATH_OR_DOM_MARKER = /[\\\\/#]|\\.[A-Za-z0-9]/;\n\n/**\n * Returns true if `node` is a `Math.random()` CallExpression.\n */\nfunction isMathRandomCall(node: TSESTree.Node): node is TSESTree.CallExpression {\n if (node.type !== \"CallExpression\") {\n return false;\n }\n const callee = node.callee;\n if (callee.type !== \"MemberExpression\" || callee.computed) {\n return false;\n }\n const { object, property } = callee;\n return (\n object.type === \"Identifier\" &&\n object.name === \"Math\" &&\n property.type === \"Identifier\" &&\n property.name === \"random\"\n );\n}\n\n/**\n * Climbs the member/call chain in which `node` is the object/callee end, and\n * returns the outermost value node of that chain. For\n * `Math.random().toString(36).slice(2)` this returns the `.slice(2)` call —\n * i.e. the value that actually gets assigned/concatenated.\n */\nfunction climbValueChain(node: TSESTree.Node): TSESTree.Node {\n let current: TSESTree.Node = node;\n let parent = current.parent;\n\n while (parent) {\n if (\n parent.type === \"MemberExpression\" &&\n parent.object === current &&\n !parent.computed\n ) {\n current = parent;\n parent = current.parent;\n continue;\n }\n if (parent.type === \"CallExpression\" && parent.callee === current) {\n current = parent;\n parent = current.parent;\n continue;\n }\n break;\n }\n\n return current;\n}\n\n/**\n * Returns true if `node` (a `Math.random()` call) is the base of a member\n * chain that calls `.toString(36)` somewhere above it, e.g.\n * `Math.random().toString(36)` or `Math.random().toString(36).slice(2)`.\n */\nfunction isPartOfToString36Chain(node: TSESTree.Node): boolean {\n let current: TSESTree.Node = node;\n let parent = current.parent;\n\n while (parent) {\n if (\n parent.type === \"MemberExpression\" &&\n parent.object === current &&\n !parent.computed &&\n parent.property.type === \"Identifier\" &&\n parent.property.name === \"toString\"\n ) {\n const grandparent = parent.parent;\n if (\n grandparent &&\n grandparent.type === \"CallExpression\" &&\n grandparent.callee === parent\n ) {\n const firstArg = grandparent.arguments[0];\n if (firstArg && firstArg.type === \"Literal\" && firstArg.value === 36) {\n return true;\n }\n }\n }\n\n if (parent.type === \"MemberExpression\" && parent.object === current) {\n current = parent;\n parent = current.parent;\n continue;\n }\n if (parent.type === \"CallExpression\" && parent.callee === current) {\n current = parent;\n parent = current.parent;\n continue;\n }\n break;\n }\n\n return false;\n}\n\n/**\n * Walks up from `node` to find the name of the nearest enclosing binding\n * (VariableDeclarator id) or property (Property / PropertyDefinition key),\n * and returns it. Passes through string concatenation and template literals so\n * that `const tempPath = base + Math.random()...` resolves to `tempPath`.\n * Returns `undefined` if no such name is found before leaving the enclosing\n * initializer/value context.\n */\nfunction findEnclosingName(node: TSESTree.Node): string | undefined {\n let current: TSESTree.Node = node;\n let parent = current.parent;\n\n while (parent) {\n if (parent.type === \"VariableDeclarator\" && parent.init === current) {\n if (parent.id.type === \"Identifier\") {\n return parent.id.name;\n }\n return undefined;\n }\n\n if (parent.type === \"Property\" && parent.value === current) {\n const key = parent.key;\n if (!parent.computed && key.type === \"Identifier\") {\n return key.name;\n }\n if (key.type === \"Literal\" && typeof key.value === \"string\") {\n return key.value;\n }\n return undefined;\n }\n\n if (parent.type === \"PropertyDefinition\" && parent.value === current) {\n const key = parent.key;\n if (!parent.computed && key.type === \"Identifier\") {\n return key.name;\n }\n if (key.type === \"Literal\" && typeof key.value === \"string\") {\n return key.value;\n }\n return undefined;\n }\n\n if (\n parent.type === \"FunctionDeclaration\" ||\n parent.type === \"FunctionExpression\" ||\n parent.type === \"ArrowFunctionExpression\" ||\n parent.type === \"BlockStatement\" ||\n parent.type === \"ReturnStatement\" ||\n parent.type === \"ExpressionStatement\"\n ) {\n return undefined;\n }\n\n current = parent;\n parent = current.parent;\n }\n\n return undefined;\n}\n\n/**\n * Collects the static string fragments of a `+` concatenation / template\n * literal subtree into `out`.\n */\nfunction collectStaticStringParts(\n node: TSESTree.Node,\n out: string[],\n): void {\n if (node.type === \"Literal\" && typeof node.value === \"string\") {\n out.push(node.value);\n return;\n }\n if (node.type === \"TemplateLiteral\") {\n for (const quasi of node.quasis) {\n out.push(quasi.value.cooked ?? quasi.value.raw);\n }\n return;\n }\n if (node.type === \"BinaryExpression\" && node.operator === \"+\") {\n collectStaticStringParts(node.left, out);\n collectStaticStringParts(node.right, out);\n }\n}\n\n/**\n * Returns true if the random value is concatenated into a string whose static\n * parts read as a filename/path/DOM id (contain a slash, backslash, `#`, or a\n * `.ext`-style fragment).\n */\nfunction isConcatenatedIntoPathOrDomId(node: TSESTree.Node): boolean {\n const valueNode = climbValueChain(node);\n\n let current: TSESTree.Node = valueNode;\n let parent = current.parent;\n let top: TSESTree.Node | undefined;\n\n while (parent) {\n if (\n parent.type === \"BinaryExpression\" &&\n parent.operator === \"+\" &&\n (parent.left === current || parent.right === current)\n ) {\n top = parent;\n current = parent;\n parent = current.parent;\n continue;\n }\n if (parent.type === \"TemplateLiteral\") {\n top = parent;\n current = parent;\n parent = current.parent;\n continue;\n }\n break;\n }\n\n if (!top) {\n return false;\n }\n\n const parts: string[] = [];\n collectStaticStringParts(top, parts);\n return parts.some((part) => PATH_OR_DOM_MARKER.test(part));\n}\n\nexport default ESLintUtils.RuleCreator(\n (name) =>\n `https://github.com/sarj-ai/linting/blob/main/packages/typescript/src/rules/${name}.ts`,\n)<Options, MessageIds>({\n name: \"no-insecure-random-id\",\n meta: {\n type: \"problem\",\n docs: {\n description:\n \"Disallow using `Math.random()` to generate identifiers, tokens, or secrets; use `crypto.randomUUID()` or `crypto.getRandomValues(...)` instead.\",\n },\n schema: [],\n messages: {\n insecureRandomId:\n \"`Math.random()` is not cryptographically secure and is predictable; do not use it to generate IDs, tokens, or secrets. Use `crypto.randomUUID()` or `crypto.getRandomValues(...)` instead.\",\n },\n },\n defaultOptions: [],\n create(context) {\n return {\n CallExpression(node: TSESTree.CallExpression): void {\n if (!isMathRandomCall(node)) {\n return;\n }\n\n const name = findEnclosingName(node);\n\n // A strong security name always fires — even a `sessionToken` or a name\n // that also happens to contain a correlation-id word.\n if (name !== undefined && STRONG_SECURITY_PATTERN.test(name)) {\n context.report({ node, messageId: \"insecureRandomId\" });\n return;\n }\n\n // Ephemeral / correlation ids (temp files, HMR sessions, dev request\n // ids, ...) are not security-sensitive — suppress, including the\n // `.toString(36)` idiom used to shape them.\n if (name !== undefined && NON_SECURITY_ID_PATTERN.test(name)) {\n return;\n }\n\n // A random value concatenated into a filename/path/DOM id is not a\n // security token.\n if (isConcatenatedIntoPathOrDomId(node)) {\n return;\n }\n\n // The classic insecure random-id idiom.\n if (isPartOfToString36Chain(node)) {\n context.report({ node, messageId: \"insecureRandomId\" });\n }\n },\n };\n },\n});\n","/**\n * @fileoverview Disallow `JSON.stringify(err)` on a (heuristically detected)\n * Error value. `JSON.stringify` on an Error produces `\"{}\"` because the\n * `message` and `stack` properties are non-enumerable, silently throwing away\n * the very information you were trying to log.\n *\n * This is a purely syntactic rule (no type information). It flags\n * `JSON.stringify(x)` when the first argument is either:\n * 1. an Identifier that is the binding of an enclosing `catch (x)` clause, or\n * matches the conventional error-name pattern /^(e|err|error|ex|exc)$/i, OR\n * 2. a member expression denoting an error value (`err.cause`, `this.lastError`) —\n * an error-suggesting property name, or an error-named base whose property is\n * not a plain string accessor (`.message` / `.stack` / `.name`).\n *\n * It suppresses the report inside the non-error branch of an `x instanceof Error`\n * guard (`x instanceof Error ? x : JSON.stringify(x)`), where stringifying the\n * non-Error fallback is exactly correct.\n *\n * Object literals and arbitrary identifiers (`JSON.stringify(user)`) are not flagged.\n */\n\nimport { ESLintUtils, type TSESTree } from \"@typescript-eslint/utils\";\nimport type { Scope, SourceCode } from \"@typescript-eslint/utils/ts-eslint\";\n\ntype MessageIds = \"noJsonStringifyError\";\ntype Options = readonly [];\n\nconst ERROR_NAME_PATTERN = /^(e|err|error|ex|exc)$/i;\n\n/** Property names whose value is itself an error object (unsafe to stringify). */\nconst ERROR_PROP_PATTERN = /^(cause|lastError|error|err|exception|originalError|innerError)$/i;\n\n/** Property names whose value is a plain string — the recommended escape hatch. */\nconst SAFE_STRING_PROPS: ReadonlySet<string> = new Set([\"message\", \"stack\", \"name\"]);\n\n/**\n * Walk up the scope chain looking for a `catch` clause whose binding matches\n * `name`. We rely on the scope analysis provided by the parser rather than\n * type information, keeping the rule type-free.\n */\nfunction isCatchBinding(scope: Scope.Scope, name: string): boolean {\n let current: Scope.Scope | null = scope;\n while (current) {\n const variable = current.set.get(name);\n if (variable) {\n for (const def of variable.defs) {\n if (def.type === \"CatchClause\") {\n return true;\n }\n }\n }\n current = current.upper;\n }\n return false;\n}\n\n/**\n * True if a member-expression argument (`err.cause`, `this.lastError`) denotes an\n * Error value: an error-suggesting property name, or an error-suggesting base whose\n * property is not a known string accessor (`.message` / `.stack` / `.name`).\n */\nfunction memberSuggestsError(\n member: TSESTree.MemberExpression,\n scope: Scope.Scope,\n): boolean {\n const propName =\n !member.computed && member.property.type === \"Identifier\" ? member.property.name : null;\n\n if (propName !== null && ERROR_PROP_PATTERN.test(propName)) {\n return true;\n }\n\n const base = member.object;\n const baseSuggestsError =\n base.type === \"Identifier\" &&\n (ERROR_NAME_PATTERN.test(base.name) || isCatchBinding(scope, base.name));\n if (baseSuggestsError) {\n return propName === null || !SAFE_STRING_PROPS.has(propName.toLowerCase());\n }\n\n return false;\n}\n\n/** The subject `x` of an `x instanceof Error` test, or null. */\nfunction instanceofErrorSubject(\n test: TSESTree.Expression,\n): TSESTree.Expression | null {\n if (\n test.type === \"BinaryExpression\" &&\n test.operator === \"instanceof\" &&\n test.right.type === \"Identifier\" &&\n test.right.name === \"Error\"\n ) {\n return test.left;\n }\n return null;\n}\n\n/** Names of a user-defined type-guard predicate: `isErrorLike`, `isError`, `hasErrorShape`. */\nconst TYPE_GUARD_PATTERN = /^(is|has)[A-Z]/;\n\n/** The narrowed subject `x` of a user-defined type-guard call `isFoo(x)`, or null. */\nfunction typeGuardSubject(\n test: TSESTree.Expression,\n): TSESTree.Expression | null {\n const arg = test.type === \"CallExpression\" ? test.arguments[0] : undefined;\n if (\n test.type === \"CallExpression\" &&\n test.callee.type === \"Identifier\" &&\n TYPE_GUARD_PATTERN.test(test.callee.name) &&\n test.arguments.length === 1 &&\n arg !== undefined &&\n arg.type !== \"SpreadElement\"\n ) {\n return arg;\n }\n return null;\n}\n\n/**\n * The subject `x` of a positive error-narrowing test — `x instanceof Error` or a\n * user-defined guard `isErrorLike(x)`. In both, the value IS the error in the\n * truthy branch, so `JSON.stringify(x)` belongs in the falsy (alternate) branch.\n */\nfunction positiveErrorSubject(\n test: TSESTree.Expression,\n): TSESTree.Expression | null {\n return instanceofErrorSubject(test) ?? typeGuardSubject(test);\n}\n\n/** The subject `x` of a negated error-narrowing test — `!(x instanceof Error)` / `!isErrorLike(x)`. */\nfunction negatedInstanceofErrorSubject(\n test: TSESTree.Expression,\n): TSESTree.Expression | null {\n if (test.type === \"UnaryExpression\" && test.operator === \"!\") {\n return positiveErrorSubject(test.argument);\n }\n return null;\n}\n\n/** Whether a branch statement unconditionally exits (its last statement returns/throws). */\nfunction branchTerminates(branch: TSESTree.Statement): boolean {\n const body = branch.type === \"BlockStatement\" ? branch.body : [branch];\n const last = body[body.length - 1];\n return (\n last !== undefined &&\n (last.type === \"ReturnStatement\" || last.type === \"ThrowStatement\")\n );\n}\n\n/**\n * True if an earlier guard `if (isErrorLike(arg)) return …` (or `instanceof Error`)\n * in an enclosing block narrows `argExpr` away from the error case before `node`,\n * so by the time `JSON.stringify(arg)` runs the value is the non-Error fallback.\n */\nfunction isNarrowedByEarlyReturn(\n node: TSESTree.Node,\n argExpr: TSESTree.Expression,\n sourceCode: Readonly<SourceCode>,\n): boolean {\n const argText = sourceCode.getText(argExpr);\n let current: TSESTree.Node | undefined = node.parent;\n while (current) {\n if (current.type === \"BlockStatement\" || current.type === \"Program\") {\n for (const stmt of current.body) {\n if (stmt.range[0] >= node.range[0]) {\n break;\n }\n if (\n stmt.type === \"IfStatement\" &&\n stmt.alternate === null &&\n branchTerminates(stmt.consequent)\n ) {\n const subject = positiveErrorSubject(stmt.test);\n if (subject && sourceCode.getText(subject) === argText) {\n return true;\n }\n }\n }\n }\n current = current.parent;\n }\n return false;\n}\n\nfunction nodeWithin(node: TSESTree.Node, container: TSESTree.Node | null): boolean {\n return (\n container !== null &&\n node.range[0] >= container.range[0] &&\n node.range[1] <= container.range[1]\n );\n}\n\n/**\n * True if `node` sits in the NON-error branch of an `argExpr instanceof Error`\n * guard — the branch where `argExpr` is provably not an Error, so stringifying it\n * is the correct fallback. Handles both the ternary and `if`/`else` shapes,\n * including the negated `!(x instanceof Error)` form.\n */\nfunction isGuardedByInstanceofError(\n node: TSESTree.Node,\n argExpr: TSESTree.Expression,\n sourceCode: Readonly<SourceCode>,\n): boolean {\n const argText = sourceCode.getText(argExpr);\n const sameSubject = (subject: TSESTree.Expression): boolean =>\n sourceCode.getText(subject) === argText;\n\n let current: TSESTree.Node | undefined = node.parent;\n while (current) {\n if (current.type === \"ConditionalExpression\") {\n const subject = positiveErrorSubject(current.test);\n if (subject && sameSubject(subject) && nodeWithin(node, current.alternate)) {\n return true;\n }\n const negated = negatedInstanceofErrorSubject(current.test);\n if (negated && sameSubject(negated) && nodeWithin(node, current.consequent)) {\n return true;\n }\n } else if (current.type === \"IfStatement\") {\n const subject = positiveErrorSubject(current.test);\n if (subject && sameSubject(subject) && nodeWithin(node, current.alternate)) {\n return true;\n }\n const negated = negatedInstanceofErrorSubject(current.test);\n if (negated && sameSubject(negated) && nodeWithin(node, current.consequent)) {\n return true;\n }\n }\n current = current.parent;\n }\n return false;\n}\n\nfunction isJsonStringify(callee: TSESTree.Expression): boolean {\n return (\n callee.type === \"MemberExpression\" &&\n !callee.computed &&\n callee.object.type === \"Identifier\" &&\n callee.object.name === \"JSON\" &&\n callee.property.type === \"Identifier\" &&\n callee.property.name === \"stringify\"\n );\n}\n\nexport default ESLintUtils.RuleCreator(\n (name) =>\n `https://github.com/sarj-ai/linting/blob/main/packages/typescript/src/rules/${name}.ts`,\n)<Options, MessageIds>({\n name: \"no-json-stringify-error\",\n meta: {\n type: \"problem\",\n docs: {\n description:\n \"Disallow `JSON.stringify` on an Error value; it yields `{}` because `message`/`stack` are non-enumerable.\",\n },\n schema: [],\n messages: {\n noJsonStringifyError:\n \"`JSON.stringify` on an Error yields `{}` because `message`/`stack` are non-enumerable. Log `err.message` / `err.stack`, or use a proper error serializer.\",\n },\n },\n defaultOptions: [],\n create(context) {\n return {\n CallExpression(node: TSESTree.CallExpression): void {\n if (!isJsonStringify(node.callee)) {\n return;\n }\n\n const firstArg = node.arguments[0];\n if (!firstArg) {\n return;\n }\n\n const scope = context.sourceCode.getScope(firstArg);\n\n let suggestsError: boolean;\n if (firstArg.type === \"Identifier\") {\n suggestsError =\n ERROR_NAME_PATTERN.test(firstArg.name) || isCatchBinding(scope, firstArg.name);\n } else if (firstArg.type === \"MemberExpression\") {\n suggestsError = memberSuggestsError(firstArg, scope);\n } else {\n return;\n }\n\n if (!suggestsError) {\n return;\n }\n\n if (\n isGuardedByInstanceofError(node, firstArg, context.sourceCode) ||\n isNarrowedByEarlyReturn(node, firstArg, context.sourceCode)\n ) {\n return;\n }\n\n context.report({\n node,\n messageId: \"noJsonStringifyError\",\n });\n },\n };\n },\n});\n","/**\n * @fileoverview Disallow `catch` clauses that only log (via `console.*` or a\n * logger receiver such as `logger.warn(...)` / `Log.error(...)`) and then\n * swallow the error. A catch that logs and falls through — with no `throw`, no\n * `return`, and no real recovery — hides failures: the program keeps running in\n * a broken state while the only signal is a log line that is easy to miss.\n * Either rethrow the error or handle it for real.\n *\n * This rule is deliberately conservative and fires in exactly two shapes:\n * - `noLogOnlyCatch`: the catch body is non-empty and *every* statement is a\n * logging call (`console.*` or a call on a logger-named receiver). Any other\n * statement (a `throw`, a `return`, a fallback assignment, a non-logging\n * call, etc.) means the catch is doing something and is left alone.\n * - `emptyCatch`: the catch body is genuinely empty AND carries no comment.\n * A comment-only catch (`catch { /* ignore, safe because … *\\/ }`) is treated\n * as an intentional, documented ignore and is exempt.\n *\n * A previous version fired the \"logging then swallowing\" message on empty and\n * comment-only catches that contained no logging call at all — the vast majority\n * of real-world hits — which was factually wrong. The two distinct message ids\n * keep each diagnostic accurate.\n *\n * Scope: this rule owns the `CatchClause` (try/catch) form ONLY. The promise\n * form — `.catch(() => {})`, `.catch(() => null)`, and every other handler that\n * provably does nothing — is owned entirely by `no-silent-promise-catch`, whose\n * detection is a strict superset of what this rule used to do there. Two rules\n * firing on one `.catch()` meant two messages and two suppression comments for\n * a single defect, so the promise path was removed from here.\n *\n * Test files opt out by default (filenames containing `.test.`, `.spec.`, or a\n * `__tests__/` path segment) since swallow-and-log is common and acceptable in\n * test scaffolding.\n *\n * A logging call is recognised by the shared `_logging` matcher: a log method on\n * a logger receiver, plus any project-declared free logging function named in\n * the `logFunctions` option (`logEvent(\"x\", { err })`). Structured loggers are\n * usually free functions, so without that option a catch that only calls one was\n * silently under-reported here — declaring it makes the shape visible.\n */\n\nimport { ESLintUtils, type TSESTree } from \"@typescript-eslint/utils\";\n\nimport {\n createLogMatcher,\n LOGGING_OPTION_PROPERTIES,\n type LoggingOptions,\n} from \"./_logging.js\";\n\ntype MessageIds = \"noLogOnlyCatch\" | \"emptyCatch\";\ntype Options = readonly [LoggingOptions?];\n\nconst DEFAULT_IGNORE_PATTERNS: readonly RegExp[] = [\n /\\.test\\./,\n /\\.spec\\./,\n /[\\\\/]__tests__[\\\\/]/,\n];\n\nexport default ESLintUtils.RuleCreator(\n (name) =>\n `https://github.com/sarj-ai/linting/blob/main/packages/typescript/src/rules/${name}.ts`,\n)<Options, MessageIds>({\n name: \"no-log-only-catch\",\n meta: {\n type: \"problem\",\n docs: {\n description:\n \"Disallow `catch` clauses that only log (or silently do nothing) and then swallow the error; rethrow or handle it instead.\",\n },\n schema: [\n {\n type: \"object\",\n additionalProperties: false,\n properties: { ...LOGGING_OPTION_PROPERTIES },\n },\n ],\n messages: {\n noLogOnlyCatch:\n \"Logging then swallowing the error hides failures. Rethrow the error or handle it for real.\",\n emptyCatch:\n \"Empty catch silently swallows the error. Rethrow it, handle it, or add a comment explaining why it is safe to ignore.\",\n },\n },\n defaultOptions: [{}],\n create(context, [loggingOptions]) {\n const matcher = createLogMatcher(loggingOptions);\n const filename = context.filename;\n\n /** True when a statement is exactly a bare logging call, e.g. `console.error(err);`. */\n function isLoggingCallStatement(statement: TSESTree.Statement): boolean {\n if (statement.type !== \"ExpressionStatement\") {\n return false;\n }\n return matcher.isLoggingCall(statement.expression);\n }\n\n const isIgnoredByDefault = DEFAULT_IGNORE_PATTERNS.some((re) =>\n re.test(filename),\n );\n\n if (isIgnoredByDefault) {\n return {};\n }\n\n return {\n CatchClause(node: TSESTree.CatchClause): void {\n const statements = node.body.body;\n\n if (statements.length === 0) {\n // A comment inside the block documents an intentional ignore; only a\n // truly empty catch is an unexplained silent swallow.\n if (context.sourceCode.getCommentsInside(node.body).length > 0) {\n return;\n }\n context.report({ node, messageId: \"emptyCatch\" });\n return;\n }\n\n const everyStatementIsLogging = statements.every((statement) =>\n isLoggingCallStatement(statement),\n );\n\n if (everyStatementIsLogging) {\n context.report({ node, messageId: \"noLogOnlyCatch\" });\n }\n },\n };\n },\n});\n","/**\n * @fileoverview Shared helpers for recognising logging / error-reporting calls.\n * Used by `no-log-only-catch`, `no-sentinel-return-on-catch` and\n * `no-secret-in-log` so all three rules agree on what counts as \"this call\n * writes to a log sink\" before deciding a catch silently swallows an error or a\n * secret leaks.\n *\n * Two shapes are recognised:\n *\n * - **Receiver-shaped** — a log METHOD (`debug`/`info`/`warn`/`error`/…) on a\n * logger RECEIVER: `console.error(...)`, `logger.warn(...)`,\n * `this.logger.info(...)`, and builder/factory chains\n * (`logger.bind({...}).info(...)`, `logging.getLogger(n).info(...)`).\n * - **Free-function-shaped** — a project-declared logging function, e.g.\n * `logEvent(\"pr_scan.failed\", { repo, error })`. Structured loggers that are\n * plain functions taking a meta object are the dominant real-world shape and\n * have no logger receiver at all, so they are invisible to the receiver\n * heuristic. Projects declare theirs via the shared `logFunctions` rule\n * option; `loggerNames` extends the receiver set the same way.\n *\n * Both options are OFF by default (empty), so default behaviour is unchanged.\n * Declaring them makes the catch rules stop reporting a correctly-logged\n * degraded return AND makes `no-secret-in-log` start inspecting those calls —\n * the second effect closes a real hole, since `logEvent(\"auth\", { botToken })`\n * was previously never examined.\n */\n\nimport { type TSESTree } from \"@typescript-eslint/utils\";\n\nexport const LOG_METHODS: ReadonlySet<string> = new Set([\n \"debug\",\n \"info\",\n \"warn\",\n \"warning\",\n \"error\",\n \"exception\",\n \"critical\",\n \"trace\",\n \"log\",\n \"fatal\",\n \"success\",\n]);\n\nexport const LOGGER_NAMES: ReadonlySet<string> = new Set([\n \"logger\",\n \"log\",\n \"logging\",\n \"loguru\",\n \"console\",\n \"_logger\",\n \"_log\",\n]);\n\n/** Factory methods that RETURN a logger (`logging.getLogger(name).info(...)`). */\nexport const LOGGER_FACTORIES: ReadonlySet<string> = new Set([\n \"getlogger\",\n \"get_logger\",\n]);\n\n/**\n * Names of free functions / methods that report an error to a handler or sink,\n * e.g. `onUnexpectedError`, `reportError`, `captureException`, `logError`. Kept\n * broad on purpose: pairing this with \"takes the caught binding\" is what makes\n * it precise.\n */\nexport const REPORT_NAME_RE = /error|report|capture|log|trace|warn/i;\n\n/** Shared `loggerNames` / `logFunctions` option shape. */\nexport interface LoggingOptions {\n readonly loggerNames?: readonly string[];\n readonly logFunctions?: readonly string[];\n}\n\n/**\n * JSON-schema properties for the shared logging options. Spread into a rule's\n * `schema[0].properties` so every rule that consults `_logging` accepts the same\n * declaration and a project configures its logger exactly once.\n */\nexport const LOGGING_OPTION_PROPERTIES = {\n loggerNames: { type: \"array\", items: { type: \"string\" } },\n logFunctions: { type: \"array\", items: { type: \"string\" } },\n} as const;\n\n/** The static callee name of a call (free function or method), or null. */\nexport function calleeName(callee: TSESTree.Node): string | null {\n if (callee.type === \"Identifier\") {\n return callee.name;\n }\n if (\n callee.type === \"MemberExpression\" &&\n !callee.computed &&\n callee.property.type === \"Identifier\"\n ) {\n return callee.property.name;\n }\n return null;\n}\n\nexport interface LogMatcher {\n /** Is `expr` a logger receiver (bare name, member chain, or factory call)? */\n isLoggerReceiver(expr: TSESTree.Expression | TSESTree.PrivateIdentifier): boolean;\n /** Is `expr` a project-declared free logging function call (`logEvent(...)`)? */\n isLogFunctionCall(expr: TSESTree.Node): boolean;\n /** Is `expr` a logging call of either shape? */\n isLoggingCall(expr: TSESTree.Node): boolean;\n}\n\n/**\n * Builds the log-recognition predicates for one rule invocation, folding in the\n * project's declared `loggerNames` / `logFunctions`. Call once per `create()`.\n */\nexport function createLogMatcher(options: LoggingOptions = {}): LogMatcher {\n const loggerNames: ReadonlySet<string> = new Set([\n ...LOGGER_NAMES,\n ...(options.loggerNames ?? []).map((name) => name.toLowerCase()),\n ]);\n const logFunctions: ReadonlySet<string> = new Set(options.logFunctions ?? []);\n\n function isLoggerReceiver(\n expr: TSESTree.Expression | TSESTree.PrivateIdentifier,\n ): boolean {\n switch (expr.type) {\n case \"Identifier\":\n return loggerNames.has(expr.name.toLowerCase());\n case \"MemberExpression\": {\n const { property, object } = expr;\n if (!expr.computed && property.type === \"Identifier\") {\n const lowered = property.name.toLowerCase();\n if (loggerNames.has(lowered) || LOGGER_FACTORIES.has(lowered)) {\n return true;\n }\n }\n return isLoggerReceiver(object);\n }\n case \"CallExpression\": {\n const callee = expr.callee;\n if (\n callee.type === \"MemberExpression\" &&\n !callee.computed &&\n callee.property.type === \"Identifier\" &&\n LOGGER_FACTORIES.has(callee.property.name.toLowerCase())\n ) {\n return true;\n }\n if (callee.type !== \"Super\") {\n return isLoggerReceiver(callee);\n }\n return false;\n }\n default:\n return false;\n }\n }\n\n function isLogFunctionCall(expr: TSESTree.Node): boolean {\n if (expr.type !== \"CallExpression\" || logFunctions.size === 0) {\n return false;\n }\n const name = calleeName(expr.callee);\n return name !== null && logFunctions.has(name);\n }\n\n function isLoggingCall(expr: TSESTree.Node): boolean {\n if (expr.type !== \"CallExpression\") {\n return false;\n }\n if (isLogFunctionCall(expr)) {\n return true;\n }\n const callee = expr.callee;\n if (\n callee.type !== \"MemberExpression\" ||\n callee.computed ||\n callee.property.type !== \"Identifier\"\n ) {\n return false;\n }\n if (!LOG_METHODS.has(callee.property.name.toLowerCase())) {\n return false;\n }\n return isLoggerReceiver(callee.object);\n }\n\n return { isLoggerReceiver, isLogFunctionCall, isLoggingCall };\n}\n","/**\n * @fileoverview Disallow direct `process.env` access. Force all env reads\n * through a Zod-validated env module so configuration is typed and validated\n * at startup.\n */\n\nimport { ESLintUtils, type TSESTree } from \"@typescript-eslint/utils\";\n\ntype MessageIds = \"noRawEnv\";\ntype Options = readonly [];\n\n/** True for the `process.env` member node (dotted or as the base of `process.env[key]`). */\nfunction isProcessEnv(node: TSESTree.MemberExpression): boolean {\n return (\n !node.computed &&\n node.object.type === \"Identifier\" &&\n node.object.name === \"process\" &&\n node.property.type === \"Identifier\" &&\n node.property.name === \"env\"\n );\n}\n\n/** True for the `import.meta.env` member node (dotted or as the base of `import.meta.env[key]`). */\nfunction isImportMetaEnv(node: TSESTree.MemberExpression): boolean {\n return (\n !node.computed &&\n node.property.type === \"Identifier\" &&\n node.property.name === \"env\" &&\n node.object.type === \"MetaProperty\" &&\n node.object.meta.name === \"import\" &&\n node.object.property.name === \"meta\"\n );\n}\n\n// Build-time constants that bundlers (webpack/Vite) statically replace — there is\n// no runtime env value to route through the validated layer, so they are exempt.\nconst BUILD_TIME_CONSTANTS: ReadonlySet<string> = new Set([\n \"NODE_ENV\",\n \"MODE\",\n \"DEV\",\n \"PROD\",\n \"SSR\",\n]);\n\n/** True when `node` is the base of a build-time-constant access like `process.env.NODE_ENV`. */\nfunction isBuildTimeConstantAccess(node: TSESTree.MemberExpression): boolean {\n const parent = node.parent;\n return (\n parent.type === \"MemberExpression\" &&\n parent.object === node &&\n !parent.computed &&\n parent.property.type === \"Identifier\" &&\n BUILD_TIME_CONSTANTS.has(parent.property.name)\n );\n}\n\nexport default ESLintUtils.RuleCreator(\n (name) =>\n `https://github.com/sarj-ai/linting/blob/main/packages/typescript/src/rules/${name}.ts`,\n)<Options, MessageIds>({\n name: \"no-raw-env\",\n meta: {\n type: \"problem\",\n docs: {\n description:\n \"Disallow direct `process.env` access; use a Zod-validated env module instead.\",\n },\n schema: [],\n messages: {\n noRawEnv:\n \"Do not read from `process.env` directly. Import the Zod-validated env module instead so values are typed and validated at startup.\",\n },\n },\n defaultOptions: [],\n create(context) {\n return {\n MemberExpression(node: TSESTree.MemberExpression): void {\n if (\n (isProcessEnv(node) || isImportMetaEnv(node)) &&\n !isBuildTimeConstantAccess(node)\n ) {\n context.report({\n node,\n messageId: \"noRawEnv\",\n });\n }\n },\n };\n },\n});\n","/**\n * @fileoverview Disallow silently swallowing an error in a `catch` clause by\n * returning a \"sentinel\" empty value as the final/only statement.\n *\n * A `catch` block whose last statement is `return null` / `return undefined` /\n * `return false` / `return []` / `return {}` (and which never `throw`s) discards\n * the caught error entirely. Downstream callers can't distinguish a genuine\n * empty result from a failure, which is a frequent source of silent data loss\n * and broken idempotency decisions.\n *\n * This rule is deliberately conservative — it prefers false negatives over\n * false positives. It does NOT flag:\n * - catch blocks that `throw`/rethrow anywhere in their body,\n * - returns of a computed/meaningful value (calls, identifiers, member\n * expressions, non-empty literals),\n * - `return 0` / `return \"\"`, which are often legitimate results,\n * - catches that LOG or REPORT the caught error before the sentinel return —\n * a `console.*`/logger call, a project-declared free logging function (the\n * shared `logFunctions` option), or an error-reporting call that mentions\n * the caught binding ANYWHERE in its arguments. The binding search walks the\n * whole argument subtree, because structured loggers take a meta object:\n * `logEvent(\"x\", { error: err instanceof Error ? err.message : String(err) })`\n * reports the error just as surely as `report(err)` does. Here the sentinel\n * is a deliberate degraded return, not a silent swallow.\n * - the typed-optional / safe-parse / predicate shape: the try body returns an\n * expression whose subtree contains a parse-style call that throws on bad\n * input (`JSON.parse(x)`, `new URL(s).protocol === \"https:\"`, or a lone\n * `await request.json()`), or the enclosing function is a declared predicate\n * (`: boolean`) or returns the same sentinel kind on a normal path. Here the\n * sentinel is the declared contract.\n *\n * The predicate exemption is deliberately limited to a declared `boolean` return\n * type. A declared `T | null` / `T | undefined` return does NOT exempt: hiding a\n * failure behind a nullable accessor is the exact true positive this rule\n * exists for, and exempting it would gut the rule.\n *\n * Scope: this rule owns the `CatchClause` (try/catch) form ONLY. The same\n * swallow written in promise form — `await load().catch(() => [])` — is owned\n * entirely by `no-silent-promise-catch`, whose detection (any handler that\n * provably does nothing: bare literal, empty collection, empty block, or a\n * block returning one of those) is a strict superset of the empty-collection\n * check this rule used to run there. Two rules firing on one `.catch()` meant\n * two messages and two suppression comments for a single defect, so the\n * promise path was removed from here.\n */\n\nimport {\n ESLintUtils,\n type TSESTree,\n AST_NODE_TYPES,\n} from \"@typescript-eslint/utils\";\n\nimport {\n createLogMatcher,\n calleeName,\n LOGGING_OPTION_PROPERTIES,\n type LoggingOptions,\n REPORT_NAME_RE,\n} from \"./_logging.js\";\n\ntype MessageIds = \"noSentinelReturn\";\ntype Options = readonly [LoggingOptions?];\n\ntype SentinelKind = \"nullish\" | \"boolean\" | \"array\" | \"object\" | \"string\";\n\n/** The sentinel \"kind\" of a returned expression, or null if not a sentinel. */\nfunction sentinelKind(arg: TSESTree.Expression | null): SentinelKind | null {\n if (arg === null) {\n return null;\n }\n if (arg.type === AST_NODE_TYPES.Literal) {\n if (arg.value === null) {\n return \"nullish\";\n }\n if (typeof arg.value === \"boolean\") {\n return \"boolean\";\n }\n if (typeof arg.value === \"string\") {\n return \"string\";\n }\n return null;\n }\n if (arg.type === AST_NODE_TYPES.Identifier && arg.name === \"undefined\") {\n return \"nullish\";\n }\n if (arg.type === AST_NODE_TYPES.ArrayExpression) {\n return \"array\";\n }\n if (arg.type === AST_NODE_TYPES.ObjectExpression) {\n return \"object\";\n }\n return null;\n}\n\n/** Whether a returned expression is one of the swallowing sentinels we flag. */\nfunction isSentinelArgument(arg: TSESTree.Expression | null): boolean {\n if (arg === null) {\n return false;\n }\n if (arg.type === AST_NODE_TYPES.Literal && arg.value === null) {\n return true;\n }\n if (arg.type === AST_NODE_TYPES.Literal && arg.value === false) {\n return true;\n }\n if (arg.type === AST_NODE_TYPES.Identifier && arg.name === \"undefined\") {\n return true;\n }\n if (arg.type === AST_NODE_TYPES.ArrayExpression && arg.elements.length === 0) {\n return true;\n }\n if (\n arg.type === AST_NODE_TYPES.ObjectExpression &&\n arg.properties.length === 0\n ) {\n return true;\n }\n return false;\n}\n\nfunction isFunctionNode(node: TSESTree.Node): boolean {\n return (\n node.type === AST_NODE_TYPES.FunctionDeclaration ||\n node.type === AST_NODE_TYPES.FunctionExpression ||\n node.type === AST_NODE_TYPES.ArrowFunctionExpression\n );\n}\n\nfunction isNode(value: unknown): value is TSESTree.Node {\n return (\n typeof value === \"object\" &&\n value !== null &&\n typeof (value as { type?: unknown }).type === \"string\"\n );\n}\n\n/**\n * Walk `node`'s subtree applying `visit`, but do not descend into nested\n * function scopes — their statements don't run synchronously for the current\n * catch. Stops early once `visit` returns true.\n */\nfunction walkWithinScope(\n node: TSESTree.Node,\n visit: (current: TSESTree.Node) => boolean,\n): boolean {\n let found = false;\n\n const recurse = (current: TSESTree.Node): void => {\n if (found) {\n return;\n }\n if (visit(current)) {\n found = true;\n return;\n }\n if (isFunctionNode(current)) {\n return;\n }\n for (const key of Object.keys(current)) {\n if (key === \"parent\") {\n continue;\n }\n const value = (current as unknown as Record<string, unknown>)[key];\n if (Array.isArray(value)) {\n for (const child of value) {\n if (isNode(child)) {\n recurse(child);\n }\n }\n } else if (isNode(value)) {\n recurse(value);\n }\n }\n };\n\n recurse(node);\n return found;\n}\n\n/** Does this subtree throw (ignoring nested function scopes)? */\nfunction containsThrow(node: TSESTree.Node): boolean {\n return walkWithinScope(\n node,\n (current) => current.type === AST_NODE_TYPES.ThrowStatement,\n );\n}\n\n/** True when a parameter pattern binds `name` (plain, default, rest, or destructured). */\nfunction bindsName(param: TSESTree.Node, name: string): boolean {\n switch (param.type) {\n case AST_NODE_TYPES.Identifier:\n return param.name === name;\n case AST_NODE_TYPES.AssignmentPattern:\n return bindsName(param.left, name);\n case AST_NODE_TYPES.RestElement:\n return bindsName(param.argument, name);\n case AST_NODE_TYPES.ArrayPattern:\n return param.elements.some(\n (element) => element !== null && bindsName(element, name),\n );\n case AST_NODE_TYPES.ObjectPattern:\n return param.properties.some((property) =>\n property.type === AST_NODE_TYPES.RestElement\n ? bindsName(property.argument, name)\n : bindsName(property.value, name),\n );\n default:\n return false;\n }\n}\n\n/**\n * Does `node`'s subtree READ the identifier `name`?\n *\n * \"Read\" means a VALUE position. A bare name match is not enough, and getting\n * that wrong silently guts the rule. Walking the whole argument subtree (so a\n * structured logger's meta object counts as reporting the error) cost 8 of 18\n * true positives when measured against the previous release, because all of\n * these matched on name alone:\n *\n * logCounter({ error: 1 }) // object KEY — a counter, not a log\n * captureMetric({ tags: { e: 1 } }) // nested key\n * reportStatus(response.err) // member PROPERTY of another object\n * logAll(items.map((error) => error.id)) // a param that merely SHADOWS it\n *\n * Each of those swallows the error while looking \"logged\". Non-computed property\n * keys and non-computed member properties are therefore skipped, and a nested\n * function that rebinds the name is not descended into.\n */\nfunction subtreeReadsName(node: TSESTree.Node, name: string): boolean {\n let found = false;\n\n /** True when this function rebinds `name`, so its body reads a different value. */\n const shadowsName = (fn: TSESTree.Node): boolean =>\n isFunctionNode(fn) &&\n (fn as unknown as { params: TSESTree.Parameter[] }).params.some((param) =>\n bindsName(param, name),\n );\n\n const recurse = (current: TSESTree.Node): void => {\n if (found) {\n return;\n }\n if (current.type === AST_NODE_TYPES.Identifier && current.name === name) {\n found = true;\n return;\n }\n if (shadowsName(current)) {\n return;\n }\n for (const key of Object.keys(current)) {\n if (key === \"parent\") {\n continue;\n }\n // `{ error: 1 }` — the key names a field; it does not read the binding.\n if (\n key === \"key\" &&\n current.type === AST_NODE_TYPES.Property &&\n !current.computed\n ) {\n continue;\n }\n // `response.err` — the property names a field on some other object.\n if (\n key === \"property\" &&\n current.type === AST_NODE_TYPES.MemberExpression &&\n !current.computed\n ) {\n continue;\n }\n const value = (current as unknown as Record<string, unknown>)[key];\n if (Array.isArray(value)) {\n for (const child of value) {\n if (isNode(child)) {\n recurse(child);\n }\n }\n } else if (isNode(value)) {\n recurse(value);\n }\n }\n };\n\n recurse(node);\n return found;\n}\n\n/**\n * Does the caught-error binding appear ANYWHERE in a call's arguments? The whole\n * argument subtree is searched, not just top-level positional args: a structured\n * logger takes the error nested in a meta object or behind a conditional\n * (`logEvent(\"x\", { error: err instanceof Error ? err.message : String(err) })`),\n * and that reports the error exactly as `report(err)` does.\n */\nfunction argsIncludeBinding(\n args: readonly TSESTree.CallExpressionArgument[],\n caughtName: string | null,\n): boolean {\n if (caughtName === null) {\n return false;\n }\n return args.some((arg) => subtreeReadsName(arg, caughtName));\n}\n\n/** The try block guarded by this catch. */\nfunction tryBlockOf(catchNode: TSESTree.CatchClause): TSESTree.BlockStatement {\n return catchNode.parent.block;\n}\n\n/** Constructors that throw on malformed input. */\nconst SAFE_PARSE_CONSTRUCTORS: ReadonlySet<string> = new Set([\n \"RegExp\",\n \"URL\",\n \"URLPattern\",\n]);\n\n/**\n * A parse-style call that throws on bad input: `JSON.parse(x)`, `YAML.parse(x)`,\n * `new RegExp(x)`, `new URL(x)`.\n */\nfunction isParseShapedNode(node: TSESTree.Node): boolean {\n if (\n node.type === AST_NODE_TYPES.CallExpression &&\n node.callee.type === AST_NODE_TYPES.MemberExpression &&\n !node.callee.computed &&\n node.callee.property.type === AST_NODE_TYPES.Identifier\n ) {\n return node.callee.property.name === \"parse\";\n }\n if (\n node.type === AST_NODE_TYPES.NewExpression &&\n node.callee.type === AST_NODE_TYPES.Identifier\n ) {\n return SAFE_PARSE_CONSTRUCTORS.has(node.callee.name);\n }\n return false;\n}\n\n/** Body-decoding methods of a `Request` / `Response` — they throw on bad input. */\nconst BODY_DECODE_METHODS: ReadonlySet<string> = new Set([\n \"json\",\n \"text\",\n \"arrayBuffer\",\n]);\n\nfunction isBodyDecodeNode(node: TSESTree.Node): boolean {\n return (\n node.type === AST_NODE_TYPES.CallExpression &&\n node.callee.type === AST_NODE_TYPES.MemberExpression &&\n !node.callee.computed &&\n node.callee.property.type === AST_NODE_TYPES.Identifier &&\n BODY_DECODE_METHODS.has(node.callee.property.name)\n );\n}\n\n/**\n * True when a return statement's argument SUBTREE contains a match. The whole\n * subtree is searched rather than the top node alone, because the parse is\n * usually consumed in place: `return new URL(s).protocol === \"https:\"` is a\n * `BinaryExpression`, not a `NewExpression`, and `return await request.json()`\n * is an `AwaitExpression`. Nested function scopes are not searched — a parse\n * inside a callback does not run when the `try` does.\n */\nfunction returnsMatching(\n stmt: TSESTree.Node,\n predicate: (node: TSESTree.Node) => boolean,\n): boolean {\n return (\n stmt.type === AST_NODE_TYPES.ReturnStatement &&\n stmt.argument !== null &&\n walkWithinScope(stmt.argument, predicate)\n );\n}\n\n/** The declared return type annotation of the nearest enclosing function, or null. */\nfunction enclosingReturnTypeNode(\n node: TSESTree.Node,\n): TSESTree.TypeNode | null {\n let current: TSESTree.Node | undefined | null = node.parent;\n while (current !== undefined && current !== null) {\n if (isFunctionNode(current) && \"returnType\" in current) {\n return current.returnType?.typeAnnotation ?? null;\n }\n current = current.parent;\n }\n return null;\n}\n\n/**\n * True when the enclosing function is a DECLARED predicate — annotated\n * `: boolean` (or `: Promise<boolean>`) — and the catch returns `false`. A\n * boolean return type cannot carry error information at all, so \"return a typed\n * Result\" is not advice that applies; the sentinel IS the whole contract. Only\n * `boolean` qualifies: a declared `T | null` return is the shape this rule\n * exists to flag and must keep firing.\n */\nfunction isDeclaredBooleanPredicate(\n catchNode: TSESTree.CatchClause,\n kind: SentinelKind,\n): boolean {\n if (kind !== \"boolean\") {\n return false;\n }\n let declared = enclosingReturnTypeNode(catchNode);\n if (\n declared?.type === AST_NODE_TYPES.TSTypeReference &&\n declared.typeName.type === AST_NODE_TYPES.Identifier &&\n declared.typeName.name === \"Promise\"\n ) {\n declared = declared.typeArguments?.params[0] ?? null;\n }\n return declared?.type === AST_NODE_TYPES.TSBooleanKeyword;\n}\n\n/**\n * Does the try body return a safe-parse-style expression?\n *\n * `JSON.parse` / `new RegExp` / `new URL` count from anywhere in the try body —\n * a read-then-parse (`const t = read(p); return JSON.parse(t)`) is still the\n * safe-parse contract. A body-decoding method (`.json()`) counts ONLY when it is\n * the try's sole statement, so `try { return await request.json() }` is exempt\n * while `try { const res = await fetch(url); return await res.json() }` is not:\n * there the catch also swallows the network failure, which is the true positive.\n */\nfunction tryReturnsSafeParse(catchNode: TSESTree.CatchClause): boolean {\n const tryBlock = tryBlockOf(catchNode);\n if (\n walkWithinScope(tryBlock, (current) =>\n returnsMatching(current, isParseShapedNode),\n )\n ) {\n return true;\n }\n const only = tryBlock.body.length === 1 ? tryBlock.body[0] : undefined;\n return only !== undefined && returnsMatching(only, isBodyDecodeNode);\n}\n\n/** The nearest enclosing function body, or null. */\nfunction enclosingFunctionBody(\n node: TSESTree.Node,\n): TSESTree.BlockStatement | null {\n let current: TSESTree.Node | undefined | null = node.parent;\n while (current !== undefined && current !== null) {\n if (\n isFunctionNode(current) &&\n \"body\" in current &&\n isNode(current.body) &&\n current.body.type === AST_NODE_TYPES.BlockStatement\n ) {\n return current.body;\n }\n current = current.parent;\n }\n return null;\n}\n\n/**\n * True when the enclosing function returns the same sentinel kind on a normal\n * (non-catch) path — a boolean predicate, a `T | undefined` accessor, etc. —\n * so the catch sentinel is the declared contract, not a swallow. Returns inside\n * the flagged catch itself are excluded.\n */\nfunction functionReturnsSameSentinelKindElsewhere(\n catchNode: TSESTree.CatchClause,\n kind: SentinelKind,\n): boolean {\n const functionBody = enclosingFunctionBody(catchNode);\n if (functionBody === null) {\n return false;\n }\n return walkWithinScope(functionBody, (current) => {\n if (current.type !== AST_NODE_TYPES.ReturnStatement) {\n return false;\n }\n if (isWithin(current, catchNode.body)) {\n return false;\n }\n return sentinelKind(current.argument) === kind;\n });\n}\n\n/** Is `node` inside `ancestor`'s subtree? */\nfunction isWithin(node: TSESTree.Node, ancestor: TSESTree.Node): boolean {\n let current: TSESTree.Node | undefined | null = node;\n while (current !== undefined && current !== null) {\n if (current === ancestor) {\n return true;\n }\n current = current.parent;\n }\n return false;\n}\n\nexport default ESLintUtils.RuleCreator(\n (name) =>\n `https://github.com/sarj-ai/linting/blob/main/packages/typescript/src/rules/${name}.ts`,\n)<Options, MessageIds>({\n name: \"no-sentinel-return-on-catch\",\n meta: {\n type: \"problem\",\n docs: {\n description:\n \"Disallow swallowing a caught error by returning an empty sentinel (`null`, `undefined`, `false`, `[]`, `{}`) as the final statement of a `catch` block, unless the error is logged/reported or the sentinel is the declared safe-parse/predicate contract.\",\n },\n schema: [\n {\n type: \"object\",\n additionalProperties: false,\n properties: { ...LOGGING_OPTION_PROPERTIES },\n },\n ],\n messages: {\n noSentinelReturn:\n \"This `catch` block swallows the error by returning an empty sentinel without logging it. Rethrow it, log/report it, or return a typed Result.\",\n },\n },\n defaultOptions: [{}],\n create(context, [loggingOptions]) {\n const matcher = createLogMatcher(loggingOptions);\n\n /**\n * Does the catch body log or report the caught error before the sentinel\n * return? Either a logging call (logger receiver or a declared\n * `logFunctions` free function), or an error-reporting call whose name\n * matches `REPORT_NAME_RE` and whose arguments mention the caught binding.\n */\n function logsOrReportsError(\n catchBody: TSESTree.BlockStatement,\n caughtName: string | null,\n ): boolean {\n return walkWithinScope(catchBody, (current) => {\n if (current.type !== AST_NODE_TYPES.CallExpression) {\n return false;\n }\n if (matcher.isLoggingCall(current)) {\n return true;\n }\n const name = calleeName(current.callee);\n return (\n name !== null &&\n REPORT_NAME_RE.test(name) &&\n argsIncludeBinding(current.arguments, caughtName)\n );\n });\n }\n\n return {\n CatchClause(node: TSESTree.CatchClause): void {\n const body = node.body.body;\n if (body.length === 0) {\n return;\n }\n\n const last = body[body.length - 1];\n if (last === undefined || last.type !== AST_NODE_TYPES.ReturnStatement) {\n return;\n }\n\n if (!isSentinelArgument(last.argument)) {\n return;\n }\n\n if (containsThrow(node.body)) {\n return;\n }\n\n const caughtName =\n node.param?.type === AST_NODE_TYPES.Identifier\n ? node.param.name\n : null;\n\n if (logsOrReportsError(node.body, caughtName)) {\n return;\n }\n\n if (tryReturnsSafeParse(node)) {\n return;\n }\n\n const kind = sentinelKind(last.argument);\n if (kind !== null && isDeclaredBooleanPredicate(node, kind)) {\n return;\n }\n\n if (\n kind !== null &&\n functionReturnsSameSentinelKindElsewhere(node, kind)\n ) {\n return;\n }\n\n context.report({\n node: last,\n messageId: \"noSentinelReturn\",\n });\n },\n };\n },\n});\n","/**\n * @fileoverview Disallow `await` expressions located directly inside the body\n * of a `for` / `for-of` / `for-in` / `while` loop (or an async `.forEach` /\n * `.map` / `.filter` callback) within the same function scope. Awaiting serially\n * inside a loop serializes I/O that is often better expressed as\n * `await Promise.all(xs.map(async (x) => ...))`, letting the operations run\n * concurrently.\n *\n * This rule is intentionally conservative — it prefers a false negative over a\n * false positive:\n * - `for await...of` is NOT flagged (async iteration is the correct tool).\n * - awaits inside a function/arrow defined within the loop are NOT flagged\n * (they belong to a different function scope).\n * - awaits not inside any loop are NOT flagged.\n *\n * Real-world sweeps (VS Code, NestJS, Next.js) surfaced whole classes of loops\n * where serial awaits are REQUIRED and `Promise.all` would change semantics.\n * Those are suppressed here:\n * (a) the loop short-circuits or retries — its body (this scope) contains a\n * `return` / `break` / `continue`;\n * (b) the awaited value threads through the iteration — `x = await f(x)`,\n * `content = await p(content)` (the assignment target is read inside the\n * awaited expression);\n * (c) the await is a timer yield — `await new Promise((r) => setTimeout(r))`;\n * (d) the iterable's name/derivation signals ordering — `*Sorted*`,\n * `.reverse()`, lifecycle `hooks`, pipeline `stages`, etc.\n * (e) a `while` / `do-while` whose CONTINUATION depends on state the body\n * computes — cursor pagination:\n * `do { const page = await list(cursor); cursor = page.nextCursor } while (cursor)`.\n * The next request's input is the previous response's output, so the\n * iteration count is unknowable up front and there is nothing to collect\n * into a `Promise.all`. Guard (b) misses this because the cursor is\n * assigned from a property of the awaited value, not from the await\n * itself; guard (a) misses it because the `while` test IS the exit.\n * Deliberately narrow: only a plain `=` assignment to a test-read\n * variable counts, so a hand-rolled counter loop (`while (i < n) { i++;\n * await g(i) }`) still fires.\n * The genuinely parallelizable shape — independent awaits whose results are\n * collected or discarded without a cross-iteration dependency or early exit —\n * still fires.\n *\n * At most one report is emitted per offending loop / callback.\n */\n\nimport { ESLintUtils, type TSESTree } from \"@typescript-eslint/utils\";\n\ntype MessageIds = \"noSequentialAwait\";\ntype Options = readonly [];\n\n/**\n * Array iteration methods whose async callback with an `await` inside is the\n * classic serial-await footgun (`.forEach` ignores the returned promise\n * entirely; a discarded `.map` / `.filter` floats its promises).\n */\nconst ARRAY_ITERATION_METHODS = new Set<string>([\"forEach\", \"map\", \"filter\"]);\n\n/**\n * Text on the iterable (its identifier name or derivation) that signals an\n * ORDERED sequence whose elements must be processed one-after-another —\n * lifecycle hooks, sorted / reversed lists, pipeline stages. Awaiting serially\n * over such a sequence is the contract, so the report is suppressed. Broad by\n * design: the rule prefers a false negative to a false positive.\n */\nconst SEQUENTIAL_ITERABLE_HINT =\n /sort|reverse|ordered|sequence|hook|middleware|pipeline|\\bstage|\\bstep|\\bphase|migration|chain|buffer|stream|teleport|chunk|\\bqueue|drain/i;\n\n/**\n * Node types that introduce a new function scope. We never descend across one\n * of these when looking for awaits belonging to a loop, because an `await`\n * inside a nested function/arrow is awaited by *that* function, not by the loop.\n */\nfunction isFunctionLike(node: TSESTree.Node): boolean {\n return (\n node.type === \"FunctionDeclaration\" ||\n node.type === \"FunctionExpression\" ||\n node.type === \"ArrowFunctionExpression\"\n );\n}\n\ntype LoopNode =\n | TSESTree.ForStatement\n | TSESTree.ForOfStatement\n | TSESTree.ForInStatement\n | TSESTree.WhileStatement\n | TSESTree.DoWhileStatement;\n\n/**\n * Statement node types that introduce a nested loop. When scanning a loop's\n * body we must NOT descend into another loop — that inner loop's awaits belong\n * to it and are reported when the inner loop is visited. This keeps reporting\n * at one-per-loop and avoids double-flagging an outer loop for an await that\n * only appears inside a nested loop.\n */\nfunction isLoop(node: TSESTree.Node): boolean {\n return (\n node.type === \"ForStatement\" ||\n node.type === \"ForOfStatement\" ||\n node.type === \"ForInStatement\" ||\n node.type === \"WhileStatement\" ||\n node.type === \"DoWhileStatement\"\n );\n}\n\nfunction isNode(value: unknown): value is TSESTree.Node {\n return (\n typeof value === \"object\" &&\n value !== null &&\n typeof (value as { type?: unknown }).type === \"string\"\n );\n}\n\n/**\n * Visits `root` and its descendants, calling `visit` on each, without crossing\n * into a nested function scope or descending into a nested loop — the same\n * ownership boundaries the rule uses to decide which awaits belong to a loop.\n */\nfunction visitScope(\n root: TSESTree.Node,\n visit: (node: TSESTree.Node) => void,\n): void {\n visit(root);\n for (const key of Object.keys(root) as (keyof TSESTree.Node)[]) {\n if (key === \"parent\") {\n continue;\n }\n const value = root[key];\n const children = Array.isArray(value) ? value : [value];\n for (const child of children) {\n if (isNode(child) && !isFunctionLike(child) && !isLoop(child)) {\n visitScope(child, visit);\n }\n }\n }\n}\n\nfunction collectAwaits(root: TSESTree.Node): TSESTree.AwaitExpression[] {\n const awaits: TSESTree.AwaitExpression[] = [];\n visitScope(root, (node) => {\n if (node.type === \"AwaitExpression\") {\n awaits.push(node);\n }\n });\n return awaits;\n}\n\n/**\n * Guard (a): the scope contains a `return` / `break` / `continue`, marking a\n * retry / short-circuit / early-exit loop whose serial awaits are intentional.\n */\nfunction hasEarlyExit(root: TSESTree.Node): boolean {\n let found = false;\n visitScope(root, (node) => {\n if (\n node.type === \"ReturnStatement\" ||\n node.type === \"BreakStatement\" ||\n node.type === \"ContinueStatement\"\n ) {\n found = true;\n }\n });\n return found;\n}\n\n/**\n * Guard (c): `await new Promise(...)` — a deliberate event-loop / timer yield,\n * not parallelizable I/O.\n */\nconst TIMER_HELPER_RE = /^(sleep|timeout|delay|wait|pause|tick)$/i;\n\nfunction calleeName(callee: TSESTree.Node): string | null {\n if (callee.type === \"Identifier\") return callee.name;\n if (\n callee.type === \"MemberExpression\" &&\n !callee.computed &&\n callee.property.type === \"Identifier\"\n ) {\n return callee.property.name;\n }\n return null;\n}\n\nfunction isTimerYield(node: TSESTree.AwaitExpression): boolean {\n const arg = node.argument;\n // `await new Promise((r) => setTimeout(r))` — the canonical event-loop yield.\n if (\n arg.type === \"NewExpression\" &&\n arg.callee.type === \"Identifier\" &&\n arg.callee.name === \"Promise\"\n ) {\n return true;\n }\n // `await sleep(ms)` / `await delay()` / `await this.wait()` — a poll/throttle\n // yield in a `while` loop, deliberately serial.\n if (arg.type === \"CallExpression\") {\n const name = calleeName(arg.callee);\n return name !== null && TIMER_HELPER_RE.test(name);\n }\n return false;\n}\n\nconst QUEUE_DRAIN_METHODS = /^(shift|pop|dequeue|next|poll)$/;\n\n/**\n * Guard: `await queue.shift()` / `await this.stack.pop()` — draining a mutable\n * receiver one element at a time. Each call consumes the shared queue, so the\n * iterations are order-dependent and cannot be parallelized.\n */\nfunction isQueueDrain(node: TSESTree.AwaitExpression): boolean {\n const arg = node.argument;\n return (\n arg.type === \"CallExpression\" &&\n arg.callee.type === \"MemberExpression\" &&\n !arg.callee.computed &&\n arg.callee.property.type === \"Identifier\" &&\n QUEUE_DRAIN_METHODS.test(arg.callee.property.name)\n );\n}\n\nfunction referencesName(root: TSESTree.Node, name: string): boolean {\n let found = false;\n visitScope(root, (node) => {\n if (node.type === \"Identifier\" && node.name === name) {\n found = true;\n }\n });\n return found;\n}\n\n/**\n * Guard (b): the awaited value is threaded into the next iteration — the await\n * is the RHS of `target = await ...` / `const target = await ...` and `target`\n * is read inside the awaited expression (`x = await f(x)`,\n * `content = await p(content)`). Parallelizing would break the data dependency.\n */\nfunction isThreadedAccumulator(node: TSESTree.AwaitExpression): boolean {\n const parent = node.parent;\n let target: string | null = null;\n if (\n parent.type === \"AssignmentExpression\" &&\n parent.operator === \"=\" &&\n parent.right === node &&\n parent.left.type === \"Identifier\"\n ) {\n target = parent.left.name;\n } else if (\n parent.type === \"VariableDeclarator\" &&\n parent.init === node &&\n parent.id.type === \"Identifier\"\n ) {\n target = parent.id.name;\n }\n if (target === null) {\n return false;\n }\n return referencesName(node.argument, target);\n}\n\n/** Every identifier name read by a loop's test expression. */\nfunction namesReadBy(test: TSESTree.Node): Set<string> {\n const names = new Set<string>();\n visitScope(test, (node) => {\n if (node.type === \"Identifier\") {\n names.add(node.name);\n }\n });\n return names;\n}\n\n/**\n * Guard (e): a `while` / `do-while` whose continuation condition is recomputed\n * by its own body — the cursor-pagination shape. True when the body plainly\n * assigns (`=`) to a variable the test reads. `++` / `+=` are excluded so a\n * hand-rolled counter loop, which IS parallelizable, keeps firing.\n */\nfunction testStateIsAssignedInBody(\n test: TSESTree.Node,\n body: TSESTree.Node,\n): boolean {\n const testNames = namesReadBy(test);\n if (testNames.size === 0) {\n return false;\n }\n let found = false;\n visitScope(body, (node) => {\n if (\n node.type === \"AssignmentExpression\" &&\n node.operator === \"=\" &&\n node.left.type === \"Identifier\" &&\n testNames.has(node.left.name)\n ) {\n found = true;\n }\n });\n return found;\n}\n\n/**\n * Decides whether a set of awaits owned by a loop/callback is worth reporting.\n * Suppressed when the loop short-circuits (a) or iterates an ordered sequence\n * (d); otherwise reported if AT LEAST ONE await is genuinely parallelizable —\n * i.e. not a timer yield (c) and not a threaded accumulator (b).\n */\nfunction shouldReport(\n awaits: readonly TSESTree.AwaitExpression[],\n earlyExit: boolean,\n iterableText: string | null,\n): boolean {\n if (awaits.length === 0) {\n return false;\n }\n if (earlyExit) {\n return false;\n }\n if (iterableText !== null && SEQUENTIAL_ITERABLE_HINT.test(iterableText)) {\n return false;\n }\n return awaits.some(\n (node) =>\n !isTimerYield(node) &&\n !isThreadedAccumulator(node) &&\n !isQueueDrain(node),\n );\n}\n\nexport default ESLintUtils.RuleCreator(\n (name) =>\n `https://github.com/sarj-ai/linting/blob/main/packages/typescript/src/rules/${name}.ts`,\n)<Options, MessageIds>({\n name: \"no-sequential-await\",\n meta: {\n type: \"problem\",\n docs: {\n description:\n \"Disallow serial `await` inside a loop; use `await Promise.all(...)` to run the operations concurrently.\",\n },\n schema: [],\n messages: {\n noSequentialAwait:\n \"Avoid `await` inside a loop — it serializes I/O. Collect the promises and `await Promise.all(xs.map(async (x) => ...))` instead.\",\n },\n },\n defaultOptions: [],\n create(context) {\n /**\n * The parts of a loop where an await \"belonging to this loop\" can live: the\n * body, plus the C-style `for` init/test/update or the for-of/for-in\n * iterable or the while/do-while test. A part that is itself a nested loop\n * is owned by that loop and checked when it is visited.\n */\n function loopParts(node: LoopNode): (TSESTree.Node | null)[] {\n // Only parts that run PER ITERATION can serialize awaits. The C-`for`\n // init and the for-of/for-in iterable are evaluated ONCE, so an `await`\n // there (`for (const x of await Promise.allSettled(...))`) is a single\n // await, not a loop-serialized one — exclude them.\n if (node.type === \"ForStatement\") {\n return [node.body, node.test, node.update];\n }\n if (node.type === \"ForOfStatement\" || node.type === \"ForInStatement\") {\n return [node.body];\n }\n return [node.body, node.test];\n }\n\n function iterableTextOf(node: LoopNode): string | null {\n if (node.type === \"ForOfStatement\" || node.type === \"ForInStatement\") {\n return context.sourceCode.getText(node.right);\n }\n return null;\n }\n\n function checkLoop(node: LoopNode): void {\n if (\n (node.type === \"WhileStatement\" || node.type === \"DoWhileStatement\") &&\n testStateIsAssignedInBody(node.test, node.body)\n ) {\n return;\n }\n\n const awaits: TSESTree.AwaitExpression[] = [];\n let earlyExit = false;\n for (const part of loopParts(node)) {\n if (part === null || isLoop(part)) {\n continue;\n }\n awaits.push(...collectAwaits(part));\n if (!earlyExit && hasEarlyExit(part)) {\n earlyExit = true;\n }\n }\n if (shouldReport(awaits, earlyExit, iterableTextOf(node))) {\n context.report({ node, messageId: \"noSequentialAwait\" });\n }\n }\n\n return {\n ForStatement: checkLoop,\n ForInStatement: checkLoop,\n WhileStatement: checkLoop,\n DoWhileStatement: checkLoop,\n ForOfStatement(node: TSESTree.ForOfStatement): void {\n // `for await...of` is correct async iteration — never flag it.\n if (node.await) {\n return;\n }\n checkLoop(node);\n },\n CallExpression(node: TSESTree.CallExpression): void {\n const callee = node.callee;\n if (callee.type !== \"MemberExpression\" || callee.computed) {\n return;\n }\n if (\n callee.property.type !== \"Identifier\" ||\n !ARRAY_ITERATION_METHODS.has(callee.property.name)\n ) {\n return;\n }\n const callback = node.arguments[0];\n if (\n callback === undefined ||\n !isFunctionLike(callback) ||\n !(\"async\" in callback && callback.async)\n ) {\n return;\n }\n // A discarded `.map` / `.filter` (statement position) floats its\n // promises just like `.forEach`; when its result is kept\n // (`Promise.all(...)`, an assignment, a `return`) the awaits are\n // consumed correctly, so only flag `.forEach` or a bare-statement call.\n if (\n callee.property.name !== \"forEach\" &&\n node.parent.type !== \"ExpressionStatement\"\n ) {\n return;\n }\n const awaits = collectAwaits(callback.body);\n const earlyExit = hasEarlyExit(callback.body);\n const iterableText = context.sourceCode.getText(callee.object);\n if (shouldReport(awaits, earlyExit, iterableText)) {\n context.report({ node, messageId: \"noSequentialAwait\" });\n }\n },\n };\n },\n});\n","/**\n * @fileoverview Disallow string accumulation via `+=` inside a loop, which is\n * the classic O(n^2) string-building antipattern: each `+=` rebuilds the whole\n * string. Push the parts onto an array and `arr.join(\"\")` after the loop\n * instead.\n *\n * This is a purely SYNTACTIC rule — it uses scope analysis (not the type\n * service) to confirm the left-hand side was declared with a string-literal\n * initializer (`let s = \"\"`, `= \"...\"`, or a template literal). It is\n * deliberately conservative: when the initializer type cannot be determined\n * (no initializer, a non-literal expression, a parameter, etc.) the `+=` is\n * NOT flagged. This mirrors the Python rule SARJ002.\n *\n * Both the compound `s += x` and the equivalent longhand `s = s + x` (a plain\n * `=` assignment whose RHS is a `+` `BinaryExpression` with the target as one\n * operand) are detected — they have identical O(n^2) behavior. A plain\n * `s = x + y` (target absent from the RHS) is NOT flagged.\n */\n\nimport { ESLintUtils, type TSESTree } from \"@typescript-eslint/utils\";\nimport type { Scope } from \"@typescript-eslint/utils/ts-eslint\";\n\ntype MessageIds = \"noStringConcatInLoop\";\ntype Options = readonly [];\n\nconst LOOP_NODE_TYPES = new Set<string>([\n \"ForStatement\",\n \"ForOfStatement\",\n \"ForInStatement\",\n \"WhileStatement\",\n \"DoWhileStatement\",\n]);\n\n/**\n * Returns true if the given expression node is a string-producing literal:\n * a string `Literal` (`\"\"`, `\"...\"`, `'...'`) or a `TemplateLiteral`.\n */\nfunction isStringLiteralInit(node: TSESTree.Expression | null): boolean {\n if (node === null) {\n return false;\n }\n if (node.type === \"TemplateLiteral\") {\n return true;\n }\n if (node.type === \"Literal\") {\n return typeof node.value === \"string\";\n }\n return false;\n}\n\n/**\n * Walk the chain of enclosing scopes to find the variable definition for the\n * given identifier name. Returns the resolved `Variable`, or `undefined` if it\n * cannot be found (e.g. an undeclared global or an out-of-scope reference).\n */\nfunction findVariable(\n scope: Scope.Scope,\n name: string,\n): Scope.Variable | undefined {\n let current: Scope.Scope | null = scope;\n while (current !== null) {\n const variable = current.variables.find((v) => v.name === name);\n if (variable !== undefined) {\n return variable;\n }\n current = current.upper;\n }\n return undefined;\n}\n\n/**\n * Returns true if the variable was declared with a string-literal initializer.\n * Conservative: if the variable has no single string-initialized declarator\n * (no init, non-literal init, multiple conflicting declarators), returns false.\n */\nfunction isStringInitializedVariable(variable: Scope.Variable): boolean {\n // A variable can technically have multiple declarators (e.g. via `var`\n // hoisting / redeclaration). Only treat it as string-initialized when there\n // is exactly one declarator and it has a string-literal initializer.\n if (variable.defs.length !== 1) {\n return false;\n }\n const def = variable.defs[0];\n if (def === undefined || def.type !== \"Variable\") {\n // Parameters, function names, imports, etc. — type unknown, don't flag.\n return false;\n }\n const declarator = def.node;\n if (declarator.type !== \"VariableDeclarator\") {\n return false;\n }\n return isStringLiteralInit(declarator.init);\n}\n\n/**\n * Returns true if `target` appears as a direct operand of a `+` expression\n * (following left-associative `+` chains, e.g. `s + a + b`). Used to recognize\n * the longhand `s = s + <...>` reassignment, which has the same O(n^2) cost as\n * `s += <...>`. A non-`+` operand (`foo.s`, `s.slice()`, `x + y`) does not match.\n */\nfunction isConcatOperand(\n node: TSESTree.Expression | TSESTree.PrivateIdentifier,\n target: string,\n): boolean {\n if (node.type === \"Identifier\") {\n return node.name === target;\n }\n if (node.type === \"BinaryExpression\" && node.operator === \"+\") {\n return (\n isConcatOperand(node.left, target) || isConcatOperand(node.right, target)\n );\n }\n return false;\n}\n\n/**\n * Returns true if `rhs` is a `+` `BinaryExpression` in which `target` appears as\n * an operand — the reassignment shape `s = s + x` / `s = x + s` / `s = s + a + b`.\n */\nfunction isConcatOntoTarget(\n rhs: TSESTree.Expression,\n target: string,\n): boolean {\n if (rhs.type !== \"BinaryExpression\" || rhs.operator !== \"+\") {\n return false;\n }\n return isConcatOperand(rhs.left, target) || isConcatOperand(rhs.right, target);\n}\n\n/**\n * Returns true if `node` is contained within the body of a loop statement.\n * Walks ancestors and, for each loop, ensures the node is inside the loop's\n * BODY (not its test/init/update clauses, which run a bounded number of times\n * relative to the body and aren't the antipattern we target).\n */\nfunction isInsideLoopBody(node: TSESTree.Node): boolean {\n let child: TSESTree.Node = node;\n let parent = node.parent;\n while (parent !== undefined && parent !== null) {\n if (LOOP_NODE_TYPES.has(parent.type)) {\n // `body` is the property that holds the looped statements for every\n // loop variant we care about.\n const loop = parent as\n | TSESTree.ForStatement\n | TSESTree.ForOfStatement\n | TSESTree.ForInStatement\n | TSESTree.WhileStatement\n | TSESTree.DoWhileStatement;\n if (loop.body === child) {\n return true;\n }\n }\n child = parent;\n parent = parent.parent;\n }\n return false;\n}\n\nexport default ESLintUtils.RuleCreator(\n (name) =>\n `https://github.com/sarj-ai/linting/blob/main/packages/typescript/src/rules/${name}.ts`,\n)<Options, MessageIds>({\n name: \"no-string-concat-in-loop\",\n meta: {\n type: \"suggestion\",\n docs: {\n description:\n \"Disallow O(n^2) string building via `+=` on a string variable inside a loop; push parts to an array and `join` instead.\",\n },\n schema: [],\n messages: {\n noStringConcatInLoop:\n \"Avoid building a string with `+=` inside a loop — this is O(n^2). Push the parts onto an array and use `arr.join(\\\"\\\")` after the loop.\",\n },\n },\n defaultOptions: [],\n create(context) {\n return {\n AssignmentExpression(node: TSESTree.AssignmentExpression): void {\n // The LHS must be a plain variable reference.\n if (node.left.type !== \"Identifier\") {\n return;\n }\n // Accept both the compound `s += x` and the longhand `s = s + x`; any\n // other operator/shape (`s = x + y`, `s -= x`, ...) is not accumulation.\n const isAccumulation =\n node.operator === \"+=\" ||\n (node.operator === \"=\" &&\n isConcatOntoTarget(node.right, node.left.name));\n if (!isAccumulation) {\n return;\n }\n // Must occur inside a loop body, else it's a one-shot append.\n if (!isInsideLoopBody(node)) {\n return;\n }\n\n const scope = context.sourceCode.getScope(node);\n const variable = findVariable(scope, node.left.name);\n // Conservative: can't resolve the declaration -> don't flag.\n if (variable === undefined) {\n return;\n }\n // Only flag when we can confirm the LHS was string-initialized; a\n // numeric initializer (or anything non-string) is intentionally\n // excluded to avoid false positives.\n if (!isStringInitializedVariable(variable)) {\n return;\n }\n\n context.report({\n node,\n messageId: \"noStringConcatInLoop\",\n });\n },\n };\n },\n});\n","/**\n * @fileoverview Flag `'use client'` files with no hooks or event handlers.\n *\n * If a file is marked `'use client'` but contains no hook calls\n * (`useState`/`useEffect`/etc.), no JSX event handlers (`onClick`,\n * `onChange`, etc.), no browser globals, no client-only imports, and no\n * other client-side indicators (classes, re-exports), the directive is\n * likely unnecessary and the file could be a React Server Component —\n * improving cold-start, bundle size, and SEO.\n *\n * False-positive watch: components that only use client-side context\n * (e.g. theme providers) without hooks or events still need `'use client'`.\n *\n * References:\n * - https://nextjs.org/docs/app/building-your-application/rendering/client-components\n */\n\nimport {\n AST_NODE_TYPES,\n ESLintUtils,\n type TSESTree,\n} from \"@typescript-eslint/utils\";\nimport type { RuleContext, Scope } from \"@typescript-eslint/utils/ts-eslint\";\n\ntype MessageIds = \"unnecessaryUseClient\";\ntype Options = readonly [];\n\nconst HOOK_REGEX = /^use([A-Z]|$)/;\nconst EVENT_PROP_REGEX = /^on[A-Z]/;\nconst ERROR_FILE_REGEX = /\\b(?:global-)?error\\.[jt]sx?$/;\n\nconst BROWSER_GLOBALS: ReadonlySet<string> = new Set([\n \"window\",\n \"document\",\n \"navigator\",\n \"localStorage\",\n \"sessionStorage\",\n \"location\",\n \"history\",\n \"screen\",\n \"requestAnimationFrame\",\n \"cancelAnimationFrame\",\n \"CustomEvent\",\n \"Event\",\n \"MouseEvent\",\n \"KeyboardEvent\",\n \"TouchEvent\",\n]);\n\nconst CLIENT_ONLY_PACKAGES_REGEX =\n /^(?:@radix-ui\\/|framer-motion|react-dom|react-day-picker|@floating-ui\\/|react-select|react-toastify|react-hook-form|recharts|react-dropzone|react-slick|react-swipeable|react-resizable|react-draggable|react-beautiful-dnd|@hello-pangea\\/dnd|react-virtualized|react-window|@tanstack\\/react-table|@tanstack\\/react-query|react-redux|recoil|jotai|zustand|@tippyjs\\/react|react-color|react-datepicker|next-themes|react-helmet|react-helmet-async|styled-components|@emotion\\/)/;\n\ntype Ctx = Readonly<RuleContext<MessageIds, Options>>;\n\nconst isUseClientDirective = (\n node: TSESTree.Statement,\n): node is TSESTree.ExpressionStatement => {\n return (\n node.type === AST_NODE_TYPES.ExpressionStatement &&\n node.expression.type === AST_NODE_TYPES.Literal &&\n node.expression.value === \"use client\"\n );\n};\n\nconst isGlobalReference = (\n node: TSESTree.Identifier,\n context: Ctx,\n): boolean => {\n if (!BROWSER_GLOBALS.has(node.name)) return false;\n\n const parent = node.parent;\n if (parent !== undefined) {\n // `obj.window` — `window` is a property name, not a global reference.\n if (\n parent.type === AST_NODE_TYPES.MemberExpression &&\n parent.property === node &&\n !parent.computed\n ) {\n return false;\n }\n // `{ window: ... }` — property key, not a global reference.\n if (\n parent.type === AST_NODE_TYPES.Property &&\n parent.key === node &&\n !parent.computed\n ) {\n return false;\n }\n // Type annotations / type-only positions are not runtime references.\n if (parent.type.startsWith(\"TS\")) {\n return false;\n }\n }\n\n // If there's a local binding for this name anywhere up the chain, it's not\n // a reference to the browser global.\n let scope: Scope.Scope | null = context.sourceCode.getScope(node);\n while (scope !== null) {\n const variable = scope.set.get(node.name);\n if (variable !== undefined && variable.defs.length > 0) {\n return false;\n }\n scope = scope.upper;\n }\n\n return true;\n};\n\nexport default ESLintUtils.RuleCreator(\n (name) =>\n `https://github.com/sarj-ai/linting/blob/main/packages/typescript/src/rules/${name}.ts`,\n)<Options, MessageIds>({\n name: \"no-unnecessary-use-client\",\n meta: {\n type: \"suggestion\",\n docs: {\n description:\n \"Flag `'use client'` files with no hooks or event handlers — they could be RSC.\",\n },\n schema: [],\n messages: {\n unnecessaryUseClient:\n \"'use client' directive but no hooks (use*), JSX event handlers (on*), browser globals, or client-only imports found. Consider removing the directive and serving as a React Server Component.\",\n },\n },\n defaultOptions: [],\n create(context) {\n const filename = context.filename;\n if (ERROR_FILE_REGEX.test(filename)) {\n return {};\n }\n\n let directiveNode: TSESTree.ExpressionStatement | null = null;\n let hasClientIndicator = false;\n\n const markIfHookOrContext = (\n callee: TSESTree.CallExpression[\"callee\"],\n ): void => {\n if (callee.type === AST_NODE_TYPES.Identifier) {\n if (HOOK_REGEX.test(callee.name) || callee.name === \"createContext\") {\n hasClientIndicator = true;\n }\n return;\n }\n if (\n callee.type === AST_NODE_TYPES.MemberExpression &&\n callee.property.type === AST_NODE_TYPES.Identifier\n ) {\n const name = callee.property.name;\n if (HOOK_REGEX.test(name) || name === \"createContext\") {\n hasClientIndicator = true;\n }\n }\n };\n\n return {\n Program(node): void {\n for (const stmt of node.body) {\n // Directives must be the first statements; once we see a non-\n // ExpressionStatement, stop scanning.\n if (stmt.type !== AST_NODE_TYPES.ExpressionStatement) break;\n if (isUseClientDirective(stmt)) {\n directiveNode = stmt;\n break;\n }\n }\n },\n CallExpression(node): void {\n // The `Program` visitor (entered first) has already determined whether\n // this file has a `'use client'` directive. If it doesn't, the result\n // can't change — skip all of the per-node indicator work, including the\n // hot scope-resolution in the `Identifier` visitor below.\n if (directiveNode === null) return;\n markIfHookOrContext(node.callee);\n },\n JSXAttribute(node): void {\n if (directiveNode === null) return;\n if (\n node.name.type === AST_NODE_TYPES.JSXIdentifier &&\n EVENT_PROP_REGEX.test(node.name.name)\n ) {\n hasClientIndicator = true;\n }\n },\n ImportDeclaration(node): void {\n if (directiveNode === null) return;\n if (\n typeof node.source.value === \"string\" &&\n CLIENT_ONLY_PACKAGES_REGEX.test(node.source.value)\n ) {\n hasClientIndicator = true;\n }\n },\n ExportNamedDeclaration(node): void {\n if (directiveNode === null) return;\n if (node.source !== null) {\n hasClientIndicator = true;\n }\n },\n ExportAllDeclaration(node): void {\n if (directiveNode === null) return;\n if (node.source !== null) {\n hasClientIndicator = true;\n }\n },\n ClassDeclaration(): void {\n if (directiveNode === null) return;\n hasClientIndicator = true;\n },\n ClassExpression(): void {\n if (directiveNode === null) return;\n hasClientIndicator = true;\n },\n Identifier(node): void {\n if (directiveNode === null) return;\n if (isGlobalReference(node, context)) {\n hasClientIndicator = true;\n }\n },\n \"Program:exit\"(): void {\n if (directiveNode !== null && !hasClientIndicator) {\n context.report({\n node: directiveNode,\n messageId: \"unnecessaryUseClient\",\n });\n }\n },\n };\n },\n});\n","/**\n * @fileoverview Flag object types that model mutually-exclusive states with a\n * boolean status flag plus many optional members. A shape like\n * `{ success: boolean; data?: T; error?: E; code?: number }` encodes \"success\n * vs. error\" implicitly and lets illegal states (e.g. `success: true` with an\n * `error`) be representable.\n *\n * Such shapes should be modelled as a discriminated union, e.g.\n * `{ ok: true; data: T } | { ok: false; error: E }`, so the compiler enforces\n * that exactly one branch's fields are present.\n *\n * This is the TypeScript mirror of the Python rule SARJ005.\n */\n\nimport { ESLintUtils, type TSESTree } from \"@typescript-eslint/utils\";\nimport { AST_NODE_TYPES } from \"@typescript-eslint/utils\";\n\ntype MessageIds = \"preferDiscriminatedUnion\";\ntype Options = readonly [];\n\n/**\n * Boolean-typed member names that read as a success/error status discriminant.\n */\nconst STATUS_MEMBER_NAMES: ReadonlySet<string> = new Set([\n \"success\",\n \"ok\",\n \"error\",\n \"failed\",\n \"isError\",\n]);\n\nconst MIN_OPTIONAL_MEMBERS = 2;\n\n/**\n * Returns the property key name for a member if it is a plain identifier or\n * string-literal property signature, otherwise `null`.\n */\nfunction getMemberName(member: TSESTree.TypeElement): string | null {\n if (member.type !== AST_NODE_TYPES.TSPropertySignature) {\n return null;\n }\n const { key } = member;\n if (key.type === AST_NODE_TYPES.Identifier) {\n return key.name;\n }\n if (key.type === AST_NODE_TYPES.Literal && typeof key.value === \"string\") {\n return key.value;\n }\n return null;\n}\n\n/**\n * Whether a property signature is annotated with `boolean`.\n */\nfunction isBooleanTyped(member: TSESTree.TSPropertySignature): boolean {\n return (\n member.typeAnnotation?.typeAnnotation.type ===\n AST_NODE_TYPES.TSBooleanKeyword\n );\n}\n\n/**\n * Returns true when the object type literal has BOTH a boolean-typed status\n * member AND at least `MIN_OPTIONAL_MEMBERS` optional members.\n */\nfunction looksLikeMutuallyExclusiveState(\n typeLiteral: TSESTree.TSTypeLiteral,\n): boolean {\n let hasStatusBoolean = false;\n let optionalCount = 0;\n\n for (const member of typeLiteral.members) {\n if (member.type !== AST_NODE_TYPES.TSPropertySignature) {\n continue;\n }\n\n if (member.optional) {\n optionalCount += 1;\n }\n\n const name = getMemberName(member);\n if (\n name !== null &&\n STATUS_MEMBER_NAMES.has(name) &&\n isBooleanTyped(member)\n ) {\n hasStatusBoolean = true;\n }\n }\n\n return hasStatusBoolean && optionalCount >= MIN_OPTIONAL_MEMBERS;\n}\n\nexport default ESLintUtils.RuleCreator(\n (name) =>\n `https://github.com/sarj-ai/linting/blob/main/packages/typescript/src/rules/${name}.ts`,\n)<Options, MessageIds>({\n name: \"prefer-discriminated-union\",\n meta: {\n type: \"suggestion\",\n docs: {\n description:\n \"Flag object types with a boolean status flag and many optionals; model them as a discriminated union instead.\",\n },\n schema: [],\n messages: {\n preferDiscriminatedUnion:\n \"This object type uses a boolean status flag alongside several optional fields, which lets illegal states be representable. Model it as a `z.discriminatedUnion` / discriminated union (e.g. `{ ok: true; data: T } | { ok: false; error: E }`) to make illegal states unrepresentable.\",\n },\n },\n defaultOptions: [],\n create(context) {\n function checkTypeLiteral(\n typeLiteral: TSESTree.TSTypeLiteral,\n reportNode: TSESTree.Node,\n ): void {\n if (looksLikeMutuallyExclusiveState(typeLiteral)) {\n context.report({\n node: reportNode,\n messageId: \"preferDiscriminatedUnion\",\n });\n }\n }\n\n return {\n TSInterfaceDeclaration(\n node: TSESTree.TSInterfaceDeclaration,\n ): void {\n // An interface body is structurally an object type literal; reuse the\n // same membership analysis by treating its `body.body` as members.\n const synthetic: TSESTree.TSTypeLiteral = {\n ...node.body,\n type: AST_NODE_TYPES.TSTypeLiteral,\n members: node.body.body,\n } as TSESTree.TSTypeLiteral;\n checkTypeLiteral(synthetic, node);\n },\n \"TSTypeAliasDeclaration > TSTypeLiteral\"(\n node: TSESTree.TSTypeLiteral,\n ): void {\n checkTypeLiteral(node, node.parent);\n },\n };\n },\n});\n","/**\n * @fileoverview Don't access `response.json()` / `JSON.parse()` fields without a\n * Zod parse first.\n *\n * Pattern flagged:\n * const data = await response.json();\n * doSomething(data.foo); // <-- unvalidated property access\n *\n * const body = JSON.parse(raw);\n * doSomething(body.foo); // <-- same `any` leak, different source\n *\n * Encouraged:\n * const data = MySchema.parse(await response.json());\n * doSomething(data.foo); // typed + validated\n *\n * const raw: unknown = JSON.parse(text); // never flagged: nothing read off it\n * const data = MySchema.parse(raw);\n *\n * Heuristic:\n * - Track variables initialized to `await someCall.json()` or `JSON.parse(x)`\n * using ESLint's scope manager.\n * - Untrack if reassigned to anything other than another raw payload source.\n * - Untrack when passed to a user-defined type-guard predicate — a call whose\n * callee name matches `/^is[A-Z]/`, or any call used in an `if`/`?:` test\n * position (`if (guard(body)) { … body.foo … }`). Hand-written guards validate\n * the payload just as a Zod `.parse()` does.\n * - Flag MemberExpression reads and destructuring off tracked variables.\n * - `.parse()` / `.safeParse()` chained directly on the json call are legit\n * and never produce a tracked binding in the first place.\n *\n * References:\n * - https://zod.dev/?id=parse\n * - https://www.totaltypescript.com/parse-don-t-validate\n */\n\nimport {\n AST_NODE_TYPES,\n ESLintUtils,\n type TSESTree,\n} from \"@typescript-eslint/utils\";\nimport type { RuleContext, Scope } from \"@typescript-eslint/utils/ts-eslint\";\n\ntype MessageIds = \"unparsedJsonAccess\";\ntype Options = readonly [];\n\ntype Ctx = Readonly<RuleContext<MessageIds, Options>>;\n\n/**\n * Peel TypeScript wrapper nodes that don't affect the underlying value\n * (`as Foo`, `<Foo>x`, `x!`, `x satisfies Foo`, parentheses, optional chain\n * wrappers). Returns the inner expression we actually care about.\n */\nconst unwrap = (\n node: TSESTree.Node | null | undefined,\n): TSESTree.Node | null => {\n let current: TSESTree.Node | null | undefined = node;\n while (current !== null && current !== undefined) {\n if (\n current.type === AST_NODE_TYPES.TSAsExpression ||\n current.type === AST_NODE_TYPES.TSTypeAssertion ||\n current.type === AST_NODE_TYPES.TSNonNullExpression ||\n current.type === AST_NODE_TYPES.TSSatisfiesExpression\n ) {\n current = current.expression;\n } else if (current.type === AST_NODE_TYPES.ChainExpression) {\n current = current.expression;\n } else {\n break;\n }\n }\n return current ?? null;\n};\n\n/**\n * Returns true if the expression is (optionally awaited) a raw payload source:\n * `<x>.json()` (a fetch/Request body) or `JSON.parse(<x>)`.\n *\n * Both hand back `any`, and the failure mode is the same: `payload.user.id`\n * type-checks against a shape the peer never sent, and surfaces at runtime as\n * `undefined` several frames away. Note this only matters at the point a FIELD\n * is read — `const raw: unknown = JSON.parse(body)` is the recommended shape and\n * is never reported, because nothing is accessed off it.\n */\nconst isRawPayloadSource = (\n node: TSESTree.Node | null | undefined,\n): boolean => {\n let current = unwrap(node);\n if (current === null) return false;\n if (current.type === AST_NODE_TYPES.AwaitExpression) {\n current = unwrap(current.argument);\n }\n if (current === null || current.type !== AST_NODE_TYPES.CallExpression) {\n return false;\n }\n const callee = unwrap(current.callee);\n if (callee === null || callee.type !== AST_NODE_TYPES.MemberExpression) {\n return false;\n }\n const property = unwrap(callee.property);\n if (property === null || property.type !== AST_NODE_TYPES.Identifier) {\n return false;\n }\n if (property.name === \"json\") {\n return true;\n }\n // `JSON.parse(...)` specifically — not any `.parse()`, which is usually the\n // schema validation we are asking for.\n const object = unwrap(callee.object);\n return (\n property.name === \"parse\" &&\n object !== null &&\n object.type === AST_NODE_TYPES.Identifier &&\n object.name === \"JSON\"\n );\n};\n\nconst findVariable = (\n scope: Scope.Scope | null,\n name: string,\n): Scope.Variable | null => {\n let current: Scope.Scope | null = scope;\n while (current !== null) {\n const variable = current.set.get(name);\n if (variable !== undefined) return variable;\n current = current.upper;\n }\n return null;\n};\n\n/** User-defined type-guard predicate names, e.g. `isProtectedResourceMetadata`. */\nconst GUARD_NAME_RE = /^is[A-Z]/;\n\n/**\n * True when a call sits in a boolean-test position (`if`/`while`/`for`/`?:`),\n * seen through `!`, `&&`/`||`, and optional-chaining wrappers — i.e. it narrows.\n */\nconst isGuardTestPosition = (node: TSESTree.Node): boolean => {\n let current: TSESTree.Node = node;\n let parent: TSESTree.Node | null | undefined = current.parent;\n while (parent !== undefined && parent !== null) {\n switch (parent.type) {\n case AST_NODE_TYPES.UnaryExpression:\n case AST_NODE_TYPES.LogicalExpression:\n case AST_NODE_TYPES.ChainExpression:\n current = parent;\n parent = parent.parent;\n continue;\n case AST_NODE_TYPES.IfStatement:\n case AST_NODE_TYPES.ConditionalExpression:\n case AST_NODE_TYPES.WhileStatement:\n case AST_NODE_TYPES.DoWhileStatement:\n case AST_NODE_TYPES.ForStatement:\n return parent.test === current;\n default:\n return false;\n }\n }\n return false;\n};\n\nconst isUnvalidatedVariableRef = (\n node: TSESTree.Node | null | undefined,\n scope: Scope.Scope,\n tracked: ReadonlySet<Scope.Variable>,\n): boolean => {\n const unwrapped = unwrap(node);\n if (unwrapped === null || unwrapped.type !== AST_NODE_TYPES.Identifier) {\n return false;\n }\n const variable = findVariable(scope, unwrapped.name);\n return variable !== null && tracked.has(variable);\n};\n\nexport default ESLintUtils.RuleCreator(\n (name) =>\n `https://github.com/sarj-ai/linting/blob/main/packages/typescript/src/rules/${name}.ts`,\n)<Options, MessageIds>({\n name: \"prefer-schema-for-api-payload\",\n meta: {\n type: \"problem\",\n docs: {\n description:\n \"Require Zod (or similar) schema validation on `response.json()` / `JSON.parse()` results before property access.\",\n },\n schema: [],\n messages: {\n unparsedJsonAccess:\n \"Property access on an unvalidated payload (`response.json()` / `JSON.parse()`) without a schema parse. Pipe through `XSchema.parse(...)` (Zod) before reading fields.\",\n },\n },\n defaultOptions: [],\n create(context: Ctx) {\n const unvalidatedVariables = new Set<Scope.Variable>();\n\n const trackInitializer = (\n declarator: TSESTree.VariableDeclarator,\n ): void => {\n if (!isRawPayloadSource(declarator.init)) return;\n const declaredVars = context.sourceCode.getDeclaredVariables(declarator);\n const variable = declaredVars[0];\n if (variable !== undefined) {\n unvalidatedVariables.add(variable);\n }\n };\n\n return {\n VariableDeclarator(node): void {\n const scope = context.sourceCode.getScope(node);\n\n if (node.id.type === AST_NODE_TYPES.Identifier) {\n trackInitializer(node);\n return;\n }\n\n if (\n node.id.type === AST_NODE_TYPES.ObjectPattern ||\n node.id.type === AST_NODE_TYPES.ArrayPattern\n ) {\n if (isRawPayloadSource(node.init)) {\n context.report({ node: node.id, messageId: \"unparsedJsonAccess\" });\n return;\n }\n if (\n isUnvalidatedVariableRef(node.init, scope, unvalidatedVariables)\n ) {\n context.report({ node: node.id, messageId: \"unparsedJsonAccess\" });\n }\n }\n },\n AssignmentExpression(node): void {\n const scope = context.sourceCode.getScope(node);\n\n if (node.left.type === AST_NODE_TYPES.Identifier) {\n const variable = findVariable(scope, node.left.name);\n if (variable === null) return;\n if (isRawPayloadSource(node.right)) {\n unvalidatedVariables.add(variable);\n } else {\n // Reassigned to a parse call or something else: drop tracking.\n unvalidatedVariables.delete(variable);\n }\n return;\n }\n\n if (\n node.left.type === AST_NODE_TYPES.ObjectPattern ||\n node.left.type === AST_NODE_TYPES.ArrayPattern\n ) {\n if (isRawPayloadSource(node.right)) {\n context.report({\n node: node.left,\n messageId: \"unparsedJsonAccess\",\n });\n return;\n }\n if (\n isUnvalidatedVariableRef(node.right, scope, unvalidatedVariables)\n ) {\n context.report({\n node: node.left,\n messageId: \"unparsedJsonAccess\",\n });\n }\n }\n },\n CallExpression(node): void {\n if (node.callee.type !== AST_NODE_TYPES.Identifier) return;\n if (!GUARD_NAME_RE.test(node.callee.name) && !isGuardTestPosition(node)) {\n return;\n }\n const scope = context.sourceCode.getScope(node);\n for (const arg of node.arguments) {\n if (arg.type === AST_NODE_TYPES.SpreadElement) continue;\n const unwrapped = unwrap(arg);\n if (unwrapped === null || unwrapped.type !== AST_NODE_TYPES.Identifier) {\n continue;\n }\n const variable = findVariable(scope, unwrapped.name);\n if (variable !== null) unvalidatedVariables.delete(variable);\n }\n },\n MemberExpression(node): void {\n const scope = context.sourceCode.getScope(node);\n const obj = unwrap(node.object);\n\n if (isRawPayloadSource(obj)) {\n // Direct `.foo` access on `(await r.json()).foo` is always bad,\n // unless the parent call is a `.parse()`/`.safeParse()` — in which\n // case it's a validation, not an unvalidated read.\n const parent = node.parent;\n if (\n parent.type === AST_NODE_TYPES.CallExpression &&\n parent.callee === node &&\n node.property.type === AST_NODE_TYPES.Identifier &&\n (node.property.name === \"parse\" ||\n node.property.name === \"safeParse\")\n ) {\n return;\n }\n context.report({ node, messageId: \"unparsedJsonAccess\" });\n return;\n }\n\n if (\n obj !== null &&\n obj.type === AST_NODE_TYPES.Identifier &&\n isUnvalidatedVariableRef(obj, scope, unvalidatedVariables)\n ) {\n context.report({ node, messageId: \"unparsedJsonAccess\" });\n const variable = findVariable(scope, obj.name);\n if (variable !== null) {\n unvalidatedVariables.delete(variable);\n }\n }\n },\n };\n },\n});\n","/**\n * @fileoverview Enforce design-system semantic color tokens over raw Tailwind\n * palette classes and hardcoded color values.\n *\n * Scoped to genuine className positions to avoid false positives on non-class\n * strings (Tailwind `safelist`, `toHaveClass(...)` test assertions, prose, color\n * maps): JSX `className`, the args of `cn()`/`clsx()`/`cva()`/`tv()`/`cx()`/\n * `twMerge()` (recursing into cva variant objects), and `*class*`-named\n * variables/object properties. Plus inline color literals on JSX `style`/`fill`/\n * `stroke`.\n *\n * Flags:\n * - raw palette classes: `text-red-500`, `bg-slate-200/50`\n * - arbitrary color values: `bg-[#fff]`, `text-[rgb(...)]`, `ring-[oklch(...)]`\n * - inline color literals: `style={{ color: \"#111827\" }}`, `fill=\"#000\"`\n *\n * Allowed: semantic tokens (`bg-primary`, `text-muted-foreground`, `bg-chart-1`),\n * `white`/`black` (the `bg-black/50` overlay idiom rarely has a token), `var(--…)`,\n * `currentColor`, and non-color arbitraries (`w-[437px]`, `grid-cols-[auto_1fr]`).\n *\n * SVG drawing data is exempt on `fill`/`stroke`/`color` attributes: any value inside\n * a `<mask>`/`<clipPath>`/`<defs>`/`<pattern>`/`<linearGradient>`/`<radialGradient>`\n * (masking breaks without literal `#fff`/`#000`), the neutral literals\n * (`#fff`/`#000`/`transparent`/`none`/`currentColor`/`inherit`), and `*.stories.*`\n * files (Storybook fixtures) never fire. Real component styling — `className` and\n * inline `style={{ … }}` objects — still fires on hardcoded colors.\n *\n * No autofix — use a semantic token, or for charts / standalone pages / 3rd-party\n * config add `// eslint-disable-next-line @sarj/prefer-semantic-colors -- <reason>`.\n */\n\nimport { AST_NODE_TYPES, ESLintUtils, type TSESTree } from \"@typescript-eslint/utils\";\n\nimport { classTokens, tailwindBase } from \"./_tailwind.js\";\n\ntype MessageIds = \"rawPalette\" | \"arbitraryColor\" | \"inlineColor\";\ntype Options = readonly [];\n\nconst COLOR_PREFIXES =\n \"text|bg|border(?:-[trblxyse])?|ring(?:-offset)?|fill|stroke|from|via|to|divide|decoration|placeholder|accent|caret|shadow|outline\";\nconst PALETTE =\n \"red|orange|amber|yellow|lime|green|emerald|teal|cyan|sky|blue|indigo|violet|purple|fuchsia|pink|rose|slate|gray|zinc|neutral|stone\";\nconst COLOR_FN = \"rgba?|hsla?|hwb|oklch|oklab|lab|lch|color\";\n\nconst RAW_PALETTE_RE = new RegExp(`^(?:${COLOR_PREFIXES})-(?:${PALETTE})-\\\\d{2,3}(?:/\\\\d{1,3})?$`);\nconst ARBITRARY_COLOR_RE = new RegExp(\n `^(?:${COLOR_PREFIXES})-\\\\[(?:#[0-9a-fA-F]{3,8}|(?:${COLOR_FN})\\\\([^\\\\]]*\\\\))\\\\]$`,\n \"i\",\n);\n\n/** Call expressions whose string args are className fragments. */\nconst CLASS_FNS = new Set<string>([\"cn\", \"clsx\", \"cva\", \"tv\", \"cx\", \"twMerge\", \"classnames\", \"classNames\"]);\nconst CLASS_NAME_RE = /class/i;\n\n/** CSS color-bearing properties, in their JSX (camelCase) and SVG-attribute forms. */\nconst STYLE_COLOR_PROPS = new Set<string>([\n \"color\",\n \"background\",\n \"backgroundColor\",\n \"borderColor\",\n \"borderTopColor\",\n \"borderRightColor\",\n \"borderBottomColor\",\n \"borderLeftColor\",\n \"outlineColor\",\n \"caretColor\",\n \"textDecorationColor\",\n \"columnRuleColor\",\n \"fill\",\n \"stroke\",\n \"stopColor\",\n \"floodColor\",\n \"lightingColor\",\n]);\nconst RAW_COLOR_VALUE_RE = new RegExp(`#[0-9a-fA-F]{3,8}\\\\b|\\\\b(?:${COLOR_FN})\\\\s*\\\\(`, \"i\");\n\nconst STORIES_FILE_RE = /\\.stories\\.[cm]?[jt]sx?$/i;\n\n/** SVG container elements whose children carry structural (not UI-token) colors. */\nconst SVG_DEFS_CONTAINERS = new Set<string>([\n \"mask\",\n \"clipPath\",\n \"defs\",\n \"pattern\",\n \"linearGradient\",\n \"radialGradient\",\n]);\n\n/** Neutral fill/stroke literals that are SVG drawing data, never a UI token. */\nconst SVG_EXEMPT_COLOR_VALUES = new Set<string>([\n \"#fff\",\n \"#ffffff\",\n \"#000\",\n \"#000000\",\n \"transparent\",\n \"none\",\n \"currentcolor\",\n \"inherit\",\n]);\n\n// A `fill`/`stroke` literal anywhere inside an `<svg>` subtree is drawing data\n// (icon/illustration artwork), not a reusable UI token — the color is inherent to\n// the graphic. Exempt any descendant of `<svg>` (which subsumes the defs\n// containers `<mask>`/`<clipPath>`/`<defs>`/`<pattern>`/gradients).\nconst isInsideSvg = (node: TSESTree.Node): boolean => {\n let current: TSESTree.Node | null | undefined = node.parent;\n while (current !== undefined && current !== null) {\n if (\n current.type === AST_NODE_TYPES.JSXElement &&\n current.openingElement.name.type === AST_NODE_TYPES.JSXIdentifier &&\n (current.openingElement.name.name === \"svg\" ||\n SVG_DEFS_CONTAINERS.has(current.openingElement.name.name))\n ) {\n return true;\n }\n current = current.parent;\n }\n return false;\n};\n\nconst propName = (key: TSESTree.Property[\"key\"]): string | null => {\n if (key.type === AST_NODE_TYPES.Identifier) return key.name;\n if (key.type === AST_NODE_TYPES.Literal && typeof key.value === \"string\") return key.value;\n return null;\n};\n\nexport default ESLintUtils.RuleCreator(\n (name) =>\n `https://github.com/sarj-ai/standards/blob/main/packages/typescript/src/rules/${name}.ts`,\n)<Options, MessageIds>({\n name: \"prefer-semantic-colors\",\n meta: {\n type: \"suggestion\",\n docs: {\n description:\n \"Enforce design-system semantic color tokens (bg-primary, text-destructive, …) over raw Tailwind palette classes (text-red-500), arbitrary color values (bg-[#fff]), and inline color literals.\",\n },\n schema: [],\n messages: {\n rawPalette:\n \"Raw palette class '{{class}}' — use a semantic token (e.g. text-foreground, bg-primary, text-destructive, bg-muted).\",\n arbitraryColor:\n \"Hardcoded color '{{class}}' — use a semantic token, or var(--…). For charts/brand add an eslint-disable with a reason.\",\n inlineColor:\n \"Hardcoded color '{{value}}' — use a semantic token / CSS variable. For charts/standalone pages add an eslint-disable with a reason.\",\n },\n },\n defaultOptions: [],\n create(context) {\n if (STORIES_FILE_RE.test(context.filename)) return {};\n\n const reportClasses = (value: string, node: TSESTree.Node): void => {\n for (const token of classTokens(value)) {\n const base = tailwindBase(token);\n if (RAW_PALETTE_RE.test(base)) {\n context.report({ node, messageId: \"rawPalette\", data: { class: token } });\n } else if (ARBITRARY_COLOR_RE.test(base)) {\n context.report({ node, messageId: \"arbitraryColor\", data: { class: token } });\n }\n }\n };\n\n // Walk a node that holds className fragments: strings, templates, arrays, cva\n // variant objects, and conditionals. CallExpressions are handled separately, so\n // they're not recursed here (avoids double-reporting cn()/cva() args).\n const checkClassNode = (node: TSESTree.Node | null): void => {\n if (node === null) return;\n switch (node.type) {\n case AST_NODE_TYPES.Literal:\n if (typeof node.value === \"string\") reportClasses(node.value, node);\n break;\n case AST_NODE_TYPES.TemplateLiteral:\n for (const quasi of node.quasis) reportClasses(quasi.value.cooked ?? \"\", quasi);\n break;\n case AST_NODE_TYPES.ArrayExpression:\n for (const element of node.elements) {\n if (element !== null && element.type !== AST_NODE_TYPES.SpreadElement) checkClassNode(element);\n }\n break;\n case AST_NODE_TYPES.ObjectExpression:\n for (const property of node.properties) {\n if (property.type === AST_NODE_TYPES.Property) checkClassNode(property.value);\n }\n break;\n case AST_NODE_TYPES.ConditionalExpression:\n checkClassNode(node.consequent);\n checkClassNode(node.alternate);\n break;\n case AST_NODE_TYPES.LogicalExpression:\n checkClassNode(node.right);\n break;\n default:\n break;\n }\n };\n\n const checkColorValueNode = (node: TSESTree.Node): void => {\n if (\n node.type === AST_NODE_TYPES.Literal &&\n typeof node.value === \"string\" &&\n RAW_COLOR_VALUE_RE.test(node.value)\n ) {\n context.report({ node, messageId: \"inlineColor\", data: { value: node.value } });\n }\n };\n\n return {\n \"JSXAttribute[name.name='className']\"(node: TSESTree.JSXAttribute): void {\n if (node.value === null) return;\n if (node.value.type === AST_NODE_TYPES.Literal) checkClassNode(node.value);\n else if (node.value.type === AST_NODE_TYPES.JSXExpressionContainer) {\n if (node.value.expression.type !== AST_NODE_TYPES.JSXEmptyExpression) {\n checkClassNode(node.value.expression);\n }\n }\n },\n CallExpression(node: TSESTree.CallExpression): void {\n if (node.callee.type === AST_NODE_TYPES.Identifier && CLASS_FNS.has(node.callee.name)) {\n for (const arg of node.arguments) {\n if (arg.type !== AST_NODE_TYPES.SpreadElement) checkClassNode(arg);\n }\n }\n },\n VariableDeclarator(node: TSESTree.VariableDeclarator): void {\n if (node.id.type === AST_NODE_TYPES.Identifier && CLASS_NAME_RE.test(node.id.name)) {\n checkClassNode(node.init);\n }\n },\n Property(node: TSESTree.Property): void {\n const name = propName(node.key);\n if (name !== null && CLASS_NAME_RE.test(name)) checkClassNode(node.value);\n },\n // SVG presentation attributes: <path fill=\"#7c3aed\" stroke=\"#7c3aed\" />.\n // Neutral drawing literals and anything inside an SVG defs container are\n // structural, not UI tokens, so they never fire.\n \"JSXAttribute[name.name=/^(fill|stroke|color)$/]\"(node: TSESTree.JSXAttribute): void {\n if (node.value?.type !== AST_NODE_TYPES.Literal) return;\n if (\n typeof node.value.value === \"string\" &&\n SVG_EXEMPT_COLOR_VALUES.has(node.value.value.toLowerCase())\n ) {\n return;\n }\n if (isInsideSvg(node)) return;\n checkColorValueNode(node.value);\n },\n // Inline style objects: style={{ color: \"#111827\", backgroundColor: \"#fff\" }}\n \"JSXAttribute[name.name='style'] ObjectExpression > Property\"(node: TSESTree.Property): void {\n const name = propName(node.key);\n if (name !== null && STYLE_COLOR_PROPS.has(name)) checkColorValueNode(node.value);\n },\n };\n },\n});\n","/**\n * @fileoverview Shared helpers for the Tailwind-className rules. className values\n * are reachable as plain string `Literal`s (attribute values, `cn()`/`clsx()`/\n * `cva()`/`tv()` args, and className-holding constants) and as the static quasis of\n * `TemplateLiteral`s — so the rules visit both node types and run these helpers.\n */\n\n/**\n * Strip Tailwind variant prefixes (`hover:`, `dark:`, `focus-visible:`, …) and a\n * leading `!` important marker, leaving the bare utility (`bg-red-500`). Variants are\n * `[a-z0-9-]+:` runs at the start; bracketed arbitrary values never start a token, so\n * a `:` inside `[url(http://…)]` is not mistaken for a variant separator.\n */\nexport const tailwindBase = (token: string): string =>\n token.replace(/^(?:[a-z0-9-]+:)+/i, \"\").replace(/^!/, \"\");\n\n/** Split a className string into its non-empty class tokens. */\nexport const classTokens = (value: string): readonly string[] =>\n value.split(/\\s+/).filter(Boolean);\n","/**\n * @fileoverview Prefer Next.js Server Actions over /api/* mutations.\n *\n * Flags mutations against internal `/api/*` URLs (POST/PUT/DELETE/PATCH) via\n * `fetch`, axios-style helpers, or direct axios/request calls. GET requests\n * and external URLs are ignored. Tests, scripts, and Next.js route handlers\n * are skipped because Server Actions don't apply there.\n *\n * The member branch (`api.post('/api/x')`) intentionally skips calls that pass\n * a function argument (e.g. `router.post('/api/x', handler)`) so Express-style\n * route *definitions* aren't mistaken for client-side mutations.\n *\n * References:\n * - https://nextjs.org/docs/app/building-your-application/data-fetching/server-actions-and-mutations\n */\n\nimport { ESLintUtils, type TSESTree } from \"@typescript-eslint/utils\";\nimport type { RuleContext, Scope } from \"@typescript-eslint/utils/ts-eslint\";\n\ntype MessageIds = \"preferServerAction\";\ntype Options = readonly [];\n\nconst MUTATION_METHODS = new Set([\"POST\", \"PUT\", \"DELETE\", \"PATCH\"]);\nconst AXIOS_MUTATION_METHODS = new Set([\"post\", \"put\", \"delete\", \"patch\"]);\n\nconst SKIP_FILE_REGEX =\n /(?:\\.test\\.[jt]sx?$|\\.spec\\.[jt]sx?$|\\/tests?\\/|\\/__tests__\\/|\\/scripts?\\/|\\/app\\/api\\/.*\\/route\\.[jt]sx?$|\\/pages\\/api\\/)/;\n\ntype Ctx = Readonly<RuleContext<MessageIds, Options>>;\n\nfunction getScope(\n context: Ctx,\n node: TSESTree.Node,\n): Scope.Scope {\n return context.sourceCode.getScope(node);\n}\n\n/**\n * Walk up the scope chain looking for a variable declared with a single\n * initializer; if found, return the initializer expression so we can analyze\n * it. Falls back to the original node when resolution is not possible.\n */\nfunction resolveNode(\n node: TSESTree.Node | null | undefined,\n context: Ctx,\n): TSESTree.Node | null {\n if (!node) return null;\n if (node.type !== \"Identifier\") return node;\n\n let scope: Scope.Scope | null = getScope(context, node);\n while (scope) {\n const variable = scope.set.get(node.name);\n if (variable && variable.defs.length === 1) {\n const def = variable.defs[0];\n if (def && def.type === \"Variable\") {\n const declarator = def.node;\n if (\n declarator.type === \"VariableDeclarator\" &&\n declarator.init\n ) {\n return declarator.init;\n }\n }\n }\n scope = scope.upper;\n }\n return node;\n}\n\nfunction isApiUrl(\n node: TSESTree.Node | null | undefined,\n context: Ctx,\n): boolean {\n const resolved = resolveNode(node, context);\n if (!resolved) return false;\n\n if (resolved.type === \"Literal\" && typeof resolved.value === \"string\") {\n return resolved.value.startsWith(\"/api/\");\n }\n if (resolved.type === \"TemplateLiteral\") {\n const firstQuasi = resolved.quasis[0];\n const cooked = firstQuasi?.value.cooked;\n return typeof cooked === \"string\" && cooked.startsWith(\"/api/\");\n }\n if (resolved.type === \"BinaryExpression\" && resolved.operator === \"+\") {\n return isApiUrl(resolved.left, context);\n }\n return false;\n}\n\nfunction isMutationMethod(\n node: TSESTree.Node | null | undefined,\n context: Ctx,\n): boolean {\n const resolved = resolveNode(node, context);\n if (!resolved) return false;\n\n if (resolved.type === \"Literal\" && typeof resolved.value === \"string\") {\n return MUTATION_METHODS.has(resolved.value.toUpperCase());\n }\n\n if (\n resolved.type === \"TemplateLiteral\" &&\n resolved.expressions.length === 0\n ) {\n const val = resolved.quasis.map((q) => q.value.cooked).join(\"\");\n return MUTATION_METHODS.has(val.toUpperCase());\n }\n\n if (resolved.type === \"ConditionalExpression\") {\n return (\n isMutationMethod(resolved.consequent, context) ||\n isMutationMethod(resolved.alternate, context)\n );\n }\n\n if (resolved.type === \"LogicalExpression\" && resolved.operator === \"||\") {\n return (\n isMutationMethod(resolved.left, context) ||\n isMutationMethod(resolved.right, context)\n );\n }\n\n return false;\n}\n\nfunction getPropertyNode(\n objNode: TSESTree.Node | null | undefined,\n propName: string,\n): TSESTree.Node | null {\n if (!objNode || objNode.type !== \"ObjectExpression\") return null;\n for (const prop of objNode.properties) {\n if (prop.type !== \"Property\") continue;\n let keyName: string | null = null;\n if (prop.key.type === \"Identifier\" && !prop.computed) {\n keyName = prop.key.name;\n } else if (\n prop.key.type === \"Literal\" &&\n typeof prop.key.value === \"string\"\n ) {\n keyName = prop.key.value;\n }\n if (keyName === propName) {\n // Skip destructuring patterns — they're not valid as config values.\n if (\n prop.value.type === \"AssignmentPattern\" ||\n prop.value.type === \"ArrayPattern\" ||\n prop.value.type === \"ObjectPattern\"\n ) {\n return null;\n }\n return prop.value;\n }\n }\n return null;\n}\n\nexport default ESLintUtils.RuleCreator(\n (name) =>\n `https://github.com/sarj-ai/linting/blob/main/packages/typescript/src/rules/${name}.ts`,\n)<Options, MessageIds>({\n name: \"prefer-server-actions\",\n meta: {\n type: \"suggestion\",\n docs: {\n description: \"Prefer Next.js Server Actions over /api/* mutations.\",\n },\n schema: [],\n messages: {\n preferServerAction:\n \"Mutation against /api/* — prefer a Next.js Server Action for type-safety and to avoid the JSON round-trip.\",\n },\n },\n defaultOptions: [],\n create(context) {\n const filename = context.filename;\n if (SKIP_FILE_REGEX.test(filename)) {\n return {};\n }\n\n return {\n CallExpression(node) {\n let isMutation = false;\n\n // 1. Standard fetch('/api/orders', { method: 'POST' })\n if (\n node.callee.type === \"Identifier\" &&\n node.callee.name === \"fetch\"\n ) {\n const urlArg = node.arguments[0];\n if (urlArg && urlArg.type !== \"SpreadElement\" && isApiUrl(urlArg, context)) {\n const initArg = node.arguments[1];\n if (initArg && initArg.type !== \"SpreadElement\") {\n const resolvedInit = resolveNode(initArg, context);\n const methodNode = getPropertyNode(resolvedInit, \"method\");\n if (methodNode && isMutationMethod(methodNode, context)) {\n isMutation = true;\n }\n }\n }\n }\n // 2. Custom wrappers or Axios: api.post('/api/orders') or axios.put('/api/orders')\n else if (\n node.callee.type === \"MemberExpression\" &&\n node.callee.property.type === \"Identifier\" &&\n !node.callee.computed\n ) {\n const methodName = node.callee.property.name.toLowerCase();\n if (AXIOS_MUTATION_METHODS.has(methodName)) {\n const urlArg = node.arguments[0];\n // Skip Express-style route definitions like\n // `router.post('/api/x', handler)`: a function argument means this\n // is registering a handler, not issuing a client mutation.\n const hasHandlerArg = node.arguments.some(\n (arg) =>\n arg.type === \"ArrowFunctionExpression\" ||\n arg.type === \"FunctionExpression\",\n );\n if (\n urlArg &&\n urlArg.type !== \"SpreadElement\" &&\n !hasHandlerArg &&\n isApiUrl(urlArg, context)\n ) {\n isMutation = true;\n }\n }\n }\n // 3. Direct axios/request call: axios({ method: 'post', url: '/api/orders' })\n else if (\n node.callee.type === \"Identifier\" &&\n (node.callee.name === \"axios\" || node.callee.name === \"request\")\n ) {\n const firstArg = node.arguments[0];\n if (firstArg && firstArg.type !== \"SpreadElement\") {\n const configArg = resolveNode(firstArg, context);\n if (configArg && configArg.type === \"ObjectExpression\") {\n const urlNode = getPropertyNode(configArg, \"url\");\n const methodNode = getPropertyNode(configArg, \"method\");\n if (\n urlNode &&\n isApiUrl(urlNode, context) &&\n methodNode &&\n isMutationMethod(methodNode, context)\n ) {\n isMutation = true;\n }\n }\n }\n }\n\n if (isMutation) {\n context.report({ node, messageId: \"preferServerAction\" });\n }\n },\n };\n },\n});\n","/**\n * @fileoverview Prefer shadcn/ui form primitives over their native HTML\n * counterparts. Limited to form/dialog elements — `<button>` and `<table>`\n * have been removed from the forbid list because they produced 100% false\n * positives during bulbul validation (icon buttons, layout tables).\n *\n * `<input>` is resolved by its `type`: a bare `<input type=\"checkbox\">` maps to\n * `<Checkbox>`, `radio` → `<RadioGroup>`, `range` → `<Slider>`, and the text-like\n * types (or no type) → `<Input>`. `type=\"hidden\"` is skipped (no shadcn primitive),\n * and a dynamic `type={…}` falls back to the generic `<Input>` rather than asserting\n * a wrong primitive.\n */\n\nimport {\n AST_NODE_TYPES,\n ESLintUtils,\n type TSESTree,\n} from \"@typescript-eslint/utils\";\n\ntype MessageIds = \"preferShadcn\";\ntype Options = readonly [];\n\nconst REPLACEMENTS: Readonly<Record<string, string>> = {\n select: \"Select\",\n textarea: \"Textarea\",\n dialog: \"Dialog\",\n};\n\n/** `<input type>` → shadcn primitive. Absent types (and text-likes) fall to Input. */\nconst INPUT_TYPE_REPLACEMENTS: Readonly<Record<string, string>> = {\n checkbox: \"Checkbox\",\n radio: \"RadioGroup\",\n range: \"Slider\",\n};\n\n/** `<input type>` values with no shadcn equivalent — never reported. */\nconst SKIPPED_INPUT_TYPES = new Set<string>([\"hidden\"]);\n\nconst kebabCase = (component: string): string =>\n component.replace(/([a-z0-9])([A-Z])/g, \"$1-$2\").toLowerCase();\n\nconst literalTypeAttr = (\n node: TSESTree.JSXOpeningElement,\n): { readonly kind: \"literal\"; readonly value: string } | { readonly kind: \"dynamic\" } | null => {\n for (const attribute of node.attributes) {\n if (\n attribute.type !== AST_NODE_TYPES.JSXAttribute ||\n attribute.name.type !== AST_NODE_TYPES.JSXIdentifier ||\n attribute.name.name !== \"type\"\n ) {\n continue;\n }\n if (attribute.value?.type === AST_NODE_TYPES.Literal && typeof attribute.value.value === \"string\") {\n return { kind: \"literal\", value: attribute.value.value.toLowerCase() };\n }\n return { kind: \"dynamic\" };\n }\n return null;\n};\n\n/** Resolve an `<input>` to its shadcn primitive, or null to skip it entirely. */\nconst resolveInputReplacement = (node: TSESTree.JSXOpeningElement): string | null => {\n const typeAttr = literalTypeAttr(node);\n if (typeAttr === null || typeAttr.kind === \"dynamic\") return \"Input\";\n if (SKIPPED_INPUT_TYPES.has(typeAttr.value)) return null;\n return INPUT_TYPE_REPLACEMENTS[typeAttr.value] ?? \"Input\";\n};\n\nexport default ESLintUtils.RuleCreator(\n (name) =>\n `https://github.com/sarj-ai/linting/blob/main/packages/typescript/src/rules/${name}.ts`,\n)<Options, MessageIds>({\n name: \"prefer-shadcn\",\n meta: {\n type: \"suggestion\",\n docs: {\n description:\n \"Prefer shadcn/ui form primitives over native `<input>`, `<select>`, `<textarea>`, and `<dialog>` elements.\",\n },\n schema: [],\n messages: {\n preferShadcn:\n \"Use the shadcn <{{replacement}}> component from @/components/ui/{{lowercase}} instead of native <{{element}}>.\",\n },\n },\n defaultOptions: [],\n create(context) {\n return {\n JSXOpeningElement(node: TSESTree.JSXOpeningElement): void {\n // Only lowercase JSXIdentifier names represent native HTML elements.\n // Member expressions (`Foo.Bar`) and namespaces (`svg:path`) are skipped.\n if (node.name.type !== \"JSXIdentifier\") {\n return;\n }\n\n const elementName = node.name.name;\n const replacement =\n elementName === \"input\" ? resolveInputReplacement(node) : REPLACEMENTS[elementName];\n\n if (replacement === undefined || replacement === null) {\n return;\n }\n\n context.report({\n node,\n messageId: \"preferShadcn\",\n data: {\n element: elementName,\n replacement,\n lowercase: kebabCase(replacement),\n },\n });\n },\n };\n },\n});\n","import {\n ESLintUtils,\n type TSESLint,\n type TSESTree,\n AST_NODE_TYPES,\n} from \"@typescript-eslint/utils\";\n\ntype MessageIds = \"missingAssertNever\";\ntype Options = readonly [];\n\n/**\n * Matches a call to `assertNever(...)` — either the bare identifier form\n * (`assertNever(x)`) or a namespaced member form (`utils.assertNever(x)`).\n */\nconst isAssertNeverCall = (expression: TSESTree.Expression): boolean => {\n if (expression.type !== AST_NODE_TYPES.CallExpression) return false;\n const callee = expression.callee;\n if (callee.type === AST_NODE_TYPES.Identifier) {\n return callee.name === \"assertNever\";\n }\n if (\n callee.type === AST_NODE_TYPES.MemberExpression &&\n !callee.computed &&\n callee.property.type === AST_NODE_TYPES.Identifier\n ) {\n return callee.property.name === \"assertNever\";\n }\n return false;\n};\n\nconst statementContainsAssertNever = (\n statement: TSESTree.Statement,\n): boolean => {\n if (statement.type === AST_NODE_TYPES.ExpressionStatement) {\n return isAssertNeverCall(statement.expression);\n }\n if (statement.type === AST_NODE_TYPES.ThrowStatement) {\n return isAssertNeverCall(statement.argument);\n }\n if (statement.type === AST_NODE_TYPES.ReturnStatement) {\n return (\n statement.argument !== null && isAssertNeverCall(statement.argument)\n );\n }\n // Recurse into block-scoped default bodies like `default: { ... }`\n if (statement.type === AST_NODE_TYPES.BlockStatement) {\n return statement.body.some(statementContainsAssertNever);\n }\n return false;\n};\n\n/**\n * Returns true if the statement performs some runtime work. An empty statement\n * or an empty block does nothing; everything else (`return`, `throw`, `break`,\n * a function call, an `if`, ...) is treated as legitimate runtime handling of\n * the default case.\n */\nconst isRuntimeHandlingStatement = (statement: TSESTree.Statement): boolean => {\n if (statement.type === AST_NODE_TYPES.EmptyStatement) return false;\n if (statement.type === AST_NODE_TYPES.BlockStatement) {\n return statement.body.some(isRuntimeHandlingStatement);\n }\n return true;\n};\n\n/**\n * A `default` clause with an empty body that is followed by another `case`\n * falls through into that case, which does the real work (e.g.\n * `default: case Single: handle();`). There is nothing to assert here.\n */\nconst isFallthroughDefault = (\n node: TSESTree.SwitchStatement,\n defaultIndex: number,\n): boolean => {\n const defaultCase = node.cases[defaultIndex];\n return (\n defaultCase !== undefined &&\n defaultCase.consequent.length === 0 &&\n defaultIndex < node.cases.length - 1\n );\n};\n\n/**\n * A `default` clause is a deliberate, documented no-op when its body is empty\n * (or an empty block) but carries a comment — e.g. `default: // do nothing`.\n * We can't distinguish a config-string switch from an exhaustive union switch\n * without type info, so a written-out intent to do nothing is honoured;\n * injecting `assertNever` there would throw at runtime. A bare empty default\n * with no comment is still flagged.\n */\nconst isCommentOnlyNoopDefault = (\n defaultCase: TSESTree.SwitchCase,\n sourceCode: Readonly<TSESLint.SourceCode>,\n): boolean => {\n if (defaultCase.consequent.length === 0) {\n const defaultToken = sourceCode.getFirstToken(defaultCase);\n const colonToken = defaultToken\n ? sourceCode.getTokenAfter(defaultToken)\n : null;\n return (\n colonToken !== null && sourceCode.getCommentsAfter(colonToken).length > 0\n );\n }\n const only = defaultCase.consequent[0];\n if (\n only !== undefined &&\n defaultCase.consequent.length === 1 &&\n only.type === AST_NODE_TYPES.BlockStatement &&\n only.body.length === 0\n ) {\n return sourceCode.getCommentsInside(only).length > 0;\n }\n return false;\n};\n\nexport default ESLintUtils.RuleCreator(\n (name) =>\n `https://github.com/sarj-ai/linting/blob/main/packages/typescript/src/rules/${name}.ts`,\n)<Options, MessageIds>({\n name: \"require-assert-never\",\n meta: {\n type: \"problem\",\n docs: {\n description:\n \"Require an exhaustive-style switch whose `default` case does no runtime work to call `assertNever(_)` so that discriminated unions are exhaustively checked at compile time. Switches with a legitimate runtime default (a reducer's `return state`, an HTTP-status `return fallback()`, a `break`, a `throw`, etc.) are left alone.\",\n },\n schema: [],\n messages: {\n missingAssertNever:\n \"Empty switch `default` case — add runtime handling or call `assertNever()` so the discriminated union is exhaustively checked at compile time.\",\n },\n },\n defaultOptions: [],\n create(context) {\n return {\n SwitchStatement(node: TSESTree.SwitchStatement): void {\n const defaultIndex = node.cases.findIndex(\n (caseNode) => caseNode.test === null,\n );\n // No `default` at all is fine — we don't demand exhaustiveness of every\n // switch, only of those that opted into a (no-op) default.\n if (defaultIndex === -1) return;\n const defaultCase = node.cases[defaultIndex];\n if (defaultCase === undefined) return;\n\n // An explicit `assertNever(...)` is the canonical exhaustiveness check.\n if (defaultCase.consequent.some(statementContainsAssertNever)) return;\n\n // A default that does real runtime work (return a fallback, break,\n // throw, log, ...) is legitimate — don't demand assertNever there.\n if (defaultCase.consequent.some(isRuntimeHandlingStatement)) return;\n\n // A fallthrough default hands control to a following case, which does\n // the work — there is nothing to assert.\n if (isFallthroughDefault(node, defaultIndex)) return;\n\n // A deliberate, comment-documented no-op default is honoured; we can't\n // prove the discriminant is a union without type info, and injecting\n // assertNever would throw at runtime on a config-string switch.\n if (isCommentOnlyNoopDefault(defaultCase, context.sourceCode)) return;\n\n // Otherwise the default is a bare, undocumented no-op: flag it.\n context.report({\n node: defaultCase,\n messageId: \"missingAssertNever\",\n });\n },\n };\n },\n});\n","/**\n * @fileoverview Require Zod validation on values read out of a `FormData`.\n * `formData.get(k)` returns `FormDataEntryValue | null` — an unvalidated,\n * attacker-controlled value. Pipe it through a schema before use.\n *\n * Validation is recognised two ways:\n * - INLINE: the `.get(...)` call sits inside a Zod `.parse(...)` /\n * `.safeParse(...)` — found by walking up the parent chain.\n * - VIA A BINDING: the value is bound and validated one or more statements\n * later, which is how a real handler reads. Tracked through the scope\n * manager (the same approach `prefer-schema-for-api-payload` uses for\n * `response.json()`), so this is not reported:\n * const tokenRaw = formData.get(\"t\");\n * const parsed = ZForm.safeParse({ t: typeof tokenRaw === \"string\" ? tokenRaw : undefined });\n *\n * A binding narrowed by `instanceof File` / `instanceof Blob` is also exempt: a\n * Zod schema has nothing useful to say about a `File`, and `instanceof` IS the\n * validation for that branch.\n *\n * A Zod receiver is recognised by name — `Schema`-suffixed (`userSchema`), the\n * `Z<Capital>` house form (`ZUser`), or the bare `z` builder — matching\n * `zod-naming-convention`, which accepts both conventions.\n */\n\nimport { ESLintUtils, type TSESTree, AST_NODE_TYPES } from \"@typescript-eslint/utils\";\nimport type { RuleContext, Scope } from \"@typescript-eslint/utils/ts-eslint\";\n\nimport { ZOD_SCHEMA_NAME_RE } from \"./_zod.js\";\n\ntype MessageIds = \"missingZodValidation\";\ntype Options = readonly [];\n\ntype Ctx = Readonly<RuleContext<MessageIds, Options>>;\n\n/**\n * Walk down a (possibly chained) receiver expression and decide whether it\n * originates from something that looks like a Zod schema — the bare `z` builder\n * (`z.object({...}).parse(...)`), a `Schema`-suffixed identifier\n * (`userSchema.parse(...)`), or a `Z`-prefixed identifier (`ZUser.parse(...)`).\n * Non-Zod receivers like `JSON` / `Date` are intentionally rejected.\n */\nconst looksLikeZodSchema = (node: TSESTree.Node): boolean => {\n let current: TSESTree.Node = node;\n while (true) {\n if (current.type === AST_NODE_TYPES.Identifier) {\n return current.name === \"z\" || ZOD_SCHEMA_NAME_RE.test(current.name);\n }\n if (current.type === AST_NODE_TYPES.CallExpression) {\n current = current.callee;\n continue;\n }\n if (current.type === AST_NODE_TYPES.MemberExpression) {\n current = current.object;\n continue;\n }\n return false;\n }\n};\n\n/**\n * Matches a Zod validation call: `<ZodSchema>.parse(...)` or\n * `<ZodSchema>.safeParse(...)`. Keys off the *receiver* looking like a Zod\n * schema rather than the method name alone, so `JSON.parse(...)` /\n * `Date.parse(...)` are NOT treated as validation.\n */\nconst isZodParseCall = (node: TSESTree.Node): boolean => {\n if (node.type !== AST_NODE_TYPES.CallExpression) return false;\n const callee = node.callee;\n if (callee.type !== AST_NODE_TYPES.MemberExpression) return false;\n if (callee.computed) return false;\n if (callee.property.type !== AST_NODE_TYPES.Identifier) return false;\n const method = callee.property.name;\n if (method !== \"parse\" && method !== \"safeParse\") return false;\n return looksLikeZodSchema(callee.object);\n};\n\n/**\n * Matches an (optionally awaited) `<x>.formData()` call — the canonical way a\n * `FormData` object is obtained from a `Request` / `Response`.\n */\nconst isFormDataMethodCall = (node: TSESTree.Node): boolean => {\n let current: TSESTree.Node = node;\n if (current.type === AST_NODE_TYPES.AwaitExpression) {\n current = current.argument;\n }\n if (current.type !== AST_NODE_TYPES.CallExpression) return false;\n const callee = current.callee;\n return (\n callee.type === AST_NODE_TYPES.MemberExpression &&\n !callee.computed &&\n callee.property.type === AST_NODE_TYPES.Identifier &&\n callee.property.name === \"formData\"\n );\n};\n\nexport default ESLintUtils.RuleCreator(\n (name) =>\n `https://github.com/sarj-ai/linting/blob/main/packages/typescript/src/rules/${name}.ts`,\n)<Options, MessageIds>({\n name: \"require-zod-form-validation\",\n meta: {\n type: \"problem\",\n docs: {\n description:\n \"Require Zod validation (`Schema.parse(...)` / `Schema.safeParse(...)`) when reading values out of a `FormData` object.\",\n },\n schema: [],\n messages: {\n missingZodValidation:\n \"FormData parsing must use Zod schema validation (e.g., Schema.parse() / Schema.safeParse())\",\n },\n },\n defaultOptions: [],\n create(context: Ctx) {\n // A receiver is a FormData source if its name reads like form data, or if\n // it is a binding initialized from a `.formData()` call.\n const isFormSourceIdentifier = (node: TSESTree.Node): boolean => {\n if (node.type !== AST_NODE_TYPES.Identifier) return false;\n if (/formdata/i.test(node.name)) return true;\n\n let scope: Scope.Scope | null = context.sourceCode.getScope(node);\n while (scope !== null) {\n const variable = scope.set.get(node.name);\n if (variable !== undefined && variable.defs.length === 1) {\n const def = variable.defs[0];\n if (\n def !== undefined &&\n def.type === \"Variable\" &&\n def.node.type === AST_NODE_TYPES.VariableDeclarator &&\n def.node.init !== null\n ) {\n return isFormDataMethodCall(def.node.init);\n }\n return false;\n }\n scope = scope.upper;\n }\n return false;\n };\n\n const isFormDataGetCall = (node: TSESTree.CallExpression): boolean => {\n const callee = node.callee;\n if (callee.type !== AST_NODE_TYPES.MemberExpression) return false;\n if (\n callee.property.type !== AST_NODE_TYPES.Identifier ||\n callee.property.name !== \"get\"\n ) {\n return false;\n }\n return isFormSourceIdentifier(callee.object);\n };\n\n // Walk up from `node` looking for a surrounding Zod `.parse(...)` /\n // `.safeParse(...)` call. `.parent` is `null` at the Program root, so we\n // must guard for both null and undefined.\n const hasZodParseAncestor = (node: TSESTree.Node): boolean => {\n let parent: TSESTree.Node | null | undefined = node.parent;\n while (parent !== null && parent !== undefined) {\n if (isZodParseCall(parent)) return true;\n parent = parent.parent;\n }\n return false;\n };\n\n // `x instanceof File` / `x instanceof Blob` — a Zod schema adds nothing over\n // the `instanceof` narrowing for a binary upload.\n const isInstanceofNarrowing = (node: TSESTree.Node): boolean => {\n const parent: TSESTree.Node | null | undefined = node.parent;\n return (\n parent !== null &&\n parent !== undefined &&\n parent.type === AST_NODE_TYPES.BinaryExpression &&\n parent.operator === \"instanceof\" &&\n parent.left === node\n );\n };\n\n /** The identifier this `.get(...)` call is bound to, or null. */\n const boundDeclarator = (\n node: TSESTree.CallExpression,\n ): TSESTree.VariableDeclarator | null => {\n const parent = node.parent;\n if (\n parent.type === AST_NODE_TYPES.VariableDeclarator &&\n parent.init === node &&\n parent.id.type === AST_NODE_TYPES.Identifier\n ) {\n return parent;\n }\n return null;\n };\n\n /** Is any read of this binding validated (Zod parse, or `instanceof File`)? */\n const bindingIsValidated = (\n declarator: TSESTree.VariableDeclarator,\n ): boolean => {\n const variable = context.sourceCode.getDeclaredVariables(declarator)[0];\n if (variable === undefined) return false;\n return variable.references.some(\n (ref) =>\n hasZodParseAncestor(ref.identifier) ||\n isInstanceofNarrowing(ref.identifier),\n );\n };\n\n return {\n CallExpression(node: TSESTree.CallExpression): void {\n if (!isFormDataGetCall(node)) return;\n\n if (hasZodParseAncestor(node) || isInstanceofNarrowing(node)) return;\n\n const declarator = boundDeclarator(node);\n if (declarator !== null && bindingIsValidated(declarator)) return;\n\n context.report({\n node,\n messageId: \"missingZodValidation\",\n });\n },\n };\n },\n});\n","/**\n * @fileoverview The single source of truth for \"does this name read as a Zod\n * schema?\". Shared by `zod-naming-convention` (which ENFORCES a convention) and\n * `require-zod-form-validation` (which RECOGNISES a schema receiver), because\n * the two disagreeing is a bug: a plugin that accepts `SubmitFormSchema` as a\n * validator in one rule must not call the same symbol non-conforming in another.\n *\n * Two conventions are recognised, and both are correct:\n * - PREFIX (`ZUser`) — lets a schema and its inferred type share a base name\n * (`type User = z.infer<typeof ZUser>`) without collision.\n * - SUFFIX (`userSchema`, `SubmitFormDataSchema`) — the dominant convention in\n * the wider Zod ecosystem and in most existing codebases.\n */\n\n/** The `Z<Capital>` prefix convention: `ZUser`, `ZSubmitForm`. */\nexport const ZOD_PREFIX_RE = /^Z[A-Z]/;\n\n/** The `XxxSchema` suffix convention: `userSchema`, `SubmitFormDataSchema`. */\nexport const ZOD_SUFFIX_RE = /Schema$/;\n\n/** Either accepted convention. */\nexport const ZOD_SCHEMA_NAME_RE = /Schema$|^Z[A-Z]/;\n","/**\n * @fileoverview Enforce a consistent naming convention for Zod schemas, so a\n * schema is recognisable at its use site without chasing the declaration.\n *\n * BOTH conventions are accepted by default (`convention: \"either\"`):\n * - `Z`-prefix (`ZUser = z.object({...})`) — lets a schema and its inferred\n * type share a base name (`type User = z.infer<typeof ZUser>`).\n * - `Schema`-suffix (`userSchema`, `SubmitFormDataSchema`) — the dominant\n * convention in the wider Zod ecosystem and in most existing codebases.\n *\n * Defaulting to prefix-only was wrong on both counts. It contradicted the rest\n * of the plugin — `require-zod-form-validation` accepts `/Schema$|^Z[A-Z]/` as\n * \"this is a Zod schema\" — and on a real 42k-LOC codebase that uniformly uses\n * the suffix it declared 220 symbols non-conforming with no defect behind any of\n * them. Both regexes now come from `_zod.ts` so the two rules cannot drift\n * apart again.\n *\n * A team that wants exactly one form sets `convention: \"prefix\"` or\n * `convention: \"suffix\"`; the point of the rule is consistency, and either\n * choice delivers it.\n */\n\nimport { ESLintUtils, type TSESTree, AST_NODE_TYPES } from \"@typescript-eslint/utils\";\n\nimport { ZOD_PREFIX_RE, ZOD_SCHEMA_NAME_RE, ZOD_SUFFIX_RE } from \"./_zod.js\";\n\ntype MessageIds = \"zPrefix\" | \"schemaSuffix\" | \"zodSchemaName\";\ntype Convention = \"prefix\" | \"suffix\" | \"either\";\ntype Options = readonly [\n {\n convention?: Convention;\n }?,\n];\n\nconst CONVENTIONS: Record<\n Convention,\n { readonly test: RegExp; readonly messageId: MessageIds }\n> = {\n prefix: { test: ZOD_PREFIX_RE, messageId: \"zPrefix\" },\n suffix: { test: ZOD_SUFFIX_RE, messageId: \"schemaSuffix\" },\n either: { test: ZOD_SCHEMA_NAME_RE, messageId: \"zodSchemaName\" },\n};\n\n/**\n * Walks down a (possibly chained) callee like `z.object().extend().refine()` and\n * returns `true` if the chain originates from a bare `z` identifier — i.e. the\n * outermost MemberExpression on the chain has `z` as its receiver.\n */\nconst calleeChainStartsWithZ = (node: TSESTree.Node): boolean => {\n let current: TSESTree.Node = node;\n\n while (current.type === AST_NODE_TYPES.MemberExpression) {\n const receiver: TSESTree.Node = current.object;\n if (receiver.type === AST_NODE_TYPES.Identifier && receiver.name === \"z\") {\n return true;\n }\n if (receiver.type === AST_NODE_TYPES.CallExpression) {\n current = receiver.callee;\n continue;\n }\n return false;\n }\n\n return false;\n};\n\nexport default ESLintUtils.RuleCreator(\n (name) =>\n `https://github.com/sarj-ai/linting/blob/main/packages/typescript/src/rules/${name}.ts`,\n)<Options, MessageIds>({\n name: \"zod-naming-convention\",\n meta: {\n type: \"suggestion\",\n docs: {\n description:\n \"Enforce a consistent Zod schema naming convention — a `Z` prefix (`ZUser`) or a `Schema` suffix (`userSchema`); both are accepted by default.\",\n },\n schema: [\n {\n type: \"object\",\n additionalProperties: false,\n properties: {\n convention: {\n type: \"string\",\n enum: [\"prefix\", \"suffix\", \"either\"],\n },\n },\n },\n ],\n messages: {\n zPrefix: \"Zod schema names should start with Z (e.g. `ZUser`)\",\n schemaSuffix: \"Zod schema names should end with Schema (e.g. `userSchema`)\",\n zodSchemaName:\n \"Zod schema names should start with Z (`ZUser`) or end with Schema (`userSchema`)\",\n },\n },\n defaultOptions: [{}],\n create(context, [optionsArg]) {\n const { test, messageId } = CONVENTIONS[optionsArg?.convention ?? \"either\"];\n\n return {\n VariableDeclarator(node: TSESTree.VariableDeclarator): void {\n const init = node.init;\n if (init === null || init === undefined) return;\n if (init.type !== AST_NODE_TYPES.CallExpression) return;\n\n const callee = init.callee;\n if (callee.type !== AST_NODE_TYPES.MemberExpression) return;\n\n if (!calleeChainStartsWithZ(callee)) return;\n\n if (node.id.type !== AST_NODE_TYPES.Identifier) return;\n if (test.test(node.id.name)) return;\n\n context.report({\n node: node.id,\n messageId,\n });\n },\n };\n },\n});\n","/**\n * @fileoverview TS port of Python SARJ028\n * (`no-cors-wildcard-with-credentials`). Flags CORS configuration that reflects\n * ANY origin (`\"*\"`) while ALSO allowing credentials. The browser treats\n * `Access-Control-Allow-Origin: *` together with\n * `Access-Control-Allow-Credentials: true` as a directive to reflect the\n * request's Origin and expose authenticated (cookie/session) responses — which\n * lets any website read them cross-origin. That is a credential-theft surface.\n *\n * Two shapes are detected, and BOTH the wildcard origin and credentials=true\n * must co-occur before the rule fires (a `\"*\"` origin without credentials, or\n * credentials with a specific origin, is safe and is NOT reported):\n *\n * 1. A `cors(...)` / `new Cors(...)` call whose options `ObjectExpression`\n * has `credentials: true` AND an `origin` property whose value subtree\n * contains a `\"*\"` string literal anywhere — the bare `\"*\"`, the `[\"*\"]`\n * array, or a `flag ? origins : \"*\"` conditional branch. Reported at the\n * call.\n *\n * 2. Manual header setting where, within the SAME function (or module) scope,\n * `Access-Control-Allow-Origin` is set to `\"*\"` AND\n * `Access-Control-Allow-Credentials` is set to `\"true\"` — via\n * `res.setHeader(...)`, `headers.set(...)` / `.append(...)` (covers\n * `NextResponse` header objects), or a single object literal\n * `{ \"Access-Control-Allow-Origin\": \"*\", \"Access-Control-Allow-Credentials\": \"true\" }`.\n * Header-name matching is case-insensitive. The object-literal form is\n * reported at the object; the split `setHeader`/`set` form is reported at\n * the wildcard-origin call.\n *\n * References:\n * - https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#credentialed_requests_and_wildcards\n */\n\nimport { ESLintUtils, type TSESTree } from \"@typescript-eslint/utils\";\n\ntype MessageIds = \"corsWildcardWithCredentials\";\ntype Options = readonly [];\n\nconst ACAO_HEADER = \"access-control-allow-origin\";\nconst ACAC_HEADER = \"access-control-allow-credentials\";\nconst HEADER_SET_METHODS = new Set([\"setheader\", \"set\", \"append\"]);\n\n/**\n * True only for the boolean literal `true` (not `1`, not a truthy expression).\n */\nfunction isTrueLiteral(node: TSESTree.Node): boolean {\n return node.type === \"Literal\" && node.value === true;\n}\n\n/**\n * True if `node` is a string literal whose value equals `\"true\"`\n * (case-insensitive), or the boolean literal `true`. Header values are strings,\n * but some frameworks coerce a boolean, so both are accepted.\n */\nfunction isCredentialsTrueValue(node: TSESTree.Node): boolean {\n if (node.type === \"Literal\") {\n if (node.value === true) {\n return true;\n }\n if (typeof node.value === \"string\") {\n return node.value.trim().toLowerCase() === \"true\";\n }\n }\n return false;\n}\n\n/**\n * True if `node` is the string literal `\"*\"`.\n */\nfunction isStarLiteral(node: TSESTree.Node): boolean {\n return node.type === \"Literal\" && node.value === \"*\";\n}\n\n/**\n * True if a `\"*\"` string literal appears anywhere in `node`'s subtree. Walking\n * the whole subtree catches `\"*\"`, `[\"*\"]`, and the `flag ? origins : \"*\"`\n * conditional branch. A dynamic `origin: someVar` has no `\"*\"` literal, so it\n * does not fire.\n */\nfunction subtreeContainsStarLiteral(node: TSESTree.Node): boolean {\n if (isStarLiteral(node)) {\n return true;\n }\n for (const key of Object.keys(node)) {\n if (key === \"parent\" || key === \"loc\" || key === \"range\") {\n continue;\n }\n const value = (node as unknown as Record<string, unknown>)[key];\n if (Array.isArray(value)) {\n for (const child of value) {\n if (isNode(child) && subtreeContainsStarLiteral(child)) {\n return true;\n }\n }\n } else if (isNode(value) && subtreeContainsStarLiteral(value)) {\n return true;\n }\n }\n return false;\n}\n\nfunction isNode(value: unknown): value is TSESTree.Node {\n return (\n typeof value === \"object\" &&\n value !== null &&\n typeof (value as { type?: unknown }).type === \"string\"\n );\n}\n\n/**\n * Returns the (non-computed) string name of a property key, or `undefined`.\n */\nfunction propertyKeyName(prop: TSESTree.Property): string | undefined {\n if (prop.computed) {\n return undefined;\n }\n const key = prop.key;\n if (key.type === \"Identifier\") {\n return key.name;\n }\n if (key.type === \"Literal\" && typeof key.value === \"string\") {\n return key.value;\n }\n return undefined;\n}\n\n/**\n * Extracts the callee's terminal identifier name for a call/new expression\n * (`cors` for `cors(...)` and `app.cors(...)`, `Cors` for `new Cors(...)`).\n */\nfunction calleeName(\n node: TSESTree.CallExpression | TSESTree.NewExpression,\n): string | undefined {\n const callee = node.callee;\n if (callee.type === \"Identifier\") {\n return callee.name;\n }\n if (\n callee.type === \"MemberExpression\" &&\n !callee.computed &&\n callee.property.type === \"Identifier\"\n ) {\n return callee.property.name;\n }\n return undefined;\n}\n\n/**\n * Detects the `cors({ origin: \"*\", credentials: true })` shape. Returns true\n * when the callee is `cors` / `Cors` and the first ObjectExpression argument\n * has `credentials: true` AND an `origin` whose subtree contains `\"*\"`.\n */\nfunction isCorsWildcardCredentialsCall(\n node: TSESTree.CallExpression | TSESTree.NewExpression,\n): boolean {\n const name = calleeName(node);\n if (name === undefined || name.toLowerCase() !== \"cors\") {\n return false;\n }\n const options = node.arguments.find(\n (arg): arg is TSESTree.ObjectExpression => arg.type === \"ObjectExpression\",\n );\n if (options === undefined) {\n return false;\n }\n let hasCredentials = false;\n let hasWildcardOrigin = false;\n for (const prop of options.properties) {\n if (prop.type !== \"Property\") {\n continue;\n }\n const key = propertyKeyName(prop);\n if (key === \"credentials\" && isTrueLiteral(prop.value)) {\n hasCredentials = true;\n } else if (key === \"origin\" && subtreeContainsStarLiteral(prop.value)) {\n hasWildcardOrigin = true;\n }\n }\n return hasCredentials && hasWildcardOrigin;\n}\n\n/**\n * True if the ObjectExpression is a header map setting BOTH\n * `Access-Control-Allow-Origin: \"*\"` and\n * `Access-Control-Allow-Credentials: \"true\"` (case-insensitive keys).\n */\nfunction isWildcardCredentialsHeaderObject(\n node: TSESTree.ObjectExpression,\n): boolean {\n let wildcardOrigin = false;\n let credentialsTrue = false;\n for (const prop of node.properties) {\n if (prop.type !== \"Property\") {\n continue;\n }\n const key = propertyKeyName(prop);\n if (key === undefined) {\n continue;\n }\n const header = key.toLowerCase();\n if (header === ACAO_HEADER && isStarLiteral(prop.value)) {\n wildcardOrigin = true;\n } else if (header === ACAC_HEADER && isCredentialsTrueValue(prop.value)) {\n credentialsTrue = true;\n }\n }\n return wildcardOrigin && credentialsTrue;\n}\n\ntype HeaderSetKind = \"origin\" | \"credentials\";\n\n/**\n * Classifies a `x.setHeader(name, value)` / `x.set(name, value)` /\n * `x.append(name, value)` call as an ACAO-wildcard set, an ACAC-true set, or\n * neither.\n */\nfunction classifyHeaderSetCall(\n node: TSESTree.CallExpression,\n): HeaderSetKind | undefined {\n const callee = node.callee;\n if (\n callee.type !== \"MemberExpression\" ||\n callee.computed ||\n callee.property.type !== \"Identifier\" ||\n !HEADER_SET_METHODS.has(callee.property.name.toLowerCase())\n ) {\n return undefined;\n }\n const [nameArg, valueArg] = node.arguments;\n if (\n nameArg === undefined ||\n valueArg === undefined ||\n nameArg.type !== \"Literal\" ||\n typeof nameArg.value !== \"string\"\n ) {\n return undefined;\n }\n const header = nameArg.value.toLowerCase();\n if (header === ACAO_HEADER && isStarLiteral(valueArg)) {\n return \"origin\";\n }\n if (header === ACAC_HEADER && isCredentialsTrueValue(valueArg)) {\n return \"credentials\";\n }\n return undefined;\n}\n\n/**\n * Nearest enclosing function node, or `undefined` for module scope. Used to\n * group split `setHeader`/`set` header assignments so a wildcard origin and a\n * credentials=true set only pair up when they live in the same scope.\n */\nfunction enclosingScope(node: TSESTree.Node): TSESTree.Node | undefined {\n let current: TSESTree.Node | undefined = node.parent;\n while (current) {\n if (\n current.type === \"FunctionDeclaration\" ||\n current.type === \"FunctionExpression\" ||\n current.type === \"ArrowFunctionExpression\"\n ) {\n return current;\n }\n current = current.parent;\n }\n return undefined;\n}\n\ninterface ScopeHeaderSets {\n originNodes: TSESTree.CallExpression[];\n credentialsNodes: TSESTree.CallExpression[];\n}\n\nexport default ESLintUtils.RuleCreator(\n (name) =>\n `https://github.com/sarj-ai/linting/blob/main/packages/typescript/src/rules/${name}.ts`,\n)<Options, MessageIds>({\n name: \"no-cors-wildcard-with-credentials\",\n meta: {\n type: \"problem\",\n docs: {\n description:\n 'Disallow CORS that reflects any Origin (`\"*\"`) while allowing credentials; any site could then read authenticated responses. Enumerate explicit trusted origins instead.',\n },\n schema: [],\n messages: {\n corsWildcardWithCredentials:\n 'CORS reflects any Origin (`\"*\"`) while allowing credentials — any site can read authenticated responses. Enumerate explicit trusted origins instead of using `\"*\"` with credentials.',\n },\n },\n defaultOptions: [],\n create(context) {\n const scopeHeaderSets = new Map<TSESTree.Node | \"module\", ScopeHeaderSets>();\n\n function recordHeaderSet(\n node: TSESTree.CallExpression,\n kind: HeaderSetKind,\n ): void {\n const key = enclosingScope(node) ?? \"module\";\n let entry = scopeHeaderSets.get(key);\n if (entry === undefined) {\n entry = { originNodes: [], credentialsNodes: [] };\n scopeHeaderSets.set(key, entry);\n }\n if (kind === \"origin\") {\n entry.originNodes.push(node);\n } else {\n entry.credentialsNodes.push(node);\n }\n }\n\n return {\n NewExpression(node: TSESTree.NewExpression): void {\n if (isCorsWildcardCredentialsCall(node)) {\n context.report({ node, messageId: \"corsWildcardWithCredentials\" });\n }\n },\n CallExpression(node: TSESTree.CallExpression): void {\n if (isCorsWildcardCredentialsCall(node)) {\n context.report({ node, messageId: \"corsWildcardWithCredentials\" });\n return;\n }\n const kind = classifyHeaderSetCall(node);\n if (kind !== undefined) {\n recordHeaderSet(node, kind);\n }\n },\n ObjectExpression(node: TSESTree.ObjectExpression): void {\n if (isWildcardCredentialsHeaderObject(node)) {\n context.report({ node, messageId: \"corsWildcardWithCredentials\" });\n }\n },\n \"Program:exit\"(): void {\n for (const { originNodes, credentialsNodes } of scopeHeaderSets.values()) {\n if (originNodes.length > 0 && credentialsNodes.length > 0) {\n for (const node of originNodes) {\n context.report({\n node,\n messageId: \"corsWildcardWithCredentials\",\n });\n }\n }\n }\n },\n };\n },\n});\n","/**\n * @fileoverview Flag `.catch()` handlers that silently swallow the rejection:\n * `promise.catch(() => null)` and friends. These are the promise-chain twin of\n * the empty-`catch`-block anti-pattern already covered by the try/catch rules —\n * the failure vanishes with no log, no metric, no rethrow, and the caller\n * receives a sentinel it usually cannot distinguish from a real value.\n *\n * Only handlers that provably do nothing are flagged: an arrow/function whose\n * entire body is a bare literal (`null`, `undefined`, a number, a string, a\n * boolean), an empty object/array literal, an empty block, or a block that\n * only `return`s one of those. A handler that references its error parameter\n * or calls anything (logging, metrics, rethrow) is never flagged.\n *\n * Two corpus-driven exemptions (5-repo sweep, 2026-07: 11/35 raw hits — 31% —\n * were these deliberate idioms):\n * - `res.json().catch(() => ({}))` / `res.text().catch(() => '')` — the\n * body-parse-fallback idiom while composing error diagnostics; the parse\n * failure itself is not the signal being handled.\n * - Test files (`.test.` / `.spec.` / `__tests__/`), where silencing a\n * promise is routine unhandled-rejection suppression.\n */\n\nimport { AST_NODE_TYPES, ESLintUtils, type TSESTree } from \"@typescript-eslint/utils\";\n\nimport { isTestFile } from \"./_paths.js\";\n\ntype MessageIds = \"silentCatch\";\ntype Options = readonly [];\n\n/** True for `x.json()` / `x.text()` — the receiver of a body-parse-fallback catch. */\nfunction isBodyParseCall(node: TSESTree.Expression): boolean {\n return (\n node.type === AST_NODE_TYPES.CallExpression &&\n node.arguments.length === 0 &&\n node.callee.type === AST_NODE_TYPES.MemberExpression &&\n !node.callee.computed &&\n node.callee.property.type === AST_NODE_TYPES.Identifier &&\n (node.callee.property.name === \"json\" ||\n node.callee.property.name === \"text\")\n );\n}\n\n/** True for expressions that provably discard the error: bare literals,\n * `undefined`, empty object/array literals. */\nfunction isSilentExpression(node: TSESTree.Expression): boolean {\n switch (node.type) {\n case AST_NODE_TYPES.Literal:\n // null / number / string / boolean literals (regex literals excluded —\n // nobody writes `.catch(() => /x/)` and they are not sentinel values).\n return !(\"regex\" in node);\n case AST_NODE_TYPES.Identifier:\n return node.name === \"undefined\";\n case AST_NODE_TYPES.UnaryExpression:\n // `void 0` — the other spelling of undefined.\n return (\n node.operator === \"void\" &&\n node.argument.type === AST_NODE_TYPES.Literal\n );\n case AST_NODE_TYPES.ObjectExpression:\n return node.properties.length === 0;\n case AST_NODE_TYPES.ArrayExpression:\n return node.elements.length === 0;\n case AST_NODE_TYPES.TSAsExpression:\n // `.catch(() => null as Foo | null)` is still silent.\n return isSilentExpression(node.expression);\n default:\n return false;\n }\n}\n\n/** True when the handler's whole body provably does nothing with the error. */\nfunction isSilentHandler(\n handler: TSESTree.ArrowFunctionExpression | TSESTree.FunctionExpression,\n): boolean {\n const body = handler.body;\n\n if (body.type !== AST_NODE_TYPES.BlockStatement) {\n // Arrow expression body: `.catch(() => null)`\n return isSilentExpression(body);\n }\n\n if (body.body.length === 0) {\n // `.catch(() => {})` / `.catch(function () {})`\n return true;\n }\n\n if (body.body.length === 1) {\n const only = body.body[0];\n if (only !== undefined && only.type === AST_NODE_TYPES.ReturnStatement) {\n // `.catch(() => { return null; })`\n return only.argument === null || isSilentExpression(only.argument);\n }\n }\n\n return false;\n}\n\nexport default ESLintUtils.RuleCreator(\n (name) =>\n `https://github.com/sarj-ai/linting/blob/main/packages/typescript/src/rules/${name}.ts`,\n)<Options, MessageIds>({\n name: \"no-silent-promise-catch\",\n meta: {\n type: \"problem\",\n docs: {\n description:\n \"Disallow `.catch()` handlers that silently swallow the rejection (e.g. `.catch(() => null)`); log, rethrow, or handle the error.\",\n },\n schema: [],\n messages: {\n silentCatch:\n \"This `.catch()` swallows the rejection without logging, rethrowing, or handling it — failures become invisible and callers get an indistinguishable sentinel. Log the error (and only then map to a fallback), or let it propagate.\",\n },\n },\n defaultOptions: [],\n create(context) {\n if (isTestFile(context.filename)) {\n return {};\n }\n\n return {\n CallExpression(node: TSESTree.CallExpression): void {\n if (\n node.callee.type !== AST_NODE_TYPES.MemberExpression ||\n node.callee.computed ||\n node.callee.property.type !== AST_NODE_TYPES.Identifier ||\n node.callee.property.name !== \"catch\"\n ) {\n return;\n }\n\n if (isBodyParseCall(node.callee.object)) {\n return;\n }\n\n if (node.arguments.length !== 1) {\n return;\n }\n const handler = node.arguments[0];\n if (\n handler === undefined ||\n (handler.type !== AST_NODE_TYPES.ArrowFunctionExpression &&\n handler.type !== AST_NODE_TYPES.FunctionExpression)\n ) {\n return;\n }\n\n if (isSilentHandler(handler)) {\n // Anchor on the CallExpression, not the handler: when the handler\n // sits on a later line than the call (multi-line `.catch(`), a\n // handler-anchored report escapes an `eslint-disable-next-line`\n // above the call AND marks that directive as unused.\n context.report({ node, messageId: \"silentCatch\" });\n }\n },\n };\n },\n});\n","/**\n * @fileoverview Shared file-path predicates for rules that are scoped by file\n * kind rather than by syntax — a timing-attack surface only exists in\n * production auth code, fixture SQL in a test legitimately breaks the\n * store-write conventions, and a dev script legitimately skips production\n * hardening. Answering \"is this a test file?\" / \"is this a script?\" in exactly\n * one place (mirroring the Python `_paths.py` extraction) is what stops the\n * per-rule regexes from drifting apart again.\n */\n\nconst SCRIPT_FILE_RE = /([\\\\/]scripts[\\\\/])|(\\.mjs$)/;\n\n/**\n * True for a test file: a `*.test.*` / `*.spec.*` basename, or anything under a\n * `test/` / `tests/` / `__tests__/` / `__mocks__/` / `fixtures/` directory.\n */\nexport function isTestFile(filename: string): boolean {\n const normalized = filename.replaceAll(\"\\\\\", \"/\");\n const base = normalized.slice(normalized.lastIndexOf(\"/\") + 1);\n if (/\\.(test|spec)\\.[cm]?[jt]sx?$/.test(base)) {\n return true;\n }\n return /(^|\\/)(tests?|__tests__|__mocks__|fixtures)\\//.test(normalized);\n}\n\n/**\n * True for one-off tooling files: anything under a `scripts/` directory or a\n * `*.mjs` file. Dev scripts run interactively and die with the terminal, so\n * production-hardening rules (e.g. fetch timeouts) do not apply there.\n */\nexport function isScriptFile(filename: string): boolean {\n return SCRIPT_FILE_RE.test(filename);\n}\n","/**\n * @fileoverview Require an abort `signal` on global `fetch()` calls. A fetch\n * without a timeout hangs forever when the upstream stalls, tying up the\n * request (or worker) with it. Pass `AbortSignal.timeout(ms)` — or a signal\n * from an `AbortController` — in the init object.\n *\n * Scope is deliberately narrow to keep false positives near zero:\n * - Only calls that resolve to the *global* `fetch` are checked: bare\n * `fetch(...)` (unless a local binding — import, parameter, variable —\n * shadows it) plus the explicit global spellings `globalThis.fetch(...)`,\n * `window.fetch(...)`, and `self.fetch(...)`. Other member calls like\n * Cloudflare Workers service bindings (`env.MY_SERVICE.fetch(...)`) or\n * custom clients (`client.fetch(...)`) are skipped.\n * - A call is flagged only when the init argument is absent, or is an\n * object literal that provably lacks `signal` (no spread, no `signal`\n * key). Anything dynamic (an identifier, a call result, a spread) is\n * assumed to carry a signal.\n * - Single-argument calls whose argument is not a string/template literal\n * are skipped: `fetch(request)` / `fetch(c.req.raw.clone())` are proxy\n * passthroughs (Workers idiom) where the inbound Request governs the\n * lifetime and attaching a fresh signal is impossible or wrong.\n * - Test files and one-off tooling (`scripts/**`, `*.mjs`) are skipped —\n * dev scripts die with the terminal, so hang-hardening is noise there.\n *\n * Wrapper modules that centralize timeout handling can be exempted via the\n * `allowIn` glob-pattern option.\n */\n\nimport {\n AST_NODE_TYPES,\n ASTUtils,\n ESLintUtils,\n type TSESTree,\n} from \"@typescript-eslint/utils\";\n\nimport { isScriptFile, isTestFile } from \"./_paths.js\";\n\ntype MessageIds = \"missingSignal\";\ntype Options = readonly [\n {\n allowIn?: readonly string[];\n }?,\n];\n\n/** The explicit-global receivers of `<obj>.fetch(...)`. */\nconst GLOBAL_OBJECTS: ReadonlySet<string> = new Set([\n \"globalThis\",\n \"window\",\n \"self\",\n]);\n\nfunction matchesAnyPattern(\n filename: string,\n patterns: readonly string[],\n): boolean {\n for (const pattern of patterns) {\n // Convert minimatch-ish globs to regex: ** -> .*, * -> [^/\\\\]*\n const regexSource = pattern\n .replace(/[.+^${}()|[\\]\\\\]/g, \"\\\\$&\")\n .replace(/\\*\\*/g, \"::DOUBLESTAR::\")\n .replace(/\\*/g, \"[^/\\\\\\\\]*\")\n .replace(/::DOUBLESTAR::/g, \".*\");\n if (new RegExp(`^${regexSource}$`).test(filename)) {\n return true;\n }\n }\n return false;\n}\n\n/**\n * True when the init argument provably lacks an abort signal: it is an object\n * literal with no `signal` property and no spread element. Any other shape\n * (identifier, call, spread, conditional, ...) may carry a signal, so it is\n * treated as safe.\n */\nfunction initProvablyLacksSignal(init: TSESTree.CallExpressionArgument): boolean {\n if (init.type !== AST_NODE_TYPES.ObjectExpression) {\n return false;\n }\n for (const prop of init.properties) {\n if (prop.type === AST_NODE_TYPES.SpreadElement) {\n return false;\n }\n if (\n (prop.key.type === AST_NODE_TYPES.Identifier &&\n prop.key.name === \"signal\") ||\n (prop.key.type === AST_NODE_TYPES.Literal && prop.key.value === \"signal\")\n ) {\n return false;\n }\n // A computed key could be \"signal\" at runtime; assume it is.\n if (prop.computed) {\n return false;\n }\n }\n return true;\n}\n\n/** True for a string or template literal — a URL spelled inline. */\nfunction isStringish(node: TSESTree.CallExpressionArgument): boolean {\n return (\n (node.type === AST_NODE_TYPES.Literal && typeof node.value === \"string\") ||\n node.type === AST_NODE_TYPES.TemplateLiteral\n );\n}\n\nexport default ESLintUtils.RuleCreator(\n (name) =>\n `https://github.com/sarj-ai/linting/blob/main/packages/typescript/src/rules/${name}.ts`,\n)<Options, MessageIds>({\n name: \"require-fetch-timeout\",\n meta: {\n type: \"problem\",\n docs: {\n description:\n \"Require an abort `signal` (e.g. `AbortSignal.timeout(ms)`) on global `fetch()` calls so stalled upstreams cannot hang the caller forever.\",\n },\n schema: [\n {\n type: \"object\",\n additionalProperties: false,\n properties: {\n allowIn: {\n description:\n \"Glob patterns for wrapper modules exempt from the rule. Matched against the ABSOLUTE file path, so anchor with a `**/` prefix (e.g. `**/http-client.ts`).\",\n type: \"array\",\n items: { type: \"string\" },\n },\n },\n },\n ],\n messages: {\n missingSignal:\n \"This `fetch()` has no abort `signal` — a stalled upstream will hang it forever. Pass `{ signal: AbortSignal.timeout(ms) }` or a signal from an AbortController.\",\n },\n },\n defaultOptions: [{}],\n create(context, [optionsArg]) {\n if (isTestFile(context.filename) || isScriptFile(context.filename)) {\n return {};\n }\n const allowIn = optionsArg?.allowIn ?? [];\n if (allowIn.length > 0 && matchesAnyPattern(context.filename, allowIn)) {\n return {};\n }\n\n /** True when `identifier` resolves to the global (no local binding shadows it). */\n function resolvesToGlobal(identifier: TSESTree.Identifier): boolean {\n const scope = context.sourceCode.getScope(identifier);\n const variable = ASTUtils.findVariable(scope, identifier.name);\n // Unresolved → implicit global. Resolved with zero defs → declared\n // global (languageOptions.globals). Any def is a local shadow.\n return variable === null || variable.defs.length === 0;\n }\n\n /** True for `fetch(...)` / `globalThis.fetch(...)` / `window.fetch(...)` /\n * `self.fetch(...)` where the receiver resolves to the global scope. */\n function isGlobalFetchCall(callee: TSESTree.Expression): boolean {\n if (callee.type === AST_NODE_TYPES.Identifier) {\n return callee.name === \"fetch\" && resolvesToGlobal(callee);\n }\n return (\n callee.type === AST_NODE_TYPES.MemberExpression &&\n !callee.computed &&\n callee.property.type === AST_NODE_TYPES.Identifier &&\n callee.property.name === \"fetch\" &&\n callee.object.type === AST_NODE_TYPES.Identifier &&\n GLOBAL_OBJECTS.has(callee.object.name) &&\n resolvesToGlobal(callee.object)\n );\n }\n\n return {\n CallExpression(node: TSESTree.CallExpression): void {\n if (!isGlobalFetchCall(node.callee)) {\n return;\n }\n\n // Proxy passthrough: a lone non-string argument is a Request (or\n // equivalent) being forwarded — the inbound request owns the\n // lifetime, and a fresh signal cannot be attached without an init.\n const [first, init] = node.arguments;\n if (node.arguments.length === 1 && first !== undefined && !isStringish(first)) {\n return;\n }\n\n if (init === undefined || initProvablyLacksSignal(init)) {\n context.report({ node, messageId: \"missingSignal\" });\n }\n },\n };\n },\n});\n","/**\n * @fileoverview Flag TanStack Router `validateSearch` implementations that\n * hand-roll \"validation\" with `as` casts. A cast asserts a shape without\n * checking it, so malformed query params flow into the app typed as clean\n * data. Use a schema validator (e.g. `zodValidator(searchSchema)` from\n * `@tanstack/zod-adapter`, or `searchSchema.parse`) so the search params are\n * actually validated at runtime.\n *\n * Deliberately narrow: only fires on a property literally named\n * `validateSearch` whose value is a function containing at least one cast —\n * `as` form or angle-bracket `<T>x` form (`as const` exempt: it narrows\n * rather than lies). Two exemptions:\n * - Casts that feed a validator are fine: an argument (transitively) of a\n * call whose callee property is `parse` / `safeParse` / `decode` — e.g.\n * the rule's own recommended remedy\n * `validateSearch: (s) => schema.parse(s as Record<string, unknown>)` —\n * is validated at runtime regardless of the cast.\n * - Test files, where route stubs are fixtures rather than real routes.\n */\n\nimport { AST_NODE_TYPES, ESLintUtils, type TSESTree } from \"@typescript-eslint/utils\";\n\nimport { isTestFile } from \"./_paths.js\";\n\ntype MessageIds = \"castInValidateSearch\";\ntype Options = readonly [];\n\n/** Callee property names whose calls validate their input at runtime. */\nconst VALIDATOR_METHODS: ReadonlySet<string> = new Set([\n \"parse\",\n \"safeParse\",\n \"decode\",\n]);\n\nfunction isConstTypeAnnotation(typeAnnotation: TSESTree.TypeNode): boolean {\n return (\n typeAnnotation.type === AST_NODE_TYPES.TSTypeReference &&\n typeAnnotation.typeName.type === AST_NODE_TYPES.Identifier &&\n typeAnnotation.typeName.name === \"const\"\n );\n}\n\n/** True for a call whose callee property is a runtime validator (`schema.parse(...)`). */\nfunction isValidatorCall(node: TSESTree.CallExpression): boolean {\n return (\n node.callee.type === AST_NODE_TYPES.MemberExpression &&\n !node.callee.computed &&\n node.callee.property.type === AST_NODE_TYPES.Identifier &&\n VALIDATOR_METHODS.has(node.callee.property.name)\n );\n}\n\n/**\n * Depth-first search for the first offending cast under `node`: a non-`const`\n * TSAsExpression or TSTypeAssertion that is not (transitively) an argument of\n * a validator call. `insideValidatorArg` is threaded through the descent so a\n * cast feeding `schema.parse(...)` is exempt however deeply it nests.\n */\nfunction findCastExpression(\n node: TSESTree.Node,\n insideValidatorArg: boolean,\n): TSESTree.TSAsExpression | TSESTree.TSTypeAssertion | null {\n if (\n (node.type === AST_NODE_TYPES.TSAsExpression ||\n node.type === AST_NODE_TYPES.TSTypeAssertion) &&\n !isConstTypeAnnotation(node.typeAnnotation) &&\n !insideValidatorArg\n ) {\n return node;\n }\n\n if (\n node.type === AST_NODE_TYPES.CallExpression &&\n isValidatorCall(node)\n ) {\n // The callee itself is still in scope; only the arguments are validated.\n const inCallee = findCastExpression(node.callee, insideValidatorArg);\n if (inCallee !== null) {\n return inCallee;\n }\n for (const arg of node.arguments) {\n const found = findCastExpression(arg, true);\n if (found !== null) {\n return found;\n }\n }\n return null;\n }\n\n for (const key of Object.keys(node)) {\n if (key === \"parent\") {\n continue;\n }\n const value = (node as unknown as Record<string, unknown>)[key];\n const children = Array.isArray(value) ? value : [value];\n for (const child of children) {\n if (\n child !== null &&\n typeof child === \"object\" &&\n \"type\" in child &&\n typeof (child as { type: unknown }).type === \"string\"\n ) {\n const found = findCastExpression(\n child as TSESTree.Node,\n insideValidatorArg,\n );\n if (found !== null) {\n return found;\n }\n }\n }\n }\n return null;\n}\n\nexport default ESLintUtils.RuleCreator(\n (name) =>\n `https://github.com/sarj-ai/linting/blob/main/packages/typescript/src/rules/${name}.ts`,\n)<Options, MessageIds>({\n name: \"require-schema-validate-search\",\n meta: {\n type: \"problem\",\n docs: {\n description:\n \"Disallow `as` casts inside hand-rolled `validateSearch` functions; use a schema validator (e.g. zodValidator) so search params are validated at runtime.\",\n },\n schema: [],\n messages: {\n castInValidateSearch:\n \"This `validateSearch` asserts the search-param shape with `as` instead of validating it — malformed query params flow through typed as clean data. Use a schema validator (e.g. `zodValidator(searchSchema)` or `searchSchema.parse`) instead of casting.\",\n },\n },\n defaultOptions: [],\n create(context) {\n if (isTestFile(context.filename)) {\n return {};\n }\n\n return {\n Property(node: TSESTree.Property): void {\n const isValidateSearchKey =\n (!node.computed &&\n node.key.type === AST_NODE_TYPES.Identifier &&\n node.key.name === \"validateSearch\") ||\n (node.key.type === AST_NODE_TYPES.Literal &&\n node.key.value === \"validateSearch\");\n if (!isValidateSearchKey) {\n return;\n }\n\n if (\n node.value.type !== AST_NODE_TYPES.ArrowFunctionExpression &&\n node.value.type !== AST_NODE_TYPES.FunctionExpression\n ) {\n return;\n }\n\n const cast = findCastExpression(node.value.body, false);\n if (cast !== null) {\n context.report({ node: cast, messageId: \"castInValidateSearch\" });\n }\n },\n };\n },\n});\n","/**\n * @fileoverview Disallow `try` blocks whose body contains more than three\n * top-level statements that can throw (TS port of Python's SARJ007).\n *\n * A fat `try` body obscures which statement is actually expected to throw and\n * widens the blast radius of the `catch` handler: unrelated failures get caught\n * (and often swallowed or mis-reported) by a handler written for a different\n * operation. Keep the `try` skinny — isolate the throwing statement(s) and move\n * the non-throwing setup and follow-up work outside.\n *\n * Only top-level statements that can *throw* are counted. What counts, and the\n * guards that keep the count aligned with intent (tuned against ~5.6k real TS\n * files to drive false positives to ~zero):\n *\n * - An `await` always counts — awaiting a promise is the canonical throwing\n * operation in async TS. A statement with an `await` in its same-scope\n * subtree counts.\n * - A synchronous call / `new` whose value is *used* (assigned, returned,\n * branched on, or passed as an argument) counts — e.g. `const x = parse(s)`,\n * `return build(x)`, `if (!validate(x))`.\n * - A bare fire-and-forget call statement with no `await` does NOT count. In\n * idiomatic TS these are side effects — React state setters (`setOpen(false)`),\n * toasts (`toast.error(...)`), `router.refresh()`, logging, optional\n * callbacks (`onSuccess?.()`). They are the post-success UI work that\n * naturally trails the one awaited action; counting them flagged nearly\n * every event handler. The exemption is applied STRUCTURALLY, recursing\n * through blocks and `if`/`else` branches, so wrapping the same call in a\n * guard (`if (!res.ok) { logEvent(\"http_error\", { path }); return null; }`)\n * does not resurrect it. A guard's TEST is still examined — a call whose\n * result is branched on (`if (!validate(x))`) still counts.\n * - Pure, non-throwing array / string / `Map` / `Object` / `Math` / `JSON`\n * helpers (`.map`, `.filter`, `.push`, `.get`, `.join`, `Object.keys`, ...)\n * do NOT count — they are data plumbing, not the operation being guarded.\n * - Calls inside a nested function / arrow body do not run when the `try`\n * executes, so they are not counted (same-scope walk).\n *\n * Two structural exemptions match the Python rule:\n *\n * - A `finally` clause is a deliberate cleanup contract that couples the body\n * to the handler — exempt.\n * - A `catch` handler guaranteed to re-throw (its body's last statement is a\n * `throw`) makes the wide body uniform error-context wrapping, not an\n * over-broad swallow — exempt.\n */\n\nimport {\n ESLintUtils,\n type TSESTree,\n AST_NODE_TYPES,\n} from \"@typescript-eslint/utils\";\n\ntype MessageIds = \"fatTryBlock\";\ntype Options = readonly [];\n\nconst MAX_TRY_BODY_STATEMENTS = 3;\n\nconst NESTED_FUNCTION_TYPES = new Set<AST_NODE_TYPES>([\n AST_NODE_TYPES.FunctionDeclaration,\n AST_NODE_TYPES.FunctionExpression,\n AST_NODE_TYPES.ArrowFunctionExpression,\n]);\n\n/** Non-throwing member methods — array / string / Map / Set data plumbing. */\nconst PURE_METHODS = new Set<string>([\n \"map\", \"filter\", \"forEach\", \"reduce\", \"reduceRight\", \"find\", \"findIndex\",\n \"findLast\", \"findLastIndex\", \"some\", \"every\", \"push\", \"pop\", \"shift\",\n \"unshift\", \"slice\", \"splice\", \"concat\", \"flat\", \"flatMap\", \"join\", \"reverse\",\n \"sort\", \"fill\", \"includes\", \"indexOf\", \"lastIndexOf\", \"at\", \"keys\", \"values\",\n \"entries\", \"has\", \"get\", \"set\", \"add\", \"delete\", \"clear\", \"toString\",\n \"toLocaleString\", \"valueOf\", \"charAt\", \"charCodeAt\", \"codePointAt\", \"split\",\n \"padStart\", \"padEnd\", \"repeat\", \"trim\", \"trimStart\", \"trimEnd\", \"toUpperCase\",\n \"toLowerCase\", \"toFixed\", \"toPrecision\", \"startsWith\", \"endsWith\",\n]);\n\n/** Non-throwing global namespaces called as `X.method(...)`. */\nconst PURE_NAMESPACES = new Set<string>([\n \"Object\", \"Array\", \"Math\", \"JSON\", \"Number\", \"String\", \"Boolean\", \"console\",\n]);\n\n/** Constructors that do not throw on construction. */\nconst PURE_CONSTRUCTORS = new Set<string>([\n \"Map\", \"Set\", \"WeakMap\", \"WeakSet\", \"Date\", \"Error\", \"TypeError\",\n \"RangeError\", \"Array\", \"Object\", \"Headers\", \"URLSearchParams\", \"FormData\",\n \"TextEncoder\", \"TextDecoder\", \"Blob\", \"ReadableStream\", \"WritableStream\",\n \"TransformStream\", \"Response\", \"AbortController\",\n]);\n\nfunction isNode(value: unknown): value is TSESTree.Node {\n return (\n typeof value === \"object\" &&\n value !== null &&\n typeof (value as { type?: unknown }).type === \"string\"\n );\n}\n\n/** A call whose value is a known pure, non-throwing helper. */\nfunction isPureCall(node: TSESTree.CallExpression): boolean {\n const callee = node.callee;\n if (callee.type !== AST_NODE_TYPES.MemberExpression) {\n return false;\n }\n const property = callee.property;\n if (property.type !== AST_NODE_TYPES.Identifier) {\n return false;\n }\n if (\n callee.object.type === AST_NODE_TYPES.Identifier &&\n PURE_NAMESPACES.has(callee.object.name)\n ) {\n return true;\n }\n return PURE_METHODS.has(property.name);\n}\n\nfunction isPureNew(node: TSESTree.NewExpression): boolean {\n return (\n node.callee.type === AST_NODE_TYPES.Identifier &&\n PURE_CONSTRUCTORS.has(node.callee.name)\n );\n}\n\n/**\n * Walk `stmt`'s same-scope subtree (not descending into nested function/arrow\n * bodies) until `predicate` matches a node.\n */\nfunction subtreeMatches(\n stmt: TSESTree.Node,\n predicate: (node: TSESTree.Node) => boolean,\n): boolean {\n let found = false;\n\n const visit = (current: TSESTree.Node): void => {\n if (found) {\n return;\n }\n if (predicate(current)) {\n found = true;\n return;\n }\n for (const key of Object.keys(current)) {\n if (key === \"parent\") {\n continue;\n }\n if (NESTED_FUNCTION_TYPES.has(current.type) && key === \"body\") {\n continue;\n }\n const value = (current as unknown as Record<string, unknown>)[key];\n if (Array.isArray(value)) {\n for (const child of value) {\n if (isNode(child)) {\n visit(child);\n }\n }\n } else if (isNode(value)) {\n visit(value);\n }\n if (found) {\n return;\n }\n }\n };\n\n visit(stmt);\n return found;\n}\n\nconst hasAwait = (node: TSESTree.Node): boolean =>\n subtreeMatches(node, (n) => n.type === AST_NODE_TYPES.AwaitExpression);\n\nconst hasThrowingCallOrNew = (node: TSESTree.Node): boolean =>\n subtreeMatches(\n node,\n (n) =>\n (n.type === AST_NODE_TYPES.CallExpression && !isPureCall(n)) ||\n (n.type === AST_NODE_TYPES.NewExpression && !isPureNew(n)),\n );\n\n/** Unwrap `await` / optional-chain / non-null wrappers to the core expression. */\nfunction unwrap(expr: TSESTree.Expression): TSESTree.Expression {\n let current = expr;\n while (\n current.type === AST_NODE_TYPES.ChainExpression ||\n current.type === AST_NODE_TYPES.TSNonNullExpression\n ) {\n current = current.expression;\n }\n return current;\n}\n\n/** A bare fire-and-forget call statement — `toast(\"done\");`, `logEvent(...);`. */\nfunction isBareCallStatement(stmt: TSESTree.Statement): boolean {\n return (\n stmt.type === AST_NODE_TYPES.ExpressionStatement &&\n unwrap(stmt.expression).type === AST_NODE_TYPES.CallExpression\n );\n}\n\n/**\n * Whether a top-level try-body statement can plausibly throw when the `try`\n * runs. See the file overview for the guards; the key ones are: `await` always\n * counts, and a bare fire-and-forget call statement (no `await`) does not.\n *\n * Blocks and `if`/`else` branches recurse so the bare-call exemption survives a\n * guard — a fire-and-forget call is no more throwing for sitting inside an\n * `if`. The guard's own TEST is still checked for a throwing call, keeping\n * `if (!validate(x))` counted. A compound statement still contributes at most\n * ONE to the caller's count; this predicate only decides whether it counts.\n */\nfunction canThrow(stmt: TSESTree.Statement): boolean {\n if (hasAwait(stmt)) {\n return true;\n }\n if (isBareCallStatement(stmt)) {\n return false;\n }\n if (stmt.type === AST_NODE_TYPES.BlockStatement) {\n return stmt.body.some(canThrow);\n }\n if (stmt.type === AST_NODE_TYPES.IfStatement) {\n return (\n hasThrowingCallOrNew(stmt.test) ||\n canThrow(stmt.consequent) ||\n (stmt.alternate !== null && canThrow(stmt.alternate))\n );\n }\n return hasThrowingCallOrNew(stmt);\n}\n\n/**\n * Conservative: is the `catch` handler guaranteed to re-throw? True when a\n * handler is present and its body's last statement is a `throw`.\n */\nfunction handlerRethrows(handler: TSESTree.CatchClause | null): boolean {\n if (handler === null) {\n return false;\n }\n const body = handler.body.body;\n const last = body[body.length - 1];\n return last !== undefined && last.type === AST_NODE_TYPES.ThrowStatement;\n}\n\nexport default ESLintUtils.RuleCreator(\n (name) =>\n `https://github.com/sarj-ai/standards/blob/main/packages/typescript/src/rules/${name}.ts`,\n)<Options, MessageIds>({\n name: \"no-fat-try-blocks\",\n meta: {\n type: \"problem\",\n docs: {\n description:\n \"Disallow `try` blocks with more than three top-level statements that can throw — isolate the throwing statement and move non-throwing work outside.\",\n },\n schema: [],\n messages: {\n fatTryBlock:\n \"This `try` block has {{count}} statements that can throw (max {{max}}). Isolate the throwing statement(s); move non-throwing work outside the `try`.\",\n },\n },\n defaultOptions: [],\n create(context) {\n const sourceCode = context.sourceCode;\n\n return {\n TryStatement(node: TSESTree.TryStatement): void {\n if (node.finalizer !== null) {\n return;\n }\n if (handlerRethrows(node.handler)) {\n return;\n }\n\n const count = node.block.body.filter(canThrow).length;\n if (count <= MAX_TRY_BODY_STATEMENTS) {\n return;\n }\n\n const tryKeyword = sourceCode.getFirstToken(node);\n context.report({\n node: tryKeyword ?? node,\n messageId: \"fatTryBlock\",\n data: { count, max: MAX_TRY_BODY_STATEMENTS },\n });\n },\n };\n },\n});\n","/**\n * @fileoverview TS port of SARJ012 (`no-secret-in-log`). Passing a secret value\n * (token, password, api key, jwt, credential, signature, ...) to a logging call\n * leaks it into log sinks — files, stdout, log aggregators — where it persists\n * far beyond its intended lifetime and is readable by anyone with log access.\n * Prefer redaction (`tokenPrefix: token.slice(0, 6)`) or omission.\n *\n * We fire on a logging call (`logger.info(...)`, `log.error(...)`, loguru/bind\n * builder chains, etc.) that passes a secret-named value either as a property of\n * an object argument (`logger.error(\"msg\", { token, apiKey })`) or as a bare\n * secret-named positional identifier (`logger.info(\"x\", password)`).\n *\n * Log recognition is shared with the catch rules via `_logging`, so the\n * `logFunctions` option applies here too. That matters: a structured logger is\n * usually a free function with no logger receiver, and `logEvent(\"slack.auth\",\n * { botToken })` was previously never even examined by this rule. Declaring the\n * project's logger closes that hole.\n *\n * The secret-name predicate matches a secret word only as a WHOLE token (after\n * snake_case / camelCase splitting) and disqualifies identifiers whose trailing\n * token is a counter / row-id / flag marker (`tokenCount`, `apiKeyId`,\n * `passwordEnabled`), so metadata *about* a secret is not mistaken for the\n * secret itself. Redaction markers (prefix/mask/hash/redact/tag) are exempt.\n *\n * References:\n * - https://owasp.org/www-community/vulnerabilities/Information_exposure_through_log_files\n */\n\nimport { ESLintUtils, type TSESTree } from \"@typescript-eslint/utils\";\n\nimport {\n createLogMatcher,\n LOGGING_OPTION_PROPERTIES,\n type LoggingOptions,\n} from \"./_logging.js\";\nimport { INNOCUOUS_WORDS, isSecretName, tokenize } from \"./_secret_names.js\";\n\ntype MessageIds = \"noSecretInLog\";\ntype Options = readonly [LoggingOptions?];\n\n/**\n * The shared metadata set plus the log-specific extras. Logging a secret's\n * label, expiry, ARN, URL, scope, or the DI component that holds it is metadata\n * ABOUT the credential, never the credential bytes, so it must not fire here —\n * `prefer-constant-time-secret-compare` uses the narrower shared set.\n */\nconst LOG_INNOCUOUS_WORDS: ReadonlySet<string> = new Set([\n ...INNOCUOUS_WORDS,\n \"name\",\n \"names\",\n \"label\",\n \"labels\",\n \"title\",\n \"expiry\",\n \"expiration\",\n \"expires\",\n \"ttl\",\n \"version\",\n \"versions\",\n \"policy\",\n \"rotation\",\n \"arn\",\n \"path\",\n \"paths\",\n \"issuer\",\n \"audience\",\n \"strength\",\n \"manager\",\n \"service\",\n \"services\",\n \"repository\",\n \"provider\",\n \"providers\",\n \"store\",\n \"factory\",\n \"handler\",\n \"controller\",\n \"bucket\",\n \"url\",\n \"uri\",\n \"endpoint\",\n \"endpoints\",\n \"scope\",\n \"scopes\",\n \"event\",\n \"events\",\n \"format\",\n \"at\",\n \"len\",\n \"length\",\n]);\n\nconst REDACTION_RE = /prefix|suffix|redact|mask|hash|hint|_len|length/i;\nconst WHOLE_TOKEN_REDACTION_MARKERS: ReadonlySet<string> = new Set([\"tag\"]);\n\n/** True if the name names a raw secret and is not a redacted derivative. */\nfunction isSecretKeyword(name: string): boolean {\n if (REDACTION_RE.test(name)) {\n return false;\n }\n if (tokenize(name).some((tok) => WHOLE_TOKEN_REDACTION_MARKERS.has(tok))) {\n return false;\n }\n return isSecretName(name, LOG_INNOCUOUS_WORDS);\n}\n\n/**\n * True if `prop`'s value is the raw secret rather than a redacted/derived form.\n * Shorthand (`{ token }`), a bare identifier (`{ apiKey: theKey }`), or a plain\n * member access (`{ apiKey: config.apiKey }`) all carry the secret verbatim. A\n * call (`token.slice(0, 6)`, `mask(token)`), template literal, ternary, concat,\n * or literal placeholder (`\"***\"`) is already redacted — logging it is safe.\n */\nfunction isRawSecretValue(prop: TSESTree.Property): boolean {\n if (prop.shorthand) {\n return true;\n }\n return prop.value.type === \"Identifier\" || prop.value.type === \"MemberExpression\";\n}\n\n/** The static string name of an object-property key, or null when not statically named. */\nfunction propertyKeyName(prop: TSESTree.Property): string | null {\n if (prop.computed) {\n return null;\n }\n if (prop.key.type === \"Identifier\") {\n return prop.key.name;\n }\n if (prop.key.type === \"Literal\" && typeof prop.key.value === \"string\") {\n return prop.key.value;\n }\n return null;\n}\n\nexport default ESLintUtils.RuleCreator(\n (name) =>\n `https://github.com/sarj-ai/standards/blob/main/packages/typescript/src/rules/${name}.ts`,\n)<Options, MessageIds>({\n name: \"no-secret-in-log\",\n meta: {\n type: \"problem\",\n docs: {\n description:\n \"Disallow passing a secret-named value to a logging call; it leaks to log sinks. Redact or omit it.\",\n },\n schema: [\n {\n type: \"object\",\n additionalProperties: false,\n properties: { ...LOGGING_OPTION_PROPERTIES },\n },\n ],\n messages: {\n noSecretInLog:\n \"Secret `{{name}}` passed to a logging call leaks it to log sinks. Redact (e.g. `{{name}}Prefix: {{name}}.slice(0, 6)`) or omit it.\",\n },\n },\n defaultOptions: [{}],\n create(context, [loggingOptions]) {\n const matcher = createLogMatcher(loggingOptions);\n\n return {\n CallExpression(node: TSESTree.CallExpression): void {\n if (!matcher.isLoggingCall(node)) {\n return;\n }\n\n for (const arg of node.arguments) {\n if (arg.type === \"Identifier\") {\n if (isSecretKeyword(arg.name)) {\n context.report({\n node: arg,\n messageId: \"noSecretInLog\",\n data: { name: arg.name },\n });\n }\n continue;\n }\n if (arg.type === \"MemberExpression\") {\n if (\n !arg.computed &&\n arg.property.type === \"Identifier\" &&\n isSecretKeyword(arg.property.name)\n ) {\n context.report({\n node: arg,\n messageId: \"noSecretInLog\",\n data: { name: arg.property.name },\n });\n }\n continue;\n }\n if (arg.type === \"ObjectExpression\") {\n for (const prop of arg.properties) {\n if (prop.type !== \"Property\") {\n continue;\n }\n const keyName = propertyKeyName(prop);\n if (keyName !== null && isSecretKeyword(keyName) && isRawSecretValue(prop)) {\n context.report({\n node: prop,\n messageId: \"noSecretInLog\",\n data: { name: keyName },\n });\n }\n }\n }\n }\n },\n };\n },\n});\n","/**\n * @fileoverview Shared predicate for deciding whether an identifier names secret\n * material. TS port of Python's `_secret_names.py`, used by `no-secret-in-log`\n * (SARJ012) and `prefer-constant-time-secret-compare` (SARJ011) so the two rules\n * never diverge on what counts as a secret.\n *\n * A naive implementation matches a secret word as a bare *substring*, which\n * misfires on a large false-positive class observed in real audits:\n *\n * - LLM usage counters that merely embed `token`: `tokenCount`, `promptTokens`,\n * `completionTokens`, `totalTokens`, `maxTokens`, `tokenize`, `tokenizer`,\n * `tokenBudget`.\n * - Row-id / handle names: `apiKeyId`, `*KeyId` — the id of a key row, not the\n * key material.\n * - Boolean feature / presence / state flags: `passwordEnabled`, `tokenPresent`,\n * `passwordSet`, `passwordConfigured` — a boolean answering \"is it there / was\n * it set\", not the credential itself. A `type` discriminator is the same:\n * `tokenType` is `\"Bearer\"`, `credentialType` is a class name.\n * - Innocent words embedding a secret word: `secretary` (embeds `secret`),\n * `keyboardEvent` (embeds `key`).\n *\n * Two rules fix this:\n *\n * 1. Match a secret word only as a WHOLE token (after snake_case / camelCase\n * splitting), never a substring. This alone clears `tokenize`, `tokenizer`,\n * `secretary`, and every *pluralized* `tokens` counter (plural `tokens` is not\n * the singular secret word `token`).\n * 2. Disqualify an identifier whose TRAILING token is a counter / row-id / flag\n * marker (`count`, `budget`, `id`, `enabled`, ...) even when a secret word is\n * also present — this clears `tokenCount`, `apiKeyId`, `passwordEnabled`,\n * while still catching a credential that merely leads with such a word\n * (`validToken`, `presentToken` are secrets, not flags).\n *\n * `isAuthSecretName` narrows further for SARJ011: a *timing-attack* surface is\n * only an authenticator whose bytes gate access, so category discriminators,\n * boolean flags, and integrity-only content hashes are stripped there while\n * `no-secret-in-log` keeps its broader reach.\n */\n\nexport const SECRET_WORDS: ReadonlySet<string> = new Set([\n \"token\",\n \"secret\",\n \"password\",\n \"passwd\",\n \"jwt\",\n \"secrets\",\n \"passwords\",\n \"credential\",\n \"credentials\",\n \"authorization\",\n \"signature\",\n \"hmac\",\n \"digest\",\n \"hash\",\n \"apikey\",\n \"bearer\",\n]);\n\n/**\n * Tokens that mark a counter, row-id, feature flag, or boolean presence/state\n * marker. As the TRAILING token they mean the identifier is metadata *about* a\n * secret, not the secret itself, so it is not a leak / timing surface even when a\n * secret word is also present: `tokenPresent`, `passwordSet`, and\n * `passwordConfigured` are booleans, not credentials. Leading such a word does\n * not disqualify — `validToken` / `presentToken` are credentials.\n */\nexport const INNOCUOUS_WORDS: ReadonlySet<string> = new Set([\n \"count\",\n \"counts\",\n \"budget\",\n \"limit\",\n \"limits\",\n \"id\",\n \"ids\",\n \"enabled\",\n \"disabled\",\n \"flag\",\n \"flags\",\n \"present\",\n \"set\",\n \"unset\",\n \"configured\",\n \"missing\",\n \"required\",\n \"valid\",\n \"invalid\",\n \"exists\",\n \"type\",\n \"types\",\n]);\n\n/**\n * Trailing token that makes the identifier metadata *about* a secret (its\n * category / handle / label), not the credential: `tokenType`, `tokenName`,\n * `sessionId`, `credentialKind`. `type`/`id` are already dropped by the shared\n * innocuous set; `name`/`kind` are added here because logging them can still\n * matter (SARJ012) but they are never a timing surface.\n */\nconst DESCRIPTOR_WORDS: ReadonlySet<string> = new Set([\n \"type\",\n \"types\",\n \"name\",\n \"names\",\n \"id\",\n \"ids\",\n \"kind\",\n \"kinds\",\n]);\n\n/**\n * A `type`/`kind` token anywhere marks an enum/category discriminator, not a\n * credential: `TOKEN_TYPE_SYSTEM`, `credentialType`, `grantKind`.\n */\nconst CATEGORY_WORDS: ReadonlySet<string> = new Set([\"type\", \"types\", \"kind\", \"kinds\"]);\n\n/**\n * A leading boolean-predicate token marks a flag, not the credential itself:\n * `isToken`, `hasSecret`, `isTokenStrategy`.\n */\nconst FLAG_PREFIXES: ReadonlySet<string> = new Set([\n \"is\",\n \"has\",\n \"was\",\n \"are\",\n \"can\",\n \"should\",\n]);\n\n/**\n * Words that make an identifier a secret *only* via an integrity/content hash\n * (`contentHash`, `metadataHash`, `rowHash`) rather than an authenticator. A name\n * that ALSO carries one of these keeps firing (`passwordHash`, `tokenHash`,\n * `computedHmac`, `signature`): those gate access, a plain digest of content does\n * not.\n */\nconst AUTH_WORDS: ReadonlySet<string> = new Set([\n \"token\",\n \"secret\",\n \"secrets\",\n \"password\",\n \"passwd\",\n \"passwords\",\n \"jwt\",\n \"credential\",\n \"credentials\",\n \"authorization\",\n \"signature\",\n \"hmac\",\n \"apikey\",\n \"bearer\",\n]);\n\n/**\n * camelCase / PascalCase / ALLCAPS / digit-run splitter, applied to each\n * snake/kebab segment. `APIKey` -> [\"API\", \"Key\"], `authToken` -> [\"auth\", \"Token\"].\n */\nconst CAMEL_RE = /[A-Z]+(?=[A-Z][a-z])|[A-Z]?[a-z]+|[A-Z]+|\\d+/g;\nconst SEGMENT_RE = /[^A-Za-z0-9]+/;\n\n/**\n * Ordered lowercase tokens from snake_case + camelCase decomposition. Also\n * yields each whole snake/kebab segment lowercased, so a pathological mixed-case\n * single word like `ToKeN` (which camel-splitting shreds into `to`/`ke`/`n`)\n * still surfaces its intended `token` form.\n */\nexport function tokenize(identifier: string): string[] {\n const tokens: string[] = [];\n for (const segment of identifier.split(SEGMENT_RE)) {\n if (!segment) {\n continue;\n }\n tokens.push(segment.toLowerCase());\n for (const part of segment.match(CAMEL_RE) ?? []) {\n tokens.push(part.toLowerCase());\n }\n }\n return tokens;\n}\n\n/**\n * The first *word* of an identifier, from camelCase splitting.\n *\n * `tokenize` deliberately emits each whole snake/kebab segment before its camel\n * parts, so `tokens[0]` for the camelCase `hasSecret` is the useless `hassecret`\n * rather than `has`. Python's rule reads `tokens[0]` directly and gets away with\n * it because Python identifiers are snake_case; TypeScript's are not, so the\n * leading-word check has to split the first segment explicitly or every\n * `isToken` / `hasSecret` flag would be mistaken for a credential.\n */\nexport function leadingWord(identifier: string): string | undefined {\n for (const segment of identifier.split(SEGMENT_RE)) {\n if (segment) {\n return (segment.match(CAMEL_RE) ?? [segment])[0]?.toLowerCase();\n }\n }\n return undefined;\n}\n\n/** True if an `api` token is immediately followed by a `key` token (`api_key`). */\nexport function hasApiKey(tokens: readonly string[]): boolean {\n for (let i = 0; i + 1 < tokens.length; i++) {\n if (tokens[i] === \"api\" && tokens[i + 1] === \"key\") {\n return true;\n }\n }\n return false;\n}\n\n/**\n * True if `identifier` names raw secret material (a credential, not metadata).\n * `innocuous` defaults to the shared metadata set; callers that need a wider\n * exemption list (e.g. `no-secret-in-log`) pass their own superset.\n */\nexport function isSecretName(\n identifier: string,\n innocuous: ReadonlySet<string> = INNOCUOUS_WORDS,\n): boolean {\n const tokens = tokenize(identifier);\n const last = tokens.at(-1);\n if (last !== undefined && innocuous.has(last)) {\n return false;\n }\n if (tokens.some((tok) => SECRET_WORDS.has(tok))) {\n return true;\n }\n return hasApiKey(tokens);\n}\n\n/**\n * True if `identifier` names an *authenticator* — an access-gating secret whose\n * bytes an attacker could recover by timing a byte-wise comparison.\n *\n * Narrows `isSecretName` for SARJ011: strips category/handle descriptors,\n * `type`/`kind` discriminators, boolean flags, and integrity-only hashes, none of\n * which are a timing-attack surface even though logging them may still matter.\n */\nexport function isAuthSecretName(identifier: string): boolean {\n if (!isSecretName(identifier)) {\n return false;\n }\n const tokens = tokenize(identifier);\n const first = leadingWord(identifier);\n if (first !== undefined && FLAG_PREFIXES.has(first)) {\n return false;\n }\n const last = tokens.at(-1);\n if (last !== undefined && DESCRIPTOR_WORDS.has(last)) {\n return false;\n }\n if (tokens.some((tok) => CATEGORY_WORDS.has(tok))) {\n return false;\n }\n if (tokens.some((tok) => AUTH_WORDS.has(tok))) {\n return true;\n }\n return hasApiKey(tokens);\n}\n","/**\n * @fileoverview Flag type-safety escape hatches that fully disable checking:\n * 1. `x as any` (and the `<any>x` assertion form) — silences every downstream\n * error on the value.\n * 2. `x as unknown as T` double-casts — assert through `unknown`/`any` to reach\n * an unrelated type, bypassing the compiler's structural check.\n *\n * `as const` is exempt — it narrows rather than widens and is the prescribed\n * pattern for literal inference.\n */\n\nimport { ESLintUtils, type TSESTree } from \"@typescript-eslint/utils\";\nimport { AST_NODE_TYPES } from \"@typescript-eslint/utils\";\n\ntype MessageIds = \"asAny\" | \"doubleCast\";\n\nfunction isAnyAnnotation(node: TSESTree.TypeNode): boolean {\n return node.type === AST_NODE_TYPES.TSAnyKeyword;\n}\n\nfunction isConstAssertion(typeAnnotation: TSESTree.TypeNode): boolean {\n return (\n typeAnnotation.type === AST_NODE_TYPES.TSTypeReference &&\n typeAnnotation.typeName.type === AST_NODE_TYPES.Identifier &&\n typeAnnotation.typeName.name === \"const\"\n );\n}\n\nexport default ESLintUtils.RuleCreator(\n (name) =>\n `https://github.com/sarj-ai/linting/blob/main/packages/typescript/src/rules/${name}.ts`,\n)<[], MessageIds>({\n name: \"no-unsafe-cast\",\n meta: {\n type: \"problem\",\n docs: {\n description:\n \"Disallow `as any`/`<any>` casts and `as unknown as T` double-casts, which fully disable type checking.\",\n },\n schema: [],\n messages: {\n asAny:\n \"`as any` disables type checking on this value. Narrow with a type guard, model the shape, or cast to a specific type instead.\",\n doubleCast:\n \"`as unknown as T` double-cast bypasses the compiler's structural check. Prefer a runtime validator (e.g. a zod schema) or an accurate type at the boundary.\",\n },\n },\n defaultOptions: [],\n create(context) {\n function checkAssertion(\n node: TSESTree.TSAsExpression | TSESTree.TSTypeAssertion,\n ): void {\n if (isConstAssertion(node.typeAnnotation)) {\n return;\n }\n\n if (isAnyAnnotation(node.typeAnnotation)) {\n context.report({ node, messageId: \"asAny\" });\n return;\n }\n\n const inner = node.expression;\n if (\n inner.type === AST_NODE_TYPES.TSAsExpression ||\n inner.type === AST_NODE_TYPES.TSTypeAssertion\n ) {\n context.report({ node, messageId: \"doubleCast\" });\n }\n }\n\n return {\n TSAsExpression: checkAssertion,\n TSTypeAssertion: checkAssertion,\n };\n },\n});\n","/**\n * @fileoverview Flag raw `string` used where a closed enumeration is clearly\n * intended, and comparison clusters against a fixed set of string literals.\n * The prescribed replacement is a string-literal union type\n * (`type Status = \"active\" | \"inactive\"`) — NOT a `StrEnum`/`enum`, since the\n * companion `no-enum` rule bans TypeScript enums.\n *\n * This is the TypeScript analog of the Python rule SARJ006 (prefer-str-enum).\n * It fires on two shapes:\n *\n * 1. **Choice-like field** — a `TSPropertySignature` (interface / type literal)\n * or class `PropertyDefinition` whose key's last word is one of the\n * high-precision CHOICE tokens (`status`, `state`, `kind`, `role`,\n * `priority`, `severity`, `direction`, `tier`, `stage`, `type`, `mode`,\n * `level`) and whose type annotation is the bare `string` keyword. Because\n * open-set API DTO fields (`status: string` from an untyped backend) are the\n * dominant false positive, a bare field fires ONLY when CORROBORATED by a\n * sibling string-literal-union member in the SAME interface / class / object\n * type. A file-wide comparison cluster on the field's name is deliberately\n * NOT used to corroborate: it flags unrelated same-named fields (DB-row casts\n * like `as Array<{ status: string }>`, passthrough DTOs). The closed-set fact\n * is still surfaced — as a `comparisonCluster` diagnostic at the comparison\n * site, which is the actionable location.\n *\n * 2. **Comparison cluster** — within one function scope, the same identifier or\n * member expression compared (`===` / `!==` / `==` / `!=`, or a `switch`)\n * against 2+ distinct short lowercase string literals (each matching\n * `^[a-z][a-z0-9_-]{0,30}$`). One diagnostic per cluster. This shape is\n * type-aware: it fires ONLY when the compared operand's resolved type is the\n * general `string` type. An operand already typed as a string-literal union\n * (`CallStatus = \"a\" | \"b\"`, a discriminated-union tag) is the target state\n * and is suppressed — a syntactic rule can't see through a named/imported\n * union, so without type information this shape is inert (the choice-field\n * shape still runs).\n *\n * A cluster inside the very function that PRODUCES the union is suppressed\n * too: when the enclosing function's declared return type is a string-literal\n * union containing every compared literal, the `string` parameter is the\n * narrowing boundary and MUST stay `string` —\n * `function parse(s: string): Status { return s === \"a\" || s === \"b\" ? s : null }`\n * is the fix, not the violation.\n *\n * `Literal`-union types (`type X = \"a\" | \"b\"`) are the target state and never\n * fire. Generated files (`*.gen.ts`, `**\\/generated/**`, `*.d.ts`, or a\n * `@generated` marker) opt out. Vendor-owned OPEN sets that merely look closed\n * (a Resend `bounceType`, a Slack `event.subtype` — dozens of values, more added\n * over time) can be listed in the `ignoreFields` option; narrowing to a union we\n * don't control would be wrong, not better.\n */\n\nimport {\n ESLintUtils,\n type TSESTree,\n type ParserServicesWithTypeInformation,\n AST_NODE_TYPES,\n} from \"@typescript-eslint/utils\";\nimport * as ts from \"typescript\";\n\ntype MessageIds = \"bareChoiceField\" | \"comparisonCluster\";\ntype Options = readonly [\n {\n ignoreFields?: readonly string[];\n }?,\n];\n\ntype FunctionNode =\n | TSESTree.FunctionDeclaration\n | TSESTree.FunctionExpression\n | TSESTree.ArrowFunctionExpression;\n\nconst CHOICE_TOKENS: ReadonlySet<string> = new Set([\n \"status\",\n \"state\",\n \"kind\",\n \"role\",\n \"priority\",\n \"severity\",\n \"direction\",\n \"tier\",\n \"stage\",\n \"type\",\n \"mode\",\n \"level\",\n]);\n\nconst LOWER_TOKEN_RE = /^[a-z][a-z0-9_-]{0,30}$/;\nconst MIN_CLUSTER_SIZE = 2;\n\nconst BOOLEANISH: ReadonlySet<string> = new Set([\"true\", \"false\"]);\n\n/**\n * An enum-shaped token worth a string-literal union: a short lowercase word of\n * 2+ chars that isn't a boolean-string. Single characters (`'a'`), file\n * paths/URLs/i18n keys (contain `/`, `:`, `.`), and `'true'`/`'false'` are NOT\n * closed-enum members — comparing against them is a flag/path/boolean guard.\n */\nfunction isEnumToken(lit: string): boolean {\n return LOWER_TOKEN_RE.test(lit) && lit.length >= 2 && !BOOLEANISH.has(lit);\n}\n\nconst IGNORE_PATTERNS: readonly RegExp[] = [\n /[\\\\/]generated[\\\\/]/,\n /\\.gen\\.tsx?$/,\n /\\.generated\\.tsx?$/,\n /\\.d\\.ts$/,\n];\n\nfunction isIgnoredFile(filename: string, sourceText: string): boolean {\n if (IGNORE_PATTERNS.some((re) => re.test(filename))) {\n return true;\n }\n return /@generated\\b/.test(sourceText.slice(0, 1024));\n}\n\n/**\n * The trailing word of a camelCase / snake_case identifier, lowercased.\n * `callStatus` -> `status`, `user_role` -> `role`, `estate` -> `estate`.\n */\nfunction lastWord(name: string): string {\n const words = name\n .replace(/([a-z0-9])([A-Z])/g, \"$1 $2\")\n .split(/[_\\s]+/)\n .filter((w) => w.length > 0);\n const last = words[words.length - 1] ?? name;\n return last.toLowerCase();\n}\n\nfunction isChoiceLikeName(name: string): boolean {\n return CHOICE_TOKENS.has(lastWord(name));\n}\n\nfunction keyName(\n key: TSESTree.PropertyDefinition[\"key\"] | TSESTree.PropertyName,\n): string | null {\n if (key.type === AST_NODE_TYPES.Identifier) {\n return key.name;\n }\n if (key.type === AST_NODE_TYPES.Literal && typeof key.value === \"string\") {\n return key.value;\n }\n return null;\n}\n\nfunction isStringLiteralMember(t: TSESTree.TypeNode): boolean {\n return (\n t.type === AST_NODE_TYPES.TSLiteralType &&\n t.literal.type === AST_NODE_TYPES.Literal &&\n typeof t.literal.value === \"string\"\n );\n}\n\n/** Whether a type node is a union of 2+ string-literal types. */\nfunction isStringLiteralUnion(node: TSESTree.TypeNode | undefined): boolean {\n if (node?.type !== AST_NODE_TYPES.TSUnionType) {\n return false;\n }\n return node.types.filter(isStringLiteralMember).length >= MIN_CLUSTER_SIZE;\n}\n\n/**\n * Whether a resolved TS type includes the general `string` type — as opposed to\n * being (a union of) string-literal types. `CallStatus = \"a\" | \"b\"` has no\n * general-string member and is already the target state; a raw `string` (or\n * `string | undefined`) does, and a comparison cluster on it should become a\n * union. Requires type information; the comparison-cluster path is inert\n * without it.\n */\nfunction typeHasRawString(type: ts.Type): boolean {\n const parts = type.isUnion() ? type.types : [type];\n return parts.some((t) => (t.flags & ts.TypeFlags.String) !== 0);\n}\n\nfunction isExternalSourceFile(sf: ts.SourceFile | undefined): boolean {\n if (sf === undefined) {\n return false;\n }\n return sf.isDeclarationFile || sf.fileName.includes(\"/node_modules/\");\n}\n\nfunction symbolIsExternallyDeclared(sym: ts.Symbol | undefined): boolean {\n return (\n sym?.declarations?.some((d) => isExternalSourceFile(d.getSourceFile())) ??\n false\n );\n}\n\n/**\n * The iterable expression a destructuring binding element draws its value from,\n * e.g. `Object.entries(x)` for `key` in `for (const [key] of Object.entries(x))`\n * or the RHS of `const { a } = rhs`.\n */\nfunction bindingSourceExpression(\n decl: ts.BindingElement,\n): ts.Expression | undefined {\n let node: ts.Node = decl.parent;\n while (\n !ts.isForOfStatement(node) &&\n !(ts.isVariableDeclaration(node) && node.initializer !== undefined)\n ) {\n if (node.parent === undefined) {\n return undefined;\n }\n node = node.parent;\n }\n return ts.isForOfStatement(node) ? node.expression : node.initializer;\n}\n\n/** A stable key for a plain identifier or non-computed member chain, else null. */\nfunction refKey(node: TSESTree.Node): string | null {\n if (node.type === AST_NODE_TYPES.Identifier) {\n return node.name;\n }\n if (node.type === AST_NODE_TYPES.MemberExpression && !node.computed) {\n const inner = refKey(node.object);\n if (inner === null || node.property.type !== AST_NODE_TYPES.Identifier) {\n return null;\n }\n return `${inner}.${node.property.name}`;\n }\n return null;\n}\n\nfunction strLiteral(node: TSESTree.Node): string | null {\n if (node.type === AST_NODE_TYPES.Literal && typeof node.value === \"string\") {\n return node.value;\n }\n return null;\n}\n\ninterface ClusterEntry {\n node: TSESTree.Node;\n literals: Set<string>;\n allTokens: boolean;\n}\n\ninterface Scope {\n clusters: Map<string, ClusterEntry>;\n /** The function this scope belongs to; null at file scope. */\n fn: FunctionNode | null;\n}\n\ninterface CollectedProperty {\n name: string;\n container: TSESTree.Node;\n node: TSESTree.Node;\n}\n\nexport default ESLintUtils.RuleCreator(\n (name) =>\n `https://github.com/sarj-ai/linting/blob/main/packages/typescript/src/rules/${name}.ts`,\n)<Options, MessageIds>({\n name: \"prefer-string-literal-union\",\n meta: {\n type: \"suggestion\",\n docs: {\n description:\n \"Flag raw `string` choice fields and string-literal comparison clusters; prefer a string-literal union type.\",\n },\n schema: [\n {\n type: \"object\",\n additionalProperties: false,\n properties: {\n ignoreFields: {\n type: \"array\",\n items: { type: \"string\" },\n },\n },\n },\n ],\n messages: {\n bareChoiceField:\n '`{{name}}: string` looks like a choice field — prefer a string-literal union type (e.g. `type X = \"a\" | \"b\"`). Enums are banned by `no-enum`; use a union.',\n comparisonCluster:\n '`{{key}}` is compared against a closed set of string literals — define a string-literal union type (e.g. `type X = \"a\" | \"b\"`).',\n },\n },\n defaultOptions: [{}],\n create(context, [optionsArg]) {\n const filename = context.filename;\n const sourceText = context.sourceCode.getText();\n if (isIgnoredFile(filename, sourceText)) {\n return {};\n }\n\n const ignoredFields = new Set(\n (optionsArg?.ignoreFields ?? []).map((name) => name.toLowerCase()),\n );\n\n let services: ParserServicesWithTypeInformation | null;\n try {\n services = ESLintUtils.getParserServices(context);\n } catch {\n services = null;\n }\n\n const scopeStack: Scope[] = [];\n const validClusters: TSESTree.Node[] = [];\n const bareChoiceProps: CollectedProperty[] = [];\n const containersWithUnion = new Set<TSESTree.Node>();\n\n function operandIsRawString(node: TSESTree.Node): boolean {\n if (services === null) {\n return false;\n }\n return typeHasRawString(services.getTypeAtLocation(node));\n }\n\n /**\n * Whether the compared value provably originates from a type we don't own —\n * a property of a `.d.ts` / node_modules type (DOM `getComputedStyle().overflowY`,\n * `Task.status` from another package), the return of such a method\n * (`URLSearchParams.get()`, `str.toLowerCase()`), or a destructuring of one\n * (`Object.entries()` keys). A string-literal union is not an available fix\n * for these, so the cluster shape must not flag them.\n */\n function originIsExternal(node: ts.Node | undefined, depth: number): boolean {\n if (node === undefined || services === null || depth > 6) {\n return false;\n }\n const checker = services.program.getTypeChecker();\n if (\n ts.isParenthesizedExpression(node) ||\n ts.isNonNullExpression(node) ||\n ts.isAsExpression(node)\n ) {\n return originIsExternal(node.expression, depth + 1);\n }\n if (ts.isPropertyAccessExpression(node)) {\n return symbolIsExternallyDeclared(checker.getSymbolAtLocation(node.name));\n }\n if (ts.isCallExpression(node)) {\n return originIsExternal(node.expression, depth + 1);\n }\n if (ts.isIdentifier(node)) {\n const decl = checker.getSymbolAtLocation(node)?.valueDeclaration;\n if (decl === undefined) {\n return false;\n }\n if (ts.isVariableDeclaration(decl) && decl.initializer !== undefined) {\n return originIsExternal(decl.initializer, depth + 1);\n }\n if (ts.isBindingElement(decl)) {\n return originIsExternal(bindingSourceExpression(decl), depth + 1);\n }\n }\n return false;\n }\n\n function operandIsFlaggable(node: TSESTree.Node): boolean {\n return (\n operandIsRawString(node) &&\n !originIsExternal(services?.esTreeNodeToTSNodeMap.get(node), 0)\n );\n }\n\n /**\n * The string-literal members of a function's DECLARED return type, resolved\n * through named aliases and `Promise<...>`. Null when the function has no\n * annotation, type information is unavailable, or the type is not a\n * string-literal union. Computed lazily — only for a function that actually\n * accumulated a cluster — since it costs a type resolution.\n */\n function declaredReturnLiterals(fn: FunctionNode): ReadonlySet<string> | null {\n const annotation = fn.returnType?.typeAnnotation;\n if (annotation === undefined || services === null) {\n return null;\n }\n const tsNode = services.esTreeNodeToTSNodeMap.get(annotation);\n if (!ts.isTypeNode(tsNode)) {\n return null;\n }\n const checker = services.program.getTypeChecker();\n const declared = checker.getTypeFromTypeNode(tsNode);\n const type = checker.getAwaitedType(declared) ?? declared;\n const literals = new Set<string>();\n for (const part of type.isUnion() ? type.types : [type]) {\n if (part.isStringLiteral()) {\n literals.add(part.value);\n }\n }\n return literals.size >= MIN_CLUSTER_SIZE ? literals : null;\n }\n\n function pushScope(node: FunctionNode): void {\n scopeStack.push({ clusters: new Map(), fn: node });\n }\n\n function popScope(): void {\n const scope = scopeStack.pop();\n if (scope === undefined) {\n return;\n }\n const candidates = [...scope.clusters.values()].filter(\n (entry) => entry.allTokens && entry.literals.size >= MIN_CLUSTER_SIZE,\n );\n if (candidates.length === 0) {\n return;\n }\n const returnLiterals =\n scope.fn === null ? null : declaredReturnLiterals(scope.fn);\n for (const entry of candidates) {\n // The enclosing function declares the very union being compared against:\n // this is the narrowing boundary that produces it, so the `string`\n // operand is required, not a defect.\n if (\n returnLiterals !== null &&\n [...entry.literals].every((lit) => returnLiterals.has(lit))\n ) {\n continue;\n }\n validClusters.push(entry.node);\n }\n }\n\n function accumulate(\n key: string,\n literals: string[],\n node: TSESTree.Node,\n ): void {\n const scope = scopeStack[scopeStack.length - 1];\n if (scope === undefined) {\n return;\n }\n const allTokens = literals.every((lit) => isEnumToken(lit));\n const existing = scope.clusters.get(key);\n if (existing === undefined) {\n scope.clusters.set(key, {\n node,\n literals: new Set(literals),\n allTokens,\n });\n return;\n }\n for (const lit of literals) {\n existing.literals.add(lit);\n }\n existing.allTokens = existing.allTokens && allTokens;\n }\n\n function collectProperty(\n key: TSESTree.PropertyDefinition[\"key\"] | TSESTree.PropertyName,\n typeNode: TSESTree.TypeNode | undefined,\n container: TSESTree.Node,\n node: TSESTree.Node,\n ): void {\n if (isStringLiteralUnion(typeNode)) {\n containersWithUnion.add(container);\n return;\n }\n if (typeNode?.type !== AST_NODE_TYPES.TSStringKeyword) {\n return;\n }\n const name = keyName(key);\n if (\n name === null ||\n !isChoiceLikeName(name) ||\n ignoredFields.has(name.toLowerCase())\n ) {\n return;\n }\n bareChoiceProps.push({ name, container, node });\n }\n\n return {\n FunctionDeclaration: pushScope,\n \"FunctionDeclaration:exit\": popScope,\n FunctionExpression: pushScope,\n \"FunctionExpression:exit\": popScope,\n ArrowFunctionExpression: pushScope,\n \"ArrowFunctionExpression:exit\": popScope,\n\n BinaryExpression(node: TSESTree.BinaryExpression): void {\n if (\n node.operator !== \"===\" &&\n node.operator !== \"!==\" &&\n node.operator !== \"==\" &&\n node.operator !== \"!=\"\n ) {\n return;\n }\n const leftKey = refKey(node.left);\n const rightLit = strLiteral(node.right);\n const rightKey = refKey(node.right);\n const leftLit = strLiteral(node.left);\n if (leftKey !== null && rightLit !== null) {\n if (operandIsFlaggable(node.left)) {\n accumulate(leftKey, [rightLit], node);\n }\n } else if (rightKey !== null && leftLit !== null) {\n if (operandIsFlaggable(node.right)) {\n accumulate(rightKey, [leftLit], node);\n }\n }\n },\n\n SwitchStatement(node: TSESTree.SwitchStatement): void {\n const key = refKey(node.discriminant);\n if (key === null || !operandIsFlaggable(node.discriminant)) {\n return;\n }\n const literals: string[] = [];\n for (const c of node.cases) {\n if (c.test !== null) {\n const lit = strLiteral(c.test);\n if (lit !== null) {\n literals.push(lit);\n }\n }\n }\n if (literals.length > 0) {\n accumulate(key, literals, node);\n }\n },\n\n TSPropertySignature(node: TSESTree.TSPropertySignature): void {\n collectProperty(\n node.key,\n node.typeAnnotation?.typeAnnotation,\n node.parent,\n node,\n );\n },\n\n PropertyDefinition(node: TSESTree.PropertyDefinition): void {\n collectProperty(\n node.key,\n node.typeAnnotation?.typeAnnotation,\n node.parent,\n node,\n );\n },\n\n \"Program:exit\"(): void {\n for (const clusterNode of validClusters) {\n context.report({\n node: clusterNode,\n messageId: \"comparisonCluster\",\n data: { key: refKeyText(clusterNode) },\n });\n }\n for (const prop of bareChoiceProps) {\n if (containersWithUnion.has(prop.container)) {\n context.report({\n node: prop.node,\n messageId: \"bareChoiceField\",\n data: { name: prop.name },\n });\n }\n }\n },\n };\n\n function refKeyText(node: TSESTree.Node): string {\n if (node.type === AST_NODE_TYPES.BinaryExpression) {\n return refKey(node.left) ?? refKey(node.right) ?? \"value\";\n }\n if (node.type === AST_NODE_TYPES.SwitchStatement) {\n return refKey(node.discriminant) ?? \"value\";\n }\n return \"value\";\n }\n },\n});\n","/**\n * @fileoverview Flag a junk-drawer module stem that has a single public export.\n * TS port of Python SARJ022. Fires ONLY when BOTH hold:\n *\n * (a) the file's basename stem is a generic \"junk-drawer\" name that describes\n * no responsibility (`utils`, `helpers`, `types`, `models`, ...), AND\n * (b) the module has exactly one public export, and that export is a named\n * function / class / function-const, so the rename target is unambiguous.\n *\n * When both hold, the sole export's name is the information-rich replacement for\n * the meaningless stem (`utils.ts` exporting `snakeCaseText` -> `snake-case-text.ts`).\n *\n * A junk-drawer stem carries no domain to lose, so replacing it with the export\n * name is strictly an improvement; an informative stem (`pagination.ts`) names a\n * domain broader than its one current export and is deliberately never flagged.\n */\n\nimport { ESLintUtils, type TSESTree, AST_NODE_TYPES } from \"@typescript-eslint/utils\";\n\ntype MessageIds = \"renameJunkDrawer\";\ntype Options = readonly [];\n\n// Generic module stems that describe no responsibility. `index` is deliberately\n// excluded: barrel files legitimately re-export many symbols under that name.\nconst JUNK_DRAWER_STEMS = new Set([\n \"util\",\n \"utils\",\n \"helper\",\n \"helpers\",\n \"common\",\n \"constant\",\n \"constants\",\n \"type\",\n \"types\",\n \"model\",\n \"models\",\n \"shared\",\n \"misc\",\n]);\n\n// Exports whose name is an idiomatic ecosystem convention that lives in a\n// junk-drawer bucket by design — flagging them fights the convention and the\n// bucket is expected to grow. `cn` is the shadcn/ui tailwind-merge className\n// helper that scaffolds into `lib/utils.ts`; renaming to `cn.ts` breaks every\n// `import { cn } from \"@/lib/utils\"`.\nconst CONVENTIONAL_BUCKET_EXPORTS = new Set([\"cn\"]);\n\n// Multi-word acronyms whose accepted kebab-case is a single token rather than a\n// letter-by-letter split (`OAuth` -> `oauth`, not `o-auth`).\nconst ACRONYM_OVERRIDES: ReadonlyArray<readonly [RegExp, string]> = [\n [/OAuth/g, \"Oauth\"],\n [/GraphQL/g, \"Graphql\"],\n [/gRPC/g, \"Grpc\"],\n];\n\n// Split on camelCase boundaries while keeping runs of capitals (acronyms)\n// together: `HTTPServer` -> `HTTP` + `Server`, `JWTHandler` -> `JWT` + `Handler`.\nconst CAMEL_BOUNDARY_RE = /(?<=[a-z0-9])(?=[A-Z])|(?<=[A-Z])(?=[A-Z][a-z])/g;\n\nconst TEST_FILE_RE = /\\.(test|spec)\\.[cm]?[jt]sx?$/i;\nconst SCRIPT_EXT_RE = /\\.[cm]?[jt]sx?$/i;\n\ninterface ExportSummary {\n readonly names: number;\n readonly hasReExport: boolean;\n readonly candidate: { name: string; node: TSESTree.Node } | null;\n}\n\nconst basename = (filename: string): string =>\n filename.split(/[/\\\\]/).pop() ?? filename;\n\nconst stemOf = (base: string): string => base.replace(SCRIPT_EXT_RE, \"\");\n\nconst kebabCase = (name: string): string => {\n let normalized = name;\n for (const [pattern, replacement] of ACRONYM_OVERRIDES) {\n normalized = normalized.replace(pattern, replacement);\n }\n return normalized.replace(CAMEL_BOUNDARY_RE, \"-\").toLowerCase();\n};\n\nconst isFunctionExpression = (node: TSESTree.Expression | null): boolean =>\n node !== null &&\n (node.type === AST_NODE_TYPES.ArrowFunctionExpression ||\n node.type === AST_NODE_TYPES.FunctionExpression);\n\n// A `const foo = () => {}` is a rename candidate; a value const (`const MAX = 5`)\n// is not — renaming a file after a bare constant loses more than it gains.\nconst functionConstName = (\n decl: TSESTree.VariableDeclaration,\n): string | null => {\n if (decl.declarations.length !== 1) return null;\n const [declarator] = decl.declarations;\n if (declarator === undefined) return null;\n if (declarator.id.type !== AST_NODE_TYPES.Identifier) return null;\n if (!isFunctionExpression(declarator.init)) return null;\n return declarator.id.name;\n};\n\nconst summarizeExports = (body: readonly TSESTree.ProgramStatement[]): ExportSummary => {\n let names = 0;\n let hasReExport = false;\n let candidate: { name: string; node: TSESTree.Node } | null = null;\n\n const addCandidate = (name: string, node: TSESTree.Node): void => {\n names += 1;\n candidate = { name, node };\n };\n\n for (const statement of body) {\n switch (statement.type) {\n case AST_NODE_TYPES.ExportAllDeclaration:\n hasReExport = true;\n break;\n case AST_NODE_TYPES.ExportDefaultDeclaration: {\n names += 1;\n const decl = statement.declaration;\n if (\n decl.type === AST_NODE_TYPES.FunctionDeclaration &&\n decl.id !== null\n ) {\n candidate = { name: decl.id.name, node: statement };\n } else if (\n decl.type === AST_NODE_TYPES.ClassDeclaration &&\n decl.id !== null\n ) {\n candidate = { name: decl.id.name, node: statement };\n }\n break;\n }\n case AST_NODE_TYPES.ExportNamedDeclaration: {\n if (statement.source !== null) {\n hasReExport = true;\n break;\n }\n const decl = statement.declaration;\n if (decl === null) {\n names += statement.specifiers.length;\n break;\n }\n switch (decl.type) {\n case AST_NODE_TYPES.FunctionDeclaration:\n if (decl.id !== null) addCandidate(decl.id.name, statement);\n else names += 1;\n break;\n case AST_NODE_TYPES.ClassDeclaration:\n if (decl.id !== null) addCandidate(decl.id.name, statement);\n else names += 1;\n break;\n case AST_NODE_TYPES.VariableDeclaration: {\n const fnName = functionConstName(decl);\n if (fnName !== null && decl.declarations.length === 1) {\n addCandidate(fnName, statement);\n } else {\n names += decl.declarations.length;\n }\n break;\n }\n default:\n names += 1;\n }\n break;\n }\n default:\n break;\n }\n }\n\n return { names, hasReExport, candidate };\n};\n\nexport default ESLintUtils.RuleCreator(\n (name) =>\n `https://github.com/sarj-ai/standards/blob/main/packages/typescript/src/rules/${name}.ts`,\n)<Options, MessageIds>({\n name: \"single-public-export\",\n meta: {\n type: \"suggestion\",\n docs: {\n description:\n \"A junk-drawer module stem (`utils`, `helpers`, `types`, ...) with a single public function/class/const export should be renamed after that export.\",\n },\n schema: [],\n messages: {\n renameJunkDrawer:\n \"Module stem `{{stem}}` is a generic junk-drawer name; its sole public export is `{{name}}` — rename the file to `{{expected}}.ts` to describe its responsibility.\",\n },\n },\n defaultOptions: [],\n create(context) {\n const base = basename(context.filename);\n\n if (base.endsWith(\".d.ts\")) return {};\n if (TEST_FILE_RE.test(base)) return {};\n\n const stem = stemOf(base);\n if (!JUNK_DRAWER_STEMS.has(stem.toLowerCase())) return {};\n\n return {\n Program(node: TSESTree.Program): void {\n const { names, hasReExport, candidate } = summarizeExports(node.body);\n if (hasReExport) return;\n if (names !== 1 || candidate === null) return;\n if (CONVENTIONAL_BUCKET_EXPORTS.has(candidate.name)) return;\n\n const expected = kebabCase(candidate.name);\n if (stem === expected) return;\n\n context.report({\n node: candidate.node,\n messageId: \"renameJunkDrawer\",\n data: { stem, name: candidate.name, expected },\n });\n },\n };\n },\n});\n","/**\n * @fileoverview TS port of SARJ025 (`no-offset-pagination`). `LIMIT n OFFSET m`\n * makes the database scan and discard every one of the `m` skipped rows before\n * returning the page, so page N costs O(N): deep pages get linearly slower until\n * they blow the request budget. Worse, under concurrent inserts the offset window\n * shifts between requests, so a row can be returned twice or skipped entirely —\n * a paginated backfill silently misses records. Keyset / cursor pagination\n * (`WHERE id > ? ORDER BY id LIMIT n`) is O(page) and stable.\n *\n * The rule reads statically-resolvable SQL strings (literals, template literals,\n * `+` concatenations, `[...].join(\" \")` fragment arrays), neutralizes string\n * values and `--` / comment bodies first, and flags an `OFFSET` keyword\n * immediately followed by a value/param token — `?` or `?1` (SQLite/D1), `:name`,\n * `@name`, `$1`, or a bare digit. A `${...}` substitution has already become `?`\n * by then, so an interpolated offset is caught too.\n *\n * Requiring the value token is what keeps false positives at zero: it excludes\n * the English word (\"offset out of range\", \"no base offset\"), an `'offset'`\n * string value or object key, and array-index constructs like BigQuery's\n * `UNNEST(...) WITH OFFSET AS col`, none of which put a value after the keyword.\n *\n * // flagged\n * `SELECT id, status FROM runs ORDER BY created_at LIMIT ? OFFSET ?`\n *\n * // preferred\n * `SELECT id, status FROM runs WHERE id > ? ORDER BY id LIMIT ?`\n *\n * Test files are out of scope — a bounded fixture query is not a production\n * pagination path.\n */\n\nimport { ESLintUtils, type TSESTree } from \"@typescript-eslint/utils\";\n\nimport { isTestFile } from \"./_paths.js\";\nimport { createSqlListener } from \"./_sql.js\";\n\ntype MessageIds = \"noOffsetPagination\";\ntype Options = readonly [];\n\n/** `OFFSET` followed by a value/param token — the real pagination construct. */\nconst OFFSET_PAGINATION = /\\bOFFSET\\s+(?:\\?\\d*|:\\w+|@\\w+|\\$\\d+|\\d+)/i;\n\n/** Cheap substring gate; noise-stripping can only ever remove keywords, never add them. */\nconst OFFSET_GATE = /offset/i;\n\nexport default ESLintUtils.RuleCreator(\n (name) =>\n `https://github.com/sarj-ai/standards/blob/main/packages/typescript/src/rules/${name}.ts`,\n)<Options, MessageIds>({\n name: \"no-offset-pagination\",\n meta: {\n type: \"problem\",\n docs: {\n description:\n \"Disallow OFFSET pagination in embedded SQL; it is O(N) per page and drops or repeats rows under concurrent writes. Use a keyset cursor.\",\n },\n schema: [],\n messages: {\n noOffsetPagination:\n \"OFFSET pagination scans and discards every skipped row (O(N) per page) and shifts under concurrent inserts, so rows get repeated or missed. Use a keyset cursor: `WHERE id > ? ORDER BY id LIMIT ?`.\",\n },\n },\n defaultOptions: [],\n create(context) {\n if (isTestFile(context.filename) || !OFFSET_GATE.test(context.sourceCode.text)) {\n return {};\n }\n return createSqlListener((sql: string, node: TSESTree.Node): void => {\n if (!OFFSET_PAGINATION.test(sql)) {\n return;\n }\n context.report({ node, messageId: \"noOffsetPagination\" });\n });\n },\n});\n","/**\n * @fileoverview Shared SQL-literal helpers for the SQL-aware store-lint rules.\n * TS port of Python's `rules/_sql.py`, adapted to where SQL actually lives in a\n * TypeScript / Cloudflare Workers codebase: D1 `db.prepare(`...`)` template\n * literals, `sql` tagged templates, `+`-concatenated fragments, and\n * `[...].join(\" \")` arrays of one-line fragments.\n *\n * These rules scan raw SQL for keywords (`INSERT`, `ON CONFLICT`, `OFFSET`,\n * `*`, ...). Scanning the raw text conflates SQL *code* with SQL string-literal\n * *values*: `WHERE p = 'on conflict'` holds no upsert clause, a `--` inside a\n * quoted value is not a comment, and `'*'` inside a value is not a projection\n * star. `stripSqlNoise` neutralizes both classes of noise before any keyword\n * scan — that single step is what keeps the false-positive rate of these rules\n * near zero.\n *\n * Template-literal substitutions (`${cols}`, `${values}`) are replaced with the\n * SQLite/D1 parameter marker `?` rather than dropped, so `LIMIT ? OFFSET ${n}`\n * still reads as a parameterised pagination clause and an interpolated\n * `VALUES ${rows}` still reads as an insert write.\n */\n\nimport { AST_NODE_TYPES, type TSESLint, type TSESTree } from \"@typescript-eslint/utils\";\n\n/**\n * Blank out SQL string-literal contents and comment bodies.\n *\n * A single left-to-right scan, so precedence between strings and comments is\n * correct: a `--` or quote inside a string literal is protected (masked as\n * string data, never read as a comment), and a quote inside a comment is\n * ignored. Every masked character becomes a space except newlines, which are\n * preserved so the text keeps its shape. Doubled quotes (`''` / `\"\"`) are SQL's\n * in-string escape and keep the scanner inside the literal.\n */\nexport function stripSqlNoise(text: string): string {\n const out = [...text];\n const n = text.length;\n let i = 0;\n while (i < n) {\n const ch = text[i];\n if (ch === \"'\" || ch === '\"') {\n out[i] = \" \";\n i += 1;\n while (i < n) {\n const c = text[i];\n if (c === ch) {\n if (i + 1 < n && text[i + 1] === ch) {\n out[i] = \" \";\n out[i + 1] = \" \";\n i += 2;\n continue;\n }\n out[i] = \" \";\n i += 1;\n break;\n }\n if (c !== \"\\n\") {\n out[i] = \" \";\n }\n i += 1;\n }\n continue;\n }\n if (ch === \"-\" && text[i + 1] === \"-\") {\n while (i < n && text[i] !== \"\\n\") {\n out[i] = \" \";\n i += 1;\n }\n continue;\n }\n if (ch === \"/\" && text[i + 1] === \"*\") {\n out[i] = \" \";\n out[i + 1] = \" \";\n i += 2;\n while (i < n && !(text[i] === \"*\" && text[i + 1] === \"/\")) {\n if (text[i] !== \"\\n\") {\n out[i] = \" \";\n }\n i += 1;\n }\n if (i < n) {\n out[i] = \" \";\n out[i + 1] = \" \";\n i += 2;\n }\n continue;\n }\n i += 1;\n }\n return out.join(\"\");\n}\n\n/** The parameter marker a `${...}` substitution is replaced with before scanning. */\nconst SUBSTITUTION_MARKER = \"?\";\n\n/**\n * Reconstruct the SQL text of a string-bearing node, or null when the node does\n * not statically resolve to one. Handles the four shapes real TS SQL takes:\n * a plain string literal, a template literal (substitutions become `?`), a\n * `+`-concatenation of those, and an array of fragments destined for `.join()`.\n */\nexport function sqlTextOf(node: TSESTree.Node): string | null {\n switch (node.type) {\n case AST_NODE_TYPES.Literal:\n return typeof node.value === \"string\" ? node.value : null;\n case AST_NODE_TYPES.TemplateLiteral:\n return node.quasis.map((q) => q.value.cooked ?? q.value.raw).join(SUBSTITUTION_MARKER);\n case AST_NODE_TYPES.TaggedTemplateExpression:\n return sqlTextOf(node.quasi);\n case AST_NODE_TYPES.BinaryExpression: {\n if (node.operator !== \"+\") {\n return null;\n }\n const left = sqlTextOf(node.left);\n const right = sqlTextOf(node.right);\n return left !== null && right !== null ? left + right : null;\n }\n case AST_NODE_TYPES.ArrayExpression: {\n const parts: string[] = [];\n for (const element of node.elements) {\n if (element === null) {\n return null;\n }\n const part = sqlTextOf(element);\n if (part === null) {\n return null;\n }\n parts.push(part);\n }\n return parts.length > 0 ? parts.join(\" \") : null;\n }\n default:\n return null;\n }\n}\n\n/**\n * True when `node` is an array whose fragments are glued together by `.join(...)`\n * — the `['INSERT INTO t (...)', 'VALUES (?)', 'ON CONFLICT ...'].join(' ')`\n * shape. Only then may the elements be read as one statement; an unrelated array\n * of strings is not SQL.\n */\nfunction isJoinedFragmentArray(node: TSESTree.ArrayExpression): boolean {\n const parent = node.parent;\n return (\n parent?.type === AST_NODE_TYPES.MemberExpression &&\n parent.object === node &&\n !parent.computed &&\n parent.property.type === AST_NODE_TYPES.Identifier &&\n parent.property.name === \"join\" &&\n parent.parent?.type === AST_NODE_TYPES.CallExpression\n );\n}\n\n/** Every string-bearing descendant that a composite node has already absorbed. */\nfunction markConsumed(node: TSESTree.Node, consumed: WeakSet<TSESTree.Node>): void {\n consumed.add(node);\n for (const key of Object.keys(node)) {\n if (key === \"parent\") {\n continue;\n }\n const value = (node as unknown as Record<string, unknown>)[key];\n for (const child of Array.isArray(value) ? value : [value]) {\n if (child !== null && typeof child === \"object\" && \"type\" in child) {\n markConsumed(child as TSESTree.Node, consumed);\n }\n }\n }\n}\n\n/**\n * Build the ESLint visitor that hands each *whole* SQL statement to `handler`\n * exactly once, along with the node to report on.\n *\n * ESLint traverses parents before children, so a composite node (a\n * `+`-concatenation or a joined fragment array) is seen first and marks its\n * string descendants consumed — the fragments are never re-reported on their own.\n */\nexport function createSqlListener(\n handler: (sql: string, node: TSESTree.Node) => void,\n): TSESLint.RuleListener {\n const consumed = new WeakSet<TSESTree.Node>();\n\n const visit = (node: TSESTree.Node): void => {\n if (consumed.has(node)) {\n return;\n }\n const text = sqlTextOf(node);\n if (text === null) {\n return;\n }\n markConsumed(node, consumed);\n handler(stripSqlNoise(text), node);\n };\n\n return {\n BinaryExpression: (node: TSESTree.BinaryExpression): void => {\n visit(node);\n },\n ArrayExpression: (node: TSESTree.ArrayExpression): void => {\n if (isJoinedFragmentArray(node)) {\n visit(node);\n }\n },\n TemplateLiteral: (node: TSESTree.TemplateLiteral): void => {\n visit(node);\n },\n Literal: (node: TSESTree.Literal): void => {\n visit(node);\n },\n };\n}\n","/**\n * @fileoverview TS port of SARJ026 (`prefer-namedtuple-over-tuple-return`). A\n * multi-field value returned across a module boundary should be an object with\n * named fields, not a positional tuple the caller has to unpack by position.\n *\n * `export async function fetchDoc(): Promise<[string, Headers, string | null]>`\n * forces every call site to remember which slot is which, and the names live\n * only in the destructuring at the call site — so two call sites can and do\n * disagree. Returning `{ body, headers, contentType }` names each field once, at\n * the definition, and a wrong-field access becomes a type error instead of a\n * silently wrong value.\n *\n * Fires on an *exported* function (or exported class method) whose declared\n * return type is a tuple of two or more elements — directly or wrapped in\n * `Promise<...>`.\n *\n * The permitted tuple uses are deliberately NOT flagged, matching the Python\n * rule's tuning plus the TS-specific idioms:\n *\n * - **Homogeneous tuples** — `[number, number]`, `[Date, Date]`: a pair of the\n * same thing (a range, a coordinate), not distinct fields.\n * - **Variadic tuples** — `[string, ...number[]]`: an immutable sequence, not a\n * fixed record.\n * - **Labeled tuple members** — `[status: number, body: string]`: TypeScript\n * surfaces those names at the call site, which is the whole point of the rule.\n * - **Discriminated tags** — `[\"ok\", T]` with a literal first element: the tuple\n * IS the discriminated union.\n * - **React hooks** — any `use*` function. `[value, setValue]` is the\n * established contract of the entire hooks ecosystem; renaming at the call\n * site is the intended affordance, not a hazard.\n * - Single-element tuples, unannotated returns, and non-exported helpers, whose\n * two or three call sites live in the same file as the definition.\n */\n\nimport { AST_NODE_TYPES, ESLintUtils, type TSESTree } from \"@typescript-eslint/utils\";\n\ntype MessageIds = \"noPositionalTupleReturn\";\ntype Options = readonly [];\n\nconst MIN_ELEMENTS = 2;\n\n/** Type wrappers whose single type argument is the value actually returned. */\nconst AWAITABLE_TYPES: ReadonlySet<string> = new Set([\"Promise\", \"PromiseLike\", \"Awaited\"]);\n\n/** The tuple type a return annotation resolves to, unwrapping `Promise<...>`. */\nfunction tupleReturnType(node: TSESTree.TypeNode): TSESTree.TSTupleType | null {\n if (node.type === AST_NODE_TYPES.TSTupleType) {\n return node;\n }\n if (\n node.type === AST_NODE_TYPES.TSTypeReference &&\n node.typeName.type === AST_NODE_TYPES.Identifier &&\n AWAITABLE_TYPES.has(node.typeName.name)\n ) {\n const argument = node.typeArguments?.params[0];\n return argument === undefined ? null : tupleReturnType(argument);\n }\n return null;\n}\n\n/** Source text with all whitespace runs collapsed, for structural comparison. */\nfunction normalizedText(sourceCode: { getText: (node: TSESTree.Node) => string }, node: TSESTree.Node): string {\n return sourceCode.getText(node).replaceAll(/\\s+/g, \" \").trim();\n}\n\n/**\n * True when the tuple is one of the permitted shapes: variadic, labeled, tagged\n * by a leading literal type, or structurally homogeneous.\n */\nfunction isPermittedTuple(\n tuple: TSESTree.TSTupleType,\n sourceCode: { getText: (node: TSESTree.Node) => string },\n): boolean {\n const elements = tuple.elementTypes;\n if (elements.length < MIN_ELEMENTS) {\n return true;\n }\n if (elements.some((element) => element.type === AST_NODE_TYPES.TSRestType)) {\n return true;\n }\n if (elements.some((element) => element.type === AST_NODE_TYPES.TSNamedTupleMember)) {\n return true;\n }\n if (elements[0]?.type === AST_NODE_TYPES.TSLiteralType) {\n return true;\n }\n const texts = new Set(elements.map((element) => normalizedText(sourceCode, element)));\n return texts.size === 1;\n}\n\n/** The declared name of a function-ish node, or null for an anonymous one. */\nfunction functionName(node: TSESTree.Node): string | null {\n if (node.type === AST_NODE_TYPES.FunctionDeclaration) {\n return node.id?.name ?? null;\n }\n const parent = node.parent;\n if (parent?.type === AST_NODE_TYPES.VariableDeclarator && parent.id.type === AST_NODE_TYPES.Identifier) {\n return parent.id.name;\n }\n if (\n (parent?.type === AST_NODE_TYPES.MethodDefinition ||\n parent?.type === AST_NODE_TYPES.PropertyDefinition ||\n parent?.type === AST_NODE_TYPES.Property) &&\n parent.key.type === AST_NODE_TYPES.Identifier\n ) {\n return parent.key.name;\n }\n return null;\n}\n\n/**\n * True when the function is reachable from outside the module — the boundary the\n * rule is about. Walks to the top-level statement that contains it and asks\n * whether that statement is exported.\n */\nfunction isExported(node: TSESTree.Node): boolean {\n for (let current: TSESTree.Node | undefined | null = node; current != null; current = current.parent) {\n const parent = current.parent;\n if (\n parent?.type === AST_NODE_TYPES.ExportNamedDeclaration ||\n parent?.type === AST_NODE_TYPES.ExportDefaultDeclaration\n ) {\n return true;\n }\n }\n return false;\n}\n\nexport default ESLintUtils.RuleCreator(\n (name) =>\n `https://github.com/sarj-ai/standards/blob/main/packages/typescript/src/rules/${name}.ts`,\n)<Options, MessageIds>({\n name: \"no-positional-tuple-return\",\n meta: {\n type: \"suggestion\",\n docs: {\n description:\n \"Disallow returning a positional tuple of distinct fields from an exported function; return a named object so call sites cannot mismatch slots.\",\n },\n schema: [],\n messages: {\n noPositionalTupleReturn:\n \"Exported `{{name}}` returns a positional {{count}}-tuple, so every call site re-invents the field names and can disagree. Return a named object (or label the tuple members) instead.\",\n },\n },\n defaultOptions: [],\n create(context) {\n const check = (\n node:\n | TSESTree.FunctionDeclaration\n | TSESTree.FunctionExpression\n | TSESTree.ArrowFunctionExpression,\n ): void => {\n const annotation = node.returnType?.typeAnnotation;\n if (annotation === undefined) {\n return;\n }\n const tuple = tupleReturnType(annotation);\n if (tuple === null || isPermittedTuple(tuple, context.sourceCode)) {\n return;\n }\n const name = functionName(node);\n if (name === null || name.startsWith(\"_\") || /^use[A-Z]/.test(name)) {\n return;\n }\n if (!isExported(node)) {\n return;\n }\n context.report({\n node: tuple,\n messageId: \"noPositionalTupleReturn\",\n data: { name, count: String(tuple.elementTypes.length) },\n });\n };\n return {\n FunctionDeclaration: check,\n FunctionExpression: check,\n ArrowFunctionExpression: check,\n };\n },\n});\n","/**\n * @fileoverview TS port of SARJ024 (`no-repeated-string-literal`). The same long,\n * *structured* string repeated three or more times across two or more functions\n * of a module is a real maintenance hazard: when one copy is edited the others\n * silently drift. A column list that gains a column in the read query but not in\n * the upsert, or a prompt template updated in one branch only, fails at runtime\n * and nowhere else.\n *\n * The rule is deliberately narrow — it fires only where cross-site drift is a\n * genuine bug, never on coincidentally-equal prose. Three filters combine:\n *\n * 1. **Structured only.** A literal qualifies only if it carries structural\n * signal that makes coincidental equality near-impossible: it contains a\n * newline (multi-line SQL / prompt templates), it matches an *uppercase* SQL\n * keyword (`SELECT`, `FROM`, `ON CONFLICT`, ...) — matched case-sensitively so\n * English prose does not trip it, only real SQL does — or it is a bare\n * snake_case / dotted identifier, i.e. a constraint / index / column-list name\n * reused across statements. Plain user-facing messages and log lines carry\n * none of these, so two same-text-different-intent messages are never coupled\n * into one shared constant.\n * 2. **Cross-function only.** Occurrences must span at least two distinct\n * enclosing functions. Two uses inside one function are edited together and\n * hoisting them buys no drift protection — that is pure locality loss.\n * 3. **Exclusions.** Template literals *with* substitutions (the f-string\n * analogue — each fragment is half a sentence, not a reusable value), import\n * and `require` sources, JSX attribute values (a repeated Tailwind class list\n * is `no-duplicate-class-names` territory, not a drift bug), and test files,\n * where fixtures legitimately repeat literal payloads.\n *\n * A substitution-free template literal IS included: in TypeScript that is just a\n * multi-line string, and it is exactly where embedded SQL lives.\n *\n * Every occurrence after the first is reported, so a deliberate duplicate can be\n * disabled on its own line.\n */\n\nimport { AST_NODE_TYPES, ESLintUtils, type TSESTree } from \"@typescript-eslint/utils\";\n\nimport { isTestFile } from \"./_paths.js\";\n\ntype MessageIds = \"noRepeatedStringLiteral\";\ntype Options = readonly [];\n\nconst MIN_LENGTH = 40;\nconst MIN_OCCURRENCES = 3;\nconst MIN_DISTINCT_SCOPES = 2;\nconst PREVIEW_LENGTH = 40;\n\n/** Case-sensitive on purpose: uppercase keywords mean SQL, lowercase means prose. */\nconst SQL_KEYWORD_RE =\n /\\b(SELECT|INSERT|UPDATE|DELETE|FROM|WHERE|JOIN|VALUES|ON CONFLICT|RETURNING|GROUP BY|ORDER BY)\\b/;\nconst IDENTIFIER_RE = /^[a-z_][a-z0-9_.]*$/;\n\nconst FUNCTION_TYPES: ReadonlySet<AST_NODE_TYPES> = new Set([\n AST_NODE_TYPES.FunctionDeclaration,\n AST_NODE_TYPES.FunctionExpression,\n AST_NODE_TYPES.ArrowFunctionExpression,\n]);\n\n/** True when the literal carries structure that rules out coincidental equality. */\nfunction isStructured(value: string): boolean {\n return value.includes(\"\\n\") || SQL_KEYWORD_RE.test(value) || IDENTIFIER_RE.test(value);\n}\n\nfunction preview(value: string): string {\n const oneLine = value.replaceAll(\"\\n\", \" \").trim();\n return oneLine.length <= PREVIEW_LENGTH ? oneLine : `${oneLine.slice(0, PREVIEW_LENGTH)}...`;\n}\n\n/** The enclosing function node, or null when the literal sits at module/class scope. */\nfunction enclosingFunction(node: TSESTree.Node): TSESTree.Node | null {\n for (let current = node.parent; current != null; current = current.parent) {\n if (FUNCTION_TYPES.has(current.type)) {\n return current;\n }\n }\n return null;\n}\n\n/**\n * True when the literal is scaffolding rather than a reusable value: an\n * import/`require` source (repeating a module path is the point) or a JSX\n * attribute value (styling strings, handled by the styling rules).\n */\nfunction isScaffolding(node: TSESTree.Node): boolean {\n const parent = node.parent;\n if (parent === undefined) {\n return true;\n }\n return (\n parent.type === AST_NODE_TYPES.ImportDeclaration ||\n parent.type === AST_NODE_TYPES.ExportNamedDeclaration ||\n parent.type === AST_NODE_TYPES.ExportAllDeclaration ||\n parent.type === AST_NODE_TYPES.TSImportType ||\n parent.type === AST_NODE_TYPES.JSXAttribute ||\n parent.type === AST_NODE_TYPES.TSLiteralType\n );\n}\n\nexport default ESLintUtils.RuleCreator(\n (name) =>\n `https://github.com/sarj-ai/standards/blob/main/packages/typescript/src/rules/${name}.ts`,\n)<Options, MessageIds>({\n name: \"no-repeated-string-literal\",\n meta: {\n type: \"suggestion\",\n docs: {\n description:\n \"Disallow a long structured string literal repeated across functions; the copies drift when one is edited. Extract a module-level constant.\",\n },\n schema: [],\n messages: {\n noRepeatedStringLiteral:\n 'Structured string literal \"{{preview}}\" is repeated across functions (first use on line {{line}}) — extract a module-level constant so the copies cannot drift.',\n },\n },\n defaultOptions: [],\n create(context) {\n if (isTestFile(context.filename)) {\n return {};\n }\n const occurrences = new Map<string, TSESTree.Node[]>();\n const scopes = new WeakMap<TSESTree.Node, TSESTree.Node | null>();\n\n const record = (value: string, node: TSESTree.Node): void => {\n if (value.length < MIN_LENGTH || !isStructured(value) || isScaffolding(node)) {\n return;\n }\n const existing = occurrences.get(value);\n if (existing === undefined) {\n occurrences.set(value, [node]);\n } else {\n existing.push(node);\n }\n scopes.set(node, enclosingFunction(node));\n };\n\n return {\n Literal(node: TSESTree.Literal): void {\n if (typeof node.value === \"string\") {\n record(node.value, node);\n }\n },\n TemplateLiteral(node: TSESTree.TemplateLiteral): void {\n const [only] = node.quasis;\n if (node.expressions.length === 0 && only !== undefined) {\n record(only.value.cooked ?? only.value.raw, node);\n }\n },\n \"Program:exit\": (): void => {\n for (const [value, nodes] of occurrences) {\n if (nodes.length < MIN_OCCURRENCES) {\n continue;\n }\n const distinctScopes = new Set(\n nodes.map((node) => scopes.get(node)).filter((scope) => scope != null),\n );\n if (distinctScopes.size < MIN_DISTINCT_SCOPES) {\n continue;\n }\n const [first, ...repeats] = nodes;\n if (first === undefined) {\n continue;\n }\n for (const node of repeats) {\n context.report({\n node,\n messageId: \"noRepeatedStringLiteral\",\n data: { preview: preview(value), line: String(first.loc.start.line) },\n });\n }\n }\n },\n };\n },\n});\n","/**\n * @fileoverview TS port of SARJ021 (`no-select-star`). `SELECT *` over-fetches\n * every column (including large JSON/text blobs the caller never reads) and,\n * more importantly, makes the row shape implicit: the moment a column is added,\n * renamed, or reordered, the zod schema that parses the row starts failing — or\n * worse, silently accepts extra keys — and nothing in the query says which\n * columns the code actually depends on. Naming the columns makes the dependency\n * explicit and pins the row contract at the query.\n *\n * The rule reads statically-resolvable SQL strings (literals, template literals,\n * `+` concatenations, `[...].join(\" \")` fragment arrays), neutralizes string\n * values and `--` / comment bodies first (so a `'*'` value is never mistaken for\n * a star), and flags a query — a string with a real `SELECT ... FROM` shape —\n * whose projection list holds a `*` in any position: bare (`SELECT *`,\n * `SELECT id, *`) or qualified (`c.*`, `main.runs.*`).\n *\n * Deliberately NOT flagged, matching the Python rule's tuning:\n * - `COUNT(*)` and other aggregate stars — the star is a function argument, not\n * a projection.\n * - `a * b` arithmetic — an operand follows the star.\n * - `EXISTS (SELECT * ...)` — the projection is unused by definition.\n * - Prose that merely contains the words \"select\" and \"from\".\n * - Test files, where a `SELECT *` assertion over a fixture table is fine.\n */\n\nimport { ESLintUtils, type TSESTree } from \"@typescript-eslint/utils\";\n\nimport { isTestFile } from \"./_paths.js\";\nimport { createSqlListener } from \"./_sql.js\";\n\ntype MessageIds = \"noSelectStar\";\ntype Options = readonly [];\n\n/** A real SQL query shape, so prose containing the bare word \"from\" isn't matched. */\nconst QUERY_SHAPE = /\\bSELECT\\b[\\s\\S]*?\\bFROM\\b/i;\nconst SELECT_KEYWORD = /\\bSELECT\\b/gi;\nconst FROM_KEYWORD = /^FROM\\b/i;\nconst EXISTS_BEFORE = /\\bEXISTS\\s*\\(\\s*$/i;\n/** A `word.` immediately preceding a `*` marks a qualified star (`c.*`, `main.runs.*`). */\nconst QUALIFIED_PREFIX = /\\w\\.$/;\n\n/** Cheap substring gate; a file with no star and no SELECT can never produce a finding. */\nconst SELECT_GATE = /select/i;\n\n/**\n * True when the `*` at `pos` is a column-projection star.\n *\n * A projection star expands columns: bare (`SELECT *`, `id, *`) or qualified\n * (`c.*`). It is NOT a `COUNT(*)` argument (parenthesised on both sides) nor an\n * `a * b` multiply (an operand follows rather than a terminator).\n */\nfunction isProjectionStar(sql: string, pos: number): boolean {\n if (QUALIFIED_PREFIX.test(sql.slice(0, pos))) {\n return true;\n }\n let before = pos - 1;\n while (before >= 0 && /\\s/.test(sql[before] ?? \"\")) {\n before -= 1;\n }\n let after = pos + 1;\n while (after < sql.length && /\\s/.test(sql[after] ?? \"\")) {\n after += 1;\n }\n const beforeChar = before >= 0 ? (sql[before] ?? \"\") : \"\";\n const afterChar = after < sql.length ? (sql[after] ?? \"\") : \"\";\n const terminates =\n afterChar === \"\" || afterChar === \",\" || afterChar === \")\" || FROM_KEYWORD.test(sql.slice(after));\n if (!terminates) {\n return false;\n }\n return !(beforeChar === \"(\" && afterChar === \")\");\n}\n\n/** True when the query projects a star that is not inside an `EXISTS (...)` subquery. */\nfunction hasRealSelectStar(sql: string): boolean {\n const selects = [...sql.matchAll(SELECT_KEYWORD)].map((m) => m.index);\n for (let pos = 0; pos < sql.length; pos++) {\n if (sql[pos] !== \"*\" || !isProjectionStar(sql, pos)) {\n continue;\n }\n const owning = selects.filter((start) => start < pos).at(-1);\n if (owning !== undefined && !EXISTS_BEFORE.test(sql.slice(0, owning))) {\n return true;\n }\n }\n return false;\n}\n\nexport default ESLintUtils.RuleCreator(\n (name) =>\n `https://github.com/sarj-ai/standards/blob/main/packages/typescript/src/rules/${name}.ts`,\n)<Options, MessageIds>({\n name: \"no-select-star\",\n meta: {\n type: \"problem\",\n docs: {\n description:\n \"Disallow SELECT * in embedded SQL; it over-fetches and leaves the row contract implicit, so a schema change breaks row parsing silently.\",\n },\n schema: [],\n messages: {\n noSelectStar:\n \"`SELECT *` over-fetches and leaves the row shape implicit — a new or reordered column silently changes what this query returns. List the columns explicitly.\",\n },\n },\n defaultOptions: [],\n create(context) {\n if (isTestFile(context.filename) || !SELECT_GATE.test(context.sourceCode.text)) {\n return {};\n }\n return createSqlListener((sql: string, node: TSESTree.Node): void => {\n if (!QUERY_SHAPE.test(sql) || !hasRealSelectStar(sql)) {\n return;\n }\n context.report({ node, messageId: \"noSelectStar\" });\n });\n },\n});\n","/**\n * @fileoverview TS port of SARJ031 (`no-sleep-in-test-body`). A real timed sleep\n * placed directly in a test body — `await new Promise((r) => setTimeout(r, 50))`\n * or `await sleep(200)` — is the canonical flaky-test pattern. The delay is a\n * guess about how long some other work takes: too short and the test fails on a\n * loaded CI runner, too long and every run pays for it. Either way the test is\n * asserting on wall-clock time rather than on the signal it actually cares about.\n *\n * The fix is to synchronize on the signal: await the promise the code returns,\n * await the flushed microtask queue, or drive time deterministically with\n * `vi.useFakeTimers()` + `await vi.advanceTimersByTimeAsync(ms)`, which makes the\n * elapsed time exact and the test instant.\n *\n * Fires only on the exact shape:\n *\n * - `new Promise(...)` whose executor body is a `setTimeout(resolve, <n>)`, or a\n * call to a bare `sleep`/`delay`/`wait`/`pause` helper, where\n * - the delay is a **nonzero numeric literal** — `setTimeout(r, 0)` is a\n * macrotask yield used to flush the event loop, not a timing guess, and a\n * non-literal `sleep(configuredDelay)` is a deliberate parameterised wait, and\n * - the **nearest enclosing function is the callback of an `it`/`test`** (any\n * `.only`/`.skip`/`.each` variant) or of a `beforeEach`/`afterEach` hook.\n *\n * The nearest-enclosing-function gate is the critical false-positive guard, and\n * it is ported deliberately: a sleep inside a nested helper or fake declared\n * within the test (`const slowFetch = async () => { await sleep(50); ... }`) is\n * *simulating* latency in order to exercise a timeout or cancellation path. That\n * is the intended use of a delay in a test, not a flaky synchronization, and it\n * must not fire. Because the check keys off the nearest enclosing function, such\n * a helper is excluded automatically. The `new Promise` executor arrow is not\n * treated as an enclosing function — it is part of the sleep idiom itself.\n *\n * Applies only in test files.\n */\n\nimport { AST_NODE_TYPES, ESLintUtils, type TSESTree } from \"@typescript-eslint/utils\";\n\nimport { isTestFile } from \"./_paths.js\";\n\ntype MessageIds = \"noSleepInTestBody\";\ntype Options = readonly [];\n\n/** Free-function sleep helpers. A `sleep(50)` reads as a sleep whatever its module. */\nconst SLEEP_HELPERS: ReadonlySet<string> = new Set([\"sleep\", \"delay\", \"wait\", \"pause\"]);\n\n/** Test-case and per-test-hook callers whose callback body is \"the test body\". */\nconst TEST_CALLERS: ReadonlySet<string> = new Set([\n \"it\",\n \"test\",\n \"beforeEach\",\n \"afterEach\",\n]);\n\nconst FUNCTION_TYPES: ReadonlySet<AST_NODE_TYPES> = new Set([\n AST_NODE_TYPES.FunctionDeclaration,\n AST_NODE_TYPES.FunctionExpression,\n AST_NODE_TYPES.ArrowFunctionExpression,\n]);\n\n/** True for a nonzero numeric literal — the timing guess, as opposed to a `0` yield. */\nfunction isNonzeroNumericLiteral(node: TSESTree.Node | undefined): boolean {\n return node?.type === AST_NODE_TYPES.Literal && typeof node.value === \"number\" && node.value !== 0;\n}\n\n/** True when `node` is `setTimeout(<anything>, <nonzero literal>)`. */\nfunction isTimedSetTimeout(node: TSESTree.Node): boolean {\n return (\n node.type === AST_NODE_TYPES.CallExpression &&\n node.callee.type === AST_NODE_TYPES.Identifier &&\n node.callee.name === \"setTimeout\" &&\n node.arguments.length >= 2 &&\n isNonzeroNumericLiteral(node.arguments[1])\n );\n}\n\n/**\n * True when `node` is `new Promise((r) => setTimeout(r, n))` — including the\n * block-bodied `{ setTimeout(r, n); }` spelling.\n */\nfunction isPromiseSleep(node: TSESTree.NewExpression): boolean {\n if (node.callee.type !== AST_NODE_TYPES.Identifier || node.callee.name !== \"Promise\") {\n return false;\n }\n const executor = node.arguments[0];\n if (\n executor?.type !== AST_NODE_TYPES.ArrowFunctionExpression &&\n executor?.type !== AST_NODE_TYPES.FunctionExpression\n ) {\n return false;\n }\n const body = executor.body;\n if (body.type !== AST_NODE_TYPES.BlockStatement) {\n return isTimedSetTimeout(body);\n }\n return body.body.some(\n (stmt) => stmt.type === AST_NODE_TYPES.ExpressionStatement && isTimedSetTimeout(stmt.expression),\n );\n}\n\n/** True when `node` is `sleep(n)` / `delay(n)` with a nonzero numeric literal. */\nfunction isHelperSleep(node: TSESTree.CallExpression): boolean {\n return (\n node.callee.type === AST_NODE_TYPES.Identifier &&\n SLEEP_HELPERS.has(node.callee.name) &&\n node.arguments.length >= 1 &&\n isNonzeroNumericLiteral(node.arguments[0])\n );\n}\n\n/** The nearest enclosing function of `node`, skipping the `new Promise` executor. */\nfunction nearestEnclosingFunction(node: TSESTree.Node): TSESTree.Node | null {\n for (let current = node.parent; current != null; current = current.parent) {\n if (!FUNCTION_TYPES.has(current.type)) {\n continue;\n }\n const grandparent = current.parent;\n const isPromiseExecutor =\n grandparent?.type === AST_NODE_TYPES.NewExpression && isPromiseSleep(grandparent);\n if (!isPromiseExecutor) {\n return current;\n }\n }\n return null;\n}\n\n/** The base callee name of a call, unwrapping `.only` / `.skip` / `.each` chains. */\nfunction testCallerName(callee: TSESTree.Node): string | null {\n if (callee.type === AST_NODE_TYPES.Identifier) {\n return callee.name;\n }\n if (callee.type === AST_NODE_TYPES.MemberExpression) {\n return testCallerName(callee.object);\n }\n if (callee.type === AST_NODE_TYPES.CallExpression) {\n return testCallerName(callee.callee);\n }\n if (callee.type === AST_NODE_TYPES.TaggedTemplateExpression) {\n return testCallerName(callee.tag);\n }\n return null;\n}\n\n/** True when `fn` is the callback argument of an `it`/`test`/per-test-hook call. */\nfunction isTestBody(fn: TSESTree.Node): boolean {\n const call = fn.parent;\n if (\n call?.type !== AST_NODE_TYPES.CallExpression ||\n !call.arguments.some((argument) => argument === fn)\n ) {\n return false;\n }\n const name = testCallerName(call.callee);\n return name !== null && TEST_CALLERS.has(name);\n}\n\nexport default ESLintUtils.RuleCreator(\n (name) =>\n `https://github.com/sarj-ai/standards/blob/main/packages/typescript/src/rules/${name}.ts`,\n)<Options, MessageIds>({\n name: \"no-sleep-in-test-body\",\n meta: {\n type: \"problem\",\n docs: {\n description:\n \"Disallow a fixed timed sleep directly in a test body; it flakes under CI load. Synchronize on the signal or use fake timers.\",\n },\n schema: [],\n messages: {\n noSleepInTestBody:\n \"A fixed sleep in a test body asserts on wall-clock time and flakes under CI load. Await the promise the code returns, or drive time with `vi.useFakeTimers()` + `await vi.advanceTimersByTimeAsync(ms)`.\",\n },\n },\n defaultOptions: [],\n create(context) {\n if (!isTestFile(context.filename)) {\n return {};\n }\n const report = (node: TSESTree.Node): void => {\n const enclosing = nearestEnclosingFunction(node);\n if (enclosing === null || !isTestBody(enclosing)) {\n return;\n }\n context.report({ node, messageId: \"noSleepInTestBody\" });\n };\n return {\n NewExpression(node: TSESTree.NewExpression): void {\n if (isPromiseSleep(node)) {\n report(node);\n }\n },\n CallExpression(node: TSESTree.CallExpression): void {\n if (isHelperSleep(node)) {\n report(node);\n }\n },\n };\n },\n});\n","/**\n * @fileoverview TS port of SARJ011 (`prefer-constant-time-secret-compare`).\n * Comparing secrets (bearer tokens, signatures, HMACs, password hashes, API\n * keys) with `===`/`!==`/`==`/`!=` is timing-attack-prone: the engine's string\n * comparison short-circuits on the first differing byte, so the time it takes to\n * return `false` leaks how many leading bytes the attacker got right. Over enough\n * requests that is enough to recover the secret byte by byte.\n *\n * On Cloudflare Workers the correct primitive is `crypto.subtle.timingSafeEqual`\n * (over equal-length `ArrayBuffer`s — SHA-256 both sides first so the lengths\n * match and no length is leaked), or a hand-rolled XOR-accumulate loop over the\n * digests. Node exposes `crypto.timingSafeEqual`. `===` is never the answer.\n *\n * The secret-name predicate is shared with `no-secret-in-log` and then narrowed\n * (`isAuthSecretName`): a timing-attack surface is only an *authenticator* whose\n * bytes gate access, so the following are deliberately NOT flagged even though\n * they are secret-shaped by name:\n *\n * - Category / handle metadata: `tokenType === \"Bearer\"`, `tokenName`,\n * `credentialKind`, `apiKeyId` — a discriminator or row id, not the credential.\n * - Boolean flags: `isTokenValid`, `hasSecret` — a decision, not the bytes.\n * - Integrity-only content hashes: `contentHash === previousHash` — a change\n * detector, not an authenticator. `passwordHash` / `tokenHash` still fire\n * because those DO gate access.\n * - Presence checks and literal sentinels: `token === null`, `secret !== undefined`,\n * `token.length === 0`, `tokenType === \"bearer\"`, `x === TOKEN_TYPE_SYSTEM` —\n * comparing against a compile-time constant or a null check reveals nothing\n * about a runtime secret.\n * - Anything in a test file: no attacker measures a test's clock, and fixture\n * assertions (`expect(res.apiKey === \"known\")`) are not an auth path.\n *\n * References:\n * - https://developers.cloudflare.com/workers/runtime-apis/web-crypto/#timingsafeequal\n * - https://codahale.com/a-lesson-in-timing-attacks/\n */\n\nimport { AST_NODE_TYPES, ESLintUtils, type TSESTree } from \"@typescript-eslint/utils\";\n\nimport { isAuthSecretName } from \"./_secret_names.js\";\nimport { isTestFile } from \"./_paths.js\";\n\ntype MessageIds = \"preferConstantTimeSecretCompare\";\ntype Options = readonly [];\n\nconst EQUALITY_OPERATORS: ReadonlySet<string> = new Set([\"===\", \"!==\", \"==\", \"!=\"]);\n\n/**\n * Identifiers that are compile-time sentinels rather than runtime values.\n * `undefined`/`NaN` make the comparison a presence check; an ALL-CAPS name is a\n * named constant or enum member (`TOKEN_TYPE_SYSTEM`), and timing a compare\n * against a value the attacker already knows leaks nothing.\n */\nconst SENTINEL_IDENTIFIERS: ReadonlySet<string> = new Set([\"undefined\", \"NaN\"]);\n\n/**\n * Words that mark a secret-SHAPED name as a placeholder rather than a live\n * credential: `TOKEN_SENTINEL`, `EMPTY_SECRET`, `PLACEHOLDER_API_KEY`. Comparing\n * against one of these is a presence check, not an authentication check, so it\n * stays excluded even though the secret-name heuristics match it.\n */\nconst SENTINEL_WORDS = /(^|_)(SENTINEL|EMPTY|NONE|NULL|UNSET|MISSING|PLACEHOLDER|DUMMY|FAKE|EXAMPLE)(_|$)/;\n\n/**\n * True when every cased character is upper-case and at least one letter exists —\n * AND the name is not itself secret-shaped.\n *\n * The ALL-CAPS carve-out exists for public named constants (`TOKEN_TYPE_SYSTEM`).\n * But environment secrets are conventionally SCREAMING_SNAKE too\n * (`ADMIN_TOKEN`, `ASHBY_API_KEY`, `SLACK_SIGNING_SECRET`), so an unqualified\n * ALL-CAPS bail-out made this rule blind to essentially every real secret\n * compare: `env.ADMIN_TOKEN === supplied` was silent while the camelCase\n * `env.adminToken === supplied` fired. That is the exact comparison this rule\n * exists to catch. Defer to the shared secret-name heuristics first.\n */\nfunction isConstantReference(identifier: string): boolean {\n if (isAuthSecretName(identifier) && !SENTINEL_WORDS.test(identifier)) return false;\n return identifier === identifier.toUpperCase() && /[A-Za-z]/.test(identifier);\n}\n\n/**\n * True when this operand makes the comparison a non-timing-attack surface:\n * any literal (string / number / boolean / null / regex), a template literal\n * with no substitutions, `undefined`/`NaN`, or an ALL-CAPS constant reference.\n */\nfunction isExcludedOperand(node: TSESTree.Node): boolean {\n switch (node.type) {\n case AST_NODE_TYPES.Literal:\n return true;\n case AST_NODE_TYPES.TemplateLiteral:\n return node.expressions.length === 0;\n case AST_NODE_TYPES.Identifier:\n return SENTINEL_IDENTIFIERS.has(node.name) || isConstantReference(node.name);\n case AST_NODE_TYPES.MemberExpression:\n return (\n !node.computed &&\n node.property.type === AST_NODE_TYPES.Identifier &&\n isConstantReference(node.property.name)\n );\n default:\n return false;\n }\n}\n\n/** The identifier a plain operand denotes, or null for anything else. */\nfunction operandName(node: TSESTree.Node): string | null {\n if (node.type === AST_NODE_TYPES.Identifier) {\n return node.name;\n }\n if (\n node.type === AST_NODE_TYPES.MemberExpression &&\n !node.computed &&\n node.property.type === AST_NODE_TYPES.Identifier\n ) {\n return node.property.name;\n }\n return null;\n}\n\n/**\n * True when the operand names an authenticator worth a constant-time compare.\n *\n * A template literal counts when it interpolates one: `header === \\`Bearer\n * ${adminToken}\\`` is the canonical Workers auth check and is exactly as\n * timing-leaky as comparing the bare token, since the constant prefix only makes\n * the first bytes free.\n */\nfunction isSecretOperand(node: TSESTree.Node): boolean {\n if (node.type === AST_NODE_TYPES.TemplateLiteral) {\n return node.expressions.some((expression) => isSecretOperand(expression));\n }\n const name = operandName(node);\n return name !== null && isAuthSecretName(name);\n}\n\n/** The secret identifier this comparison exposes, for the diagnostic message. */\nfunction secretNameOf(node: TSESTree.Node): string | null {\n if (node.type === AST_NODE_TYPES.TemplateLiteral) {\n for (const expression of node.expressions) {\n const nested = secretNameOf(expression);\n if (nested !== null) {\n return nested;\n }\n }\n return null;\n }\n return operandName(node);\n}\n\nexport default ESLintUtils.RuleCreator(\n (name) =>\n `https://github.com/sarj-ai/standards/blob/main/packages/typescript/src/rules/${name}.ts`,\n)<Options, MessageIds>({\n name: \"prefer-constant-time-secret-compare\",\n meta: {\n type: \"problem\",\n docs: {\n description:\n \"Disallow `===`/`!==` on a secret-like value; short-circuiting comparison leaks the secret through timing. Use a constant-time compare.\",\n },\n schema: [],\n messages: {\n preferConstantTimeSecretCompare:\n \"`{{operator}}` on secret `{{name}}` short-circuits on the first differing byte and leaks it through timing. Compare constant-time instead (`crypto.subtle.timingSafeEqual` over equal-length SHA-256 digests).\",\n },\n },\n defaultOptions: [],\n create(context) {\n if (isTestFile(context.filename)) {\n return {};\n }\n return {\n BinaryExpression(node: TSESTree.BinaryExpression): void {\n if (!EQUALITY_OPERATORS.has(node.operator)) {\n return;\n }\n const { left, right } = node;\n if (isExcludedOperand(left) || isExcludedOperand(right)) {\n return;\n }\n const secret = [left, right].find((operand) => isSecretOperand(operand));\n if (secret === undefined) {\n return;\n }\n context.report({\n node,\n messageId: \"preferConstantTimeSecretCompare\",\n data: { operator: node.operator, name: secretNameOf(secret) ?? \"\" },\n });\n },\n };\n },\n});\n","/**\n * @fileoverview TS port of SARJ018 (`store-insert-requires-on-conflict`).\n * An embedded `INSERT INTO ... VALUES/SELECT` with no conflict clause must\n * become an idempotent upsert.\n *\n * Store write paths run under retries, races, and replays — and on Cloudflare\n * Workers that is the *normal* case, not the exception: a cron trigger can fire\n * twice, a Queue message is redelivered on any handler throw, and a `waitUntil`\n * task can be retried after the response is already sent. A bare `INSERT` under\n * redelivery either duplicates rows (a second Slack post, a second email, a\n * double-counted referral) or throws on a unique-constraint violation, which\n * fails the handler, which triggers another redelivery. Every store write should\n * be `INSERT ... ON CONFLICT ... DO UPDATE` / `DO NOTHING` so replay is a no-op.\n *\n * The rule reads every statically-resolvable SQL string in the file — plain\n * literals, template literals (`${...}` becomes a `?` parameter marker), `+`\n * concatenations, and `[...].join(\" \")` fragment arrays — and flags one that\n * contains a genuine `INSERT INTO ... VALUES` / `... SELECT` write with no\n * conflict handling. SQL string-literal values and `--` / comment bodies are\n * neutralized first, so an `ON CONFLICT` living inside a quoted value never\n * excuses a bare insert, a `--` inside a value never eats a real clause, and\n * commented-out keywords neither trigger nor excuse a finding.\n *\n * Deliberately NOT flagged:\n * - SQLite/D1's own idempotent insert forms: `INSERT OR IGNORE INTO ...` and\n * `INSERT OR REPLACE INTO ...` already survive replay.\n * - MySQL's `ON DUPLICATE KEY UPDATE`, the same contract under another name.\n * - Pure reads, DDL, and `RETURNING`-only tails.\n * - Test files. A fresh in-memory D1 has nothing to conflict with, so fixture\n * seeding legitimately uses a bare `INSERT`; flagging it would train people to\n * ignore the rule.\n *\n * For a deliberate append-only write (an event/audit log where duplicates are\n * the point) disable with an inline `eslint-disable-next-line` and a reason.\n */\n\nimport { ESLintUtils, type TSESTree } from \"@typescript-eslint/utils\";\n\nimport { isTestFile } from \"./_paths.js\";\nimport { createSqlListener } from \"./_sql.js\";\n\ntype MessageIds = \"storeInsertRequiresOnConflict\";\ntype Options = readonly [];\n\n/**\n * A real insert *write*: the keyword, a table identifier, an optional column\n * list, then `VALUES` / `SELECT` / `DEFAULT VALUES` with nothing in between.\n * Requiring that exact adjacency is what keeps English prose out — \"failed to\n * insert into the queue: values were rejected\" has words between the table and\n * the verb, so it does not match. The optional `OR <action>` clause is SQLite's\n * conflict resolution; it is matched here so `INSERT OR IGNORE INTO` is\n * recognised as an insert at all, then excused below.\n */\nconst INSERT_WRITE =\n /\\bINSERT\\s+(?:OR\\s+\\w+\\s+)?INTO\\s+[\\w.\"'`?$:@-]+\\s*(?:\\([^)]*\\)\\s*)?(?:VALUES|SELECT|DEFAULT\\s+VALUES)\\b/i;\n\n/** Conflict handling that makes the write replay-safe. */\nconst CONFLICT_HANDLED = /\\bON\\s+CONFLICT\\b|\\bON\\s+DUPLICATE\\s+KEY\\b|\\bINSERT\\s+OR\\s+(?:IGNORE|REPLACE)\\b/i;\n\n/**\n * Cheap substring gate. Noise-stripping only ever blanks characters to spaces,\n * so it can never introduce a keyword the raw text lacks — a file with no\n * `insert` at all can never produce a finding, and most files in a repo sweep\n * are not SQL-bearing.\n */\nconst INSERT_GATE = /insert/i;\n\nexport default ESLintUtils.RuleCreator(\n (name) =>\n `https://github.com/sarj-ai/standards/blob/main/packages/typescript/src/rules/${name}.ts`,\n)<Options, MessageIds>({\n name: \"store-insert-requires-on-conflict\",\n meta: {\n type: \"problem\",\n docs: {\n description:\n \"Require an embedded SQL INSERT to carry ON CONFLICT; store writes replay under cron re-runs and queue redelivery and must be idempotent upserts.\",\n },\n schema: [],\n messages: {\n storeInsertRequiresOnConflict:\n \"This INSERT is not replay-safe: a cron re-run or queue redelivery duplicates the row (or fails the handler on a unique-constraint violation). Add `ON CONFLICT (...) DO UPDATE` / `DO NOTHING` (or `INSERT OR IGNORE`).\",\n },\n },\n defaultOptions: [],\n create(context) {\n if (isTestFile(context.filename) || !INSERT_GATE.test(context.sourceCode.text)) {\n return {};\n }\n return createSqlListener((sql: string, node: TSESTree.Node): void => {\n if (!INSERT_WRITE.test(sql) || CONFLICT_HANDLED.test(sql)) {\n return;\n }\n context.report({ node, messageId: \"storeInsertRequiresOnConflict\" });\n });\n },\n});\n","/**\n * @fileoverview Disallow building a SQL statement out of runtime values.\n *\n * `db.prepare(sql)` takes a STATIC statement plus `?` / `$1` placeholders bound\n * through `.bind(...)`. Interpolating a value into the statement text bypasses\n * the binding layer completely: that is SQL injection, and it also defeats the\n * driver's prepared-statement cache, because every distinct value produces a\n * distinct statement to compile. The shape is identical across Cloudflare D1,\n * better-sqlite3 and node-postgres, so the rule is driver-agnostic.\n *\n * WHAT IT CATCHES\n * db.prepare(`select * from users where id = '${userId}'`)\n * db.prepare(\"select * from users where id = '\" + userId + \"'\")\n * db.exec(`delete from sessions where token = '${token}'`)\n *\n * NOT FLAGGED\n * - `${CONSTANT_CASE}` fragments. A module-level constant — the column-list\n * constants several repos keep (`${CANDIDATE_COLS}`, `${TABLES.USERS}`) —\n * is a compile-time value, not user input. Anything starting lowercase is\n * treated as runtime data.\n * - A template literal with no interpolations at all.\n * - Tagged templates (`` sql`select ... ${id}` ``). A tag function receives the\n * static strings and the values separately and is the parameterising\n * mechanism, not a bypass of it.\n * - `.prepare()` on something that is not a database. Requiring an\n * interpolated runtime value keeps this rare in practice.\n *\n * CONFIGURATION\n * `methods` is the list of statement-taking method names to inspect. Extend it\n * for a driver that names things differently:\n *\n * \"@sarj/no-dynamic-sql\": [\"error\", { \"methods\": [\"prepare\", \"exec\", \"raw\"] }]\n *\n * Supplying `methods` REPLACES the defaults.\n */\n\nimport { AST_NODE_TYPES, ESLintUtils, type TSESTree } from \"@typescript-eslint/utils\";\n\ntype MessageIds = \"dynamicSql\";\n\nexport interface RuleOptions {\n /** Statement-taking method names to inspect. Replaces the defaults. */\n readonly methods?: readonly string[];\n}\n\ntype Options = readonly [RuleOptions?];\n\nconst DEFAULT_METHODS: readonly string[] = [\"prepare\", \"exec\", \"query\"];\n\n/** A module-level constant fragment: `CANDIDATE_COLS`, `TABLE_NAME`. */\nconst CONSTANT_CASE_RE = /^[A-Z][A-Z0-9_]*$/;\n\n/**\n * True when an interpolated expression is a compile-time SQL fragment rather\n * than runtime data: a CONSTANT_CASE identifier, a member access whose final\n * property is CONSTANT_CASE (`TABLES.USERS`), or a string literal.\n */\nfunction isStaticFragment(expression: TSESTree.Expression): boolean {\n if (expression.type === AST_NODE_TYPES.Identifier) {\n return CONSTANT_CASE_RE.test(expression.name);\n }\n if (\n expression.type === AST_NODE_TYPES.MemberExpression &&\n !expression.computed &&\n expression.property.type === AST_NODE_TYPES.Identifier\n ) {\n return CONSTANT_CASE_RE.test(expression.property.name);\n }\n if (expression.type === AST_NODE_TYPES.Literal) {\n return typeof expression.value === \"string\";\n }\n return false;\n}\n\n/** The interpolated runtime expressions in a template literal. */\nfunction runtimeInterpolations(\n template: TSESTree.TemplateLiteral,\n): TSESTree.Expression[] {\n return template.expressions.filter(\n (expression) => !isStaticFragment(expression),\n );\n}\n\n/**\n * Flatten a `+` chain into its operands. `\"a\" + b + \"c\"` yields three nodes so\n * each can be judged independently.\n */\nfunction concatOperands(node: TSESTree.Expression): TSESTree.Expression[] {\n if (node.type === AST_NODE_TYPES.BinaryExpression && node.operator === \"+\") {\n return [...concatOperands(node.left), ...concatOperands(node.right)];\n }\n return [node];\n}\n\n/**\n * The runtime operands of a string-concatenation chain, or an empty array when\n * the node is not a concatenation that mixes a literal with a runtime value.\n * Requiring at least one string literal is what distinguishes statement\n * building from ordinary arithmetic.\n */\nfunction runtimeConcatOperands(node: TSESTree.Node): TSESTree.Expression[] {\n if (node.type !== AST_NODE_TYPES.BinaryExpression || node.operator !== \"+\") {\n return [];\n }\n const operands = concatOperands(node);\n const hasStringLiteral = operands.some(\n (operand) =>\n operand.type === AST_NODE_TYPES.Literal &&\n typeof operand.value === \"string\",\n );\n if (!hasStringLiteral) {\n return [];\n }\n return operands.filter(\n (operand) =>\n operand.type !== AST_NODE_TYPES.Literal && !isStaticFragment(operand),\n );\n}\n\n/** The inspected method name of `receiver.method(...)`, or null. */\nfunction statementMethodName(\n node: TSESTree.CallExpression,\n methods: ReadonlySet<string>,\n): string | null {\n const callee = node.callee;\n if (\n callee.type !== AST_NODE_TYPES.MemberExpression ||\n callee.computed ||\n callee.property.type !== AST_NODE_TYPES.Identifier\n ) {\n return null;\n }\n const name = callee.property.name;\n return methods.has(name) ? name : null;\n}\n\nexport default ESLintUtils.RuleCreator(\n (name) =>\n `https://github.com/sarj-ai/standards/blob/main/packages/typescript/src/rules/${name}.ts`,\n)<Options, MessageIds>({\n name: \"no-dynamic-sql\",\n meta: {\n type: \"problem\",\n docs: {\n description:\n \"Disallow interpolating or concatenating a runtime value into a SQL statement passed to `prepare`/`exec`/`query`; use a placeholder and bind the value.\",\n },\n schema: [\n {\n type: \"object\",\n properties: {\n methods: {\n type: \"array\",\n items: { type: \"string\" },\n description:\n \"Statement-taking method names to inspect. Replaces the defaults.\",\n },\n },\n additionalProperties: false,\n },\n ],\n messages: {\n dynamicSql:\n \"Runtime value built into a SQL statement passed to `{{method}}()`. Use a `?` placeholder and pass the value through `.bind(...)` so the driver parameterises it.\",\n },\n },\n defaultOptions: [{}],\n create(context, [options]) {\n const methods = new Set(options?.methods ?? DEFAULT_METHODS);\n\n return {\n CallExpression(node: TSESTree.CallExpression): void {\n const method = statementMethodName(node, methods);\n if (method === null) {\n return;\n }\n\n const statement = node.arguments[0];\n if (statement === undefined) {\n return;\n }\n\n const offenders =\n statement.type === AST_NODE_TYPES.TemplateLiteral\n ? runtimeInterpolations(statement)\n : runtimeConcatOperands(statement);\n\n for (const offender of offenders) {\n context.report({\n node: offender,\n messageId: \"dynamicSql\",\n data: { method },\n });\n }\n },\n };\n },\n});\n","/**\n * @fileoverview Keep outbound HTTP behind a client module.\n *\n * A bare `fetch()` in a route handler, server action or component opts out of\n * whatever the codebase's client layer provides — retry/backoff, timeouts,\n * status handling, auth headers, structured log breadcrumbs. It is also the\n * shape that cannot be stubbed in a test without monkey-patching global\n * `fetch`, so the call site quietly becomes untestable.\n *\n * WHAT IT CATCHES\n * fetch(url) // bare global\n * globalThis.fetch(url) // explicit global receiver\n * window.fetch(url)\n *\n * NOT FLAGGED\n * - Files whose path matches one of the `allow` patterns. The defaults cover\n * the conventions we have seen in practice — a `clients/` directory, a\n * `*-client.ts` module, an `http-client.*` wrapper — plus test files.\n * - A method named `fetch` on some other receiver (`cache.fetch(k)`,\n * `queryClient.fetch()`): only the global is HTTP.\n * - `new Request(...)` / `axios(...)` and friends. This rule is about the\n * global `fetch`, not about every HTTP library.\n *\n * CONFIGURATION\n * `allow` is a list of regular-expression sources matched against the absolute\n * filename, so a repo that keeps its client layer somewhere else can say so\n * rather than sprinkling disable comments:\n *\n * \"@sarj/no-raw-fetch-outside-clients\": [\"error\", {\n * \"allow\": [\"[\\\\\\\\/]lib[\\\\\\\\/]api[\\\\\\\\/]\", \"-gateway\\\\\\\\.ts$\"]\n * }]\n *\n * Supplying `allow` REPLACES the defaults, so include the test patterns if you\n * still want test files exempt.\n */\n\nimport { ESLintUtils, type TSESTree } from \"@typescript-eslint/utils\";\n\ntype MessageIds = \"rawFetch\";\n\nexport interface RuleOptions {\n /** Regular-expression sources matched against the filename. */\n readonly allow?: readonly string[];\n}\n\ntype Options = readonly [RuleOptions?];\n\n/**\n * Path shapes that legitimately own outbound HTTP, plus test files. Written as\n * regex sources (not globs) so they can express both path separators.\n */\nconst DEFAULT_ALLOW: readonly string[] = [\n \"[\\\\\\\\/]clients?[\\\\\\\\/]\",\n \"-client\\\\.[cm]?[jt]sx?$\",\n \"[\\\\\\\\/]http-client\\\\.[cm]?[jt]sx?$\",\n \"\\\\.test\\\\.\",\n \"\\\\.spec\\\\.\",\n \"[\\\\\\\\/]__tests__[\\\\\\\\/]\",\n \"[\\\\\\\\/]__mocks__[\\\\\\\\/]\",\n];\n\n/** Receivers on which `.fetch()` is the global, not some cache/query API. */\nconst GLOBAL_RECEIVERS: ReadonlySet<string> = new Set([\n \"globalThis\",\n \"window\",\n \"self\",\n]);\n\n/** True when `node` is a call to the global `fetch`. */\nfunction isGlobalFetchCall(node: TSESTree.CallExpression): boolean {\n const callee = node.callee;\n\n if (callee.type === \"Identifier\") {\n return callee.name === \"fetch\";\n }\n\n if (\n callee.type === \"MemberExpression\" &&\n !callee.computed &&\n callee.property.type === \"Identifier\" &&\n callee.property.name === \"fetch\" &&\n callee.object.type === \"Identifier\"\n ) {\n return GLOBAL_RECEIVERS.has(callee.object.name);\n }\n\n return false;\n}\n\n/**\n * Compile the configured patterns once per file. An invalid pattern is skipped\n * rather than thrown: a bad `allow` entry should not take the whole lint run\n * down, and the rule failing closed (still reporting) is the safe direction.\n */\nfunction compile(patterns: readonly string[]): RegExp[] {\n const compiled: RegExp[] = [];\n for (const pattern of patterns) {\n try {\n compiled.push(new RegExp(pattern));\n } catch {\n // Skip the malformed entry; the remaining patterns still apply.\n }\n }\n return compiled;\n}\n\nexport default ESLintUtils.RuleCreator(\n (name) =>\n `https://github.com/sarj-ai/standards/blob/main/packages/typescript/src/rules/${name}.ts`,\n)<Options, MessageIds>({\n name: \"no-raw-fetch-outside-clients\",\n meta: {\n type: \"problem\",\n docs: {\n description:\n \"Disallow calling the global `fetch` outside the client layer; route outbound HTTP through a client module that owns retry, timeout and status handling.\",\n },\n schema: [\n {\n type: \"object\",\n properties: {\n allow: {\n type: \"array\",\n items: { type: \"string\" },\n description:\n \"Regular-expression sources matched against the filename. Replaces the defaults.\",\n },\n },\n additionalProperties: false,\n },\n ],\n messages: {\n rawFetch:\n \"Raw `fetch()` outside a client module. Route the call through a client (e.g. `clients/*-client.ts`) so it inherits retry, timeout and status handling and stays stubbable in tests.\",\n },\n },\n defaultOptions: [{}],\n create(context, [options]) {\n const patterns = options?.allow ?? DEFAULT_ALLOW;\n const allowed = compile(patterns);\n const filename = context.filename;\n\n if (allowed.some((re) => re.test(filename))) {\n return {};\n }\n\n return {\n CallExpression(node: TSESTree.CallExpression): void {\n if (isGlobalFetchCall(node)) {\n context.report({ node, messageId: \"rawFetch\" });\n }\n },\n };\n },\n});\n","/**\n * @fileoverview Keep modules that are stateless by design free of private\n * storage.\n *\n * Some features are stateless deliberately: they derive everything they need\n * from reads against the systems of record (Slack, Linear, GitHub, a CRM) plus\n * markers in the artefacts they themselves produced. The reason is operational\n * — such a feature can be re-run and back-filled freely, whereas a private\n * table or key/value namespace immediately diverges from what a human can\n * actually see and audit in the system of record. Adding a store to one of\n * these modules silently deletes that property, and nothing else in the\n * toolchain notices.\n *\n * WHAT IT CATCHES, inside the configured modules only\n * db.prepare(sql) // a SQL statement\n * kv.put(key, value) // a key/value write\n * kv.getWithMetadata(key) // a key/value read\n *\n * OPT-IN BY DESIGN\n * `modules` defaults to an EMPTY list, which makes the rule a no-op. That is\n * deliberate: the method names alone (`put`, `prepare`) carry no type\n * information, so the rule is only meaningful — and only quiet enough to live\n * in a shared preset — when it is pointed at the specific directories a team\n * has declared stateless.\n *\n * \"@sarj/no-storage-in-stateless-modules\": [\"error\", {\n * \"modules\": [\"[\\\\\\\\/]engineer-digest[\\\\\\\\/]\", \"[\\\\\\\\/]digest[\\\\\\\\/]\"]\n * }]\n *\n * `modules` entries are regular-expression sources matched against the absolute\n * filename. `methods` overrides the storage method names if a driver names\n * things differently.\n *\n * NOT FLAGGED\n * - Anything outside the configured modules.\n * - `.put()` with fewer than two arguments — a one-argument `put` is more\n * often a builder or queue helper than a key/value write.\n *\n * If a feature genuinely cannot be expressed statelessly, that is a design\n * conversation, not a disable comment.\n */\n\nimport { AST_NODE_TYPES, ESLintUtils, type TSESTree } from \"@typescript-eslint/utils\";\n\ntype MessageIds = \"storageInStatelessModule\";\n\nexport interface RuleOptions {\n /** Regex sources matched against the filename. Empty means the rule is off. */\n readonly modules?: readonly string[];\n /** Storage method names to flag. Replaces the defaults. */\n readonly methods?: readonly string[];\n}\n\ntype Options = readonly [RuleOptions?];\n\nconst DEFAULT_METHODS: readonly string[] = [\n \"prepare\",\n \"put\",\n \"getWithMetadata\",\n];\n\n/**\n * Minimum argument count before a method call counts as storage access. `put`\n * needs a key AND a value; a single-argument `put` is usually something else.\n * Methods absent from this map need one argument.\n */\nconst MIN_ARGUMENTS: ReadonlyMap<string, number> = new Map([[\"put\", 2]]);\n\n/** Compile regex sources, skipping malformed entries rather than throwing. */\nfunction compile(patterns: readonly string[]): RegExp[] {\n const compiled: RegExp[] = [];\n for (const pattern of patterns) {\n try {\n compiled.push(new RegExp(pattern));\n } catch {\n // Skip the malformed entry; the remaining patterns still apply.\n }\n }\n return compiled;\n}\n\n/** The flagged storage method name of `receiver.method(...)`, or null. */\nfunction storageMethodName(\n node: TSESTree.CallExpression,\n methods: ReadonlySet<string>,\n): string | null {\n const callee = node.callee;\n if (\n callee.type !== AST_NODE_TYPES.MemberExpression ||\n callee.computed ||\n callee.property.type !== AST_NODE_TYPES.Identifier\n ) {\n return null;\n }\n const name = callee.property.name;\n if (!methods.has(name)) {\n return null;\n }\n if (node.arguments.length < (MIN_ARGUMENTS.get(name) ?? 1)) {\n return null;\n }\n return name;\n}\n\nexport default ESLintUtils.RuleCreator(\n (name) =>\n `https://github.com/sarj-ai/standards/blob/main/packages/typescript/src/rules/${name}.ts`,\n)<Options, MessageIds>({\n name: \"no-storage-in-stateless-modules\",\n meta: {\n type: \"problem\",\n docs: {\n description:\n \"Disallow SQL or key/value access inside modules a team has declared stateless; derive state from the systems of record instead. No-op until `modules` is configured.\",\n },\n schema: [\n {\n type: \"object\",\n properties: {\n modules: {\n type: \"array\",\n items: { type: \"string\" },\n description:\n \"Regex sources matched against the filename. Empty (the default) disables the rule.\",\n },\n methods: {\n type: \"array\",\n items: { type: \"string\" },\n description: \"Storage method names to flag. Replaces the defaults.\",\n },\n },\n additionalProperties: false,\n },\n ],\n messages: {\n storageInStatelessModule:\n \"`{{method}}()` reaches for private storage inside a module declared stateless. Derive the state from a read against the system of record, or from a marker in the artefact this feature already produces.\",\n },\n },\n defaultOptions: [{}],\n create(context, [options]) {\n const modules = options?.modules ?? [];\n if (modules.length === 0) {\n return {};\n }\n\n const scoped = compile(modules);\n if (!scoped.some((re) => re.test(context.filename))) {\n return {};\n }\n\n const methods = new Set(options?.methods ?? DEFAULT_METHODS);\n\n return {\n CallExpression(node: TSESTree.CallExpression): void {\n const method = storageMethodName(node, methods);\n if (method !== null) {\n context.report({\n node,\n messageId: \"storageInStatelessModule\",\n data: { method },\n });\n }\n },\n };\n },\n});\n","/**\n * @fileoverview Disallow `z.nativeEnum(...)` in zod schemas; use\n * `z.enum([\"a\", \"b\"])` and derive the type with `z.infer<typeof Schema>`.\n *\n * Rationale — this is the schema-layer sibling of the `no-enum` rule. Zod's\n * `nativeEnum` exists for exactly one purpose: to wrap a TypeScript `enum`,\n * which `no-enum` already bans (enums emit runtime code, have unintuitive\n * numeric defaults, and don't tree-shake). Reaching for `nativeEnum` is\n * therefore either (a) importing a banned construct through the back door, or\n * (b) wrapping an `as const` object, in which case `z.enum` over the value list\n * is the shorter, better-inferring form. Either way the target state is the\n * same string-literal union `no-enum` prescribes, so the two rules point at one\n * destination.\n *\n * Two shapes fire:\n *\n * 1. **`z.nativeEnum(x)`** — always. Autofixable ONLY when the argument is an\n * inline object literal (optionally `as const`) whose every value is a\n * string literal: that set is fully known at the call site, so the rewrite\n * to `z.enum([...])` is mechanical and value-preserving. A numeric member\n * (`{ A: 1 }`) is NOT fixed — `z.enum` accepts strings only, so rewriting\n * would silently change the accepted input. A spread, computed key, shorthand\n * property, method, or an empty object is not fixed either (the member set\n * isn't statically known, and `z.enum([])` is not a valid schema). An\n * identifier argument (`z.nativeEnum(Fruits)`) is reported without a fix:\n * inlining the values at the call site would duplicate the literal set that\n * the named object exists to own, so the correct edit is a human one.\n *\n * 2. **`z.enum(SomeTsEnum)`** — zod v4 lets `z.enum` take a TS enum directly,\n * which is `nativeEnum` under a friendlier name and re-opens the same hole.\n * Detected two ways: lexical resolution of the identifier to a\n * `TSEnumDeclaration` in the same file, and — when type information is\n * available — the resolved symbol carrying an enum flag, which also catches\n * an enum imported from another module. `z.enum(COLORS)` where `COLORS` is a\n * `readonly string[]` / `as const` array is the prescribed pattern and never\n * fires.\n *\n * False positives handled: a bare `nativeEnum(...)` call fires only when the\n * name is imported from a zod module, so a same-named local helper is not\n * flagged. Generated files (`*.gen.ts`, `**\\/generated/**`, `*.d.ts`, or a\n * `@generated` marker) opt out, matching `no-enum` — codegen from an OpenAPI\n * spec legitimately emits enums and the schemas that wrap them.\n */\n\nimport {\n ESLintUtils,\n type TSESLint,\n type TSESTree,\n type ParserServicesWithTypeInformation,\n AST_NODE_TYPES,\n} from \"@typescript-eslint/utils\";\nimport * as ts from \"typescript\";\n\ntype MessageIds = \"nativeEnum\" | \"enumOfTsEnum\";\ntype Options = readonly [];\n\nconst IGNORE_PATTERNS: readonly RegExp[] = [\n /[\\\\/]generated[\\\\/]/,\n /\\.gen\\.tsx?$/,\n /\\.generated\\.tsx?$/,\n /\\.d\\.ts$/,\n];\n\nfunction isIgnoredFile(filename: string, sourceText: string): boolean {\n if (IGNORE_PATTERNS.some((re) => re.test(filename))) {\n return true;\n }\n return /@generated\\b/.test(sourceText.slice(0, 1024));\n}\n\n/** `zod`, `zod/v4`, `zod/mini`, `@hono/zod-openapi`, `@/lib/zod`, ... */\nfunction isZodModule(source: string): boolean {\n return /(^|[/@-])zod([/-]|$)/.test(source);\n}\n\n/** Unwraps `x as const` / `x satisfies T` / `(x)` down to the inner expression. */\nfunction unwrap(node: TSESTree.Expression): TSESTree.Expression {\n if (\n node.type === AST_NODE_TYPES.TSAsExpression ||\n node.type === AST_NODE_TYPES.TSSatisfiesExpression\n ) {\n return unwrap(node.expression);\n }\n return node;\n}\n\n/**\n * The string values of an object literal whose every property is a plain\n * `key: \"literal\"` pair, as raw source text (so quote style survives the fix).\n * Returns null when any member is a spread, a computed key, a method, a\n * shorthand, or a non-string value — those sets are not statically rewritable.\n */\nfunction stringValueTexts(\n node: TSESTree.ObjectExpression,\n sourceCode: Readonly<TSESLint.SourceCode>,\n): string[] | null {\n const texts: string[] = [];\n for (const prop of node.properties) {\n if (prop.type !== AST_NODE_TYPES.Property) {\n return null;\n }\n if (prop.computed || prop.shorthand || prop.method || prop.kind !== \"init\") {\n return null;\n }\n const value = prop.value;\n if (\n value.type !== AST_NODE_TYPES.Literal ||\n typeof value.value !== \"string\"\n ) {\n return null;\n }\n const text = sourceCode.getText(value);\n if (!texts.includes(text)) {\n texts.push(text);\n }\n }\n return texts.length > 0 ? texts : null;\n}\n\n/** Resolves an identifier to a `TSEnumDeclaration` declared in this file. */\nfunction resolvesToLocalEnum(\n node: TSESTree.Identifier,\n scope: TSESLint.Scope.Scope,\n): boolean {\n let current: TSESLint.Scope.Scope | null = scope;\n while (current !== null) {\n const variable = current.variables.find((v) => v.name === node.name);\n if (variable !== undefined) {\n return variable.defs.some(\n (def) => def.node.type === AST_NODE_TYPES.TSEnumDeclaration,\n );\n }\n current = current.upper;\n }\n return false;\n}\n\nconst ENUM_SYMBOL_FLAGS =\n ts.SymbolFlags.RegularEnum | ts.SymbolFlags.ConstEnum | ts.SymbolFlags.Enum;\n\n/**\n * Whether the identifier's resolved symbol is a TypeScript enum, following\n * import aliases. Catches `import { Status } from \"./types\"; z.enum(Status)`,\n * which lexical resolution alone cannot see.\n */\nfunction resolvesToImportedEnum(\n node: TSESTree.Identifier,\n services: ParserServicesWithTypeInformation,\n): boolean {\n const checker = services.program.getTypeChecker();\n const tsNode = services.esTreeNodeToTSNodeMap.get(node);\n let symbol = checker.getSymbolAtLocation(tsNode);\n if (symbol === undefined) {\n return false;\n }\n if ((symbol.flags & ts.SymbolFlags.Alias) !== 0) {\n symbol = checker.getAliasedSymbol(symbol);\n }\n return (symbol.flags & ENUM_SYMBOL_FLAGS) !== 0;\n}\n\nexport default ESLintUtils.RuleCreator(\n (name) =>\n `https://github.com/sarj-ai/linting/blob/main/packages/typescript/src/rules/${name}.ts`,\n)<Options, MessageIds>({\n name: \"no-zod-native-enum\",\n meta: {\n type: \"suggestion\",\n fixable: \"code\",\n docs: {\n description:\n \"Disallow `z.nativeEnum()` (and `z.enum()` over a TypeScript enum); use `z.enum([\\\"a\\\", \\\"b\\\"])` with a string-literal union instead.\",\n },\n schema: [],\n messages: {\n nativeEnum:\n '`z.nativeEnum()` exists to wrap a TypeScript `enum`, which `no-enum` bans. Use `z.enum([\"a\", \"b\"])` and derive the union with `z.infer<typeof Schema>`.',\n enumOfTsEnum:\n '`z.enum()` is being passed the TypeScript enum `{{name}}`, which `no-enum` bans. Pass a string-literal array instead: `z.enum([\"a\", \"b\"])`.',\n },\n },\n defaultOptions: [],\n create(context) {\n const sourceCode = context.sourceCode;\n if (isIgnoredFile(context.filename, sourceCode.getText())) {\n return {};\n }\n\n let services: ParserServicesWithTypeInformation | null;\n try {\n services = ESLintUtils.getParserServices(context);\n } catch {\n services = null;\n }\n\n /** Local names imported from a zod module, e.g. `nativeEnum`, `enum_`. */\n const zodImportedNames = new Map<string, string>();\n\n function isZodMemberCall(node: TSESTree.CallExpression, api: string): boolean {\n const callee = node.callee;\n if (\n callee.type === AST_NODE_TYPES.MemberExpression &&\n !callee.computed &&\n callee.property.type === AST_NODE_TYPES.Identifier\n ) {\n return callee.property.name === api;\n }\n if (callee.type === AST_NODE_TYPES.Identifier) {\n return zodImportedNames.get(callee.name) === api;\n }\n return false;\n }\n\n function buildFix(\n node: TSESTree.CallExpression,\n ): TSESLint.ReportFixFunction | null {\n // A bare `nativeEnum(...)` imported from zod cannot be renamed in place —\n // `enum` is a reserved word, so there is no bare callee to rewrite to.\n // Rewriting only the argument would leave a `nativeEnum` call taking an\n // array, so this shape is report-only.\n const callee = node.callee;\n if (\n callee.type !== AST_NODE_TYPES.MemberExpression ||\n callee.property.type !== AST_NODE_TYPES.Identifier\n ) {\n return null;\n }\n const arg = node.arguments[0];\n if (\n arg === undefined ||\n node.arguments.length !== 1 ||\n arg.type === AST_NODE_TYPES.SpreadElement\n ) {\n return null;\n }\n const inner = unwrap(arg);\n if (inner.type !== AST_NODE_TYPES.ObjectExpression) {\n return null;\n }\n const values = stringValueTexts(inner, sourceCode);\n if (values === null) {\n return null;\n }\n const property = callee.property;\n const replacementArg = `[${values.join(\", \")}]`;\n return (fixer) => [\n fixer.replaceText(property, \"enum\"),\n fixer.replaceText(arg, replacementArg),\n ];\n }\n\n return {\n ImportDeclaration(node: TSESTree.ImportDeclaration): void {\n if (!isZodModule(node.source.value)) {\n return;\n }\n for (const spec of node.specifiers) {\n if (\n spec.type === AST_NODE_TYPES.ImportSpecifier &&\n spec.imported.type === AST_NODE_TYPES.Identifier\n ) {\n zodImportedNames.set(spec.local.name, spec.imported.name);\n }\n }\n },\n\n CallExpression(node: TSESTree.CallExpression): void {\n if (isZodMemberCall(node, \"nativeEnum\")) {\n const fix = buildFix(node);\n context.report({\n node,\n messageId: \"nativeEnum\",\n ...(fix === null ? {} : { fix }),\n });\n return;\n }\n\n if (!isZodMemberCall(node, \"enum\")) {\n return;\n }\n const arg = node.arguments[0];\n if (arg === undefined || arg.type !== AST_NODE_TYPES.Identifier) {\n return;\n }\n const isEnum =\n resolvesToLocalEnum(arg, sourceCode.getScope(arg)) ||\n (services !== null && resolvesToImportedEnum(arg, services));\n if (isEnum) {\n context.report({\n node,\n messageId: \"enumOfTsEnum\",\n data: { name: arg.name },\n });\n }\n },\n };\n },\n});\n","/**\n * @fileoverview Flag a literal-only constant collection (or regex) declared\n * INSIDE a function body that should be hoisted to module scope.\n *\n * Rationale — this is the single most frequent recurring review comment in the\n * mined PR corpus (~37 distinct PRs, TypeScript and Python alike): a lookup\n * table, allow-list, `Set` membership test or validation regex written at the\n * top of a function, rebuilt on every single call. Three costs, in increasing\n * order of severity:\n *\n * 1. Allocation — every call re-walks the literal and re-allocates the array /\n * object / Set / Map. In a hot path or a React render this is pure waste.\n * 2. Identity churn — a fresh object every call means a fresh reference every\n * render, which silently defeats `useMemo`/`useEffect` dependency arrays and\n * `React.memo` on anything the value is threaded into.\n * 3. Discoverability — a domain constant buried in a function body is invisible\n * to the next reader and cannot be exported, tested, or reused, so it gets\n * duplicated in the next function that needs it. That is the defect class:\n * the duplicated copies drift apart.\n *\n * This rule is deliberately NOT a duplicate of `unicorn/consistent-function-scoping`,\n * which is enabled at error in the shipped strict config. That rule reports\n * nested FUNCTION declarations that reference nothing from their enclosing\n * scope; its entire visitor surface is the function node types and it never\n * looks at a `VariableDeclarator` whose init is an array, object, `new Set`,\n * `new Map` or a regex. The two rules are disjoint by construction.\n *\n * What fires — a `const` binding inside a function whose initializer is one of:\n *\n * - an array literal, an object literal, `new Set([...])`, `new Map([...])`,\n * or `Object.freeze(...)` around any of those, with at least `minElements`\n * entries and where EVERY leaf is a literal; or\n * - a regular-expression literal without the `g`/`y` flags.\n *\n * \"Every leaf is a literal\" means string/number/boolean/null, an unsigned or\n * negated numeric literal, a template literal with no interpolation, or a\n * nested array/object of the same — no identifiers, no calls, no member\n * expressions, no spreads, no computed non-literal keys, no shorthand\n * properties. That single condition is what makes the hoist provably safe and\n * is also what eliminates the largest false-positive class outright.\n *\n * False positives handled explicitly:\n *\n * - **Closes over a parameter or an outer binding.** `new Map([[userId, 1]])`\n * or `[prefix + \"-a\"]` contains an identifier / a computed value, so it is\n * not literal-only and never fires. Hoisting those would be a compile error\n * or a behaviour change, so the literal-only gate is load-bearing, not a\n * stylistic preference.\n * - **Deliberately fresh per call because someone mutates it.** Every\n * reference to the binding must be a provably non-mutating read: a member\n * read, a call to a known non-mutating method, `for…of` iteration, or a\n * spread into a NEW literal or argument list (which copies). A call to\n * `.push`/`.set`/`.add`/`.sort`/`.splice`/…, an index or property\n * assignment, a `delete`, or an `X++` bails immediately.\n * - **Escaping value the CALLER may mutate.** Returning the binding, passing\n * it bare as an argument, aliasing it into another variable, or embedding it\n * in a returned object/array all bail. Once the value leaves the function\n * this rule cannot see what happens to it, and a shared hoisted array that a\n * caller mutates is a genuine cross-call data-corruption bug — exactly the\n * kind of defect a lint rule must not introduce. Reads from an escaping\n * CLOSURE are fine and still fire: a nested arrow that only reads the\n * constant is unaffected by hoisting.\n * - **Tiny literals where hoisting hurts readability.** A one- or two-element\n * literal reads better next to its use, so `minElements` (default 3) sets\n * the floor and can be raised per repo.\n * - **Stateful regexes.** A `/…/g` or `/…/y` regex carries `lastIndex` across\n * calls to `.test()`/`.exec()`. Hoisting one changes behaviour — the second\n * call resumes mid-string — so global and sticky regexes are never reported\n * even though they are the most expensive to recompile.\n * - **Test files.** Fixture tables inside a test body are local by design and\n * hoisting them separates the data from the assertion that explains it.\n * Exempt by default via `ignoreTestFiles`.\n * - **Generated files** (`*.gen.ts`, `**\\/generated/**`, `*.d.ts`, or a\n * `@generated` marker) opt out, matching `no-enum` and `no-zod-native-enum`.\n *\n * There is no autofix. Hoisting has to pick an insertion point and may collide\n * with an existing module-scope name; both are judgement calls that belong to a\n * human, and a wrong automated hoist is worse than the warning.\n */\n\nimport {\n ESLintUtils,\n type TSESTree,\n AST_NODE_TYPES,\n} from \"@typescript-eslint/utils\";\n\ntype MessageIds = \"hoistCollection\" | \"hoistRegex\";\n\ntype Options = readonly [\n {\n minElements?: number;\n checkRegex?: boolean;\n ignoreTestFiles?: boolean;\n }?,\n];\n\nconst DEFAULT_MIN_ELEMENTS = 3;\n\n/** How deep a nested literal may go before we stop trying to prove it static. */\nconst MAX_LITERAL_DEPTH = 4;\n\nconst IGNORE_PATTERNS: readonly RegExp[] = [\n /[\\\\/]generated[\\\\/]/,\n /\\.gen\\.tsx?$/,\n /\\.generated\\.tsx?$/,\n /\\.d\\.ts$/,\n];\n\nconst TEST_FILE_PATTERNS: readonly RegExp[] = [\n /\\.(?:test|spec)\\.[cm]?[jt]sx?$/,\n /[\\\\/]__tests__[\\\\/]/,\n /[\\\\/]__mocks__[\\\\/]/,\n /[\\\\/]tests?[\\\\/]/,\n /\\.stories\\.[cm]?[jt]sx?$/,\n];\n\n/**\n * Methods that mutate the receiver. A call to any of these on the binding is\n * proof the value is meant to be rebuilt per call.\n */\nconst MUTATING_METHODS: ReadonlySet<string> = new Set([\n // Array\n \"push\",\n \"pop\",\n \"shift\",\n \"unshift\",\n \"splice\",\n \"sort\",\n \"reverse\",\n \"fill\",\n \"copyWithin\",\n // Set / Map\n \"add\",\n \"set\",\n \"delete\",\n \"clear\",\n // Object-ish escape hatches\n \"assign\",\n]);\n\nconst FUNCTION_TYPES: ReadonlySet<AST_NODE_TYPES> = new Set([\n AST_NODE_TYPES.FunctionDeclaration,\n AST_NODE_TYPES.FunctionExpression,\n AST_NODE_TYPES.ArrowFunctionExpression,\n]);\n\nconst COLLECTION_CONSTRUCTORS: ReadonlySet<string> = new Set([\"Set\", \"Map\"]);\n\nfunction isIgnoredFile(filename: string, sourceText: string): boolean {\n if (IGNORE_PATTERNS.some((re) => re.test(filename))) {\n return true;\n }\n return /@generated\\b/.test(sourceText.slice(0, 1024));\n}\n\nfunction isTestFile(filename: string): boolean {\n return TEST_FILE_PATTERNS.some((re) => re.test(filename));\n}\n\n/** Unwraps `x as const` / `x satisfies T` down to the inner expression. */\nfunction unwrap(node: TSESTree.Node): TSESTree.Node {\n if (\n node.type === AST_NODE_TYPES.TSAsExpression ||\n node.type === AST_NODE_TYPES.TSSatisfiesExpression ||\n node.type === AST_NODE_TYPES.TSNonNullExpression\n ) {\n return unwrap(node.expression);\n }\n return node;\n}\n\nfunction isRegexLiteral(node: TSESTree.Node): node is TSESTree.RegExpLiteral {\n return (\n node.type === AST_NODE_TYPES.Literal &&\n \"regex\" in node &&\n node.regex !== undefined\n );\n}\n\n/**\n * Whether the expression is built entirely out of literals — no identifier, no\n * call, no member access, no interpolation, no spread. This is the gate that\n * makes hoisting provably safe: a literal-only value cannot capture a\n * parameter, cannot observe call-time state, and cannot have side effects.\n */\nfunction isLiteralOnly(node: TSESTree.Node, depth: number): boolean {\n if (depth > MAX_LITERAL_DEPTH) {\n return false;\n }\n const inner = unwrap(node);\n switch (inner.type) {\n case AST_NODE_TYPES.Literal: {\n return true;\n }\n case AST_NODE_TYPES.TemplateLiteral: {\n return inner.expressions.length === 0;\n }\n case AST_NODE_TYPES.UnaryExpression: {\n return (\n (inner.operator === \"-\" || inner.operator === \"+\") &&\n inner.argument.type === AST_NODE_TYPES.Literal &&\n typeof inner.argument.value === \"number\"\n );\n }\n case AST_NODE_TYPES.ArrayExpression: {\n return inner.elements.every(\n (el) =>\n el !== null &&\n el.type !== AST_NODE_TYPES.SpreadElement &&\n isLiteralOnly(el, depth + 1),\n );\n }\n case AST_NODE_TYPES.ObjectExpression: {\n return inner.properties.every((prop) => {\n if (prop.type !== AST_NODE_TYPES.Property) {\n return false;\n }\n if (prop.shorthand || prop.method || prop.kind !== \"init\") {\n return false;\n }\n if (prop.computed && prop.key.type !== AST_NODE_TYPES.Literal) {\n return false;\n }\n return isLiteralOnly(prop.value, depth + 1);\n });\n }\n default: {\n return false;\n }\n }\n}\n\n/** `Object.freeze(x)` → `x`; anything else is returned untouched. */\nfunction unwrapObjectFreeze(node: TSESTree.Node): TSESTree.Node {\n const inner = unwrap(node);\n if (\n inner.type === AST_NODE_TYPES.CallExpression &&\n inner.callee.type === AST_NODE_TYPES.MemberExpression &&\n !inner.callee.computed &&\n inner.callee.object.type === AST_NODE_TYPES.Identifier &&\n inner.callee.object.name === \"Object\" &&\n inner.callee.property.type === AST_NODE_TYPES.Identifier &&\n inner.callee.property.name === \"freeze\" &&\n inner.arguments.length === 1 &&\n inner.arguments[0] !== undefined &&\n inner.arguments[0].type !== AST_NODE_TYPES.SpreadElement\n ) {\n return unwrap(inner.arguments[0]);\n }\n return inner;\n}\n\ntype Candidate =\n | { kind: \"array\" | \"object\" | \"Set\" | \"Map\"; size: number }\n | { kind: \"regex\"; size: number };\n\n/**\n * Classifies the initializer, or returns null when it is not a hoistable\n * literal-only collection / regex.\n */\nfunction classify(init: TSESTree.Node, checkRegex: boolean): Candidate | null {\n const node = unwrapObjectFreeze(init);\n\n if (isRegexLiteral(node)) {\n if (!checkRegex) {\n return null;\n }\n // `g` and `y` carry `lastIndex` between calls — hoisting changes behaviour.\n if (/[gy]/.test(node.regex.flags)) {\n return null;\n }\n return { kind: \"regex\", size: 1 };\n }\n\n if (node.type === AST_NODE_TYPES.ArrayExpression) {\n return isLiteralOnly(node, 0)\n ? { kind: \"array\", size: node.elements.length }\n : null;\n }\n\n if (node.type === AST_NODE_TYPES.ObjectExpression) {\n return isLiteralOnly(node, 0)\n ? { kind: \"object\", size: node.properties.length }\n : null;\n }\n\n if (\n node.type === AST_NODE_TYPES.NewExpression &&\n node.callee.type === AST_NODE_TYPES.Identifier &&\n COLLECTION_CONSTRUCTORS.has(node.callee.name)\n ) {\n const arg = node.arguments[0];\n if (\n node.arguments.length !== 1 ||\n arg === undefined ||\n arg.type === AST_NODE_TYPES.SpreadElement\n ) {\n return null;\n }\n const entries = unwrap(arg);\n if (entries.type !== AST_NODE_TYPES.ArrayExpression) {\n return null;\n }\n return isLiteralOnly(entries, 0)\n ? { kind: node.callee.name === \"Set\" ? \"Set\" : \"Map\", size: entries.elements.length }\n : null;\n }\n\n return null;\n}\n\n/** The nearest enclosing function, or null when the node is at module scope. */\nfunction enclosingFunction(node: TSESTree.Node): TSESTree.Node | null {\n let current: TSESTree.Node | undefined | null = node.parent;\n while (current !== undefined && current !== null) {\n if (FUNCTION_TYPES.has(current.type)) {\n return current;\n }\n current = current.parent;\n }\n return null;\n}\n\n/**\n * Built-ins that read their argument and return a fresh value without keeping\n * or mutating the original, so passing the binding to them is still a read.\n */\nconst NON_RETAINING_BUILTINS: ReadonlyMap<string, ReadonlySet<string>> = new Map(\n [\n [\n \"Object\",\n new Set([\"keys\", \"values\", \"entries\", \"freeze\", \"fromEntries\", \"assign\"]),\n ],\n [\"Array\", new Set([\"from\", \"isArray\"])],\n [\"JSON\", new Set([\"stringify\"])],\n ],\n);\n\nfunction isNonRetainingBuiltinCall(\n node: TSESTree.CallExpression,\n argument: TSESTree.Identifier,\n): boolean {\n const callee = node.callee;\n if (\n callee.type === AST_NODE_TYPES.Identifier &&\n callee.name === \"structuredClone\"\n ) {\n return true;\n }\n if (\n callee.type !== AST_NODE_TYPES.MemberExpression ||\n callee.computed ||\n callee.object.type !== AST_NODE_TYPES.Identifier ||\n callee.property.type !== AST_NODE_TYPES.Identifier\n ) {\n return false;\n }\n const members = NON_RETAINING_BUILTINS.get(callee.object.name);\n if (members === undefined || !members.has(callee.property.name)) {\n return false;\n }\n // `Object.assign(X, src)` mutates its FIRST argument; only later positions\n // (sources) are reads.\n if (callee.object.name === \"Object\" && callee.property.name === \"assign\") {\n return node.arguments[0] !== argument;\n }\n return true;\n}\n\n/**\n * Whether this single reference to the binding is a provably non-mutating,\n * non-escaping read. Anything not on the whitelist is treated as unsafe, so an\n * unrecognised usage suppresses the report rather than risking a bad hoist.\n */\nfunction isSafeRead(identifier: TSESTree.Identifier): boolean {\n const parent = identifier.parent;\n\n if (parent.type === AST_NODE_TYPES.MemberExpression) {\n if (parent.object !== identifier) {\n // `foo[X]` — the binding is used as a key, which is a plain read.\n return true;\n }\n const grandparent = parent.parent;\n // `X.a = 1`, `X[0] = 1`, `X.a += 1`\n if (\n grandparent.type === AST_NODE_TYPES.AssignmentExpression &&\n grandparent.left === parent\n ) {\n return false;\n }\n // `X.a++`\n if (grandparent.type === AST_NODE_TYPES.UpdateExpression) {\n return false;\n }\n // `delete X.a`\n if (\n grandparent.type === AST_NODE_TYPES.UnaryExpression &&\n grandparent.operator === \"delete\"\n ) {\n return false;\n }\n // `X.push(...)`, `X.sort()`, ...\n if (\n !parent.computed &&\n parent.property.type === AST_NODE_TYPES.Identifier &&\n MUTATING_METHODS.has(parent.property.name) &&\n grandparent.type === AST_NODE_TYPES.CallExpression &&\n grandparent.callee === parent\n ) {\n return false;\n }\n // Everything else through a member expression — `X.length`, `X.includes(v)`,\n // `X[i]`, `X.get(k)`, even `arr.map(X.has)` — reads a property of the\n // binding without handing the binding itself out, so it cannot mutate it.\n return true;\n }\n\n // `for (const x of X)` — iteration is a read.\n if (\n parent.type === AST_NODE_TYPES.ForOfStatement &&\n parent.right === identifier\n ) {\n return true;\n }\n\n // `[...X]`, `{...X}`, `f(...X)` — every spread copies, so the original is\n // never handed out and hoisting stays safe.\n if (parent.type === AST_NODE_TYPES.SpreadElement) {\n return true;\n }\n\n // `\"a\" in X`, `X instanceof Y`, `X === undefined`\n if (parent.type === AST_NODE_TYPES.BinaryExpression) {\n return true;\n }\n\n // A bare argument to a built-in that is known not to retain or mutate its\n // input: `Object.entries(X)`, `Array.from(X)`, `JSON.stringify(X)`. Any other\n // call receiving the binding bare is an escape.\n if (\n parent.type === AST_NODE_TYPES.CallExpression &&\n parent.arguments.includes(identifier) &&\n isNonRetainingBuiltinCall(parent, identifier)\n ) {\n return true;\n }\n\n // `typeof X`, `!X`\n if (\n parent.type === AST_NODE_TYPES.UnaryExpression &&\n parent.operator !== \"delete\"\n ) {\n return true;\n }\n\n return false;\n}\n\nexport default ESLintUtils.RuleCreator(\n (name) =>\n `https://github.com/sarj-ai/linting/blob/main/packages/typescript/src/rules/${name}.ts`,\n)<Options, MessageIds>({\n name: \"prefer-module-level-constant\",\n meta: {\n type: \"suggestion\",\n docs: {\n description:\n \"Hoist literal-only constant collections and regexes out of function bodies to module scope so they are allocated once.\",\n },\n schema: [\n {\n type: \"object\",\n additionalProperties: false,\n properties: {\n minElements: { type: \"number\", minimum: 1 },\n checkRegex: { type: \"boolean\" },\n ignoreTestFiles: { type: \"boolean\" },\n },\n },\n ],\n messages: {\n hoistCollection:\n \"`{{name}}` is a literal-only {{kind}} rebuilt on every call. Hoist it to module scope so it is allocated once and can be reused, exported, and tested.\",\n hoistRegex:\n \"`{{name}}` is a constant regex recompiled on every call. Hoist it to module scope.\",\n },\n },\n defaultOptions: [{}],\n create(context, [optionsArg]) {\n const options = optionsArg ?? {};\n const minElements = options.minElements ?? DEFAULT_MIN_ELEMENTS;\n const checkRegex = options.checkRegex ?? true;\n const ignoreTestFiles = options.ignoreTestFiles ?? true;\n\n const sourceCode = context.sourceCode;\n const filename = context.filename;\n\n if (isIgnoredFile(filename, sourceCode.getText())) {\n return {};\n }\n if (ignoreTestFiles && isTestFile(filename)) {\n return {};\n }\n\n function allReferencesAreSafeReads(\n declarator: TSESTree.VariableDeclarator,\n ): boolean {\n const variables = sourceCode.getDeclaredVariables(declarator);\n const variable = variables[0];\n if (variable === undefined) {\n return false;\n }\n for (const reference of variable.references) {\n // The initializer write itself is not a usage.\n if (reference.init === true) {\n continue;\n }\n if (reference.isWrite()) {\n return false;\n }\n // A `JSXIdentifier` reference means the constant is rendered as a JSX\n // tag name — not something this rule reasons about, so bail.\n if (reference.identifier.type !== AST_NODE_TYPES.Identifier) {\n return false;\n }\n if (!isSafeRead(reference.identifier)) {\n return false;\n }\n }\n return true;\n }\n\n return {\n VariableDeclarator(node: TSESTree.VariableDeclarator): void {\n const declaration = node.parent;\n if (\n declaration.type !== AST_NODE_TYPES.VariableDeclaration ||\n declaration.kind !== \"const\" ||\n declaration.declare === true\n ) {\n return;\n }\n if (node.id.type !== AST_NODE_TYPES.Identifier || node.init === null) {\n return;\n }\n if (enclosingFunction(node) === null) {\n return;\n }\n\n const candidate = classify(node.init, checkRegex);\n if (candidate === null) {\n return;\n }\n if (candidate.kind !== \"regex\" && candidate.size < minElements) {\n return;\n }\n if (!allReferencesAreSafeReads(node)) {\n return;\n }\n\n context.report({\n node: node.id,\n messageId:\n candidate.kind === \"regex\" ? \"hoistRegex\" : \"hoistCollection\",\n data: { name: node.id.name, kind: candidate.kind },\n });\n },\n };\n },\n});\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA,mBAA2D;AA4B3D,IAAM,oBAAoB,CACxB,cACkB;AAClB,UAAQ,UAAU,MAAM;AAAA,IACtB,KAAK,4BAAe;AAClB,aAAO;AAAA,IACT,KAAK,4BAAe;AAClB,aAAO;AAAA,IACT,KAAK,4BAAe;AAGlB,aAAO,UAAU,gBAAgB,OAAO,aAAa;AAAA,IACvD;AACE,aAAO;AAAA,EACX;AACF;AAEA,IAAM,oBAAoB,CAAC,cACzB,UAAU,SAAS,4BAAe,uBAClC,UAAU,WAAW,SAAS,4BAAe,WAC7C,OAAO,UAAU,WAAW,UAAU,YACtC,UAAU,WAAW,MAAM,WAAW,MAAM;AAE9C,IAAM,uBAAuB,CAC3B,cACY;AACZ,MAAI,UAAU,SAAS,4BAAe,oBAAqB,QAAO;AAClE,QAAM,OAAO,UAAU;AACvB,MAAI,KAAK,SAAS,4BAAe,QAAS,QAAO;AACjD,SAAO,KAAK,UAAU;AACxB;AAEA,IAAO,iCAAQ,yBAAY;AAAA,EACzB,CAAC,SACC,8EAA8E,IAAI;AACtF,EAAuB;AAAA,EACrB,MAAM;AAAA,EACN,MAAM;AAAA,IACJ,MAAM;AAAA,IACN,MAAM;AAAA,MACJ,aACE;AAAA,IACJ;AAAA,IACA,QAAQ,CAAC;AAAA,IACT,UAAU;AAAA,MACR,cACE;AAAA,MACF,oBACE;AAAA,IACJ;AAAA,EACF;AAAA,EACA,gBAAgB,CAAC;AAAA,EACjB,OAAO,SAAS;AACd,WAAO;AAAA,MACL,QAAQ,MAA8B;AACpC,cAAM,OAAO,KAAK;AAElB,cAAM,qBAAqB,KAAK;AAAA,UAC9B,CAAC,WAAW,UAAU,QAAQ,KAAK,qBAAqB,SAAS;AAAA,QACnE;AACA,YAAI,uBAAuB,QAAW;AACpC,kBAAQ,OAAO;AAAA,YACb,MAAM;AAAA,YACN,WAAW;AAAA,UACb,CAAC;AAAA,QACH;AAEA,YAAI,WAAW;AAEf,mBAAW,aAAa,MAAM;AAC5B,cAAI,kBAAkB,SAAS,EAAG;AAElC,kBAAQ,kBAAkB,SAAS,GAAG;AAAA,YACpC,KAAK;AACH;AAAA,YACF,KAAK;AACH,yBAAW;AACX;AAAA,YACF,KAAK;AACH,kBAAI,UAAU;AACZ,wBAAQ,OAAO;AAAA,kBACb,MAAM;AAAA,kBACN,WAAW;AAAA,gBACb,CAAC;AAAA,cACH;AACA;AAAA,UACJ;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF,CAAC;;;ACtFD,IAAAA,gBAIO;AAKP,IAAM,aAAkC,oBAAI,IAAI,CAAC,SAAS,MAAM,YAAY,CAAC;AAI7E,IAAM,oBAAyC,oBAAI,IAAI;AAAA,EACrD;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAMD,IAAM,qBAA0C,oBAAI,IAAI;AAAA,EACtD;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAED,SAAS,iBAAiB,MAAwC;AAChE,QAAM,SAAS,KAAK;AAGpB,MAAI,OAAO,SAAS,6BAAe,YAAY;AAC7C,WAAO,OAAO,SAAS,eAAe,OAAO,SAAS;AAAA,EACxD;AAGA,MACE,OAAO,SAAS,6BAAe,oBAC/B,CAAC,OAAO,YACR,OAAO,OAAO,SAAS,6BAAe,cACtC,OAAO,OAAO,SAAS,WACvB,OAAO,SAAS,SAAS,6BAAe,YACxC;AACA,WACE,OAAO,SAAS,SAAS,eACzB,OAAO,SAAS,SAAS;AAAA,EAE7B;AAEA,SAAO;AACT;AAMA,SAAS,mBACP,YACe;AACf,MAAI,CAAC,cAAc,WAAW,SAAS,6BAAe,kBAAkB;AACtE,WAAO;AAAA,EACT;AACA,aAAW,QAAQ,WAAW,YAAY;AACxC,QAAI,KAAK,SAAS,6BAAe,SAAU;AAC3C,QAAI,KAAK,SAAU;AACnB,UAAM,MAAM,KAAK;AACjB,UAAM,mBACH,IAAI,SAAS,6BAAe,cAAc,IAAI,SAAS,YACvD,IAAI,SAAS,6BAAe,WAAW,IAAI,UAAU;AACxD,QAAI,CAAC,iBAAkB;AACvB,QACE,KAAK,MAAM,SAAS,6BAAe,WACnC,OAAO,KAAK,MAAM,UAAU,UAC5B;AACA,aAAO,KAAK,MAAM,MAAM,YAAY;AAAA,IACtC;AACA,WAAO;AAAA,EACT;AACA,SAAO;AACT;AAEA,SAAS,YAAY,MAAwC;AAC3D,QAAM,SAAS,KAAK;AAGpB,MACE,OAAO,SAAS,6BAAe,cAC/B,OAAO,SAAS,SAChB;AACA,UAAM,SAAS,mBAAmB,KAAK,UAAU,CAAC,CAAC;AACnD,QAAI,WAAW,QAAQ,WAAW,OAAO;AACvC,aAAO;AAAA,IACT;AACA,WAAO;AAAA,EACT;AAGA,MACE,OAAO,SAAS,6BAAe,oBAC/B,CAAC,OAAO,YACR,OAAO,OAAO,SAAS,6BAAe,cACtC,WAAW,IAAI,OAAO,OAAO,IAAI,KACjC,OAAO,SAAS,SAAS,6BAAe,YACxC;AAGA,WAAO,kBAAkB,IAAI,OAAO,SAAS,IAAI;AAAA,EACnD;AAGA,MACE,OAAO,SAAS,6BAAe,eAC9B,OAAO,SAAS,WAAW,OAAO,SAAS,OAC5C;AACA,UAAM,WAAW,KAAK,UAAU,CAAC;AACjC,UAAM,YAAY,KAAK,UAAU,CAAC;AAClC,QAAI;AACJ,QAAI,UAAU,SAAS,6BAAe,kBAAkB;AACtD,kBAAY;AAAA,IACd,WAAW,WAAW,SAAS,6BAAe,kBAAkB;AAC9D,kBAAY;AAAA,IACd;AACA,UAAM,SAAS,mBAAmB,SAAS;AAC3C,QAAI,WAAW,QAAQ,WAAW,OAAO;AACvC,aAAO;AAAA,IACT;AACA,WAAO;AAAA,EACT;AAEA,SAAO;AACT;AAEA,SAAS,iBAAiB,MAAuC;AAC/D,QAAM,WAAW,KAAK,UAAU,CAAC;AACjC,MAAI,CAAC,SAAU,QAAO;AAEtB,MACE,SAAS,SAAS,6BAAe,WACjC,OAAO,SAAS,UAAU,UAC1B;AACA,WAAO,SAAS;AAAA,EAClB;AACA,MAAI,SAAS,SAAS,6BAAe,iBAAiB;AACpD,WAAO,SAAS,OAAO,IAAI,CAAC,MAAM,EAAE,MAAM,MAAM,EAAE,KAAK,EAAE;AAAA,EAC3D;AACA,MAAI,SAAS,SAAS,6BAAe,YAAY;AAC/C,WAAO,SAAS;AAAA,EAClB;AACA,SAAO;AACT;AAEA,SAAS,gBAAgB,MAAwC;AAC/D,QAAM,MAAM,iBAAiB,IAAI,EAAE,YAAY;AAC/C,MAAI,QAAQ,GAAI,QAAO;AAGvB,SAAO,IACJ,MAAM,MAAM,EACZ,KAAK,CAAC,YAAY,mBAAmB,IAAI,OAAO,CAAC;AACtD;AAEA,IAAO,uCAAQ,0BAAY;AAAA,EACzB,CAAC,SACC,8EAA8E,IAAI;AACtF,EAAuB;AAAA,EACrB,MAAM;AAAA,EACN,MAAM;AAAA,IACJ,MAAM;AAAA,IACN,MAAM;AAAA,MACJ,aACE;AAAA,IACJ;AAAA,IACA,QAAQ,CAAC;AAAA,IACT,UAAU;AAAA,MACR,eACE;AAAA,IACJ;AAAA,EACF;AAAA,EACA,gBAAgB,CAAC;AAAA,EACjB,OAAO,SAAS;AACd,QAAI,cAAc;AAClB,WAAO;AAAA,MACL,eAAe,MAAqC;AAClD,YAAI,iBAAiB,IAAI,GAAG;AAC1B,yBAAe;AACf;AAAA,QACF;AACA,YAAI,gBAAgB,EAAG;AACvB,YAAI,CAAC,YAAY,IAAI,EAAG;AACxB,YAAI,gBAAgB,IAAI,EAAG;AAC3B,gBAAQ,OAAO,EAAE,MAAM,WAAW,gBAAgB,CAAC;AAAA,MACrD;AAAA,MACA,sBAAsB,MAAqC;AACzD,YAAI,iBAAiB,IAAI,GAAG;AAC1B,yBAAe;AAAA,QACjB;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF,CAAC;;;AC9ND,IAAAC,gBAA2C;AAS3C,IAAM,uBAAuB;AAK7B,IAAM,oBACJ;AAIF,IAAM,qBACJ;AAGF,IAAM,eACJ;AAEF,IAAM,aACJ;AAEF,IAAM,iBAAiB;AAEvB,IAAM,gBAAgB;AACtB,IAAM,YAAY;AAElB,IAAM,kBACJ;AACF,IAAM,eAAe;AAMrB,IAAM,oBACJ;AAIF,IAAM,gBAAgB;AAItB,SAAS,mBAAmB,MAAsB;AAChD,SAAO,KAAK,QAAQ,eAAe,EAAE,EAAE,QAAQ,WAAW,EAAE,EAAE,KAAK;AACrE;AAEA,SAAS,YAAY,MAAuB;AAC1C,SAAO,aAAa,KAAK,KAAK,KAAK,CAAC;AACtC;AAEA,SAAS,SAAS,MAAuB;AACvC,QAAM,IAAI,KAAK,KAAK;AACpB,MAAI,CAAC,EAAG,QAAO;AACf,SAAO,eAAe,KAAK,CAAC,KAAK,cAAc,KAAK,CAAC,KAAK,UAAU,KAAK,CAAC;AAC5E;AAEA,SAAS,cAAc,MAAuB;AAC5C,QAAM,IAAI,KAAK,KAAK;AACpB,MAAI,CAAC,EAAG,QAAO;AACf,MAAI,gBAAgB,KAAK,CAAC,KAAK,aAAa,KAAK,CAAC,EAAG,QAAO;AAC5D,SAAO,kBAAkB,KAAK,CAAC;AACjC;AAEA,SAAS,cAAc,MAAuB;AAC5C,SAAO,cAAc,KAAK,IAAI;AAChC;AAKA,SAAS,QAAQ,MAAuB;AACtC,QAAM,IAAI,KAAK,KAAK;AACpB,MAAI,CAAC,EAAG,QAAO;AACf,MAAI,EAAE,SAAS,GAAG,EAAG,QAAO;AAC5B,MACE,SAAS,KAAK,CAAC,KACf,KAAK,KAAK,CAAC,KACX,QAAQ,KAAK,CAAC,KACd,CAAC,cAAc,CAAC,KAChB,EAAE,MAAM,KAAK,EAAE,UAAU,GACzB;AACA,WAAO;AAAA,EACT;AACA,SAAO;AACT;AASA,SAAS,qBAAqB,MAAuB;AACnD,QAAM,IAAI,KAAK,KAAK;AACpB,MAAI,CAAC,KAAK,cAAc,CAAC,KAAK,cAAc,CAAC,EAAG,QAAO;AACvD,MAAI,kBAAkB,KAAK,CAAC,EAAG,QAAO;AACtC,MAAI,mBAAmB,KAAK,CAAC,EAAG,QAAO;AACvC,SAAO;AACT;AAEA,SAAS,oBACP,OACA,gBACS;AACT,WAAS,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;AACrC,UAAM,OAAO,MAAM,CAAC;AACpB,QAAI,SAAS,UAAa,CAAC,cAAc,IAAI,KAAK,cAAc,IAAI,GAAG;AACrE;AAAA,IACF;AACA,UAAM,OAAO,IAAI,IAAI,MAAM,IAAI,CAAC,IAAI;AACpC,QAAI,SAAS,SAAY,QAAQ,IAAI,IAAI,eAAgB;AACzD,WAAO;AAAA,EACT;AACA,SAAO;AACT;AAEA,IAAO,2BAAQ,0BAAY;AAAA,EACzB,CAAC,SACC,gFAAgF,IAAI;AACxF,EAAuB;AAAA,EACrB,MAAM;AAAA,EACN,MAAM;AAAA,IACJ,MAAM;AAAA,IACN,MAAM;AAAA,MACJ,aACE;AAAA,IACJ;AAAA,IACA,QAAQ,CAAC;AAAA,IACT,UAAU;AAAA,MACR,kBACE;AAAA,MACF,eACE;AAAA,MACF,oBACE;AAAA,MACF,oBACE;AAAA,IACJ;AAAA,EACF;AAAA,EACA,gBAAgB,CAAC;AAAA,EACjB,OAAO,SAAS;AACd,UAAM,aAAa,QAAQ;AAE3B,aAAS,aAAa,SAAoC;AACxD,YAAM,SAAS,WAAW,eAAe,SAAS;AAAA,QAChD,iBAAiB;AAAA,MACnB,CAAC;AACD,aAAO,CAAC,UAAU,OAAO,IAAI,IAAI,OAAO,QAAQ,IAAI,MAAM;AAAA,IAC5D;AAEA,aAAS,QAAQ,SAAoC;AACnD,aAAO,QAAQ,SAAS,WAAW,MAAM,KAAK,QAAQ,KAAK;AAAA,IAC7D;AAEA,aAAS,sBACP,UACA,eACM;AACN,YAAM,UAA8B,CAAC;AACrC,UAAI,WAA0B;AAC9B,iBAAW,WAAW,UAAU;AAC9B,YAAI,QAAQ,SAAS,OAAQ;AAC7B,YAAI,QAAQ,IAAI,MAAM,QAAQ,cAAe;AAC7C,YAAI,CAAC,aAAa,OAAO,EAAG;AAC5B,cAAM,OAAO,mBAAmB,QAAQ,KAAK;AAC7C,YAAI,YAAY,IAAI,KAAK,KAAK,WAAW,GAAG,EAAG;AAC/C,YAAI,aAAa,QAAQ,QAAQ,IAAI,MAAM,SAAS,WAAW,EAAG;AAClE,gBAAQ,KAAK,OAAO;AACpB,mBAAW,QAAQ,IAAI,MAAM;AAAA,MAC/B;AACA,YAAM,QAAQ,QAAQ,CAAC;AACvB,UAAI,UAAU,UAAa,QAAQ,SAAS,qBAAsB;AAClE,YAAM,SAAS,QAAQ,IAAI,CAAC,MAAM,mBAAmB,EAAE,KAAK,CAAC;AAC7D,UAAI,OAAO,KAAK,CAAC,SAAS,WAAW,KAAK,IAAI,CAAC,EAAG;AAGlD,UAAI,OAAO,KAAK,CAAC,SAAS,QAAQ,IAAI,CAAC,EAAG;AAC1C,cAAQ,OAAO,EAAE,MAAM,OAAO,WAAW,qBAAqB,CAAC;AAAA,IACjE;AAEA,WAAO;AAAA,MACL,UAAgB;AACd,cAAM,WAAW,WAAW,eAAe;AAC3C,cAAM,gBACJ,WAAW,IAAI,OAAO,CAAC,GAAG,IAAI,MAAM,QAAQ,OAAO;AAErD,iBAAS,IAAI,GAAG,IAAI,SAAS,QAAQ,KAAK;AACxC,gBAAM,UAAU,SAAS,CAAC;AAC1B,cAAI,YAAY,OAAW;AAC3B,cAAI,QAAQ,OAAO,KAAK,CAAC,aAAa,OAAO,EAAG;AAChD,cAAI,WAAW,KAAK,QAAQ,KAAK,EAAG;AACpC,gBAAM,QAAQ,QAAQ,MACnB,MAAM,IAAI,EACV,IAAI,kBAAkB,EACtB,OAAO,CAAC,MAAM,EAAE,SAAS,KAAK,CAAC,YAAY,CAAC,CAAC;AAChD,cAAI,MAAM,KAAK,QAAQ,GAAG;AACxB,oBAAQ,OAAO,EAAE,MAAM,SAAS,WAAW,gBAAgB,CAAC;AAC5D;AAAA,UACF;AACA,gBAAM,OAAO,SAAS,IAAI,CAAC;AAC3B,gBAAM,iBACJ,SAAS,UACT,KAAK,SAAS,UACd,KAAK,IAAI,IAAI,SAAS,QAAQ,IAAI,MAAM,OAAO,KAC/C,QAAQ,mBAAmB,KAAK,KAAK,CAAC;AACxC,cAAI,oBAAoB,OAAO,cAAc,GAAG;AAC9C,oBAAQ,OAAO,EAAE,MAAM,SAAS,WAAW,mBAAmB,CAAC;AAC/D;AAAA,UACF;AAIA,cAAI,QAAQ,SAAS,UAAU,MAAM,WAAW,GAAG;AACjD,kBAAM,OAAO,MAAM,CAAC;AACpB,gBAAI,SAAS,UAAa,qBAAqB,IAAI,GAAG;AACpD,sBAAQ,OAAO,EAAE,MAAM,SAAS,WAAW,qBAAqB,CAAC;AAAA,YACnE;AAAA,UACF;AAAA,QACF;AAEA,8BAAsB,UAAU,aAAa;AAAA,MAC/C;AAAA,IACF;AAAA,EACF;AACF,CAAC;;;ACrPD,IAAAC,gBAA2C;AAS3C,IAAM,0BAA6C;AAAA,EACjD;AAAA,EACA;AAAA,EACA;AACF;AAEA,SAAS,kBACP,UACA,UACS;AACT,aAAW,WAAW,UAAU;AAE9B,UAAM,cAAc,QACjB,QAAQ,qBAAqB,MAAM,EACnC,QAAQ,SAAS,gBAAgB,EACjC,QAAQ,OAAO,WAAW,EAC1B,QAAQ,mBAAmB,IAAI;AAClC,QAAI,IAAI,OAAO,IAAI,WAAW,GAAG,EAAE,KAAK,QAAQ,GAAG;AACjD,aAAO;AAAA,IACT;AAAA,EACF;AACA,SAAO;AACT;AAEA,SAAS,mBAAmB,YAA6B;AAEvD,QAAM,OAAO,WAAW,MAAM,GAAG,IAAI;AACrC,SAAO,eAAe,KAAK,IAAI;AACjC;AAEA,IAAO,kBAAQ,0BAAY;AAAA,EACzB,CAAC,SACC,8EAA8E,IAAI;AACtF,EAAuB;AAAA,EACrB,MAAM;AAAA,EACN,MAAM;AAAA,IACJ,MAAM;AAAA,IACN,MAAM;AAAA,MACJ,aACE;AAAA,IACJ;AAAA,IACA,QAAQ;AAAA,MACN;AAAA,QACE,MAAM;AAAA,QACN,sBAAsB;AAAA,QACtB,YAAY;AAAA,UACV,aAAa;AAAA,YACX,MAAM;AAAA,YACN,OAAO,EAAE,MAAM,SAAS;AAAA,UAC1B;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,IACA,UAAU;AAAA,MACR,QACE;AAAA,IACJ;AAAA,EACF;AAAA,EACA,gBAAgB,CAAC,CAAC,CAAC;AAAA,EACnB,OAAO,SAAS,CAAC,UAAU,GAAG;AAC5B,UAAM,UAAU,cAAc,CAAC;AAC/B,UAAM,cAAc,QAAQ,eAAe,CAAC;AAC5C,UAAM,WAAW,QAAQ;AACzB,UAAM,aAAa,QAAQ,WAAW,QAAQ;AAE9C,UAAM,qBAAqB,wBAAwB;AAAA,MAAK,CAAC,OACvD,GAAG,KAAK,QAAQ;AAAA,IAClB;AACA,UAAM,oBACJ,YAAY,SAAS,KAAK,kBAAkB,UAAU,WAAW;AACnE,UAAM,cAAc,mBAAmB,UAAU;AAEjD,QAAI,sBAAsB,qBAAqB,aAAa;AAC1D,aAAO,CAAC;AAAA,IACV;AAEA,WAAO;AAAA,MACL,kBAAkB,MAAwC;AACxD,gBAAQ,OAAO;AAAA,UACb;AAAA,UACA,WAAW;AAAA,QACb,CAAC;AAAA,MACH;AAAA,IACF;AAAA,EACF;AACF,CAAC;;;AC/DD,IAAAC,gBAA2C;AAK3C,IAAM,0BACJ;AAEF,IAAM,0BACJ;AAGF,IAAM,qBAAqB;AAK3B,SAAS,iBAAiB,MAAsD;AAC9E,MAAI,KAAK,SAAS,kBAAkB;AAClC,WAAO;AAAA,EACT;AACA,QAAM,SAAS,KAAK;AACpB,MAAI,OAAO,SAAS,sBAAsB,OAAO,UAAU;AACzD,WAAO;AAAA,EACT;AACA,QAAM,EAAE,QAAQ,SAAS,IAAI;AAC7B,SACE,OAAO,SAAS,gBAChB,OAAO,SAAS,UAChB,SAAS,SAAS,gBAClB,SAAS,SAAS;AAEtB;AAQA,SAAS,gBAAgB,MAAoC;AAC3D,MAAI,UAAyB;AAC7B,MAAI,SAAS,QAAQ;AAErB,SAAO,QAAQ;AACb,QACE,OAAO,SAAS,sBAChB,OAAO,WAAW,WAClB,CAAC,OAAO,UACR;AACA,gBAAU;AACV,eAAS,QAAQ;AACjB;AAAA,IACF;AACA,QAAI,OAAO,SAAS,oBAAoB,OAAO,WAAW,SAAS;AACjE,gBAAU;AACV,eAAS,QAAQ;AACjB;AAAA,IACF;AACA;AAAA,EACF;AAEA,SAAO;AACT;AAOA,SAAS,wBAAwB,MAA8B;AAC7D,MAAI,UAAyB;AAC7B,MAAI,SAAS,QAAQ;AAErB,SAAO,QAAQ;AACb,QACE,OAAO,SAAS,sBAChB,OAAO,WAAW,WAClB,CAAC,OAAO,YACR,OAAO,SAAS,SAAS,gBACzB,OAAO,SAAS,SAAS,YACzB;AACA,YAAM,cAAc,OAAO;AAC3B,UACE,eACA,YAAY,SAAS,oBACrB,YAAY,WAAW,QACvB;AACA,cAAM,WAAW,YAAY,UAAU,CAAC;AACxC,YAAI,YAAY,SAAS,SAAS,aAAa,SAAS,UAAU,IAAI;AACpE,iBAAO;AAAA,QACT;AAAA,MACF;AAAA,IACF;AAEA,QAAI,OAAO,SAAS,sBAAsB,OAAO,WAAW,SAAS;AACnE,gBAAU;AACV,eAAS,QAAQ;AACjB;AAAA,IACF;AACA,QAAI,OAAO,SAAS,oBAAoB,OAAO,WAAW,SAAS;AACjE,gBAAU;AACV,eAAS,QAAQ;AACjB;AAAA,IACF;AACA;AAAA,EACF;AAEA,SAAO;AACT;AAUA,SAAS,kBAAkB,MAAyC;AAClE,MAAI,UAAyB;AAC7B,MAAI,SAAS,QAAQ;AAErB,SAAO,QAAQ;AACb,QAAI,OAAO,SAAS,wBAAwB,OAAO,SAAS,SAAS;AACnE,UAAI,OAAO,GAAG,SAAS,cAAc;AACnC,eAAO,OAAO,GAAG;AAAA,MACnB;AACA,aAAO;AAAA,IACT;AAEA,QAAI,OAAO,SAAS,cAAc,OAAO,UAAU,SAAS;AAC1D,YAAM,MAAM,OAAO;AACnB,UAAI,CAAC,OAAO,YAAY,IAAI,SAAS,cAAc;AACjD,eAAO,IAAI;AAAA,MACb;AACA,UAAI,IAAI,SAAS,aAAa,OAAO,IAAI,UAAU,UAAU;AAC3D,eAAO,IAAI;AAAA,MACb;AACA,aAAO;AAAA,IACT;AAEA,QAAI,OAAO,SAAS,wBAAwB,OAAO,UAAU,SAAS;AACpE,YAAM,MAAM,OAAO;AACnB,UAAI,CAAC,OAAO,YAAY,IAAI,SAAS,cAAc;AACjD,eAAO,IAAI;AAAA,MACb;AACA,UAAI,IAAI,SAAS,aAAa,OAAO,IAAI,UAAU,UAAU;AAC3D,eAAO,IAAI;AAAA,MACb;AACA,aAAO;AAAA,IACT;AAEA,QACE,OAAO,SAAS,yBAChB,OAAO,SAAS,wBAChB,OAAO,SAAS,6BAChB,OAAO,SAAS,oBAChB,OAAO,SAAS,qBAChB,OAAO,SAAS,uBAChB;AACA,aAAO;AAAA,IACT;AAEA,cAAU;AACV,aAAS,QAAQ;AAAA,EACnB;AAEA,SAAO;AACT;AAMA,SAAS,yBACP,MACA,KACM;AACN,MAAI,KAAK,SAAS,aAAa,OAAO,KAAK,UAAU,UAAU;AAC7D,QAAI,KAAK,KAAK,KAAK;AACnB;AAAA,EACF;AACA,MAAI,KAAK,SAAS,mBAAmB;AACnC,eAAW,SAAS,KAAK,QAAQ;AAC/B,UAAI,KAAK,MAAM,MAAM,UAAU,MAAM,MAAM,GAAG;AAAA,IAChD;AACA;AAAA,EACF;AACA,MAAI,KAAK,SAAS,sBAAsB,KAAK,aAAa,KAAK;AAC7D,6BAAyB,KAAK,MAAM,GAAG;AACvC,6BAAyB,KAAK,OAAO,GAAG;AAAA,EAC1C;AACF;AAOA,SAAS,8BAA8B,MAA8B;AACnE,QAAM,YAAY,gBAAgB,IAAI;AAEtC,MAAI,UAAyB;AAC7B,MAAI,SAAS,QAAQ;AACrB,MAAI;AAEJ,SAAO,QAAQ;AACb,QACE,OAAO,SAAS,sBAChB,OAAO,aAAa,QACnB,OAAO,SAAS,WAAW,OAAO,UAAU,UAC7C;AACA,YAAM;AACN,gBAAU;AACV,eAAS,QAAQ;AACjB;AAAA,IACF;AACA,QAAI,OAAO,SAAS,mBAAmB;AACrC,YAAM;AACN,gBAAU;AACV,eAAS,QAAQ;AACjB;AAAA,IACF;AACA;AAAA,EACF;AAEA,MAAI,CAAC,KAAK;AACR,WAAO;AAAA,EACT;AAEA,QAAM,QAAkB,CAAC;AACzB,2BAAyB,KAAK,KAAK;AACnC,SAAO,MAAM,KAAK,CAAC,SAAS,mBAAmB,KAAK,IAAI,CAAC;AAC3D;AAEA,IAAO,gCAAQ,0BAAY;AAAA,EACzB,CAAC,SACC,8EAA8E,IAAI;AACtF,EAAuB;AAAA,EACrB,MAAM;AAAA,EACN,MAAM;AAAA,IACJ,MAAM;AAAA,IACN,MAAM;AAAA,MACJ,aACE;AAAA,IACJ;AAAA,IACA,QAAQ,CAAC;AAAA,IACT,UAAU;AAAA,MACR,kBACE;AAAA,IACJ;AAAA,EACF;AAAA,EACA,gBAAgB,CAAC;AAAA,EACjB,OAAO,SAAS;AACd,WAAO;AAAA,MACL,eAAe,MAAqC;AAClD,YAAI,CAAC,iBAAiB,IAAI,GAAG;AAC3B;AAAA,QACF;AAEA,cAAM,OAAO,kBAAkB,IAAI;AAInC,YAAI,SAAS,UAAa,wBAAwB,KAAK,IAAI,GAAG;AAC5D,kBAAQ,OAAO,EAAE,MAAM,WAAW,mBAAmB,CAAC;AACtD;AAAA,QACF;AAKA,YAAI,SAAS,UAAa,wBAAwB,KAAK,IAAI,GAAG;AAC5D;AAAA,QACF;AAIA,YAAI,8BAA8B,IAAI,GAAG;AACvC;AAAA,QACF;AAGA,YAAI,wBAAwB,IAAI,GAAG;AACjC,kBAAQ,OAAO,EAAE,MAAM,WAAW,mBAAmB,CAAC;AAAA,QACxD;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF,CAAC;;;ACvTD,IAAAC,gBAA2C;AAM3C,IAAM,qBAAqB;AAG3B,IAAM,qBAAqB;AAG3B,IAAM,oBAAyC,oBAAI,IAAI,CAAC,WAAW,SAAS,MAAM,CAAC;AAOnF,SAAS,eAAe,OAAoB,MAAuB;AACjE,MAAI,UAA8B;AAClC,SAAO,SAAS;AACd,UAAM,WAAW,QAAQ,IAAI,IAAI,IAAI;AACrC,QAAI,UAAU;AACZ,iBAAW,OAAO,SAAS,MAAM;AAC/B,YAAI,IAAI,SAAS,eAAe;AAC9B,iBAAO;AAAA,QACT;AAAA,MACF;AAAA,IACF;AACA,cAAU,QAAQ;AAAA,EACpB;AACA,SAAO;AACT;AAOA,SAAS,oBACP,QACA,OACS;AACT,QAAMC,YACJ,CAAC,OAAO,YAAY,OAAO,SAAS,SAAS,eAAe,OAAO,SAAS,OAAO;AAErF,MAAIA,cAAa,QAAQ,mBAAmB,KAAKA,SAAQ,GAAG;AAC1D,WAAO;AAAA,EACT;AAEA,QAAM,OAAO,OAAO;AACpB,QAAM,oBACJ,KAAK,SAAS,iBACb,mBAAmB,KAAK,KAAK,IAAI,KAAK,eAAe,OAAO,KAAK,IAAI;AACxE,MAAI,mBAAmB;AACrB,WAAOA,cAAa,QAAQ,CAAC,kBAAkB,IAAIA,UAAS,YAAY,CAAC;AAAA,EAC3E;AAEA,SAAO;AACT;AAGA,SAAS,uBACP,MAC4B;AAC5B,MACE,KAAK,SAAS,sBACd,KAAK,aAAa,gBAClB,KAAK,MAAM,SAAS,gBACpB,KAAK,MAAM,SAAS,SACpB;AACA,WAAO,KAAK;AAAA,EACd;AACA,SAAO;AACT;AAGA,IAAM,qBAAqB;AAG3B,SAAS,iBACP,MAC4B;AAC5B,QAAM,MAAM,KAAK,SAAS,mBAAmB,KAAK,UAAU,CAAC,IAAI;AACjE,MACE,KAAK,SAAS,oBACd,KAAK,OAAO,SAAS,gBACrB,mBAAmB,KAAK,KAAK,OAAO,IAAI,KACxC,KAAK,UAAU,WAAW,KAC1B,QAAQ,UACR,IAAI,SAAS,iBACb;AACA,WAAO;AAAA,EACT;AACA,SAAO;AACT;AAOA,SAAS,qBACP,MAC4B;AAC5B,SAAO,uBAAuB,IAAI,KAAK,iBAAiB,IAAI;AAC9D;AAGA,SAAS,8BACP,MAC4B;AAC5B,MAAI,KAAK,SAAS,qBAAqB,KAAK,aAAa,KAAK;AAC5D,WAAO,qBAAqB,KAAK,QAAQ;AAAA,EAC3C;AACA,SAAO;AACT;AAGA,SAAS,iBAAiB,QAAqC;AAC7D,QAAM,OAAO,OAAO,SAAS,mBAAmB,OAAO,OAAO,CAAC,MAAM;AACrE,QAAM,OAAO,KAAK,KAAK,SAAS,CAAC;AACjC,SACE,SAAS,WACR,KAAK,SAAS,qBAAqB,KAAK,SAAS;AAEtD;AAOA,SAAS,wBACP,MACA,SACA,YACS;AACT,QAAM,UAAU,WAAW,QAAQ,OAAO;AAC1C,MAAI,UAAqC,KAAK;AAC9C,SAAO,SAAS;AACd,QAAI,QAAQ,SAAS,oBAAoB,QAAQ,SAAS,WAAW;AACnE,iBAAW,QAAQ,QAAQ,MAAM;AAC/B,YAAI,KAAK,MAAM,CAAC,KAAK,KAAK,MAAM,CAAC,GAAG;AAClC;AAAA,QACF;AACA,YACE,KAAK,SAAS,iBACd,KAAK,cAAc,QACnB,iBAAiB,KAAK,UAAU,GAChC;AACA,gBAAM,UAAU,qBAAqB,KAAK,IAAI;AAC9C,cAAI,WAAW,WAAW,QAAQ,OAAO,MAAM,SAAS;AACtD,mBAAO;AAAA,UACT;AAAA,QACF;AAAA,MACF;AAAA,IACF;AACA,cAAU,QAAQ;AAAA,EACpB;AACA,SAAO;AACT;AAEA,SAAS,WAAW,MAAqB,WAA0C;AACjF,SACE,cAAc,QACd,KAAK,MAAM,CAAC,KAAK,UAAU,MAAM,CAAC,KAClC,KAAK,MAAM,CAAC,KAAK,UAAU,MAAM,CAAC;AAEtC;AAQA,SAAS,2BACP,MACA,SACA,YACS;AACT,QAAM,UAAU,WAAW,QAAQ,OAAO;AAC1C,QAAM,cAAc,CAAC,YACnB,WAAW,QAAQ,OAAO,MAAM;AAElC,MAAI,UAAqC,KAAK;AAC9C,SAAO,SAAS;AACd,QAAI,QAAQ,SAAS,yBAAyB;AAC5C,YAAM,UAAU,qBAAqB,QAAQ,IAAI;AACjD,UAAI,WAAW,YAAY,OAAO,KAAK,WAAW,MAAM,QAAQ,SAAS,GAAG;AAC1E,eAAO;AAAA,MACT;AACA,YAAM,UAAU,8BAA8B,QAAQ,IAAI;AAC1D,UAAI,WAAW,YAAY,OAAO,KAAK,WAAW,MAAM,QAAQ,UAAU,GAAG;AAC3E,eAAO;AAAA,MACT;AAAA,IACF,WAAW,QAAQ,SAAS,eAAe;AACzC,YAAM,UAAU,qBAAqB,QAAQ,IAAI;AACjD,UAAI,WAAW,YAAY,OAAO,KAAK,WAAW,MAAM,QAAQ,SAAS,GAAG;AAC1E,eAAO;AAAA,MACT;AACA,YAAM,UAAU,8BAA8B,QAAQ,IAAI;AAC1D,UAAI,WAAW,YAAY,OAAO,KAAK,WAAW,MAAM,QAAQ,UAAU,GAAG;AAC3E,eAAO;AAAA,MACT;AAAA,IACF;AACA,cAAU,QAAQ;AAAA,EACpB;AACA,SAAO;AACT;AAEA,SAAS,gBAAgB,QAAsC;AAC7D,SACE,OAAO,SAAS,sBAChB,CAAC,OAAO,YACR,OAAO,OAAO,SAAS,gBACvB,OAAO,OAAO,SAAS,UACvB,OAAO,SAAS,SAAS,gBACzB,OAAO,SAAS,SAAS;AAE7B;AAEA,IAAO,kCAAQ,0BAAY;AAAA,EACzB,CAAC,SACC,8EAA8E,IAAI;AACtF,EAAuB;AAAA,EACrB,MAAM;AAAA,EACN,MAAM;AAAA,IACJ,MAAM;AAAA,IACN,MAAM;AAAA,MACJ,aACE;AAAA,IACJ;AAAA,IACA,QAAQ,CAAC;AAAA,IACT,UAAU;AAAA,MACR,sBACE;AAAA,IACJ;AAAA,EACF;AAAA,EACA,gBAAgB,CAAC;AAAA,EACjB,OAAO,SAAS;AACd,WAAO;AAAA,MACL,eAAe,MAAqC;AAClD,YAAI,CAAC,gBAAgB,KAAK,MAAM,GAAG;AACjC;AAAA,QACF;AAEA,cAAM,WAAW,KAAK,UAAU,CAAC;AACjC,YAAI,CAAC,UAAU;AACb;AAAA,QACF;AAEA,cAAM,QAAQ,QAAQ,WAAW,SAAS,QAAQ;AAElD,YAAI;AACJ,YAAI,SAAS,SAAS,cAAc;AAClC,0BACE,mBAAmB,KAAK,SAAS,IAAI,KAAK,eAAe,OAAO,SAAS,IAAI;AAAA,QACjF,WAAW,SAAS,SAAS,oBAAoB;AAC/C,0BAAgB,oBAAoB,UAAU,KAAK;AAAA,QACrD,OAAO;AACL;AAAA,QACF;AAEA,YAAI,CAAC,eAAe;AAClB;AAAA,QACF;AAEA,YACE,2BAA2B,MAAM,UAAU,QAAQ,UAAU,KAC7D,wBAAwB,MAAM,UAAU,QAAQ,UAAU,GAC1D;AACA;AAAA,QACF;AAEA,gBAAQ,OAAO;AAAA,UACb;AAAA,UACA,WAAW;AAAA,QACb,CAAC;AAAA,MACH;AAAA,IACF;AAAA,EACF;AACF,CAAC;;;ACzQD,IAAAC,gBAA2C;;;ACb3C,IAAAC,gBAA8B;AAEvB,IAAM,cAAmC,oBAAI,IAAI;AAAA,EACtD;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAEM,IAAM,eAAoC,oBAAI,IAAI;AAAA,EACvD;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAGM,IAAM,mBAAwC,oBAAI,IAAI;AAAA,EAC3D;AAAA,EACA;AACF,CAAC;AAQM,IAAM,iBAAiB;AAavB,IAAM,4BAA4B;AAAA,EACvC,aAAa,EAAE,MAAM,SAAS,OAAO,EAAE,MAAM,SAAS,EAAE;AAAA,EACxD,cAAc,EAAE,MAAM,SAAS,OAAO,EAAE,MAAM,SAAS,EAAE;AAC3D;AAGO,SAAS,WAAW,QAAsC;AAC/D,MAAI,OAAO,SAAS,cAAc;AAChC,WAAO,OAAO;AAAA,EAChB;AACA,MACE,OAAO,SAAS,sBAChB,CAAC,OAAO,YACR,OAAO,SAAS,SAAS,cACzB;AACA,WAAO,OAAO,SAAS;AAAA,EACzB;AACA,SAAO;AACT;AAeO,SAAS,iBAAiB,UAA0B,CAAC,GAAe;AACzE,QAAM,cAAmC,oBAAI,IAAI;AAAA,IAC/C,GAAG;AAAA,IACH,IAAI,QAAQ,eAAe,CAAC,GAAG,IAAI,CAAC,SAAS,KAAK,YAAY,CAAC;AAAA,EACjE,CAAC;AACD,QAAM,eAAoC,IAAI,IAAI,QAAQ,gBAAgB,CAAC,CAAC;AAE5E,WAAS,iBACP,MACS;AACT,YAAQ,KAAK,MAAM;AAAA,MACjB,KAAK;AACH,eAAO,YAAY,IAAI,KAAK,KAAK,YAAY,CAAC;AAAA,MAChD,KAAK,oBAAoB;AACvB,cAAM,EAAE,UAAU,OAAO,IAAI;AAC7B,YAAI,CAAC,KAAK,YAAY,SAAS,SAAS,cAAc;AACpD,gBAAM,UAAU,SAAS,KAAK,YAAY;AAC1C,cAAI,YAAY,IAAI,OAAO,KAAK,iBAAiB,IAAI,OAAO,GAAG;AAC7D,mBAAO;AAAA,UACT;AAAA,QACF;AACA,eAAO,iBAAiB,MAAM;AAAA,MAChC;AAAA,MACA,KAAK,kBAAkB;AACrB,cAAM,SAAS,KAAK;AACpB,YACE,OAAO,SAAS,sBAChB,CAAC,OAAO,YACR,OAAO,SAAS,SAAS,gBACzB,iBAAiB,IAAI,OAAO,SAAS,KAAK,YAAY,CAAC,GACvD;AACA,iBAAO;AAAA,QACT;AACA,YAAI,OAAO,SAAS,SAAS;AAC3B,iBAAO,iBAAiB,MAAM;AAAA,QAChC;AACA,eAAO;AAAA,MACT;AAAA,MACA;AACE,eAAO;AAAA,IACX;AAAA,EACF;AAEA,WAAS,kBAAkB,MAA8B;AACvD,QAAI,KAAK,SAAS,oBAAoB,aAAa,SAAS,GAAG;AAC7D,aAAO;AAAA,IACT;AACA,UAAM,OAAO,WAAW,KAAK,MAAM;AACnC,WAAO,SAAS,QAAQ,aAAa,IAAI,IAAI;AAAA,EAC/C;AAEA,WAAS,cAAc,MAA8B;AACnD,QAAI,KAAK,SAAS,kBAAkB;AAClC,aAAO;AAAA,IACT;AACA,QAAI,kBAAkB,IAAI,GAAG;AAC3B,aAAO;AAAA,IACT;AACA,UAAM,SAAS,KAAK;AACpB,QACE,OAAO,SAAS,sBAChB,OAAO,YACP,OAAO,SAAS,SAAS,cACzB;AACA,aAAO;AAAA,IACT;AACA,QAAI,CAAC,YAAY,IAAI,OAAO,SAAS,KAAK,YAAY,CAAC,GAAG;AACxD,aAAO;AAAA,IACT;AACA,WAAO,iBAAiB,OAAO,MAAM;AAAA,EACvC;AAEA,SAAO,EAAE,kBAAkB,mBAAmB,cAAc;AAC9D;;;ADrIA,IAAMC,2BAA6C;AAAA,EACjD;AAAA,EACA;AAAA,EACA;AACF;AAEA,IAAO,4BAAQ,0BAAY;AAAA,EACzB,CAAC,SACC,8EAA8E,IAAI;AACtF,EAAuB;AAAA,EACrB,MAAM;AAAA,EACN,MAAM;AAAA,IACJ,MAAM;AAAA,IACN,MAAM;AAAA,MACJ,aACE;AAAA,IACJ;AAAA,IACA,QAAQ;AAAA,MACN;AAAA,QACE,MAAM;AAAA,QACN,sBAAsB;AAAA,QACtB,YAAY,EAAE,GAAG,0BAA0B;AAAA,MAC7C;AAAA,IACF;AAAA,IACA,UAAU;AAAA,MACR,gBACE;AAAA,MACF,YACE;AAAA,IACJ;AAAA,EACF;AAAA,EACA,gBAAgB,CAAC,CAAC,CAAC;AAAA,EACnB,OAAO,SAAS,CAAC,cAAc,GAAG;AAChC,UAAM,UAAU,iBAAiB,cAAc;AAC/C,UAAM,WAAW,QAAQ;AAGzB,aAAS,uBAAuB,WAAwC;AACtE,UAAI,UAAU,SAAS,uBAAuB;AAC5C,eAAO;AAAA,MACT;AACA,aAAO,QAAQ,cAAc,UAAU,UAAU;AAAA,IACnD;AAEA,UAAM,qBAAqBA,yBAAwB;AAAA,MAAK,CAAC,OACvD,GAAG,KAAK,QAAQ;AAAA,IAClB;AAEA,QAAI,oBAAoB;AACtB,aAAO,CAAC;AAAA,IACV;AAEA,WAAO;AAAA,MACL,YAAY,MAAkC;AAC5C,cAAM,aAAa,KAAK,KAAK;AAE7B,YAAI,WAAW,WAAW,GAAG;AAG3B,cAAI,QAAQ,WAAW,kBAAkB,KAAK,IAAI,EAAE,SAAS,GAAG;AAC9D;AAAA,UACF;AACA,kBAAQ,OAAO,EAAE,MAAM,WAAW,aAAa,CAAC;AAChD;AAAA,QACF;AAEA,cAAM,0BAA0B,WAAW;AAAA,UAAM,CAAC,cAChD,uBAAuB,SAAS;AAAA,QAClC;AAEA,YAAI,yBAAyB;AAC3B,kBAAQ,OAAO,EAAE,MAAM,WAAW,iBAAiB,CAAC;AAAA,QACtD;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF,CAAC;;;AEzHD,IAAAC,gBAA2C;AAM3C,SAAS,aAAa,MAA0C;AAC9D,SACE,CAAC,KAAK,YACN,KAAK,OAAO,SAAS,gBACrB,KAAK,OAAO,SAAS,aACrB,KAAK,SAAS,SAAS,gBACvB,KAAK,SAAS,SAAS;AAE3B;AAGA,SAAS,gBAAgB,MAA0C;AACjE,SACE,CAAC,KAAK,YACN,KAAK,SAAS,SAAS,gBACvB,KAAK,SAAS,SAAS,SACvB,KAAK,OAAO,SAAS,kBACrB,KAAK,OAAO,KAAK,SAAS,YAC1B,KAAK,OAAO,SAAS,SAAS;AAElC;AAIA,IAAM,uBAA4C,oBAAI,IAAI;AAAA,EACxD;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAGD,SAAS,0BAA0B,MAA0C;AAC3E,QAAM,SAAS,KAAK;AACpB,SACE,OAAO,SAAS,sBAChB,OAAO,WAAW,QAClB,CAAC,OAAO,YACR,OAAO,SAAS,SAAS,gBACzB,qBAAqB,IAAI,OAAO,SAAS,IAAI;AAEjD;AAEA,IAAO,qBAAQ,0BAAY;AAAA,EACzB,CAAC,SACC,8EAA8E,IAAI;AACtF,EAAuB;AAAA,EACrB,MAAM;AAAA,EACN,MAAM;AAAA,IACJ,MAAM;AAAA,IACN,MAAM;AAAA,MACJ,aACE;AAAA,IACJ;AAAA,IACA,QAAQ,CAAC;AAAA,IACT,UAAU;AAAA,MACR,UACE;AAAA,IACJ;AAAA,EACF;AAAA,EACA,gBAAgB,CAAC;AAAA,EACjB,OAAO,SAAS;AACd,WAAO;AAAA,MACL,iBAAiB,MAAuC;AACtD,aACG,aAAa,IAAI,KAAK,gBAAgB,IAAI,MAC3C,CAAC,0BAA0B,IAAI,GAC/B;AACA,kBAAQ,OAAO;AAAA,YACb;AAAA,YACA,WAAW;AAAA,UACb,CAAC;AAAA,QACH;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF,CAAC;;;AC3CD,IAAAC,iBAIO;AAgBP,SAAS,aAAa,KAAsD;AAC1E,MAAI,QAAQ,MAAM;AAChB,WAAO;AAAA,EACT;AACA,MAAI,IAAI,SAAS,8BAAe,SAAS;AACvC,QAAI,IAAI,UAAU,MAAM;AACtB,aAAO;AAAA,IACT;AACA,QAAI,OAAO,IAAI,UAAU,WAAW;AAClC,aAAO;AAAA,IACT;AACA,QAAI,OAAO,IAAI,UAAU,UAAU;AACjC,aAAO;AAAA,IACT;AACA,WAAO;AAAA,EACT;AACA,MAAI,IAAI,SAAS,8BAAe,cAAc,IAAI,SAAS,aAAa;AACtE,WAAO;AAAA,EACT;AACA,MAAI,IAAI,SAAS,8BAAe,iBAAiB;AAC/C,WAAO;AAAA,EACT;AACA,MAAI,IAAI,SAAS,8BAAe,kBAAkB;AAChD,WAAO;AAAA,EACT;AACA,SAAO;AACT;AAGA,SAAS,mBAAmB,KAA0C;AACpE,MAAI,QAAQ,MAAM;AAChB,WAAO;AAAA,EACT;AACA,MAAI,IAAI,SAAS,8BAAe,WAAW,IAAI,UAAU,MAAM;AAC7D,WAAO;AAAA,EACT;AACA,MAAI,IAAI,SAAS,8BAAe,WAAW,IAAI,UAAU,OAAO;AAC9D,WAAO;AAAA,EACT;AACA,MAAI,IAAI,SAAS,8BAAe,cAAc,IAAI,SAAS,aAAa;AACtE,WAAO;AAAA,EACT;AACA,MAAI,IAAI,SAAS,8BAAe,mBAAmB,IAAI,SAAS,WAAW,GAAG;AAC5E,WAAO;AAAA,EACT;AACA,MACE,IAAI,SAAS,8BAAe,oBAC5B,IAAI,WAAW,WAAW,GAC1B;AACA,WAAO;AAAA,EACT;AACA,SAAO;AACT;AAEA,SAAS,eAAe,MAA8B;AACpD,SACE,KAAK,SAAS,8BAAe,uBAC7B,KAAK,SAAS,8BAAe,sBAC7B,KAAK,SAAS,8BAAe;AAEjC;AAEA,SAAS,OAAO,OAAwC;AACtD,SACE,OAAO,UAAU,YACjB,UAAU,QACV,OAAQ,MAA6B,SAAS;AAElD;AAOA,SAAS,gBACP,MACA,OACS;AACT,MAAI,QAAQ;AAEZ,QAAM,UAAU,CAAC,YAAiC;AAChD,QAAI,OAAO;AACT;AAAA,IACF;AACA,QAAI,MAAM,OAAO,GAAG;AAClB,cAAQ;AACR;AAAA,IACF;AACA,QAAI,eAAe,OAAO,GAAG;AAC3B;AAAA,IACF;AACA,eAAW,OAAO,OAAO,KAAK,OAAO,GAAG;AACtC,UAAI,QAAQ,UAAU;AACpB;AAAA,MACF;AACA,YAAM,QAAS,QAA+C,GAAG;AACjE,UAAI,MAAM,QAAQ,KAAK,GAAG;AACxB,mBAAW,SAAS,OAAO;AACzB,cAAI,OAAO,KAAK,GAAG;AACjB,oBAAQ,KAAK;AAAA,UACf;AAAA,QACF;AAAA,MACF,WAAW,OAAO,KAAK,GAAG;AACxB,gBAAQ,KAAK;AAAA,MACf;AAAA,IACF;AAAA,EACF;AAEA,UAAQ,IAAI;AACZ,SAAO;AACT;AAGA,SAAS,cAAc,MAA8B;AACnD,SAAO;AAAA,IACL;AAAA,IACA,CAAC,YAAY,QAAQ,SAAS,8BAAe;AAAA,EAC/C;AACF;AAGA,SAAS,UAAU,OAAsB,MAAuB;AAC9D,UAAQ,MAAM,MAAM;AAAA,IAClB,KAAK,8BAAe;AAClB,aAAO,MAAM,SAAS;AAAA,IACxB,KAAK,8BAAe;AAClB,aAAO,UAAU,MAAM,MAAM,IAAI;AAAA,IACnC,KAAK,8BAAe;AAClB,aAAO,UAAU,MAAM,UAAU,IAAI;AAAA,IACvC,KAAK,8BAAe;AAClB,aAAO,MAAM,SAAS;AAAA,QACpB,CAAC,YAAY,YAAY,QAAQ,UAAU,SAAS,IAAI;AAAA,MAC1D;AAAA,IACF,KAAK,8BAAe;AAClB,aAAO,MAAM,WAAW;AAAA,QAAK,CAAC,aAC5B,SAAS,SAAS,8BAAe,cAC7B,UAAU,SAAS,UAAU,IAAI,IACjC,UAAU,SAAS,OAAO,IAAI;AAAA,MACpC;AAAA,IACF;AACE,aAAO;AAAA,EACX;AACF;AAoBA,SAAS,iBAAiB,MAAqB,MAAuB;AACpE,MAAI,QAAQ;AAGZ,QAAM,cAAc,CAAC,OACnB,eAAe,EAAE,KAChB,GAAmD,OAAO;AAAA,IAAK,CAAC,UAC/D,UAAU,OAAO,IAAI;AAAA,EACvB;AAEF,QAAM,UAAU,CAAC,YAAiC;AAChD,QAAI,OAAO;AACT;AAAA,IACF;AACA,QAAI,QAAQ,SAAS,8BAAe,cAAc,QAAQ,SAAS,MAAM;AACvE,cAAQ;AACR;AAAA,IACF;AACA,QAAI,YAAY,OAAO,GAAG;AACxB;AAAA,IACF;AACA,eAAW,OAAO,OAAO,KAAK,OAAO,GAAG;AACtC,UAAI,QAAQ,UAAU;AACpB;AAAA,MACF;AAEA,UACE,QAAQ,SACR,QAAQ,SAAS,8BAAe,YAChC,CAAC,QAAQ,UACT;AACA;AAAA,MACF;AAEA,UACE,QAAQ,cACR,QAAQ,SAAS,8BAAe,oBAChC,CAAC,QAAQ,UACT;AACA;AAAA,MACF;AACA,YAAM,QAAS,QAA+C,GAAG;AACjE,UAAI,MAAM,QAAQ,KAAK,GAAG;AACxB,mBAAW,SAAS,OAAO;AACzB,cAAI,OAAO,KAAK,GAAG;AACjB,oBAAQ,KAAK;AAAA,UACf;AAAA,QACF;AAAA,MACF,WAAW,OAAO,KAAK,GAAG;AACxB,gBAAQ,KAAK;AAAA,MACf;AAAA,IACF;AAAA,EACF;AAEA,UAAQ,IAAI;AACZ,SAAO;AACT;AASA,SAAS,mBACP,MACA,YACS;AACT,MAAI,eAAe,MAAM;AACvB,WAAO;AAAA,EACT;AACA,SAAO,KAAK,KAAK,CAAC,QAAQ,iBAAiB,KAAK,UAAU,CAAC;AAC7D;AAGA,SAAS,WAAW,WAA0D;AAC5E,SAAO,UAAU,OAAO;AAC1B;AAGA,IAAM,0BAA+C,oBAAI,IAAI;AAAA,EAC3D;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAMD,SAAS,kBAAkB,MAA8B;AACvD,MACE,KAAK,SAAS,8BAAe,kBAC7B,KAAK,OAAO,SAAS,8BAAe,oBACpC,CAAC,KAAK,OAAO,YACb,KAAK,OAAO,SAAS,SAAS,8BAAe,YAC7C;AACA,WAAO,KAAK,OAAO,SAAS,SAAS;AAAA,EACvC;AACA,MACE,KAAK,SAAS,8BAAe,iBAC7B,KAAK,OAAO,SAAS,8BAAe,YACpC;AACA,WAAO,wBAAwB,IAAI,KAAK,OAAO,IAAI;AAAA,EACrD;AACA,SAAO;AACT;AAGA,IAAM,sBAA2C,oBAAI,IAAI;AAAA,EACvD;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAED,SAAS,iBAAiB,MAA8B;AACtD,SACE,KAAK,SAAS,8BAAe,kBAC7B,KAAK,OAAO,SAAS,8BAAe,oBACpC,CAAC,KAAK,OAAO,YACb,KAAK,OAAO,SAAS,SAAS,8BAAe,cAC7C,oBAAoB,IAAI,KAAK,OAAO,SAAS,IAAI;AAErD;AAUA,SAAS,gBACP,MACA,WACS;AACT,SACE,KAAK,SAAS,8BAAe,mBAC7B,KAAK,aAAa,QAClB,gBAAgB,KAAK,UAAU,SAAS;AAE5C;AAGA,SAAS,wBACP,MAC0B;AAC1B,MAAI,UAA4C,KAAK;AACrD,SAAO,YAAY,UAAa,YAAY,MAAM;AAChD,QAAI,eAAe,OAAO,KAAK,gBAAgB,SAAS;AACtD,aAAO,QAAQ,YAAY,kBAAkB;AAAA,IAC/C;AACA,cAAU,QAAQ;AAAA,EACpB;AACA,SAAO;AACT;AAUA,SAAS,2BACP,WACA,MACS;AACT,MAAI,SAAS,WAAW;AACtB,WAAO;AAAA,EACT;AACA,MAAI,WAAW,wBAAwB,SAAS;AAChD,MACE,UAAU,SAAS,8BAAe,mBAClC,SAAS,SAAS,SAAS,8BAAe,cAC1C,SAAS,SAAS,SAAS,WAC3B;AACA,eAAW,SAAS,eAAe,OAAO,CAAC,KAAK;AAAA,EAClD;AACA,SAAO,UAAU,SAAS,8BAAe;AAC3C;AAYA,SAAS,oBAAoB,WAA0C;AACrE,QAAM,WAAW,WAAW,SAAS;AACrC,MACE;AAAA,IAAgB;AAAA,IAAU,CAAC,YACzB,gBAAgB,SAAS,iBAAiB;AAAA,EAC5C,GACA;AACA,WAAO;AAAA,EACT;AACA,QAAM,OAAO,SAAS,KAAK,WAAW,IAAI,SAAS,KAAK,CAAC,IAAI;AAC7D,SAAO,SAAS,UAAa,gBAAgB,MAAM,gBAAgB;AACrE;AAGA,SAAS,sBACP,MACgC;AAChC,MAAI,UAA4C,KAAK;AACrD,SAAO,YAAY,UAAa,YAAY,MAAM;AAChD,QACE,eAAe,OAAO,KACtB,UAAU,WACV,OAAO,QAAQ,IAAI,KACnB,QAAQ,KAAK,SAAS,8BAAe,gBACrC;AACA,aAAO,QAAQ;AAAA,IACjB;AACA,cAAU,QAAQ;AAAA,EACpB;AACA,SAAO;AACT;AAQA,SAAS,yCACP,WACA,MACS;AACT,QAAM,eAAe,sBAAsB,SAAS;AACpD,MAAI,iBAAiB,MAAM;AACzB,WAAO;AAAA,EACT;AACA,SAAO,gBAAgB,cAAc,CAAC,YAAY;AAChD,QAAI,QAAQ,SAAS,8BAAe,iBAAiB;AACnD,aAAO;AAAA,IACT;AACA,QAAI,SAAS,SAAS,UAAU,IAAI,GAAG;AACrC,aAAO;AAAA,IACT;AACA,WAAO,aAAa,QAAQ,QAAQ,MAAM;AAAA,EAC5C,CAAC;AACH;AAGA,SAAS,SAAS,MAAqB,UAAkC;AACvE,MAAI,UAA4C;AAChD,SAAO,YAAY,UAAa,YAAY,MAAM;AAChD,QAAI,YAAY,UAAU;AACxB,aAAO;AAAA,IACT;AACA,cAAU,QAAQ;AAAA,EACpB;AACA,SAAO;AACT;AAEA,IAAO,sCAAQ,2BAAY;AAAA,EACzB,CAAC,SACC,8EAA8E,IAAI;AACtF,EAAuB;AAAA,EACrB,MAAM;AAAA,EACN,MAAM;AAAA,IACJ,MAAM;AAAA,IACN,MAAM;AAAA,MACJ,aACE;AAAA,IACJ;AAAA,IACA,QAAQ;AAAA,MACN;AAAA,QACE,MAAM;AAAA,QACN,sBAAsB;AAAA,QACtB,YAAY,EAAE,GAAG,0BAA0B;AAAA,MAC7C;AAAA,IACF;AAAA,IACA,UAAU;AAAA,MACR,kBACE;AAAA,IACJ;AAAA,EACF;AAAA,EACA,gBAAgB,CAAC,CAAC,CAAC;AAAA,EACnB,OAAO,SAAS,CAAC,cAAc,GAAG;AAChC,UAAM,UAAU,iBAAiB,cAAc;AAQ/C,aAAS,mBACP,WACA,YACS;AACT,aAAO,gBAAgB,WAAW,CAAC,YAAY;AAC7C,YAAI,QAAQ,SAAS,8BAAe,gBAAgB;AAClD,iBAAO;AAAA,QACT;AACA,YAAI,QAAQ,cAAc,OAAO,GAAG;AAClC,iBAAO;AAAA,QACT;AACA,cAAM,OAAO,WAAW,QAAQ,MAAM;AACtC,eACE,SAAS,QACT,eAAe,KAAK,IAAI,KACxB,mBAAmB,QAAQ,WAAW,UAAU;AAAA,MAEpD,CAAC;AAAA,IACH;AAEA,WAAO;AAAA,MACL,YAAY,MAAkC;AAC5C,cAAM,OAAO,KAAK,KAAK;AACvB,YAAI,KAAK,WAAW,GAAG;AACrB;AAAA,QACF;AAEA,cAAM,OAAO,KAAK,KAAK,SAAS,CAAC;AACjC,YAAI,SAAS,UAAa,KAAK,SAAS,8BAAe,iBAAiB;AACtE;AAAA,QACF;AAEA,YAAI,CAAC,mBAAmB,KAAK,QAAQ,GAAG;AACtC;AAAA,QACF;AAEA,YAAI,cAAc,KAAK,IAAI,GAAG;AAC5B;AAAA,QACF;AAEA,cAAM,aACJ,KAAK,OAAO,SAAS,8BAAe,aAChC,KAAK,MAAM,OACX;AAEN,YAAI,mBAAmB,KAAK,MAAM,UAAU,GAAG;AAC7C;AAAA,QACF;AAEA,YAAI,oBAAoB,IAAI,GAAG;AAC7B;AAAA,QACF;AAEA,cAAM,OAAO,aAAa,KAAK,QAAQ;AACvC,YAAI,SAAS,QAAQ,2BAA2B,MAAM,IAAI,GAAG;AAC3D;AAAA,QACF;AAEA,YACE,SAAS,QACT,yCAAyC,MAAM,IAAI,GACnD;AACA;AAAA,QACF;AAEA,gBAAQ,OAAO;AAAA,UACb,MAAM;AAAA,UACN,WAAW;AAAA,QACb,CAAC;AAAA,MACH;AAAA,IACF;AAAA,EACF;AACF,CAAC;;;AC1iBD,IAAAC,iBAA2C;AAU3C,IAAM,0BAA0B,oBAAI,IAAY,CAAC,WAAW,OAAO,QAAQ,CAAC;AAS5E,IAAM,2BACJ;AAOF,SAAS,eAAe,MAA8B;AACpD,SACE,KAAK,SAAS,yBACd,KAAK,SAAS,wBACd,KAAK,SAAS;AAElB;AAgBA,SAAS,OAAO,MAA8B;AAC5C,SACE,KAAK,SAAS,kBACd,KAAK,SAAS,oBACd,KAAK,SAAS,oBACd,KAAK,SAAS,oBACd,KAAK,SAAS;AAElB;AAEA,SAASC,QAAO,OAAwC;AACtD,SACE,OAAO,UAAU,YACjB,UAAU,QACV,OAAQ,MAA6B,SAAS;AAElD;AAOA,SAAS,WACP,MACA,OACM;AACN,QAAM,IAAI;AACV,aAAW,OAAO,OAAO,KAAK,IAAI,GAA8B;AAC9D,QAAI,QAAQ,UAAU;AACpB;AAAA,IACF;AACA,UAAM,QAAQ,KAAK,GAAG;AACtB,UAAM,WAAW,MAAM,QAAQ,KAAK,IAAI,QAAQ,CAAC,KAAK;AACtD,eAAW,SAAS,UAAU;AAC5B,UAAIA,QAAO,KAAK,KAAK,CAAC,eAAe,KAAK,KAAK,CAAC,OAAO,KAAK,GAAG;AAC7D,mBAAW,OAAO,KAAK;AAAA,MACzB;AAAA,IACF;AAAA,EACF;AACF;AAEA,SAAS,cAAc,MAAiD;AACtE,QAAM,SAAqC,CAAC;AAC5C,aAAW,MAAM,CAAC,SAAS;AACzB,QAAI,KAAK,SAAS,mBAAmB;AACnC,aAAO,KAAK,IAAI;AAAA,IAClB;AAAA,EACF,CAAC;AACD,SAAO;AACT;AAMA,SAAS,aAAa,MAA8B;AAClD,MAAI,QAAQ;AACZ,aAAW,MAAM,CAAC,SAAS;AACzB,QACE,KAAK,SAAS,qBACd,KAAK,SAAS,oBACd,KAAK,SAAS,qBACd;AACA,cAAQ;AAAA,IACV;AAAA,EACF,CAAC;AACD,SAAO;AACT;AAMA,IAAM,kBAAkB;AAExB,SAASC,YAAW,QAAsC;AACxD,MAAI,OAAO,SAAS,aAAc,QAAO,OAAO;AAChD,MACE,OAAO,SAAS,sBAChB,CAAC,OAAO,YACR,OAAO,SAAS,SAAS,cACzB;AACA,WAAO,OAAO,SAAS;AAAA,EACzB;AACA,SAAO;AACT;AAEA,SAAS,aAAa,MAAyC;AAC7D,QAAM,MAAM,KAAK;AAEjB,MACE,IAAI,SAAS,mBACb,IAAI,OAAO,SAAS,gBACpB,IAAI,OAAO,SAAS,WACpB;AACA,WAAO;AAAA,EACT;AAGA,MAAI,IAAI,SAAS,kBAAkB;AACjC,UAAM,OAAOA,YAAW,IAAI,MAAM;AAClC,WAAO,SAAS,QAAQ,gBAAgB,KAAK,IAAI;AAAA,EACnD;AACA,SAAO;AACT;AAEA,IAAM,sBAAsB;AAO5B,SAAS,aAAa,MAAyC;AAC7D,QAAM,MAAM,KAAK;AACjB,SACE,IAAI,SAAS,oBACb,IAAI,OAAO,SAAS,sBACpB,CAAC,IAAI,OAAO,YACZ,IAAI,OAAO,SAAS,SAAS,gBAC7B,oBAAoB,KAAK,IAAI,OAAO,SAAS,IAAI;AAErD;AAEA,SAAS,eAAe,MAAqB,MAAuB;AAClE,MAAI,QAAQ;AACZ,aAAW,MAAM,CAAC,SAAS;AACzB,QAAI,KAAK,SAAS,gBAAgB,KAAK,SAAS,MAAM;AACpD,cAAQ;AAAA,IACV;AAAA,EACF,CAAC;AACD,SAAO;AACT;AAQA,SAAS,sBAAsB,MAAyC;AACtE,QAAM,SAAS,KAAK;AACpB,MAAI,SAAwB;AAC5B,MACE,OAAO,SAAS,0BAChB,OAAO,aAAa,OACpB,OAAO,UAAU,QACjB,OAAO,KAAK,SAAS,cACrB;AACA,aAAS,OAAO,KAAK;AAAA,EACvB,WACE,OAAO,SAAS,wBAChB,OAAO,SAAS,QAChB,OAAO,GAAG,SAAS,cACnB;AACA,aAAS,OAAO,GAAG;AAAA,EACrB;AACA,MAAI,WAAW,MAAM;AACnB,WAAO;AAAA,EACT;AACA,SAAO,eAAe,KAAK,UAAU,MAAM;AAC7C;AAGA,SAAS,YAAY,MAAkC;AACrD,QAAM,QAAQ,oBAAI,IAAY;AAC9B,aAAW,MAAM,CAAC,SAAS;AACzB,QAAI,KAAK,SAAS,cAAc;AAC9B,YAAM,IAAI,KAAK,IAAI;AAAA,IACrB;AAAA,EACF,CAAC;AACD,SAAO;AACT;AAQA,SAAS,0BACP,MACA,MACS;AACT,QAAM,YAAY,YAAY,IAAI;AAClC,MAAI,UAAU,SAAS,GAAG;AACxB,WAAO;AAAA,EACT;AACA,MAAI,QAAQ;AACZ,aAAW,MAAM,CAAC,SAAS;AACzB,QACE,KAAK,SAAS,0BACd,KAAK,aAAa,OAClB,KAAK,KAAK,SAAS,gBACnB,UAAU,IAAI,KAAK,KAAK,IAAI,GAC5B;AACA,cAAQ;AAAA,IACV;AAAA,EACF,CAAC;AACD,SAAO;AACT;AAQA,SAAS,aACP,QACA,WACA,cACS;AACT,MAAI,OAAO,WAAW,GAAG;AACvB,WAAO;AAAA,EACT;AACA,MAAI,WAAW;AACb,WAAO;AAAA,EACT;AACA,MAAI,iBAAiB,QAAQ,yBAAyB,KAAK,YAAY,GAAG;AACxE,WAAO;AAAA,EACT;AACA,SAAO,OAAO;AAAA,IACZ,CAAC,SACC,CAAC,aAAa,IAAI,KAClB,CAAC,sBAAsB,IAAI,KAC3B,CAAC,aAAa,IAAI;AAAA,EACtB;AACF;AAEA,IAAO,8BAAQ,2BAAY;AAAA,EACzB,CAAC,SACC,8EAA8E,IAAI;AACtF,EAAuB;AAAA,EACrB,MAAM;AAAA,EACN,MAAM;AAAA,IACJ,MAAM;AAAA,IACN,MAAM;AAAA,MACJ,aACE;AAAA,IACJ;AAAA,IACA,QAAQ,CAAC;AAAA,IACT,UAAU;AAAA,MACR,mBACE;AAAA,IACJ;AAAA,EACF;AAAA,EACA,gBAAgB,CAAC;AAAA,EACjB,OAAO,SAAS;AAOd,aAAS,UAAU,MAA0C;AAK3D,UAAI,KAAK,SAAS,gBAAgB;AAChC,eAAO,CAAC,KAAK,MAAM,KAAK,MAAM,KAAK,MAAM;AAAA,MAC3C;AACA,UAAI,KAAK,SAAS,oBAAoB,KAAK,SAAS,kBAAkB;AACpE,eAAO,CAAC,KAAK,IAAI;AAAA,MACnB;AACA,aAAO,CAAC,KAAK,MAAM,KAAK,IAAI;AAAA,IAC9B;AAEA,aAAS,eAAe,MAA+B;AACrD,UAAI,KAAK,SAAS,oBAAoB,KAAK,SAAS,kBAAkB;AACpE,eAAO,QAAQ,WAAW,QAAQ,KAAK,KAAK;AAAA,MAC9C;AACA,aAAO;AAAA,IACT;AAEA,aAAS,UAAU,MAAsB;AACvC,WACG,KAAK,SAAS,oBAAoB,KAAK,SAAS,uBACjD,0BAA0B,KAAK,MAAM,KAAK,IAAI,GAC9C;AACA;AAAA,MACF;AAEA,YAAM,SAAqC,CAAC;AAC5C,UAAI,YAAY;AAChB,iBAAW,QAAQ,UAAU,IAAI,GAAG;AAClC,YAAI,SAAS,QAAQ,OAAO,IAAI,GAAG;AACjC;AAAA,QACF;AACA,eAAO,KAAK,GAAG,cAAc,IAAI,CAAC;AAClC,YAAI,CAAC,aAAa,aAAa,IAAI,GAAG;AACpC,sBAAY;AAAA,QACd;AAAA,MACF;AACA,UAAI,aAAa,QAAQ,WAAW,eAAe,IAAI,CAAC,GAAG;AACzD,gBAAQ,OAAO,EAAE,MAAM,WAAW,oBAAoB,CAAC;AAAA,MACzD;AAAA,IACF;AAEA,WAAO;AAAA,MACL,cAAc;AAAA,MACd,gBAAgB;AAAA,MAChB,gBAAgB;AAAA,MAChB,kBAAkB;AAAA,MAClB,eAAe,MAAqC;AAElD,YAAI,KAAK,OAAO;AACd;AAAA,QACF;AACA,kBAAU,IAAI;AAAA,MAChB;AAAA,MACA,eAAe,MAAqC;AAClD,cAAM,SAAS,KAAK;AACpB,YAAI,OAAO,SAAS,sBAAsB,OAAO,UAAU;AACzD;AAAA,QACF;AACA,YACE,OAAO,SAAS,SAAS,gBACzB,CAAC,wBAAwB,IAAI,OAAO,SAAS,IAAI,GACjD;AACA;AAAA,QACF;AACA,cAAM,WAAW,KAAK,UAAU,CAAC;AACjC,YACE,aAAa,UACb,CAAC,eAAe,QAAQ,KACxB,EAAE,WAAW,YAAY,SAAS,QAClC;AACA;AAAA,QACF;AAKA,YACE,OAAO,SAAS,SAAS,aACzB,KAAK,OAAO,SAAS,uBACrB;AACA;AAAA,QACF;AACA,cAAM,SAAS,cAAc,SAAS,IAAI;AAC1C,cAAM,YAAY,aAAa,SAAS,IAAI;AAC5C,cAAM,eAAe,QAAQ,WAAW,QAAQ,OAAO,MAAM;AAC7D,YAAI,aAAa,QAAQ,WAAW,YAAY,GAAG;AACjD,kBAAQ,OAAO,EAAE,MAAM,WAAW,oBAAoB,CAAC;AAAA,QACzD;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF,CAAC;;;ACzaD,IAAAC,iBAA2C;AAM3C,IAAM,kBAAkB,oBAAI,IAAY;AAAA,EACtC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAMD,SAAS,oBAAoB,MAA2C;AACtE,MAAI,SAAS,MAAM;AACjB,WAAO;AAAA,EACT;AACA,MAAI,KAAK,SAAS,mBAAmB;AACnC,WAAO;AAAA,EACT;AACA,MAAI,KAAK,SAAS,WAAW;AAC3B,WAAO,OAAO,KAAK,UAAU;AAAA,EAC/B;AACA,SAAO;AACT;AAOA,SAAS,aACP,OACA,MAC4B;AAC5B,MAAI,UAA8B;AAClC,SAAO,YAAY,MAAM;AACvB,UAAM,WAAW,QAAQ,UAAU,KAAK,CAAC,MAAM,EAAE,SAAS,IAAI;AAC9D,QAAI,aAAa,QAAW;AAC1B,aAAO;AAAA,IACT;AACA,cAAU,QAAQ;AAAA,EACpB;AACA,SAAO;AACT;AAOA,SAAS,4BAA4B,UAAmC;AAItE,MAAI,SAAS,KAAK,WAAW,GAAG;AAC9B,WAAO;AAAA,EACT;AACA,QAAM,MAAM,SAAS,KAAK,CAAC;AAC3B,MAAI,QAAQ,UAAa,IAAI,SAAS,YAAY;AAEhD,WAAO;AAAA,EACT;AACA,QAAM,aAAa,IAAI;AACvB,MAAI,WAAW,SAAS,sBAAsB;AAC5C,WAAO;AAAA,EACT;AACA,SAAO,oBAAoB,WAAW,IAAI;AAC5C;AAQA,SAAS,gBACP,MACA,QACS;AACT,MAAI,KAAK,SAAS,cAAc;AAC9B,WAAO,KAAK,SAAS;AAAA,EACvB;AACA,MAAI,KAAK,SAAS,sBAAsB,KAAK,aAAa,KAAK;AAC7D,WACE,gBAAgB,KAAK,MAAM,MAAM,KAAK,gBAAgB,KAAK,OAAO,MAAM;AAAA,EAE5E;AACA,SAAO;AACT;AAMA,SAAS,mBACP,KACA,QACS;AACT,MAAI,IAAI,SAAS,sBAAsB,IAAI,aAAa,KAAK;AAC3D,WAAO;AAAA,EACT;AACA,SAAO,gBAAgB,IAAI,MAAM,MAAM,KAAK,gBAAgB,IAAI,OAAO,MAAM;AAC/E;AAQA,SAAS,iBAAiB,MAA8B;AACtD,MAAI,QAAuB;AAC3B,MAAI,SAAS,KAAK;AAClB,SAAO,WAAW,UAAa,WAAW,MAAM;AAC9C,QAAI,gBAAgB,IAAI,OAAO,IAAI,GAAG;AAGpC,YAAM,OAAO;AAMb,UAAI,KAAK,SAAS,OAAO;AACvB,eAAO;AAAA,MACT;AAAA,IACF;AACA,YAAQ;AACR,aAAS,OAAO;AAAA,EAClB;AACA,SAAO;AACT;AAEA,IAAO,mCAAQ,2BAAY;AAAA,EACzB,CAAC,SACC,8EAA8E,IAAI;AACtF,EAAuB;AAAA,EACrB,MAAM;AAAA,EACN,MAAM;AAAA,IACJ,MAAM;AAAA,IACN,MAAM;AAAA,MACJ,aACE;AAAA,IACJ;AAAA,IACA,QAAQ,CAAC;AAAA,IACT,UAAU;AAAA,MACR,sBACE;AAAA,IACJ;AAAA,EACF;AAAA,EACA,gBAAgB,CAAC;AAAA,EACjB,OAAO,SAAS;AACd,WAAO;AAAA,MACL,qBAAqB,MAA2C;AAE9D,YAAI,KAAK,KAAK,SAAS,cAAc;AACnC;AAAA,QACF;AAGA,cAAM,iBACJ,KAAK,aAAa,QACjB,KAAK,aAAa,OACjB,mBAAmB,KAAK,OAAO,KAAK,KAAK,IAAI;AACjD,YAAI,CAAC,gBAAgB;AACnB;AAAA,QACF;AAEA,YAAI,CAAC,iBAAiB,IAAI,GAAG;AAC3B;AAAA,QACF;AAEA,cAAM,QAAQ,QAAQ,WAAW,SAAS,IAAI;AAC9C,cAAM,WAAW,aAAa,OAAO,KAAK,KAAK,IAAI;AAEnD,YAAI,aAAa,QAAW;AAC1B;AAAA,QACF;AAIA,YAAI,CAAC,4BAA4B,QAAQ,GAAG;AAC1C;AAAA,QACF;AAEA,gBAAQ,OAAO;AAAA,UACb;AAAA,UACA,WAAW;AAAA,QACb,CAAC;AAAA,MACH;AAAA,IACF;AAAA,EACF;AACF,CAAC;;;ACxMD,IAAAC,iBAIO;AAMP,IAAM,aAAa;AACnB,IAAM,mBAAmB;AACzB,IAAM,mBAAmB;AAEzB,IAAM,kBAAuC,oBAAI,IAAI;AAAA,EACnD;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAED,IAAM,6BACJ;AAIF,IAAM,uBAAuB,CAC3B,SACyC;AACzC,SACE,KAAK,SAAS,8BAAe,uBAC7B,KAAK,WAAW,SAAS,8BAAe,WACxC,KAAK,WAAW,UAAU;AAE9B;AAEA,IAAM,oBAAoB,CACxB,MACA,YACY;AACZ,MAAI,CAAC,gBAAgB,IAAI,KAAK,IAAI,EAAG,QAAO;AAE5C,QAAM,SAAS,KAAK;AACpB,MAAI,WAAW,QAAW;AAExB,QACE,OAAO,SAAS,8BAAe,oBAC/B,OAAO,aAAa,QACpB,CAAC,OAAO,UACR;AACA,aAAO;AAAA,IACT;AAEA,QACE,OAAO,SAAS,8BAAe,YAC/B,OAAO,QAAQ,QACf,CAAC,OAAO,UACR;AACA,aAAO;AAAA,IACT;AAEA,QAAI,OAAO,KAAK,WAAW,IAAI,GAAG;AAChC,aAAO;AAAA,IACT;AAAA,EACF;AAIA,MAAI,QAA4B,QAAQ,WAAW,SAAS,IAAI;AAChE,SAAO,UAAU,MAAM;AACrB,UAAM,WAAW,MAAM,IAAI,IAAI,KAAK,IAAI;AACxC,QAAI,aAAa,UAAa,SAAS,KAAK,SAAS,GAAG;AACtD,aAAO;AAAA,IACT;AACA,YAAQ,MAAM;AAAA,EAChB;AAEA,SAAO;AACT;AAEA,IAAO,oCAAQ,2BAAY;AAAA,EACzB,CAAC,SACC,8EAA8E,IAAI;AACtF,EAAuB;AAAA,EACrB,MAAM;AAAA,EACN,MAAM;AAAA,IACJ,MAAM;AAAA,IACN,MAAM;AAAA,MACJ,aACE;AAAA,IACJ;AAAA,IACA,QAAQ,CAAC;AAAA,IACT,UAAU;AAAA,MACR,sBACE;AAAA,IACJ;AAAA,EACF;AAAA,EACA,gBAAgB,CAAC;AAAA,EACjB,OAAO,SAAS;AACd,UAAM,WAAW,QAAQ;AACzB,QAAI,iBAAiB,KAAK,QAAQ,GAAG;AACnC,aAAO,CAAC;AAAA,IACV;AAEA,QAAI,gBAAqD;AACzD,QAAI,qBAAqB;AAEzB,UAAM,sBAAsB,CAC1B,WACS;AACT,UAAI,OAAO,SAAS,8BAAe,YAAY;AAC7C,YAAI,WAAW,KAAK,OAAO,IAAI,KAAK,OAAO,SAAS,iBAAiB;AACnE,+BAAqB;AAAA,QACvB;AACA;AAAA,MACF;AACA,UACE,OAAO,SAAS,8BAAe,oBAC/B,OAAO,SAAS,SAAS,8BAAe,YACxC;AACA,cAAM,OAAO,OAAO,SAAS;AAC7B,YAAI,WAAW,KAAK,IAAI,KAAK,SAAS,iBAAiB;AACrD,+BAAqB;AAAA,QACvB;AAAA,MACF;AAAA,IACF;AAEA,WAAO;AAAA,MACL,QAAQ,MAAY;AAClB,mBAAW,QAAQ,KAAK,MAAM;AAG5B,cAAI,KAAK,SAAS,8BAAe,oBAAqB;AACtD,cAAI,qBAAqB,IAAI,GAAG;AAC9B,4BAAgB;AAChB;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAAA,MACA,eAAe,MAAY;AAKzB,YAAI,kBAAkB,KAAM;AAC5B,4BAAoB,KAAK,MAAM;AAAA,MACjC;AAAA,MACA,aAAa,MAAY;AACvB,YAAI,kBAAkB,KAAM;AAC5B,YACE,KAAK,KAAK,SAAS,8BAAe,iBAClC,iBAAiB,KAAK,KAAK,KAAK,IAAI,GACpC;AACA,+BAAqB;AAAA,QACvB;AAAA,MACF;AAAA,MACA,kBAAkB,MAAY;AAC5B,YAAI,kBAAkB,KAAM;AAC5B,YACE,OAAO,KAAK,OAAO,UAAU,YAC7B,2BAA2B,KAAK,KAAK,OAAO,KAAK,GACjD;AACA,+BAAqB;AAAA,QACvB;AAAA,MACF;AAAA,MACA,uBAAuB,MAAY;AACjC,YAAI,kBAAkB,KAAM;AAC5B,YAAI,KAAK,WAAW,MAAM;AACxB,+BAAqB;AAAA,QACvB;AAAA,MACF;AAAA,MACA,qBAAqB,MAAY;AAC/B,YAAI,kBAAkB,KAAM;AAC5B,YAAI,KAAK,WAAW,MAAM;AACxB,+BAAqB;AAAA,QACvB;AAAA,MACF;AAAA,MACA,mBAAyB;AACvB,YAAI,kBAAkB,KAAM;AAC5B,6BAAqB;AAAA,MACvB;AAAA,MACA,kBAAwB;AACtB,YAAI,kBAAkB,KAAM;AAC5B,6BAAqB;AAAA,MACvB;AAAA,MACA,WAAW,MAAY;AACrB,YAAI,kBAAkB,KAAM;AAC5B,YAAI,kBAAkB,MAAM,OAAO,GAAG;AACpC,+BAAqB;AAAA,QACvB;AAAA,MACF;AAAA,MACA,iBAAuB;AACrB,YAAI,kBAAkB,QAAQ,CAAC,oBAAoB;AACjD,kBAAQ,OAAO;AAAA,YACb,MAAM;AAAA,YACN,WAAW;AAAA,UACb,CAAC;AAAA,QACH;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF,CAAC;;;ACvND,IAAAC,iBAA2C;AAC3C,IAAAA,iBAA+B;AAQ/B,IAAM,sBAA2C,oBAAI,IAAI;AAAA,EACvD;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAED,IAAM,uBAAuB;AAM7B,SAAS,cAAc,QAA6C;AAClE,MAAI,OAAO,SAAS,8BAAe,qBAAqB;AACtD,WAAO;AAAA,EACT;AACA,QAAM,EAAE,IAAI,IAAI;AAChB,MAAI,IAAI,SAAS,8BAAe,YAAY;AAC1C,WAAO,IAAI;AAAA,EACb;AACA,MAAI,IAAI,SAAS,8BAAe,WAAW,OAAO,IAAI,UAAU,UAAU;AACxE,WAAO,IAAI;AAAA,EACb;AACA,SAAO;AACT;AAKA,SAAS,eAAe,QAA+C;AACrE,SACE,OAAO,gBAAgB,eAAe,SACtC,8BAAe;AAEnB;AAMA,SAAS,gCACP,aACS;AACT,MAAI,mBAAmB;AACvB,MAAI,gBAAgB;AAEpB,aAAW,UAAU,YAAY,SAAS;AACxC,QAAI,OAAO,SAAS,8BAAe,qBAAqB;AACtD;AAAA,IACF;AAEA,QAAI,OAAO,UAAU;AACnB,uBAAiB;AAAA,IACnB;AAEA,UAAM,OAAO,cAAc,MAAM;AACjC,QACE,SAAS,QACT,oBAAoB,IAAI,IAAI,KAC5B,eAAe,MAAM,GACrB;AACA,yBAAmB;AAAA,IACrB;AAAA,EACF;AAEA,SAAO,oBAAoB,iBAAiB;AAC9C;AAEA,IAAO,qCAAQ,2BAAY;AAAA,EACzB,CAAC,SACC,8EAA8E,IAAI;AACtF,EAAuB;AAAA,EACrB,MAAM;AAAA,EACN,MAAM;AAAA,IACJ,MAAM;AAAA,IACN,MAAM;AAAA,MACJ,aACE;AAAA,IACJ;AAAA,IACA,QAAQ,CAAC;AAAA,IACT,UAAU;AAAA,MACR,0BACE;AAAA,IACJ;AAAA,EACF;AAAA,EACA,gBAAgB,CAAC;AAAA,EACjB,OAAO,SAAS;AACd,aAAS,iBACP,aACA,YACM;AACN,UAAI,gCAAgC,WAAW,GAAG;AAChD,gBAAQ,OAAO;AAAA,UACb,MAAM;AAAA,UACN,WAAW;AAAA,QACb,CAAC;AAAA,MACH;AAAA,IACF;AAEA,WAAO;AAAA,MACL,uBACE,MACM;AAGN,cAAM,YAAoC;AAAA,UACxC,GAAG,KAAK;AAAA,UACR,MAAM,8BAAe;AAAA,UACrB,SAAS,KAAK,KAAK;AAAA,QACrB;AACA,yBAAiB,WAAW,IAAI;AAAA,MAClC;AAAA,MACA,yCACE,MACM;AACN,yBAAiB,MAAM,KAAK,MAAM;AAAA,MACpC;AAAA,IACF;AAAA,EACF;AACF,CAAC;;;AC7GD,IAAAC,iBAIO;AAaP,IAAM,SAAS,CACb,SACyB;AACzB,MAAI,UAA4C;AAChD,SAAO,YAAY,QAAQ,YAAY,QAAW;AAChD,QACE,QAAQ,SAAS,8BAAe,kBAChC,QAAQ,SAAS,8BAAe,mBAChC,QAAQ,SAAS,8BAAe,uBAChC,QAAQ,SAAS,8BAAe,uBAChC;AACA,gBAAU,QAAQ;AAAA,IACpB,WAAW,QAAQ,SAAS,8BAAe,iBAAiB;AAC1D,gBAAU,QAAQ;AAAA,IACpB,OAAO;AACL;AAAA,IACF;AAAA,EACF;AACA,SAAO,WAAW;AACpB;AAYA,IAAM,qBAAqB,CACzB,SACY;AACZ,MAAI,UAAU,OAAO,IAAI;AACzB,MAAI,YAAY,KAAM,QAAO;AAC7B,MAAI,QAAQ,SAAS,8BAAe,iBAAiB;AACnD,cAAU,OAAO,QAAQ,QAAQ;AAAA,EACnC;AACA,MAAI,YAAY,QAAQ,QAAQ,SAAS,8BAAe,gBAAgB;AACtE,WAAO;AAAA,EACT;AACA,QAAM,SAAS,OAAO,QAAQ,MAAM;AACpC,MAAI,WAAW,QAAQ,OAAO,SAAS,8BAAe,kBAAkB;AACtE,WAAO;AAAA,EACT;AACA,QAAM,WAAW,OAAO,OAAO,QAAQ;AACvC,MAAI,aAAa,QAAQ,SAAS,SAAS,8BAAe,YAAY;AACpE,WAAO;AAAA,EACT;AACA,MAAI,SAAS,SAAS,QAAQ;AAC5B,WAAO;AAAA,EACT;AAGA,QAAM,SAAS,OAAO,OAAO,MAAM;AACnC,SACE,SAAS,SAAS,WAClB,WAAW,QACX,OAAO,SAAS,8BAAe,cAC/B,OAAO,SAAS;AAEpB;AAEA,IAAMC,gBAAe,CACnB,OACA,SAC0B;AAC1B,MAAI,UAA8B;AAClC,SAAO,YAAY,MAAM;AACvB,UAAM,WAAW,QAAQ,IAAI,IAAI,IAAI;AACrC,QAAI,aAAa,OAAW,QAAO;AACnC,cAAU,QAAQ;AAAA,EACpB;AACA,SAAO;AACT;AAGA,IAAM,gBAAgB;AAMtB,IAAM,sBAAsB,CAAC,SAAiC;AAC5D,MAAI,UAAyB;AAC7B,MAAI,SAA2C,QAAQ;AACvD,SAAO,WAAW,UAAa,WAAW,MAAM;AAC9C,YAAQ,OAAO,MAAM;AAAA,MACnB,KAAK,8BAAe;AAAA,MACpB,KAAK,8BAAe;AAAA,MACpB,KAAK,8BAAe;AAClB,kBAAU;AACV,iBAAS,OAAO;AAChB;AAAA,MACF,KAAK,8BAAe;AAAA,MACpB,KAAK,8BAAe;AAAA,MACpB,KAAK,8BAAe;AAAA,MACpB,KAAK,8BAAe;AAAA,MACpB,KAAK,8BAAe;AAClB,eAAO,OAAO,SAAS;AAAA,MACzB;AACE,eAAO;AAAA,IACX;AAAA,EACF;AACA,SAAO;AACT;AAEA,IAAM,2BAA2B,CAC/B,MACA,OACA,YACY;AACZ,QAAM,YAAY,OAAO,IAAI;AAC7B,MAAI,cAAc,QAAQ,UAAU,SAAS,8BAAe,YAAY;AACtE,WAAO;AAAA,EACT;AACA,QAAM,WAAWA,cAAa,OAAO,UAAU,IAAI;AACnD,SAAO,aAAa,QAAQ,QAAQ,IAAI,QAAQ;AAClD;AAEA,IAAO,wCAAQ,2BAAY;AAAA,EACzB,CAAC,SACC,8EAA8E,IAAI;AACtF,EAAuB;AAAA,EACrB,MAAM;AAAA,EACN,MAAM;AAAA,IACJ,MAAM;AAAA,IACN,MAAM;AAAA,MACJ,aACE;AAAA,IACJ;AAAA,IACA,QAAQ,CAAC;AAAA,IACT,UAAU;AAAA,MACR,oBACE;AAAA,IACJ;AAAA,EACF;AAAA,EACA,gBAAgB,CAAC;AAAA,EACjB,OAAO,SAAc;AACnB,UAAM,uBAAuB,oBAAI,IAAoB;AAErD,UAAM,mBAAmB,CACvB,eACS;AACT,UAAI,CAAC,mBAAmB,WAAW,IAAI,EAAG;AAC1C,YAAM,eAAe,QAAQ,WAAW,qBAAqB,UAAU;AACvE,YAAM,WAAW,aAAa,CAAC;AAC/B,UAAI,aAAa,QAAW;AAC1B,6BAAqB,IAAI,QAAQ;AAAA,MACnC;AAAA,IACF;AAEA,WAAO;AAAA,MACL,mBAAmB,MAAY;AAC7B,cAAM,QAAQ,QAAQ,WAAW,SAAS,IAAI;AAE9C,YAAI,KAAK,GAAG,SAAS,8BAAe,YAAY;AAC9C,2BAAiB,IAAI;AACrB;AAAA,QACF;AAEA,YACE,KAAK,GAAG,SAAS,8BAAe,iBAChC,KAAK,GAAG,SAAS,8BAAe,cAChC;AACA,cAAI,mBAAmB,KAAK,IAAI,GAAG;AACjC,oBAAQ,OAAO,EAAE,MAAM,KAAK,IAAI,WAAW,qBAAqB,CAAC;AACjE;AAAA,UACF;AACA,cACE,yBAAyB,KAAK,MAAM,OAAO,oBAAoB,GAC/D;AACA,oBAAQ,OAAO,EAAE,MAAM,KAAK,IAAI,WAAW,qBAAqB,CAAC;AAAA,UACnE;AAAA,QACF;AAAA,MACF;AAAA,MACA,qBAAqB,MAAY;AAC/B,cAAM,QAAQ,QAAQ,WAAW,SAAS,IAAI;AAE9C,YAAI,KAAK,KAAK,SAAS,8BAAe,YAAY;AAChD,gBAAM,WAAWA,cAAa,OAAO,KAAK,KAAK,IAAI;AACnD,cAAI,aAAa,KAAM;AACvB,cAAI,mBAAmB,KAAK,KAAK,GAAG;AAClC,iCAAqB,IAAI,QAAQ;AAAA,UACnC,OAAO;AAEL,iCAAqB,OAAO,QAAQ;AAAA,UACtC;AACA;AAAA,QACF;AAEA,YACE,KAAK,KAAK,SAAS,8BAAe,iBAClC,KAAK,KAAK,SAAS,8BAAe,cAClC;AACA,cAAI,mBAAmB,KAAK,KAAK,GAAG;AAClC,oBAAQ,OAAO;AAAA,cACb,MAAM,KAAK;AAAA,cACX,WAAW;AAAA,YACb,CAAC;AACD;AAAA,UACF;AACA,cACE,yBAAyB,KAAK,OAAO,OAAO,oBAAoB,GAChE;AACA,oBAAQ,OAAO;AAAA,cACb,MAAM,KAAK;AAAA,cACX,WAAW;AAAA,YACb,CAAC;AAAA,UACH;AAAA,QACF;AAAA,MACF;AAAA,MACA,eAAe,MAAY;AACzB,YAAI,KAAK,OAAO,SAAS,8BAAe,WAAY;AACpD,YAAI,CAAC,cAAc,KAAK,KAAK,OAAO,IAAI,KAAK,CAAC,oBAAoB,IAAI,GAAG;AACvE;AAAA,QACF;AACA,cAAM,QAAQ,QAAQ,WAAW,SAAS,IAAI;AAC9C,mBAAW,OAAO,KAAK,WAAW;AAChC,cAAI,IAAI,SAAS,8BAAe,cAAe;AAC/C,gBAAM,YAAY,OAAO,GAAG;AAC5B,cAAI,cAAc,QAAQ,UAAU,SAAS,8BAAe,YAAY;AACtE;AAAA,UACF;AACA,gBAAM,WAAWA,cAAa,OAAO,UAAU,IAAI;AACnD,cAAI,aAAa,KAAM,sBAAqB,OAAO,QAAQ;AAAA,QAC7D;AAAA,MACF;AAAA,MACA,iBAAiB,MAAY;AAC3B,cAAM,QAAQ,QAAQ,WAAW,SAAS,IAAI;AAC9C,cAAM,MAAM,OAAO,KAAK,MAAM;AAE9B,YAAI,mBAAmB,GAAG,GAAG;AAI3B,gBAAM,SAAS,KAAK;AACpB,cACE,OAAO,SAAS,8BAAe,kBAC/B,OAAO,WAAW,QAClB,KAAK,SAAS,SAAS,8BAAe,eACrC,KAAK,SAAS,SAAS,WACtB,KAAK,SAAS,SAAS,cACzB;AACA;AAAA,UACF;AACA,kBAAQ,OAAO,EAAE,MAAM,WAAW,qBAAqB,CAAC;AACxD;AAAA,QACF;AAEA,YACE,QAAQ,QACR,IAAI,SAAS,8BAAe,cAC5B,yBAAyB,KAAK,OAAO,oBAAoB,GACzD;AACA,kBAAQ,OAAO,EAAE,MAAM,WAAW,qBAAqB,CAAC;AACxD,gBAAM,WAAWA,cAAa,OAAO,IAAI,IAAI;AAC7C,cAAI,aAAa,MAAM;AACrB,iCAAqB,OAAO,QAAQ;AAAA,UACtC;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF,CAAC;;;AC9RD,IAAAC,iBAA2D;;;AClBpD,IAAM,eAAe,CAAC,UAC3B,MAAM,QAAQ,sBAAsB,EAAE,EAAE,QAAQ,MAAM,EAAE;AAGnD,IAAM,cAAc,CAAC,UAC1B,MAAM,MAAM,KAAK,EAAE,OAAO,OAAO;;;ADoBnC,IAAM,iBACJ;AACF,IAAM,UACJ;AACF,IAAM,WAAW;AAEjB,IAAM,iBAAiB,IAAI,OAAO,OAAO,cAAc,QAAQ,OAAO,2BAA2B;AACjG,IAAM,qBAAqB,IAAI;AAAA,EAC7B,OAAO,cAAc,gCAAgC,QAAQ;AAAA,EAC7D;AACF;AAGA,IAAM,YAAY,oBAAI,IAAY,CAAC,MAAM,QAAQ,OAAO,MAAM,MAAM,WAAW,cAAc,YAAY,CAAC;AAC1G,IAAM,gBAAgB;AAGtB,IAAM,oBAAoB,oBAAI,IAAY;AAAA,EACxC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;AACD,IAAM,qBAAqB,IAAI,OAAO,8BAA8B,QAAQ,YAAY,GAAG;AAE3F,IAAM,kBAAkB;AAGxB,IAAM,sBAAsB,oBAAI,IAAY;AAAA,EAC1C;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAGD,IAAM,0BAA0B,oBAAI,IAAY;AAAA,EAC9C;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAMD,IAAM,cAAc,CAAC,SAAiC;AACpD,MAAI,UAA4C,KAAK;AACrD,SAAO,YAAY,UAAa,YAAY,MAAM;AAChD,QACE,QAAQ,SAAS,8BAAe,cAChC,QAAQ,eAAe,KAAK,SAAS,8BAAe,kBACnD,QAAQ,eAAe,KAAK,SAAS,SACpC,oBAAoB,IAAI,QAAQ,eAAe,KAAK,IAAI,IAC1D;AACA,aAAO;AAAA,IACT;AACA,cAAU,QAAQ;AAAA,EACpB;AACA,SAAO;AACT;AAEA,IAAM,WAAW,CAAC,QAAiD;AACjE,MAAI,IAAI,SAAS,8BAAe,WAAY,QAAO,IAAI;AACvD,MAAI,IAAI,SAAS,8BAAe,WAAW,OAAO,IAAI,UAAU,SAAU,QAAO,IAAI;AACrF,SAAO;AACT;AAEA,IAAO,iCAAQ,2BAAY;AAAA,EACzB,CAAC,SACC,gFAAgF,IAAI;AACxF,EAAuB;AAAA,EACrB,MAAM;AAAA,EACN,MAAM;AAAA,IACJ,MAAM;AAAA,IACN,MAAM;AAAA,MACJ,aACE;AAAA,IACJ;AAAA,IACA,QAAQ,CAAC;AAAA,IACT,UAAU;AAAA,MACR,YACE;AAAA,MACF,gBACE;AAAA,MACF,aACE;AAAA,IACJ;AAAA,EACF;AAAA,EACA,gBAAgB,CAAC;AAAA,EACjB,OAAO,SAAS;AACd,QAAI,gBAAgB,KAAK,QAAQ,QAAQ,EAAG,QAAO,CAAC;AAEpD,UAAM,gBAAgB,CAAC,OAAe,SAA8B;AAClE,iBAAW,SAAS,YAAY,KAAK,GAAG;AACtC,cAAM,OAAO,aAAa,KAAK;AAC/B,YAAI,eAAe,KAAK,IAAI,GAAG;AAC7B,kBAAQ,OAAO,EAAE,MAAM,WAAW,cAAc,MAAM,EAAE,OAAO,MAAM,EAAE,CAAC;AAAA,QAC1E,WAAW,mBAAmB,KAAK,IAAI,GAAG;AACxC,kBAAQ,OAAO,EAAE,MAAM,WAAW,kBAAkB,MAAM,EAAE,OAAO,MAAM,EAAE,CAAC;AAAA,QAC9E;AAAA,MACF;AAAA,IACF;AAKA,UAAM,iBAAiB,CAAC,SAAqC;AAC3D,UAAI,SAAS,KAAM;AACnB,cAAQ,KAAK,MAAM;AAAA,QACjB,KAAK,8BAAe;AAClB,cAAI,OAAO,KAAK,UAAU,SAAU,eAAc,KAAK,OAAO,IAAI;AAClE;AAAA,QACF,KAAK,8BAAe;AAClB,qBAAW,SAAS,KAAK,OAAQ,eAAc,MAAM,MAAM,UAAU,IAAI,KAAK;AAC9E;AAAA,QACF,KAAK,8BAAe;AAClB,qBAAW,WAAW,KAAK,UAAU;AACnC,gBAAI,YAAY,QAAQ,QAAQ,SAAS,8BAAe,cAAe,gBAAe,OAAO;AAAA,UAC/F;AACA;AAAA,QACF,KAAK,8BAAe;AAClB,qBAAW,YAAY,KAAK,YAAY;AACtC,gBAAI,SAAS,SAAS,8BAAe,SAAU,gBAAe,SAAS,KAAK;AAAA,UAC9E;AACA;AAAA,QACF,KAAK,8BAAe;AAClB,yBAAe,KAAK,UAAU;AAC9B,yBAAe,KAAK,SAAS;AAC7B;AAAA,QACF,KAAK,8BAAe;AAClB,yBAAe,KAAK,KAAK;AACzB;AAAA,QACF;AACE;AAAA,MACJ;AAAA,IACF;AAEA,UAAM,sBAAsB,CAAC,SAA8B;AACzD,UACE,KAAK,SAAS,8BAAe,WAC7B,OAAO,KAAK,UAAU,YACtB,mBAAmB,KAAK,KAAK,KAAK,GAClC;AACA,gBAAQ,OAAO,EAAE,MAAM,WAAW,eAAe,MAAM,EAAE,OAAO,KAAK,MAAM,EAAE,CAAC;AAAA,MAChF;AAAA,IACF;AAEA,WAAO;AAAA,MACL,sCAAsC,MAAmC;AACvE,YAAI,KAAK,UAAU,KAAM;AACzB,YAAI,KAAK,MAAM,SAAS,8BAAe,QAAS,gBAAe,KAAK,KAAK;AAAA,iBAChE,KAAK,MAAM,SAAS,8BAAe,wBAAwB;AAClE,cAAI,KAAK,MAAM,WAAW,SAAS,8BAAe,oBAAoB;AACpE,2BAAe,KAAK,MAAM,UAAU;AAAA,UACtC;AAAA,QACF;AAAA,MACF;AAAA,MACA,eAAe,MAAqC;AAClD,YAAI,KAAK,OAAO,SAAS,8BAAe,cAAc,UAAU,IAAI,KAAK,OAAO,IAAI,GAAG;AACrF,qBAAW,OAAO,KAAK,WAAW;AAChC,gBAAI,IAAI,SAAS,8BAAe,cAAe,gBAAe,GAAG;AAAA,UACnE;AAAA,QACF;AAAA,MACF;AAAA,MACA,mBAAmB,MAAyC;AAC1D,YAAI,KAAK,GAAG,SAAS,8BAAe,cAAc,cAAc,KAAK,KAAK,GAAG,IAAI,GAAG;AAClF,yBAAe,KAAK,IAAI;AAAA,QAC1B;AAAA,MACF;AAAA,MACA,SAAS,MAA+B;AACtC,cAAM,OAAO,SAAS,KAAK,GAAG;AAC9B,YAAI,SAAS,QAAQ,cAAc,KAAK,IAAI,EAAG,gBAAe,KAAK,KAAK;AAAA,MAC1E;AAAA;AAAA;AAAA;AAAA,MAIA,kDAAkD,MAAmC;AACnF,YAAI,KAAK,OAAO,SAAS,8BAAe,QAAS;AACjD,YACE,OAAO,KAAK,MAAM,UAAU,YAC5B,wBAAwB,IAAI,KAAK,MAAM,MAAM,YAAY,CAAC,GAC1D;AACA;AAAA,QACF;AACA,YAAI,YAAY,IAAI,EAAG;AACvB,4BAAoB,KAAK,KAAK;AAAA,MAChC;AAAA;AAAA,MAEA,8DAA8D,MAA+B;AAC3F,cAAM,OAAO,SAAS,KAAK,GAAG;AAC9B,YAAI,SAAS,QAAQ,kBAAkB,IAAI,IAAI,EAAG,qBAAoB,KAAK,KAAK;AAAA,MAClF;AAAA,IACF;AAAA,EACF;AACF,CAAC;;;AE7OD,IAAAC,iBAA2C;AAM3C,IAAM,mBAAmB,oBAAI,IAAI,CAAC,QAAQ,OAAO,UAAU,OAAO,CAAC;AACnE,IAAM,yBAAyB,oBAAI,IAAI,CAAC,QAAQ,OAAO,UAAU,OAAO,CAAC;AAEzE,IAAM,kBACJ;AAIF,SAAS,SACP,SACA,MACa;AACb,SAAO,QAAQ,WAAW,SAAS,IAAI;AACzC;AAOA,SAAS,YACP,MACA,SACsB;AACtB,MAAI,CAAC,KAAM,QAAO;AAClB,MAAI,KAAK,SAAS,aAAc,QAAO;AAEvC,MAAI,QAA4B,SAAS,SAAS,IAAI;AACtD,SAAO,OAAO;AACZ,UAAM,WAAW,MAAM,IAAI,IAAI,KAAK,IAAI;AACxC,QAAI,YAAY,SAAS,KAAK,WAAW,GAAG;AAC1C,YAAM,MAAM,SAAS,KAAK,CAAC;AAC3B,UAAI,OAAO,IAAI,SAAS,YAAY;AAClC,cAAM,aAAa,IAAI;AACvB,YACE,WAAW,SAAS,wBACpB,WAAW,MACX;AACA,iBAAO,WAAW;AAAA,QACpB;AAAA,MACF;AAAA,IACF;AACA,YAAQ,MAAM;AAAA,EAChB;AACA,SAAO;AACT;AAEA,SAAS,SACP,MACA,SACS;AACT,QAAM,WAAW,YAAY,MAAM,OAAO;AAC1C,MAAI,CAAC,SAAU,QAAO;AAEtB,MAAI,SAAS,SAAS,aAAa,OAAO,SAAS,UAAU,UAAU;AACrE,WAAO,SAAS,MAAM,WAAW,OAAO;AAAA,EAC1C;AACA,MAAI,SAAS,SAAS,mBAAmB;AACvC,UAAM,aAAa,SAAS,OAAO,CAAC;AACpC,UAAM,SAAS,YAAY,MAAM;AACjC,WAAO,OAAO,WAAW,YAAY,OAAO,WAAW,OAAO;AAAA,EAChE;AACA,MAAI,SAAS,SAAS,sBAAsB,SAAS,aAAa,KAAK;AACrE,WAAO,SAAS,SAAS,MAAM,OAAO;AAAA,EACxC;AACA,SAAO;AACT;AAEA,SAAS,iBACP,MACA,SACS;AACT,QAAM,WAAW,YAAY,MAAM,OAAO;AAC1C,MAAI,CAAC,SAAU,QAAO;AAEtB,MAAI,SAAS,SAAS,aAAa,OAAO,SAAS,UAAU,UAAU;AACrE,WAAO,iBAAiB,IAAI,SAAS,MAAM,YAAY,CAAC;AAAA,EAC1D;AAEA,MACE,SAAS,SAAS,qBAClB,SAAS,YAAY,WAAW,GAChC;AACA,UAAM,MAAM,SAAS,OAAO,IAAI,CAAC,MAAM,EAAE,MAAM,MAAM,EAAE,KAAK,EAAE;AAC9D,WAAO,iBAAiB,IAAI,IAAI,YAAY,CAAC;AAAA,EAC/C;AAEA,MAAI,SAAS,SAAS,yBAAyB;AAC7C,WACE,iBAAiB,SAAS,YAAY,OAAO,KAC7C,iBAAiB,SAAS,WAAW,OAAO;AAAA,EAEhD;AAEA,MAAI,SAAS,SAAS,uBAAuB,SAAS,aAAa,MAAM;AACvE,WACE,iBAAiB,SAAS,MAAM,OAAO,KACvC,iBAAiB,SAAS,OAAO,OAAO;AAAA,EAE5C;AAEA,SAAO;AACT;AAEA,SAAS,gBACP,SACAC,WACsB;AACtB,MAAI,CAAC,WAAW,QAAQ,SAAS,mBAAoB,QAAO;AAC5D,aAAW,QAAQ,QAAQ,YAAY;AACrC,QAAI,KAAK,SAAS,WAAY;AAC9B,QAAIC,WAAyB;AAC7B,QAAI,KAAK,IAAI,SAAS,gBAAgB,CAAC,KAAK,UAAU;AACpD,MAAAA,WAAU,KAAK,IAAI;AAAA,IACrB,WACE,KAAK,IAAI,SAAS,aAClB,OAAO,KAAK,IAAI,UAAU,UAC1B;AACA,MAAAA,WAAU,KAAK,IAAI;AAAA,IACrB;AACA,QAAIA,aAAYD,WAAU;AAExB,UACE,KAAK,MAAM,SAAS,uBACpB,KAAK,MAAM,SAAS,kBACpB,KAAK,MAAM,SAAS,iBACpB;AACA,eAAO;AAAA,MACT;AACA,aAAO,KAAK;AAAA,IACd;AAAA,EACF;AACA,SAAO;AACT;AAEA,IAAO,gCAAQ,2BAAY;AAAA,EACzB,CAAC,SACC,8EAA8E,IAAI;AACtF,EAAuB;AAAA,EACrB,MAAM;AAAA,EACN,MAAM;AAAA,IACJ,MAAM;AAAA,IACN,MAAM;AAAA,MACJ,aAAa;AAAA,IACf;AAAA,IACA,QAAQ,CAAC;AAAA,IACT,UAAU;AAAA,MACR,oBACE;AAAA,IACJ;AAAA,EACF;AAAA,EACA,gBAAgB,CAAC;AAAA,EACjB,OAAO,SAAS;AACd,UAAM,WAAW,QAAQ;AACzB,QAAI,gBAAgB,KAAK,QAAQ,GAAG;AAClC,aAAO,CAAC;AAAA,IACV;AAEA,WAAO;AAAA,MACL,eAAe,MAAM;AACnB,YAAI,aAAa;AAGjB,YACE,KAAK,OAAO,SAAS,gBACrB,KAAK,OAAO,SAAS,SACrB;AACA,gBAAM,SAAS,KAAK,UAAU,CAAC;AAC/B,cAAI,UAAU,OAAO,SAAS,mBAAmB,SAAS,QAAQ,OAAO,GAAG;AAC1E,kBAAM,UAAU,KAAK,UAAU,CAAC;AAChC,gBAAI,WAAW,QAAQ,SAAS,iBAAiB;AAC/C,oBAAM,eAAe,YAAY,SAAS,OAAO;AACjD,oBAAM,aAAa,gBAAgB,cAAc,QAAQ;AACzD,kBAAI,cAAc,iBAAiB,YAAY,OAAO,GAAG;AACvD,6BAAa;AAAA,cACf;AAAA,YACF;AAAA,UACF;AAAA,QACF,WAGE,KAAK,OAAO,SAAS,sBACrB,KAAK,OAAO,SAAS,SAAS,gBAC9B,CAAC,KAAK,OAAO,UACb;AACA,gBAAM,aAAa,KAAK,OAAO,SAAS,KAAK,YAAY;AACzD,cAAI,uBAAuB,IAAI,UAAU,GAAG;AAC1C,kBAAM,SAAS,KAAK,UAAU,CAAC;AAI/B,kBAAM,gBAAgB,KAAK,UAAU;AAAA,cACnC,CAAC,QACC,IAAI,SAAS,6BACb,IAAI,SAAS;AAAA,YACjB;AACA,gBACE,UACA,OAAO,SAAS,mBAChB,CAAC,iBACD,SAAS,QAAQ,OAAO,GACxB;AACA,2BAAa;AAAA,YACf;AAAA,UACF;AAAA,QACF,WAGE,KAAK,OAAO,SAAS,iBACpB,KAAK,OAAO,SAAS,WAAW,KAAK,OAAO,SAAS,YACtD;AACA,gBAAM,WAAW,KAAK,UAAU,CAAC;AACjC,cAAI,YAAY,SAAS,SAAS,iBAAiB;AACjD,kBAAM,YAAY,YAAY,UAAU,OAAO;AAC/C,gBAAI,aAAa,UAAU,SAAS,oBAAoB;AACtD,oBAAM,UAAU,gBAAgB,WAAW,KAAK;AAChD,oBAAM,aAAa,gBAAgB,WAAW,QAAQ;AACtD,kBACE,WACA,SAAS,SAAS,OAAO,KACzB,cACA,iBAAiB,YAAY,OAAO,GACpC;AACA,6BAAa;AAAA,cACf;AAAA,YACF;AAAA,UACF;AAAA,QACF;AAEA,YAAI,YAAY;AACd,kBAAQ,OAAO,EAAE,MAAM,WAAW,qBAAqB,CAAC;AAAA,QAC1D;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF,CAAC;;;ACpPD,IAAAE,iBAIO;AAKP,IAAM,eAAiD;AAAA,EACrD,QAAQ;AAAA,EACR,UAAU;AAAA,EACV,QAAQ;AACV;AAGA,IAAM,0BAA4D;AAAA,EAChE,UAAU;AAAA,EACV,OAAO;AAAA,EACP,OAAO;AACT;AAGA,IAAM,sBAAsB,oBAAI,IAAY,CAAC,QAAQ,CAAC;AAEtD,IAAM,YAAY,CAAC,cACjB,UAAU,QAAQ,sBAAsB,OAAO,EAAE,YAAY;AAE/D,IAAM,kBAAkB,CACtB,SAC+F;AAC/F,aAAW,aAAa,KAAK,YAAY;AACvC,QACE,UAAU,SAAS,8BAAe,gBAClC,UAAU,KAAK,SAAS,8BAAe,iBACvC,UAAU,KAAK,SAAS,QACxB;AACA;AAAA,IACF;AACA,QAAI,UAAU,OAAO,SAAS,8BAAe,WAAW,OAAO,UAAU,MAAM,UAAU,UAAU;AACjG,aAAO,EAAE,MAAM,WAAW,OAAO,UAAU,MAAM,MAAM,YAAY,EAAE;AAAA,IACvE;AACA,WAAO,EAAE,MAAM,UAAU;AAAA,EAC3B;AACA,SAAO;AACT;AAGA,IAAM,0BAA0B,CAAC,SAAoD;AACnF,QAAM,WAAW,gBAAgB,IAAI;AACrC,MAAI,aAAa,QAAQ,SAAS,SAAS,UAAW,QAAO;AAC7D,MAAI,oBAAoB,IAAI,SAAS,KAAK,EAAG,QAAO;AACpD,SAAO,wBAAwB,SAAS,KAAK,KAAK;AACpD;AAEA,IAAO,wBAAQ,2BAAY;AAAA,EACzB,CAAC,SACC,8EAA8E,IAAI;AACtF,EAAuB;AAAA,EACrB,MAAM;AAAA,EACN,MAAM;AAAA,IACJ,MAAM;AAAA,IACN,MAAM;AAAA,MACJ,aACE;AAAA,IACJ;AAAA,IACA,QAAQ,CAAC;AAAA,IACT,UAAU;AAAA,MACR,cACE;AAAA,IACJ;AAAA,EACF;AAAA,EACA,gBAAgB,CAAC;AAAA,EACjB,OAAO,SAAS;AACd,WAAO;AAAA,MACL,kBAAkB,MAAwC;AAGxD,YAAI,KAAK,KAAK,SAAS,iBAAiB;AACtC;AAAA,QACF;AAEA,cAAM,cAAc,KAAK,KAAK;AAC9B,cAAM,cACJ,gBAAgB,UAAU,wBAAwB,IAAI,IAAI,aAAa,WAAW;AAEpF,YAAI,gBAAgB,UAAa,gBAAgB,MAAM;AACrD;AAAA,QACF;AAEA,gBAAQ,OAAO;AAAA,UACb;AAAA,UACA,WAAW;AAAA,UACX,MAAM;AAAA,YACJ,SAAS;AAAA,YACT;AAAA,YACA,WAAW,UAAU,WAAW;AAAA,UAClC;AAAA,QACF,CAAC;AAAA,MACH;AAAA,IACF;AAAA,EACF;AACF,CAAC;;;ACnHD,IAAAC,iBAKO;AASP,IAAM,oBAAoB,CAAC,eAA6C;AACtE,MAAI,WAAW,SAAS,8BAAe,eAAgB,QAAO;AAC9D,QAAM,SAAS,WAAW;AAC1B,MAAI,OAAO,SAAS,8BAAe,YAAY;AAC7C,WAAO,OAAO,SAAS;AAAA,EACzB;AACA,MACE,OAAO,SAAS,8BAAe,oBAC/B,CAAC,OAAO,YACR,OAAO,SAAS,SAAS,8BAAe,YACxC;AACA,WAAO,OAAO,SAAS,SAAS;AAAA,EAClC;AACA,SAAO;AACT;AAEA,IAAM,+BAA+B,CACnC,cACY;AACZ,MAAI,UAAU,SAAS,8BAAe,qBAAqB;AACzD,WAAO,kBAAkB,UAAU,UAAU;AAAA,EAC/C;AACA,MAAI,UAAU,SAAS,8BAAe,gBAAgB;AACpD,WAAO,kBAAkB,UAAU,QAAQ;AAAA,EAC7C;AACA,MAAI,UAAU,SAAS,8BAAe,iBAAiB;AACrD,WACE,UAAU,aAAa,QAAQ,kBAAkB,UAAU,QAAQ;AAAA,EAEvE;AAEA,MAAI,UAAU,SAAS,8BAAe,gBAAgB;AACpD,WAAO,UAAU,KAAK,KAAK,4BAA4B;AAAA,EACzD;AACA,SAAO;AACT;AAQA,IAAM,6BAA6B,CAAC,cAA2C;AAC7E,MAAI,UAAU,SAAS,8BAAe,eAAgB,QAAO;AAC7D,MAAI,UAAU,SAAS,8BAAe,gBAAgB;AACpD,WAAO,UAAU,KAAK,KAAK,0BAA0B;AAAA,EACvD;AACA,SAAO;AACT;AAOA,IAAM,uBAAuB,CAC3B,MACA,iBACY;AACZ,QAAM,cAAc,KAAK,MAAM,YAAY;AAC3C,SACE,gBAAgB,UAChB,YAAY,WAAW,WAAW,KAClC,eAAe,KAAK,MAAM,SAAS;AAEvC;AAUA,IAAM,2BAA2B,CAC/B,aACA,eACY;AACZ,MAAI,YAAY,WAAW,WAAW,GAAG;AACvC,UAAM,eAAe,WAAW,cAAc,WAAW;AACzD,UAAM,aAAa,eACf,WAAW,cAAc,YAAY,IACrC;AACJ,WACE,eAAe,QAAQ,WAAW,iBAAiB,UAAU,EAAE,SAAS;AAAA,EAE5E;AACA,QAAM,OAAO,YAAY,WAAW,CAAC;AACrC,MACE,SAAS,UACT,YAAY,WAAW,WAAW,KAClC,KAAK,SAAS,8BAAe,kBAC7B,KAAK,KAAK,WAAW,GACrB;AACA,WAAO,WAAW,kBAAkB,IAAI,EAAE,SAAS;AAAA,EACrD;AACA,SAAO;AACT;AAEA,IAAO,+BAAQ,2BAAY;AAAA,EACzB,CAAC,SACC,8EAA8E,IAAI;AACtF,EAAuB;AAAA,EACrB,MAAM;AAAA,EACN,MAAM;AAAA,IACJ,MAAM;AAAA,IACN,MAAM;AAAA,MACJ,aACE;AAAA,IACJ;AAAA,IACA,QAAQ,CAAC;AAAA,IACT,UAAU;AAAA,MACR,oBACE;AAAA,IACJ;AAAA,EACF;AAAA,EACA,gBAAgB,CAAC;AAAA,EACjB,OAAO,SAAS;AACd,WAAO;AAAA,MACL,gBAAgB,MAAsC;AACpD,cAAM,eAAe,KAAK,MAAM;AAAA,UAC9B,CAAC,aAAa,SAAS,SAAS;AAAA,QAClC;AAGA,YAAI,iBAAiB,GAAI;AACzB,cAAM,cAAc,KAAK,MAAM,YAAY;AAC3C,YAAI,gBAAgB,OAAW;AAG/B,YAAI,YAAY,WAAW,KAAK,4BAA4B,EAAG;AAI/D,YAAI,YAAY,WAAW,KAAK,0BAA0B,EAAG;AAI7D,YAAI,qBAAqB,MAAM,YAAY,EAAG;AAK9C,YAAI,yBAAyB,aAAa,QAAQ,UAAU,EAAG;AAG/D,gBAAQ,OAAO;AAAA,UACb,MAAM;AAAA,UACN,WAAW;AAAA,QACb,CAAC;AAAA,MACH;AAAA,IACF;AAAA,EACF;AACF,CAAC;;;ACjJD,IAAAC,iBAA2D;;;ACTpD,IAAM,gBAAgB;AAGtB,IAAM,gBAAgB;AAGtB,IAAM,qBAAqB;;;ADoBlC,IAAM,qBAAqB,CAAC,SAAiC;AAC3D,MAAI,UAAyB;AAC7B,SAAO,MAAM;AACX,QAAI,QAAQ,SAAS,8BAAe,YAAY;AAC9C,aAAO,QAAQ,SAAS,OAAO,mBAAmB,KAAK,QAAQ,IAAI;AAAA,IACrE;AACA,QAAI,QAAQ,SAAS,8BAAe,gBAAgB;AAClD,gBAAU,QAAQ;AAClB;AAAA,IACF;AACA,QAAI,QAAQ,SAAS,8BAAe,kBAAkB;AACpD,gBAAU,QAAQ;AAClB;AAAA,IACF;AACA,WAAO;AAAA,EACT;AACF;AAQA,IAAM,iBAAiB,CAAC,SAAiC;AACvD,MAAI,KAAK,SAAS,8BAAe,eAAgB,QAAO;AACxD,QAAM,SAAS,KAAK;AACpB,MAAI,OAAO,SAAS,8BAAe,iBAAkB,QAAO;AAC5D,MAAI,OAAO,SAAU,QAAO;AAC5B,MAAI,OAAO,SAAS,SAAS,8BAAe,WAAY,QAAO;AAC/D,QAAM,SAAS,OAAO,SAAS;AAC/B,MAAI,WAAW,WAAW,WAAW,YAAa,QAAO;AACzD,SAAO,mBAAmB,OAAO,MAAM;AACzC;AAMA,IAAM,uBAAuB,CAAC,SAAiC;AAC7D,MAAI,UAAyB;AAC7B,MAAI,QAAQ,SAAS,8BAAe,iBAAiB;AACnD,cAAU,QAAQ;AAAA,EACpB;AACA,MAAI,QAAQ,SAAS,8BAAe,eAAgB,QAAO;AAC3D,QAAM,SAAS,QAAQ;AACvB,SACE,OAAO,SAAS,8BAAe,oBAC/B,CAAC,OAAO,YACR,OAAO,SAAS,SAAS,8BAAe,cACxC,OAAO,SAAS,SAAS;AAE7B;AAEA,IAAO,sCAAQ,2BAAY;AAAA,EACzB,CAAC,SACC,8EAA8E,IAAI;AACtF,EAAuB;AAAA,EACrB,MAAM;AAAA,EACN,MAAM;AAAA,IACJ,MAAM;AAAA,IACN,MAAM;AAAA,MACJ,aACE;AAAA,IACJ;AAAA,IACA,QAAQ,CAAC;AAAA,IACT,UAAU;AAAA,MACR,sBACE;AAAA,IACJ;AAAA,EACF;AAAA,EACA,gBAAgB,CAAC;AAAA,EACjB,OAAO,SAAc;AAGnB,UAAM,yBAAyB,CAAC,SAAiC;AAC/D,UAAI,KAAK,SAAS,8BAAe,WAAY,QAAO;AACpD,UAAI,YAAY,KAAK,KAAK,IAAI,EAAG,QAAO;AAExC,UAAI,QAA4B,QAAQ,WAAW,SAAS,IAAI;AAChE,aAAO,UAAU,MAAM;AACrB,cAAM,WAAW,MAAM,IAAI,IAAI,KAAK,IAAI;AACxC,YAAI,aAAa,UAAa,SAAS,KAAK,WAAW,GAAG;AACxD,gBAAM,MAAM,SAAS,KAAK,CAAC;AAC3B,cACE,QAAQ,UACR,IAAI,SAAS,cACb,IAAI,KAAK,SAAS,8BAAe,sBACjC,IAAI,KAAK,SAAS,MAClB;AACA,mBAAO,qBAAqB,IAAI,KAAK,IAAI;AAAA,UAC3C;AACA,iBAAO;AAAA,QACT;AACA,gBAAQ,MAAM;AAAA,MAChB;AACA,aAAO;AAAA,IACT;AAEA,UAAM,oBAAoB,CAAC,SAA2C;AACpE,YAAM,SAAS,KAAK;AACpB,UAAI,OAAO,SAAS,8BAAe,iBAAkB,QAAO;AAC5D,UACE,OAAO,SAAS,SAAS,8BAAe,cACxC,OAAO,SAAS,SAAS,OACzB;AACA,eAAO;AAAA,MACT;AACA,aAAO,uBAAuB,OAAO,MAAM;AAAA,IAC7C;AAKA,UAAM,sBAAsB,CAAC,SAAiC;AAC5D,UAAI,SAA2C,KAAK;AACpD,aAAO,WAAW,QAAQ,WAAW,QAAW;AAC9C,YAAI,eAAe,MAAM,EAAG,QAAO;AACnC,iBAAS,OAAO;AAAA,MAClB;AACA,aAAO;AAAA,IACT;AAIA,UAAM,wBAAwB,CAAC,SAAiC;AAC9D,YAAM,SAA2C,KAAK;AACtD,aACE,WAAW,QACX,WAAW,UACX,OAAO,SAAS,8BAAe,oBAC/B,OAAO,aAAa,gBACpB,OAAO,SAAS;AAAA,IAEpB;AAGA,UAAM,kBAAkB,CACtB,SACuC;AACvC,YAAM,SAAS,KAAK;AACpB,UACE,OAAO,SAAS,8BAAe,sBAC/B,OAAO,SAAS,QAChB,OAAO,GAAG,SAAS,8BAAe,YAClC;AACA,eAAO;AAAA,MACT;AACA,aAAO;AAAA,IACT;AAGA,UAAM,qBAAqB,CACzB,eACY;AACZ,YAAM,WAAW,QAAQ,WAAW,qBAAqB,UAAU,EAAE,CAAC;AACtE,UAAI,aAAa,OAAW,QAAO;AACnC,aAAO,SAAS,WAAW;AAAA,QACzB,CAAC,QACC,oBAAoB,IAAI,UAAU,KAClC,sBAAsB,IAAI,UAAU;AAAA,MACxC;AAAA,IACF;AAEA,WAAO;AAAA,MACL,eAAe,MAAqC;AAClD,YAAI,CAAC,kBAAkB,IAAI,EAAG;AAE9B,YAAI,oBAAoB,IAAI,KAAK,sBAAsB,IAAI,EAAG;AAE9D,cAAM,aAAa,gBAAgB,IAAI;AACvC,YAAI,eAAe,QAAQ,mBAAmB,UAAU,EAAG;AAE3D,gBAAQ,OAAO;AAAA,UACb;AAAA,UACA,WAAW;AAAA,QACb,CAAC;AAAA,MACH;AAAA,IACF;AAAA,EACF;AACF,CAAC;;;AEvMD,IAAAC,iBAA2D;AAY3D,IAAM,cAGF;AAAA,EACF,QAAQ,EAAE,MAAM,eAAe,WAAW,UAAU;AAAA,EACpD,QAAQ,EAAE,MAAM,eAAe,WAAW,eAAe;AAAA,EACzD,QAAQ,EAAE,MAAM,oBAAoB,WAAW,gBAAgB;AACjE;AAOA,IAAM,yBAAyB,CAAC,SAAiC;AAC/D,MAAI,UAAyB;AAE7B,SAAO,QAAQ,SAAS,8BAAe,kBAAkB;AACvD,UAAM,WAA0B,QAAQ;AACxC,QAAI,SAAS,SAAS,8BAAe,cAAc,SAAS,SAAS,KAAK;AACxE,aAAO;AAAA,IACT;AACA,QAAI,SAAS,SAAS,8BAAe,gBAAgB;AACnD,gBAAU,SAAS;AACnB;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAEA,SAAO;AACT;AAEA,IAAO,gCAAQ,2BAAY;AAAA,EACzB,CAAC,SACC,8EAA8E,IAAI;AACtF,EAAuB;AAAA,EACrB,MAAM;AAAA,EACN,MAAM;AAAA,IACJ,MAAM;AAAA,IACN,MAAM;AAAA,MACJ,aACE;AAAA,IACJ;AAAA,IACA,QAAQ;AAAA,MACN;AAAA,QACE,MAAM;AAAA,QACN,sBAAsB;AAAA,QACtB,YAAY;AAAA,UACV,YAAY;AAAA,YACV,MAAM;AAAA,YACN,MAAM,CAAC,UAAU,UAAU,QAAQ;AAAA,UACrC;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,IACA,UAAU;AAAA,MACR,SAAS;AAAA,MACT,cAAc;AAAA,MACd,eACE;AAAA,IACJ;AAAA,EACF;AAAA,EACA,gBAAgB,CAAC,CAAC,CAAC;AAAA,EACnB,OAAO,SAAS,CAAC,UAAU,GAAG;AAC5B,UAAM,EAAE,MAAM,UAAU,IAAI,YAAY,YAAY,cAAc,QAAQ;AAE1E,WAAO;AAAA,MACL,mBAAmB,MAAyC;AAC1D,cAAM,OAAO,KAAK;AAClB,YAAI,SAAS,QAAQ,SAAS,OAAW;AACzC,YAAI,KAAK,SAAS,8BAAe,eAAgB;AAEjD,cAAM,SAAS,KAAK;AACpB,YAAI,OAAO,SAAS,8BAAe,iBAAkB;AAErD,YAAI,CAAC,uBAAuB,MAAM,EAAG;AAErC,YAAI,KAAK,GAAG,SAAS,8BAAe,WAAY;AAChD,YAAI,KAAK,KAAK,KAAK,GAAG,IAAI,EAAG;AAE7B,gBAAQ,OAAO;AAAA,UACb,MAAM,KAAK;AAAA,UACX;AAAA,QACF,CAAC;AAAA,MACH;AAAA,IACF;AAAA,EACF;AACF,CAAC;;;ACxFD,IAAAC,iBAA2C;AAK3C,IAAM,cAAc;AACpB,IAAM,cAAc;AACpB,IAAM,qBAAqB,oBAAI,IAAI,CAAC,aAAa,OAAO,QAAQ,CAAC;AAKjE,SAAS,cAAc,MAA8B;AACnD,SAAO,KAAK,SAAS,aAAa,KAAK,UAAU;AACnD;AAOA,SAAS,uBAAuB,MAA8B;AAC5D,MAAI,KAAK,SAAS,WAAW;AAC3B,QAAI,KAAK,UAAU,MAAM;AACvB,aAAO;AAAA,IACT;AACA,QAAI,OAAO,KAAK,UAAU,UAAU;AAClC,aAAO,KAAK,MAAM,KAAK,EAAE,YAAY,MAAM;AAAA,IAC7C;AAAA,EACF;AACA,SAAO;AACT;AAKA,SAAS,cAAc,MAA8B;AACnD,SAAO,KAAK,SAAS,aAAa,KAAK,UAAU;AACnD;AAQA,SAAS,2BAA2B,MAA8B;AAChE,MAAI,cAAc,IAAI,GAAG;AACvB,WAAO;AAAA,EACT;AACA,aAAW,OAAO,OAAO,KAAK,IAAI,GAAG;AACnC,QAAI,QAAQ,YAAY,QAAQ,SAAS,QAAQ,SAAS;AACxD;AAAA,IACF;AACA,UAAM,QAAS,KAA4C,GAAG;AAC9D,QAAI,MAAM,QAAQ,KAAK,GAAG;AACxB,iBAAW,SAAS,OAAO;AACzB,YAAIC,QAAO,KAAK,KAAK,2BAA2B,KAAK,GAAG;AACtD,iBAAO;AAAA,QACT;AAAA,MACF;AAAA,IACF,WAAWA,QAAO,KAAK,KAAK,2BAA2B,KAAK,GAAG;AAC7D,aAAO;AAAA,IACT;AAAA,EACF;AACA,SAAO;AACT;AAEA,SAASA,QAAO,OAAwC;AACtD,SACE,OAAO,UAAU,YACjB,UAAU,QACV,OAAQ,MAA6B,SAAS;AAElD;AAKA,SAAS,gBAAgB,MAA6C;AACpE,MAAI,KAAK,UAAU;AACjB,WAAO;AAAA,EACT;AACA,QAAM,MAAM,KAAK;AACjB,MAAI,IAAI,SAAS,cAAc;AAC7B,WAAO,IAAI;AAAA,EACb;AACA,MAAI,IAAI,SAAS,aAAa,OAAO,IAAI,UAAU,UAAU;AAC3D,WAAO,IAAI;AAAA,EACb;AACA,SAAO;AACT;AAMA,SAASC,YACP,MACoB;AACpB,QAAM,SAAS,KAAK;AACpB,MAAI,OAAO,SAAS,cAAc;AAChC,WAAO,OAAO;AAAA,EAChB;AACA,MACE,OAAO,SAAS,sBAChB,CAAC,OAAO,YACR,OAAO,SAAS,SAAS,cACzB;AACA,WAAO,OAAO,SAAS;AAAA,EACzB;AACA,SAAO;AACT;AAOA,SAAS,8BACP,MACS;AACT,QAAM,OAAOA,YAAW,IAAI;AAC5B,MAAI,SAAS,UAAa,KAAK,YAAY,MAAM,QAAQ;AACvD,WAAO;AAAA,EACT;AACA,QAAM,UAAU,KAAK,UAAU;AAAA,IAC7B,CAAC,QAA0C,IAAI,SAAS;AAAA,EAC1D;AACA,MAAI,YAAY,QAAW;AACzB,WAAO;AAAA,EACT;AACA,MAAI,iBAAiB;AACrB,MAAI,oBAAoB;AACxB,aAAW,QAAQ,QAAQ,YAAY;AACrC,QAAI,KAAK,SAAS,YAAY;AAC5B;AAAA,IACF;AACA,UAAM,MAAM,gBAAgB,IAAI;AAChC,QAAI,QAAQ,iBAAiB,cAAc,KAAK,KAAK,GAAG;AACtD,uBAAiB;AAAA,IACnB,WAAW,QAAQ,YAAY,2BAA2B,KAAK,KAAK,GAAG;AACrE,0BAAoB;AAAA,IACtB;AAAA,EACF;AACA,SAAO,kBAAkB;AAC3B;AAOA,SAAS,kCACP,MACS;AACT,MAAI,iBAAiB;AACrB,MAAI,kBAAkB;AACtB,aAAW,QAAQ,KAAK,YAAY;AAClC,QAAI,KAAK,SAAS,YAAY;AAC5B;AAAA,IACF;AACA,UAAM,MAAM,gBAAgB,IAAI;AAChC,QAAI,QAAQ,QAAW;AACrB;AAAA,IACF;AACA,UAAM,SAAS,IAAI,YAAY;AAC/B,QAAI,WAAW,eAAe,cAAc,KAAK,KAAK,GAAG;AACvD,uBAAiB;AAAA,IACnB,WAAW,WAAW,eAAe,uBAAuB,KAAK,KAAK,GAAG;AACvE,wBAAkB;AAAA,IACpB;AAAA,EACF;AACA,SAAO,kBAAkB;AAC3B;AASA,SAAS,sBACP,MAC2B;AAC3B,QAAM,SAAS,KAAK;AACpB,MACE,OAAO,SAAS,sBAChB,OAAO,YACP,OAAO,SAAS,SAAS,gBACzB,CAAC,mBAAmB,IAAI,OAAO,SAAS,KAAK,YAAY,CAAC,GAC1D;AACA,WAAO;AAAA,EACT;AACA,QAAM,CAAC,SAAS,QAAQ,IAAI,KAAK;AACjC,MACE,YAAY,UACZ,aAAa,UACb,QAAQ,SAAS,aACjB,OAAO,QAAQ,UAAU,UACzB;AACA,WAAO;AAAA,EACT;AACA,QAAM,SAAS,QAAQ,MAAM,YAAY;AACzC,MAAI,WAAW,eAAe,cAAc,QAAQ,GAAG;AACrD,WAAO;AAAA,EACT;AACA,MAAI,WAAW,eAAe,uBAAuB,QAAQ,GAAG;AAC9D,WAAO;AAAA,EACT;AACA,SAAO;AACT;AAOA,SAAS,eAAe,MAAgD;AACtE,MAAI,UAAqC,KAAK;AAC9C,SAAO,SAAS;AACd,QACE,QAAQ,SAAS,yBACjB,QAAQ,SAAS,wBACjB,QAAQ,SAAS,2BACjB;AACA,aAAO;AAAA,IACT;AACA,cAAU,QAAQ;AAAA,EACpB;AACA,SAAO;AACT;AAOA,IAAO,4CAAQ,2BAAY;AAAA,EACzB,CAAC,SACC,8EAA8E,IAAI;AACtF,EAAuB;AAAA,EACrB,MAAM;AAAA,EACN,MAAM;AAAA,IACJ,MAAM;AAAA,IACN,MAAM;AAAA,MACJ,aACE;AAAA,IACJ;AAAA,IACA,QAAQ,CAAC;AAAA,IACT,UAAU;AAAA,MACR,6BACE;AAAA,IACJ;AAAA,EACF;AAAA,EACA,gBAAgB,CAAC;AAAA,EACjB,OAAO,SAAS;AACd,UAAM,kBAAkB,oBAAI,IAA+C;AAE3E,aAAS,gBACP,MACA,MACM;AACN,YAAM,MAAM,eAAe,IAAI,KAAK;AACpC,UAAI,QAAQ,gBAAgB,IAAI,GAAG;AACnC,UAAI,UAAU,QAAW;AACvB,gBAAQ,EAAE,aAAa,CAAC,GAAG,kBAAkB,CAAC,EAAE;AAChD,wBAAgB,IAAI,KAAK,KAAK;AAAA,MAChC;AACA,UAAI,SAAS,UAAU;AACrB,cAAM,YAAY,KAAK,IAAI;AAAA,MAC7B,OAAO;AACL,cAAM,iBAAiB,KAAK,IAAI;AAAA,MAClC;AAAA,IACF;AAEA,WAAO;AAAA,MACL,cAAc,MAAoC;AAChD,YAAI,8BAA8B,IAAI,GAAG;AACvC,kBAAQ,OAAO,EAAE,MAAM,WAAW,8BAA8B,CAAC;AAAA,QACnE;AAAA,MACF;AAAA,MACA,eAAe,MAAqC;AAClD,YAAI,8BAA8B,IAAI,GAAG;AACvC,kBAAQ,OAAO,EAAE,MAAM,WAAW,8BAA8B,CAAC;AACjE;AAAA,QACF;AACA,cAAM,OAAO,sBAAsB,IAAI;AACvC,YAAI,SAAS,QAAW;AACtB,0BAAgB,MAAM,IAAI;AAAA,QAC5B;AAAA,MACF;AAAA,MACA,iBAAiB,MAAuC;AACtD,YAAI,kCAAkC,IAAI,GAAG;AAC3C,kBAAQ,OAAO,EAAE,MAAM,WAAW,8BAA8B,CAAC;AAAA,QACnE;AAAA,MACF;AAAA,MACA,iBAAuB;AACrB,mBAAW,EAAE,aAAa,iBAAiB,KAAK,gBAAgB,OAAO,GAAG;AACxE,cAAI,YAAY,SAAS,KAAK,iBAAiB,SAAS,GAAG;AACzD,uBAAW,QAAQ,aAAa;AAC9B,sBAAQ,OAAO;AAAA,gBACb;AAAA,gBACA,WAAW;AAAA,cACb,CAAC;AAAA,YACH;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF,CAAC;;;ACnUD,IAAAC,iBAA2D;;;ACZ3D,IAAM,iBAAiB;AAMhB,SAAS,WAAW,UAA2B;AACpD,QAAM,aAAa,SAAS,WAAW,MAAM,GAAG;AAChD,QAAM,OAAO,WAAW,MAAM,WAAW,YAAY,GAAG,IAAI,CAAC;AAC7D,MAAI,+BAA+B,KAAK,IAAI,GAAG;AAC7C,WAAO;AAAA,EACT;AACA,SAAO,gDAAgD,KAAK,UAAU;AACxE;AAOO,SAAS,aAAa,UAA2B;AACtD,SAAO,eAAe,KAAK,QAAQ;AACrC;;;ADFA,SAAS,gBAAgB,MAAoC;AAC3D,SACE,KAAK,SAAS,8BAAe,kBAC7B,KAAK,UAAU,WAAW,KAC1B,KAAK,OAAO,SAAS,8BAAe,oBACpC,CAAC,KAAK,OAAO,YACb,KAAK,OAAO,SAAS,SAAS,8BAAe,eAC5C,KAAK,OAAO,SAAS,SAAS,UAC7B,KAAK,OAAO,SAAS,SAAS;AAEpC;AAIA,SAAS,mBAAmB,MAAoC;AAC9D,UAAQ,KAAK,MAAM;AAAA,IACjB,KAAK,8BAAe;AAGlB,aAAO,EAAE,WAAW;AAAA,IACtB,KAAK,8BAAe;AAClB,aAAO,KAAK,SAAS;AAAA,IACvB,KAAK,8BAAe;AAElB,aACE,KAAK,aAAa,UAClB,KAAK,SAAS,SAAS,8BAAe;AAAA,IAE1C,KAAK,8BAAe;AAClB,aAAO,KAAK,WAAW,WAAW;AAAA,IACpC,KAAK,8BAAe;AAClB,aAAO,KAAK,SAAS,WAAW;AAAA,IAClC,KAAK,8BAAe;AAElB,aAAO,mBAAmB,KAAK,UAAU;AAAA,IAC3C;AACE,aAAO;AAAA,EACX;AACF;AAGA,SAAS,gBACP,SACS;AACT,QAAM,OAAO,QAAQ;AAErB,MAAI,KAAK,SAAS,8BAAe,gBAAgB;AAE/C,WAAO,mBAAmB,IAAI;AAAA,EAChC;AAEA,MAAI,KAAK,KAAK,WAAW,GAAG;AAE1B,WAAO;AAAA,EACT;AAEA,MAAI,KAAK,KAAK,WAAW,GAAG;AAC1B,UAAM,OAAO,KAAK,KAAK,CAAC;AACxB,QAAI,SAAS,UAAa,KAAK,SAAS,8BAAe,iBAAiB;AAEtE,aAAO,KAAK,aAAa,QAAQ,mBAAmB,KAAK,QAAQ;AAAA,IACnE;AAAA,EACF;AAEA,SAAO;AACT;AAEA,IAAO,kCAAQ,2BAAY;AAAA,EACzB,CAAC,SACC,8EAA8E,IAAI;AACtF,EAAuB;AAAA,EACrB,MAAM;AAAA,EACN,MAAM;AAAA,IACJ,MAAM;AAAA,IACN,MAAM;AAAA,MACJ,aACE;AAAA,IACJ;AAAA,IACA,QAAQ,CAAC;AAAA,IACT,UAAU;AAAA,MACR,aACE;AAAA,IACJ;AAAA,EACF;AAAA,EACA,gBAAgB,CAAC;AAAA,EACjB,OAAO,SAAS;AACd,QAAI,WAAW,QAAQ,QAAQ,GAAG;AAChC,aAAO,CAAC;AAAA,IACV;AAEA,WAAO;AAAA,MACL,eAAe,MAAqC;AAClD,YACE,KAAK,OAAO,SAAS,8BAAe,oBACpC,KAAK,OAAO,YACZ,KAAK,OAAO,SAAS,SAAS,8BAAe,cAC7C,KAAK,OAAO,SAAS,SAAS,SAC9B;AACA;AAAA,QACF;AAEA,YAAI,gBAAgB,KAAK,OAAO,MAAM,GAAG;AACvC;AAAA,QACF;AAEA,YAAI,KAAK,UAAU,WAAW,GAAG;AAC/B;AAAA,QACF;AACA,cAAM,UAAU,KAAK,UAAU,CAAC;AAChC,YACE,YAAY,UACX,QAAQ,SAAS,8BAAe,2BAC/B,QAAQ,SAAS,8BAAe,oBAClC;AACA;AAAA,QACF;AAEA,YAAI,gBAAgB,OAAO,GAAG;AAK5B,kBAAQ,OAAO,EAAE,MAAM,WAAW,cAAc,CAAC;AAAA,QACnD;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF,CAAC;;;AEjID,IAAAC,iBAKO;AAYP,IAAM,iBAAsC,oBAAI,IAAI;AAAA,EAClD;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAED,SAASC,mBACP,UACA,UACS;AACT,aAAW,WAAW,UAAU;AAE9B,UAAM,cAAc,QACjB,QAAQ,qBAAqB,MAAM,EACnC,QAAQ,SAAS,gBAAgB,EACjC,QAAQ,OAAO,WAAW,EAC1B,QAAQ,mBAAmB,IAAI;AAClC,QAAI,IAAI,OAAO,IAAI,WAAW,GAAG,EAAE,KAAK,QAAQ,GAAG;AACjD,aAAO;AAAA,IACT;AAAA,EACF;AACA,SAAO;AACT;AAQA,SAAS,wBAAwB,MAAgD;AAC/E,MAAI,KAAK,SAAS,8BAAe,kBAAkB;AACjD,WAAO;AAAA,EACT;AACA,aAAW,QAAQ,KAAK,YAAY;AAClC,QAAI,KAAK,SAAS,8BAAe,eAAe;AAC9C,aAAO;AAAA,IACT;AACA,QACG,KAAK,IAAI,SAAS,8BAAe,cAChC,KAAK,IAAI,SAAS,YACnB,KAAK,IAAI,SAAS,8BAAe,WAAW,KAAK,IAAI,UAAU,UAChE;AACA,aAAO;AAAA,IACT;AAEA,QAAI,KAAK,UAAU;AACjB,aAAO;AAAA,IACT;AAAA,EACF;AACA,SAAO;AACT;AAGA,SAAS,YAAY,MAAgD;AACnE,SACG,KAAK,SAAS,8BAAe,WAAW,OAAO,KAAK,UAAU,YAC/D,KAAK,SAAS,8BAAe;AAEjC;AAEA,IAAO,gCAAQ,2BAAY;AAAA,EACzB,CAAC,SACC,8EAA8E,IAAI;AACtF,EAAuB;AAAA,EACrB,MAAM;AAAA,EACN,MAAM;AAAA,IACJ,MAAM;AAAA,IACN,MAAM;AAAA,MACJ,aACE;AAAA,IACJ;AAAA,IACA,QAAQ;AAAA,MACN;AAAA,QACE,MAAM;AAAA,QACN,sBAAsB;AAAA,QACtB,YAAY;AAAA,UACV,SAAS;AAAA,YACP,aACE;AAAA,YACF,MAAM;AAAA,YACN,OAAO,EAAE,MAAM,SAAS;AAAA,UAC1B;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,IACA,UAAU;AAAA,MACR,eACE;AAAA,IACJ;AAAA,EACF;AAAA,EACA,gBAAgB,CAAC,CAAC,CAAC;AAAA,EACnB,OAAO,SAAS,CAAC,UAAU,GAAG;AAC5B,QAAI,WAAW,QAAQ,QAAQ,KAAK,aAAa,QAAQ,QAAQ,GAAG;AAClE,aAAO,CAAC;AAAA,IACV;AACA,UAAM,UAAU,YAAY,WAAW,CAAC;AACxC,QAAI,QAAQ,SAAS,KAAKA,mBAAkB,QAAQ,UAAU,OAAO,GAAG;AACtE,aAAO,CAAC;AAAA,IACV;AAGA,aAAS,iBAAiB,YAA0C;AAClE,YAAM,QAAQ,QAAQ,WAAW,SAAS,UAAU;AACpD,YAAM,WAAW,wBAAS,aAAa,OAAO,WAAW,IAAI;AAG7D,aAAO,aAAa,QAAQ,SAAS,KAAK,WAAW;AAAA,IACvD;AAIA,aAASC,mBAAkB,QAAsC;AAC/D,UAAI,OAAO,SAAS,8BAAe,YAAY;AAC7C,eAAO,OAAO,SAAS,WAAW,iBAAiB,MAAM;AAAA,MAC3D;AACA,aACE,OAAO,SAAS,8BAAe,oBAC/B,CAAC,OAAO,YACR,OAAO,SAAS,SAAS,8BAAe,cACxC,OAAO,SAAS,SAAS,WACzB,OAAO,OAAO,SAAS,8BAAe,cACtC,eAAe,IAAI,OAAO,OAAO,IAAI,KACrC,iBAAiB,OAAO,MAAM;AAAA,IAElC;AAEA,WAAO;AAAA,MACL,eAAe,MAAqC;AAClD,YAAI,CAACA,mBAAkB,KAAK,MAAM,GAAG;AACnC;AAAA,QACF;AAKA,cAAM,CAAC,OAAO,IAAI,IAAI,KAAK;AAC3B,YAAI,KAAK,UAAU,WAAW,KAAK,UAAU,UAAa,CAAC,YAAY,KAAK,GAAG;AAC7E;AAAA,QACF;AAEA,YAAI,SAAS,UAAa,wBAAwB,IAAI,GAAG;AACvD,kBAAQ,OAAO,EAAE,MAAM,WAAW,gBAAgB,CAAC;AAAA,QACrD;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF,CAAC;;;AC5KD,IAAAC,iBAA2D;AAQ3D,IAAM,oBAAyC,oBAAI,IAAI;AAAA,EACrD;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAED,SAAS,sBAAsB,gBAA4C;AACzE,SACE,eAAe,SAAS,8BAAe,mBACvC,eAAe,SAAS,SAAS,8BAAe,cAChD,eAAe,SAAS,SAAS;AAErC;AAGA,SAAS,gBAAgB,MAAwC;AAC/D,SACE,KAAK,OAAO,SAAS,8BAAe,oBACpC,CAAC,KAAK,OAAO,YACb,KAAK,OAAO,SAAS,SAAS,8BAAe,cAC7C,kBAAkB,IAAI,KAAK,OAAO,SAAS,IAAI;AAEnD;AAQA,SAAS,mBACP,MACA,oBAC2D;AAC3D,OACG,KAAK,SAAS,8BAAe,kBAC5B,KAAK,SAAS,8BAAe,oBAC/B,CAAC,sBAAsB,KAAK,cAAc,KAC1C,CAAC,oBACD;AACA,WAAO;AAAA,EACT;AAEA,MACE,KAAK,SAAS,8BAAe,kBAC7B,gBAAgB,IAAI,GACpB;AAEA,UAAM,WAAW,mBAAmB,KAAK,QAAQ,kBAAkB;AACnE,QAAI,aAAa,MAAM;AACrB,aAAO;AAAA,IACT;AACA,eAAW,OAAO,KAAK,WAAW;AAChC,YAAM,QAAQ,mBAAmB,KAAK,IAAI;AAC1C,UAAI,UAAU,MAAM;AAClB,eAAO;AAAA,MACT;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAEA,aAAW,OAAO,OAAO,KAAK,IAAI,GAAG;AACnC,QAAI,QAAQ,UAAU;AACpB;AAAA,IACF;AACA,UAAM,QAAS,KAA4C,GAAG;AAC9D,UAAM,WAAW,MAAM,QAAQ,KAAK,IAAI,QAAQ,CAAC,KAAK;AACtD,eAAW,SAAS,UAAU;AAC5B,UACE,UAAU,QACV,OAAO,UAAU,YACjB,UAAU,SACV,OAAQ,MAA4B,SAAS,UAC7C;AACA,cAAM,QAAQ;AAAA,UACZ;AAAA,UACA;AAAA,QACF;AACA,YAAI,UAAU,MAAM;AAClB,iBAAO;AAAA,QACT;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACA,SAAO;AACT;AAEA,IAAO,yCAAQ,2BAAY;AAAA,EACzB,CAAC,SACC,8EAA8E,IAAI;AACtF,EAAuB;AAAA,EACrB,MAAM;AAAA,EACN,MAAM;AAAA,IACJ,MAAM;AAAA,IACN,MAAM;AAAA,MACJ,aACE;AAAA,IACJ;AAAA,IACA,QAAQ,CAAC;AAAA,IACT,UAAU;AAAA,MACR,sBACE;AAAA,IACJ;AAAA,EACF;AAAA,EACA,gBAAgB,CAAC;AAAA,EACjB,OAAO,SAAS;AACd,QAAI,WAAW,QAAQ,QAAQ,GAAG;AAChC,aAAO,CAAC;AAAA,IACV;AAEA,WAAO;AAAA,MACL,SAAS,MAA+B;AACtC,cAAM,sBACH,CAAC,KAAK,YACL,KAAK,IAAI,SAAS,8BAAe,cACjC,KAAK,IAAI,SAAS,oBACnB,KAAK,IAAI,SAAS,8BAAe,WAChC,KAAK,IAAI,UAAU;AACvB,YAAI,CAAC,qBAAqB;AACxB;AAAA,QACF;AAEA,YACE,KAAK,MAAM,SAAS,8BAAe,2BACnC,KAAK,MAAM,SAAS,8BAAe,oBACnC;AACA;AAAA,QACF;AAEA,cAAM,OAAO,mBAAmB,KAAK,MAAM,MAAM,KAAK;AACtD,YAAI,SAAS,MAAM;AACjB,kBAAQ,OAAO,EAAE,MAAM,MAAM,WAAW,uBAAuB,CAAC;AAAA,QAClE;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF,CAAC;;;ACvHD,IAAAC,iBAIO;AAKP,IAAM,0BAA0B;AAEhC,IAAM,wBAAwB,oBAAI,IAAoB;AAAA,EACpD,8BAAe;AAAA,EACf,8BAAe;AAAA,EACf,8BAAe;AACjB,CAAC;AAGD,IAAM,eAAe,oBAAI,IAAY;AAAA,EACnC;AAAA,EAAO;AAAA,EAAU;AAAA,EAAW;AAAA,EAAU;AAAA,EAAe;AAAA,EAAQ;AAAA,EAC7D;AAAA,EAAY;AAAA,EAAiB;AAAA,EAAQ;AAAA,EAAS;AAAA,EAAQ;AAAA,EAAO;AAAA,EAC7D;AAAA,EAAW;AAAA,EAAS;AAAA,EAAU;AAAA,EAAU;AAAA,EAAQ;AAAA,EAAW;AAAA,EAAQ;AAAA,EACnE;AAAA,EAAQ;AAAA,EAAQ;AAAA,EAAY;AAAA,EAAW;AAAA,EAAe;AAAA,EAAM;AAAA,EAAQ;AAAA,EACpE;AAAA,EAAW;AAAA,EAAO;AAAA,EAAO;AAAA,EAAO;AAAA,EAAO;AAAA,EAAU;AAAA,EAAS;AAAA,EAC1D;AAAA,EAAkB;AAAA,EAAW;AAAA,EAAU;AAAA,EAAc;AAAA,EAAe;AAAA,EACpE;AAAA,EAAY;AAAA,EAAU;AAAA,EAAU;AAAA,EAAQ;AAAA,EAAa;AAAA,EAAW;AAAA,EAChE;AAAA,EAAe;AAAA,EAAW;AAAA,EAAe;AAAA,EAAc;AACzD,CAAC;AAGD,IAAM,kBAAkB,oBAAI,IAAY;AAAA,EACtC;AAAA,EAAU;AAAA,EAAS;AAAA,EAAQ;AAAA,EAAQ;AAAA,EAAU;AAAA,EAAU;AAAA,EAAW;AACpE,CAAC;AAGD,IAAM,oBAAoB,oBAAI,IAAY;AAAA,EACxC;AAAA,EAAO;AAAA,EAAO;AAAA,EAAW;AAAA,EAAW;AAAA,EAAQ;AAAA,EAAS;AAAA,EACrD;AAAA,EAAc;AAAA,EAAS;AAAA,EAAU;AAAA,EAAW;AAAA,EAAmB;AAAA,EAC/D;AAAA,EAAe;AAAA,EAAe;AAAA,EAAQ;AAAA,EAAkB;AAAA,EACxD;AAAA,EAAmB;AAAA,EAAY;AACjC,CAAC;AAED,SAASC,QAAO,OAAwC;AACtD,SACE,OAAO,UAAU,YACjB,UAAU,QACV,OAAQ,MAA6B,SAAS;AAElD;AAGA,SAAS,WAAW,MAAwC;AAC1D,QAAM,SAAS,KAAK;AACpB,MAAI,OAAO,SAAS,8BAAe,kBAAkB;AACnD,WAAO;AAAA,EACT;AACA,QAAM,WAAW,OAAO;AACxB,MAAI,SAAS,SAAS,8BAAe,YAAY;AAC/C,WAAO;AAAA,EACT;AACA,MACE,OAAO,OAAO,SAAS,8BAAe,cACtC,gBAAgB,IAAI,OAAO,OAAO,IAAI,GACtC;AACA,WAAO;AAAA,EACT;AACA,SAAO,aAAa,IAAI,SAAS,IAAI;AACvC;AAEA,SAAS,UAAU,MAAuC;AACxD,SACE,KAAK,OAAO,SAAS,8BAAe,cACpC,kBAAkB,IAAI,KAAK,OAAO,IAAI;AAE1C;AAMA,SAAS,eACP,MACA,WACS;AACT,MAAI,QAAQ;AAEZ,QAAM,QAAQ,CAAC,YAAiC;AAC9C,QAAI,OAAO;AACT;AAAA,IACF;AACA,QAAI,UAAU,OAAO,GAAG;AACtB,cAAQ;AACR;AAAA,IACF;AACA,eAAW,OAAO,OAAO,KAAK,OAAO,GAAG;AACtC,UAAI,QAAQ,UAAU;AACpB;AAAA,MACF;AACA,UAAI,sBAAsB,IAAI,QAAQ,IAAI,KAAK,QAAQ,QAAQ;AAC7D;AAAA,MACF;AACA,YAAM,QAAS,QAA+C,GAAG;AACjE,UAAI,MAAM,QAAQ,KAAK,GAAG;AACxB,mBAAW,SAAS,OAAO;AACzB,cAAIA,QAAO,KAAK,GAAG;AACjB,kBAAM,KAAK;AAAA,UACb;AAAA,QACF;AAAA,MACF,WAAWA,QAAO,KAAK,GAAG;AACxB,cAAM,KAAK;AAAA,MACb;AACA,UAAI,OAAO;AACT;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,QAAM,IAAI;AACV,SAAO;AACT;AAEA,IAAM,WAAW,CAAC,SAChB,eAAe,MAAM,CAAC,MAAM,EAAE,SAAS,8BAAe,eAAe;AAEvE,IAAM,uBAAuB,CAAC,SAC5B;AAAA,EACE;AAAA,EACA,CAAC,MACE,EAAE,SAAS,8BAAe,kBAAkB,CAAC,WAAW,CAAC,KACzD,EAAE,SAAS,8BAAe,iBAAiB,CAAC,UAAU,CAAC;AAC5D;AAGF,SAASC,QAAO,MAAgD;AAC9D,MAAI,UAAU;AACd,SACE,QAAQ,SAAS,8BAAe,mBAChC,QAAQ,SAAS,8BAAe,qBAChC;AACA,cAAU,QAAQ;AAAA,EACpB;AACA,SAAO;AACT;AAGA,SAAS,oBAAoB,MAAmC;AAC9D,SACE,KAAK,SAAS,8BAAe,uBAC7BA,QAAO,KAAK,UAAU,EAAE,SAAS,8BAAe;AAEpD;AAaA,SAAS,SAAS,MAAmC;AACnD,MAAI,SAAS,IAAI,GAAG;AAClB,WAAO;AAAA,EACT;AACA,MAAI,oBAAoB,IAAI,GAAG;AAC7B,WAAO;AAAA,EACT;AACA,MAAI,KAAK,SAAS,8BAAe,gBAAgB;AAC/C,WAAO,KAAK,KAAK,KAAK,QAAQ;AAAA,EAChC;AACA,MAAI,KAAK,SAAS,8BAAe,aAAa;AAC5C,WACE,qBAAqB,KAAK,IAAI,KAC9B,SAAS,KAAK,UAAU,KACvB,KAAK,cAAc,QAAQ,SAAS,KAAK,SAAS;AAAA,EAEvD;AACA,SAAO,qBAAqB,IAAI;AAClC;AAMA,SAAS,gBAAgB,SAA+C;AACtE,MAAI,YAAY,MAAM;AACpB,WAAO;AAAA,EACT;AACA,QAAM,OAAO,QAAQ,KAAK;AAC1B,QAAM,OAAO,KAAK,KAAK,SAAS,CAAC;AACjC,SAAO,SAAS,UAAa,KAAK,SAAS,8BAAe;AAC5D;AAEA,IAAO,4BAAQ,2BAAY;AAAA,EACzB,CAAC,SACC,gFAAgF,IAAI;AACxF,EAAuB;AAAA,EACrB,MAAM;AAAA,EACN,MAAM;AAAA,IACJ,MAAM;AAAA,IACN,MAAM;AAAA,MACJ,aACE;AAAA,IACJ;AAAA,IACA,QAAQ,CAAC;AAAA,IACT,UAAU;AAAA,MACR,aACE;AAAA,IACJ;AAAA,EACF;AAAA,EACA,gBAAgB,CAAC;AAAA,EACjB,OAAO,SAAS;AACd,UAAM,aAAa,QAAQ;AAE3B,WAAO;AAAA,MACL,aAAa,MAAmC;AAC9C,YAAI,KAAK,cAAc,MAAM;AAC3B;AAAA,QACF;AACA,YAAI,gBAAgB,KAAK,OAAO,GAAG;AACjC;AAAA,QACF;AAEA,cAAM,QAAQ,KAAK,MAAM,KAAK,OAAO,QAAQ,EAAE;AAC/C,YAAI,SAAS,yBAAyB;AACpC;AAAA,QACF;AAEA,cAAM,aAAa,WAAW,cAAc,IAAI;AAChD,gBAAQ,OAAO;AAAA,UACb,MAAM,cAAc;AAAA,UACpB,WAAW;AAAA,UACX,MAAM,EAAE,OAAO,KAAK,wBAAwB;AAAA,QAC9C,CAAC;AAAA,MACH;AAAA,IACF;AAAA,EACF;AACF,CAAC;;;ACjQD,IAAAC,iBAA2C;;;ACWpC,IAAM,eAAoC,oBAAI,IAAI;AAAA,EACvD;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAUM,IAAM,kBAAuC,oBAAI,IAAI;AAAA,EAC1D;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;AASD,IAAM,mBAAwC,oBAAI,IAAI;AAAA,EACpD;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAMD,IAAM,iBAAsC,oBAAI,IAAI,CAAC,QAAQ,SAAS,QAAQ,OAAO,CAAC;AAMtF,IAAM,gBAAqC,oBAAI,IAAI;AAAA,EACjD;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;AASD,IAAM,aAAkC,oBAAI,IAAI;AAAA,EAC9C;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAMD,IAAM,WAAW;AACjB,IAAM,aAAa;AAQZ,SAAS,SAAS,YAA8B;AACrD,QAAM,SAAmB,CAAC;AAC1B,aAAW,WAAW,WAAW,MAAM,UAAU,GAAG;AAClD,QAAI,CAAC,SAAS;AACZ;AAAA,IACF;AACA,WAAO,KAAK,QAAQ,YAAY,CAAC;AACjC,eAAW,QAAQ,QAAQ,MAAM,QAAQ,KAAK,CAAC,GAAG;AAChD,aAAO,KAAK,KAAK,YAAY,CAAC;AAAA,IAChC;AAAA,EACF;AACA,SAAO;AACT;AAYO,SAAS,YAAY,YAAwC;AAClE,aAAW,WAAW,WAAW,MAAM,UAAU,GAAG;AAClD,QAAI,SAAS;AACX,cAAQ,QAAQ,MAAM,QAAQ,KAAK,CAAC,OAAO,GAAG,CAAC,GAAG,YAAY;AAAA,IAChE;AAAA,EACF;AACA,SAAO;AACT;AAGO,SAAS,UAAU,QAAoC;AAC5D,WAAS,IAAI,GAAG,IAAI,IAAI,OAAO,QAAQ,KAAK;AAC1C,QAAI,OAAO,CAAC,MAAM,SAAS,OAAO,IAAI,CAAC,MAAM,OAAO;AAClD,aAAO;AAAA,IACT;AAAA,EACF;AACA,SAAO;AACT;AAOO,SAAS,aACd,YACA,YAAiC,iBACxB;AACT,QAAM,SAAS,SAAS,UAAU;AAClC,QAAM,OAAO,OAAO,GAAG,EAAE;AACzB,MAAI,SAAS,UAAa,UAAU,IAAI,IAAI,GAAG;AAC7C,WAAO;AAAA,EACT;AACA,MAAI,OAAO,KAAK,CAAC,QAAQ,aAAa,IAAI,GAAG,CAAC,GAAG;AAC/C,WAAO;AAAA,EACT;AACA,SAAO,UAAU,MAAM;AACzB;AAUO,SAAS,iBAAiB,YAA6B;AAC5D,MAAI,CAAC,aAAa,UAAU,GAAG;AAC7B,WAAO;AAAA,EACT;AACA,QAAM,SAAS,SAAS,UAAU;AAClC,QAAM,QAAQ,YAAY,UAAU;AACpC,MAAI,UAAU,UAAa,cAAc,IAAI,KAAK,GAAG;AACnD,WAAO;AAAA,EACT;AACA,QAAM,OAAO,OAAO,GAAG,EAAE;AACzB,MAAI,SAAS,UAAa,iBAAiB,IAAI,IAAI,GAAG;AACpD,WAAO;AAAA,EACT;AACA,MAAI,OAAO,KAAK,CAAC,QAAQ,eAAe,IAAI,GAAG,CAAC,GAAG;AACjD,WAAO;AAAA,EACT;AACA,MAAI,OAAO,KAAK,CAAC,QAAQ,WAAW,IAAI,GAAG,CAAC,GAAG;AAC7C,WAAO;AAAA,EACT;AACA,SAAO,UAAU,MAAM;AACzB;;;ADlNA,IAAM,sBAA2C,oBAAI,IAAI;AAAA,EACvD,GAAG;AAAA,EACH;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAED,IAAM,eAAe;AACrB,IAAM,gCAAqD,oBAAI,IAAI,CAAC,KAAK,CAAC;AAG1E,SAAS,gBAAgB,MAAuB;AAC9C,MAAI,aAAa,KAAK,IAAI,GAAG;AAC3B,WAAO;AAAA,EACT;AACA,MAAI,SAAS,IAAI,EAAE,KAAK,CAAC,QAAQ,8BAA8B,IAAI,GAAG,CAAC,GAAG;AACxE,WAAO;AAAA,EACT;AACA,SAAO,aAAa,MAAM,mBAAmB;AAC/C;AASA,SAAS,iBAAiB,MAAkC;AAC1D,MAAI,KAAK,WAAW;AAClB,WAAO;AAAA,EACT;AACA,SAAO,KAAK,MAAM,SAAS,gBAAgB,KAAK,MAAM,SAAS;AACjE;AAGA,SAASC,iBAAgB,MAAwC;AAC/D,MAAI,KAAK,UAAU;AACjB,WAAO;AAAA,EACT;AACA,MAAI,KAAK,IAAI,SAAS,cAAc;AAClC,WAAO,KAAK,IAAI;AAAA,EAClB;AACA,MAAI,KAAK,IAAI,SAAS,aAAa,OAAO,KAAK,IAAI,UAAU,UAAU;AACrE,WAAO,KAAK,IAAI;AAAA,EAClB;AACA,SAAO;AACT;AAEA,IAAO,2BAAQ,2BAAY;AAAA,EACzB,CAAC,SACC,gFAAgF,IAAI;AACxF,EAAuB;AAAA,EACrB,MAAM;AAAA,EACN,MAAM;AAAA,IACJ,MAAM;AAAA,IACN,MAAM;AAAA,MACJ,aACE;AAAA,IACJ;AAAA,IACA,QAAQ;AAAA,MACN;AAAA,QACE,MAAM;AAAA,QACN,sBAAsB;AAAA,QACtB,YAAY,EAAE,GAAG,0BAA0B;AAAA,MAC7C;AAAA,IACF;AAAA,IACA,UAAU;AAAA,MACR,eACE;AAAA,IACJ;AAAA,EACF;AAAA,EACA,gBAAgB,CAAC,CAAC,CAAC;AAAA,EACnB,OAAO,SAAS,CAAC,cAAc,GAAG;AAChC,UAAM,UAAU,iBAAiB,cAAc;AAE/C,WAAO;AAAA,MACL,eAAe,MAAqC;AAClD,YAAI,CAAC,QAAQ,cAAc,IAAI,GAAG;AAChC;AAAA,QACF;AAEA,mBAAW,OAAO,KAAK,WAAW;AAChC,cAAI,IAAI,SAAS,cAAc;AAC7B,gBAAI,gBAAgB,IAAI,IAAI,GAAG;AAC7B,sBAAQ,OAAO;AAAA,gBACb,MAAM;AAAA,gBACN,WAAW;AAAA,gBACX,MAAM,EAAE,MAAM,IAAI,KAAK;AAAA,cACzB,CAAC;AAAA,YACH;AACA;AAAA,UACF;AACA,cAAI,IAAI,SAAS,oBAAoB;AACnC,gBACE,CAAC,IAAI,YACL,IAAI,SAAS,SAAS,gBACtB,gBAAgB,IAAI,SAAS,IAAI,GACjC;AACA,sBAAQ,OAAO;AAAA,gBACb,MAAM;AAAA,gBACN,WAAW;AAAA,gBACX,MAAM,EAAE,MAAM,IAAI,SAAS,KAAK;AAAA,cAClC,CAAC;AAAA,YACH;AACA;AAAA,UACF;AACA,cAAI,IAAI,SAAS,oBAAoB;AACnC,uBAAW,QAAQ,IAAI,YAAY;AACjC,kBAAI,KAAK,SAAS,YAAY;AAC5B;AAAA,cACF;AACA,oBAAMC,WAAUD,iBAAgB,IAAI;AACpC,kBAAIC,aAAY,QAAQ,gBAAgBA,QAAO,KAAK,iBAAiB,IAAI,GAAG;AAC1E,wBAAQ,OAAO;AAAA,kBACb,MAAM;AAAA,kBACN,WAAW;AAAA,kBACX,MAAM,EAAE,MAAMA,SAAQ;AAAA,gBACxB,CAAC;AAAA,cACH;AAAA,YACF;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF,CAAC;;;AExMD,IAAAC,iBAA2C;AAC3C,IAAAA,iBAA+B;AAI/B,SAAS,gBAAgB,MAAkC;AACzD,SAAO,KAAK,SAAS,8BAAe;AACtC;AAEA,SAAS,iBAAiB,gBAA4C;AACpE,SACE,eAAe,SAAS,8BAAe,mBACvC,eAAe,SAAS,SAAS,8BAAe,cAChD,eAAe,SAAS,SAAS;AAErC;AAEA,IAAO,yBAAQ,2BAAY;AAAA,EACzB,CAAC,SACC,8EAA8E,IAAI;AACtF,EAAkB;AAAA,EAChB,MAAM;AAAA,EACN,MAAM;AAAA,IACJ,MAAM;AAAA,IACN,MAAM;AAAA,MACJ,aACE;AAAA,IACJ;AAAA,IACA,QAAQ,CAAC;AAAA,IACT,UAAU;AAAA,MACR,OACE;AAAA,MACF,YACE;AAAA,IACJ;AAAA,EACF;AAAA,EACA,gBAAgB,CAAC;AAAA,EACjB,OAAO,SAAS;AACd,aAAS,eACP,MACM;AACN,UAAI,iBAAiB,KAAK,cAAc,GAAG;AACzC;AAAA,MACF;AAEA,UAAI,gBAAgB,KAAK,cAAc,GAAG;AACxC,gBAAQ,OAAO,EAAE,MAAM,WAAW,QAAQ,CAAC;AAC3C;AAAA,MACF;AAEA,YAAM,QAAQ,KAAK;AACnB,UACE,MAAM,SAAS,8BAAe,kBAC9B,MAAM,SAAS,8BAAe,iBAC9B;AACA,gBAAQ,OAAO,EAAE,MAAM,WAAW,aAAa,CAAC;AAAA,MAClD;AAAA,IACF;AAEA,WAAO;AAAA,MACL,gBAAgB;AAAA,MAChB,iBAAiB;AAAA,IACnB;AAAA,EACF;AACF,CAAC;;;ACzBD,IAAAC,iBAKO;AACP,SAAoB;AAcpB,IAAM,gBAAqC,oBAAI,IAAI;AAAA,EACjD;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAED,IAAM,iBAAiB;AACvB,IAAM,mBAAmB;AAEzB,IAAM,aAAkC,oBAAI,IAAI,CAAC,QAAQ,OAAO,CAAC;AAQjE,SAAS,YAAY,KAAsB;AACzC,SAAO,eAAe,KAAK,GAAG,KAAK,IAAI,UAAU,KAAK,CAAC,WAAW,IAAI,GAAG;AAC3E;AAEA,IAAM,kBAAqC;AAAA,EACzC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAEA,SAAS,cAAc,UAAkB,YAA6B;AACpE,MAAI,gBAAgB,KAAK,CAAC,OAAO,GAAG,KAAK,QAAQ,CAAC,GAAG;AACnD,WAAO;AAAA,EACT;AACA,SAAO,eAAe,KAAK,WAAW,MAAM,GAAG,IAAI,CAAC;AACtD;AAMA,SAAS,SAAS,MAAsB;AACtC,QAAM,QAAQ,KACX,QAAQ,sBAAsB,OAAO,EACrC,MAAM,QAAQ,EACd,OAAO,CAAC,MAAM,EAAE,SAAS,CAAC;AAC7B,QAAM,OAAO,MAAM,MAAM,SAAS,CAAC,KAAK;AACxC,SAAO,KAAK,YAAY;AAC1B;AAEA,SAAS,iBAAiB,MAAuB;AAC/C,SAAO,cAAc,IAAI,SAAS,IAAI,CAAC;AACzC;AAEA,SAAS,QACP,KACe;AACf,MAAI,IAAI,SAAS,8BAAe,YAAY;AAC1C,WAAO,IAAI;AAAA,EACb;AACA,MAAI,IAAI,SAAS,8BAAe,WAAW,OAAO,IAAI,UAAU,UAAU;AACxE,WAAO,IAAI;AAAA,EACb;AACA,SAAO;AACT;AAEA,SAAS,sBAAsB,GAA+B;AAC5D,SACE,EAAE,SAAS,8BAAe,iBAC1B,EAAE,QAAQ,SAAS,8BAAe,WAClC,OAAO,EAAE,QAAQ,UAAU;AAE/B;AAGA,SAAS,qBAAqB,MAA8C;AAC1E,MAAI,MAAM,SAAS,8BAAe,aAAa;AAC7C,WAAO;AAAA,EACT;AACA,SAAO,KAAK,MAAM,OAAO,qBAAqB,EAAE,UAAU;AAC5D;AAUA,SAAS,iBAAiB,MAAwB;AAChD,QAAM,QAAQ,KAAK,QAAQ,IAAI,KAAK,QAAQ,CAAC,IAAI;AACjD,SAAO,MAAM,KAAK,CAAC,OAAO,EAAE,QAAW,aAAU,YAAY,CAAC;AAChE;AAEA,SAAS,qBAAqB,IAAwC;AACpE,MAAI,OAAO,QAAW;AACpB,WAAO;AAAA,EACT;AACA,SAAO,GAAG,qBAAqB,GAAG,SAAS,SAAS,gBAAgB;AACtE;AAEA,SAAS,2BAA2B,KAAqC;AACvE,SACE,KAAK,cAAc,KAAK,CAAC,MAAM,qBAAqB,EAAE,cAAc,CAAC,CAAC,KACtE;AAEJ;AAOA,SAAS,wBACP,MAC2B;AAC3B,MAAI,OAAgB,KAAK;AACzB,SACE,CAAI,oBAAiB,IAAI,KACzB,EAAK,yBAAsB,IAAI,KAAK,KAAK,gBAAgB,SACzD;AACA,QAAI,KAAK,WAAW,QAAW;AAC7B,aAAO;AAAA,IACT;AACA,WAAO,KAAK;AAAA,EACd;AACA,SAAU,oBAAiB,IAAI,IAAI,KAAK,aAAa,KAAK;AAC5D;AAGA,SAAS,OAAO,MAAoC;AAClD,MAAI,KAAK,SAAS,8BAAe,YAAY;AAC3C,WAAO,KAAK;AAAA,EACd;AACA,MAAI,KAAK,SAAS,8BAAe,oBAAoB,CAAC,KAAK,UAAU;AACnE,UAAM,QAAQ,OAAO,KAAK,MAAM;AAChC,QAAI,UAAU,QAAQ,KAAK,SAAS,SAAS,8BAAe,YAAY;AACtE,aAAO;AAAA,IACT;AACA,WAAO,GAAG,KAAK,IAAI,KAAK,SAAS,IAAI;AAAA,EACvC;AACA,SAAO;AACT;AAEA,SAAS,WAAW,MAAoC;AACtD,MAAI,KAAK,SAAS,8BAAe,WAAW,OAAO,KAAK,UAAU,UAAU;AAC1E,WAAO,KAAK;AAAA,EACd;AACA,SAAO;AACT;AAoBA,IAAO,sCAAQ,2BAAY;AAAA,EACzB,CAAC,SACC,8EAA8E,IAAI;AACtF,EAAuB;AAAA,EACrB,MAAM;AAAA,EACN,MAAM;AAAA,IACJ,MAAM;AAAA,IACN,MAAM;AAAA,MACJ,aACE;AAAA,IACJ;AAAA,IACA,QAAQ;AAAA,MACN;AAAA,QACE,MAAM;AAAA,QACN,sBAAsB;AAAA,QACtB,YAAY;AAAA,UACV,cAAc;AAAA,YACZ,MAAM;AAAA,YACN,OAAO,EAAE,MAAM,SAAS;AAAA,UAC1B;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,IACA,UAAU;AAAA,MACR,iBACE;AAAA,MACF,mBACE;AAAA,IACJ;AAAA,EACF;AAAA,EACA,gBAAgB,CAAC,CAAC,CAAC;AAAA,EACnB,OAAO,SAAS,CAAC,UAAU,GAAG;AAC5B,UAAM,WAAW,QAAQ;AACzB,UAAM,aAAa,QAAQ,WAAW,QAAQ;AAC9C,QAAI,cAAc,UAAU,UAAU,GAAG;AACvC,aAAO,CAAC;AAAA,IACV;AAEA,UAAM,gBAAgB,IAAI;AAAA,OACvB,YAAY,gBAAgB,CAAC,GAAG,IAAI,CAAC,SAAS,KAAK,YAAY,CAAC;AAAA,IACnE;AAEA,QAAI;AACJ,QAAI;AACF,iBAAW,2BAAY,kBAAkB,OAAO;AAAA,IAClD,QAAQ;AACN,iBAAW;AAAA,IACb;AAEA,UAAM,aAAsB,CAAC;AAC7B,UAAM,gBAAiC,CAAC;AACxC,UAAM,kBAAuC,CAAC;AAC9C,UAAM,sBAAsB,oBAAI,IAAmB;AAEnD,aAAS,mBAAmB,MAA8B;AACxD,UAAI,aAAa,MAAM;AACrB,eAAO;AAAA,MACT;AACA,aAAO,iBAAiB,SAAS,kBAAkB,IAAI,CAAC;AAAA,IAC1D;AAUA,aAAS,iBAAiB,MAA2B,OAAwB;AAC3E,UAAI,SAAS,UAAa,aAAa,QAAQ,QAAQ,GAAG;AACxD,eAAO;AAAA,MACT;AACA,YAAM,UAAU,SAAS,QAAQ,eAAe;AAChD,UACK,6BAA0B,IAAI,KAC9B,uBAAoB,IAAI,KACxB,kBAAe,IAAI,GACtB;AACA,eAAO,iBAAiB,KAAK,YAAY,QAAQ,CAAC;AAAA,MACpD;AACA,UAAO,8BAA2B,IAAI,GAAG;AACvC,eAAO,2BAA2B,QAAQ,oBAAoB,KAAK,IAAI,CAAC;AAAA,MAC1E;AACA,UAAO,oBAAiB,IAAI,GAAG;AAC7B,eAAO,iBAAiB,KAAK,YAAY,QAAQ,CAAC;AAAA,MACpD;AACA,UAAO,gBAAa,IAAI,GAAG;AACzB,cAAM,OAAO,QAAQ,oBAAoB,IAAI,GAAG;AAChD,YAAI,SAAS,QAAW;AACtB,iBAAO;AAAA,QACT;AACA,YAAO,yBAAsB,IAAI,KAAK,KAAK,gBAAgB,QAAW;AACpE,iBAAO,iBAAiB,KAAK,aAAa,QAAQ,CAAC;AAAA,QACrD;AACA,YAAO,oBAAiB,IAAI,GAAG;AAC7B,iBAAO,iBAAiB,wBAAwB,IAAI,GAAG,QAAQ,CAAC;AAAA,QAClE;AAAA,MACF;AACA,aAAO;AAAA,IACT;AAEA,aAAS,mBAAmB,MAA8B;AACxD,aACE,mBAAmB,IAAI,KACvB,CAAC,iBAAiB,UAAU,sBAAsB,IAAI,IAAI,GAAG,CAAC;AAAA,IAElE;AASA,aAAS,uBAAuB,IAA8C;AAC5E,YAAM,aAAa,GAAG,YAAY;AAClC,UAAI,eAAe,UAAa,aAAa,MAAM;AACjD,eAAO;AAAA,MACT;AACA,YAAM,SAAS,SAAS,sBAAsB,IAAI,UAAU;AAC5D,UAAI,CAAI,cAAW,MAAM,GAAG;AAC1B,eAAO;AAAA,MACT;AACA,YAAM,UAAU,SAAS,QAAQ,eAAe;AAChD,YAAM,WAAW,QAAQ,oBAAoB,MAAM;AACnD,YAAM,OAAO,QAAQ,eAAe,QAAQ,KAAK;AACjD,YAAM,WAAW,oBAAI,IAAY;AACjC,iBAAW,QAAQ,KAAK,QAAQ,IAAI,KAAK,QAAQ,CAAC,IAAI,GAAG;AACvD,YAAI,KAAK,gBAAgB,GAAG;AAC1B,mBAAS,IAAI,KAAK,KAAK;AAAA,QACzB;AAAA,MACF;AACA,aAAO,SAAS,QAAQ,mBAAmB,WAAW;AAAA,IACxD;AAEA,aAAS,UAAU,MAA0B;AAC3C,iBAAW,KAAK,EAAE,UAAU,oBAAI,IAAI,GAAG,IAAI,KAAK,CAAC;AAAA,IACnD;AAEA,aAAS,WAAiB;AACxB,YAAM,QAAQ,WAAW,IAAI;AAC7B,UAAI,UAAU,QAAW;AACvB;AAAA,MACF;AACA,YAAM,aAAa,CAAC,GAAG,MAAM,SAAS,OAAO,CAAC,EAAE;AAAA,QAC9C,CAAC,UAAU,MAAM,aAAa,MAAM,SAAS,QAAQ;AAAA,MACvD;AACA,UAAI,WAAW,WAAW,GAAG;AAC3B;AAAA,MACF;AACA,YAAM,iBACJ,MAAM,OAAO,OAAO,OAAO,uBAAuB,MAAM,EAAE;AAC5D,iBAAW,SAAS,YAAY;AAI9B,YACE,mBAAmB,QACnB,CAAC,GAAG,MAAM,QAAQ,EAAE,MAAM,CAAC,QAAQ,eAAe,IAAI,GAAG,CAAC,GAC1D;AACA;AAAA,QACF;AACA,sBAAc,KAAK,MAAM,IAAI;AAAA,MAC/B;AAAA,IACF;AAEA,aAAS,WACP,KACA,UACA,MACM;AACN,YAAM,QAAQ,WAAW,WAAW,SAAS,CAAC;AAC9C,UAAI,UAAU,QAAW;AACvB;AAAA,MACF;AACA,YAAM,YAAY,SAAS,MAAM,CAAC,QAAQ,YAAY,GAAG,CAAC;AAC1D,YAAM,WAAW,MAAM,SAAS,IAAI,GAAG;AACvC,UAAI,aAAa,QAAW;AAC1B,cAAM,SAAS,IAAI,KAAK;AAAA,UACtB;AAAA,UACA,UAAU,IAAI,IAAI,QAAQ;AAAA,UAC1B;AAAA,QACF,CAAC;AACD;AAAA,MACF;AACA,iBAAW,OAAO,UAAU;AAC1B,iBAAS,SAAS,IAAI,GAAG;AAAA,MAC3B;AACA,eAAS,YAAY,SAAS,aAAa;AAAA,IAC7C;AAEA,aAAS,gBACP,KACA,UACA,WACA,MACM;AACN,UAAI,qBAAqB,QAAQ,GAAG;AAClC,4BAAoB,IAAI,SAAS;AACjC;AAAA,MACF;AACA,UAAI,UAAU,SAAS,8BAAe,iBAAiB;AACrD;AAAA,MACF;AACA,YAAM,OAAO,QAAQ,GAAG;AACxB,UACE,SAAS,QACT,CAAC,iBAAiB,IAAI,KACtB,cAAc,IAAI,KAAK,YAAY,CAAC,GACpC;AACA;AAAA,MACF;AACA,sBAAgB,KAAK,EAAE,MAAM,WAAW,KAAK,CAAC;AAAA,IAChD;AAEA,WAAO;AAAA,MACL,qBAAqB;AAAA,MACrB,4BAA4B;AAAA,MAC5B,oBAAoB;AAAA,MACpB,2BAA2B;AAAA,MAC3B,yBAAyB;AAAA,MACzB,gCAAgC;AAAA,MAEhC,iBAAiB,MAAuC;AACtD,YACE,KAAK,aAAa,SAClB,KAAK,aAAa,SAClB,KAAK,aAAa,QAClB,KAAK,aAAa,MAClB;AACA;AAAA,QACF;AACA,cAAM,UAAU,OAAO,KAAK,IAAI;AAChC,cAAM,WAAW,WAAW,KAAK,KAAK;AACtC,cAAM,WAAW,OAAO,KAAK,KAAK;AAClC,cAAM,UAAU,WAAW,KAAK,IAAI;AACpC,YAAI,YAAY,QAAQ,aAAa,MAAM;AACzC,cAAI,mBAAmB,KAAK,IAAI,GAAG;AACjC,uBAAW,SAAS,CAAC,QAAQ,GAAG,IAAI;AAAA,UACtC;AAAA,QACF,WAAW,aAAa,QAAQ,YAAY,MAAM;AAChD,cAAI,mBAAmB,KAAK,KAAK,GAAG;AAClC,uBAAW,UAAU,CAAC,OAAO,GAAG,IAAI;AAAA,UACtC;AAAA,QACF;AAAA,MACF;AAAA,MAEA,gBAAgB,MAAsC;AACpD,cAAM,MAAM,OAAO,KAAK,YAAY;AACpC,YAAI,QAAQ,QAAQ,CAAC,mBAAmB,KAAK,YAAY,GAAG;AAC1D;AAAA,QACF;AACA,cAAM,WAAqB,CAAC;AAC5B,mBAAW,KAAK,KAAK,OAAO;AAC1B,cAAI,EAAE,SAAS,MAAM;AACnB,kBAAM,MAAM,WAAW,EAAE,IAAI;AAC7B,gBAAI,QAAQ,MAAM;AAChB,uBAAS,KAAK,GAAG;AAAA,YACnB;AAAA,UACF;AAAA,QACF;AACA,YAAI,SAAS,SAAS,GAAG;AACvB,qBAAW,KAAK,UAAU,IAAI;AAAA,QAChC;AAAA,MACF;AAAA,MAEA,oBAAoB,MAA0C;AAC5D;AAAA,UACE,KAAK;AAAA,UACL,KAAK,gBAAgB;AAAA,UACrB,KAAK;AAAA,UACL;AAAA,QACF;AAAA,MACF;AAAA,MAEA,mBAAmB,MAAyC;AAC1D;AAAA,UACE,KAAK;AAAA,UACL,KAAK,gBAAgB;AAAA,UACrB,KAAK;AAAA,UACL;AAAA,QACF;AAAA,MACF;AAAA,MAEA,iBAAuB;AACrB,mBAAW,eAAe,eAAe;AACvC,kBAAQ,OAAO;AAAA,YACb,MAAM;AAAA,YACN,WAAW;AAAA,YACX,MAAM,EAAE,KAAK,WAAW,WAAW,EAAE;AAAA,UACvC,CAAC;AAAA,QACH;AACA,mBAAW,QAAQ,iBAAiB;AAClC,cAAI,oBAAoB,IAAI,KAAK,SAAS,GAAG;AAC3C,oBAAQ,OAAO;AAAA,cACb,MAAM,KAAK;AAAA,cACX,WAAW;AAAA,cACX,MAAM,EAAE,MAAM,KAAK,KAAK;AAAA,YAC1B,CAAC;AAAA,UACH;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAEA,aAAS,WAAW,MAA6B;AAC/C,UAAI,KAAK,SAAS,8BAAe,kBAAkB;AACjD,eAAO,OAAO,KAAK,IAAI,KAAK,OAAO,KAAK,KAAK,KAAK;AAAA,MACpD;AACA,UAAI,KAAK,SAAS,8BAAe,iBAAiB;AAChD,eAAO,OAAO,KAAK,YAAY,KAAK;AAAA,MACtC;AACA,aAAO;AAAA,IACT;AAAA,EACF;AACF,CAAC;;;ACliBD,IAAAC,iBAA2D;AAO3D,IAAM,oBAAoB,oBAAI,IAAI;AAAA,EAChC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAOD,IAAM,8BAA8B,oBAAI,IAAI,CAAC,IAAI,CAAC;AAIlD,IAAM,oBAA8D;AAAA,EAClE,CAAC,UAAU,OAAO;AAAA,EAClB,CAAC,YAAY,SAAS;AAAA,EACtB,CAAC,SAAS,MAAM;AAClB;AAIA,IAAM,oBAAoB;AAE1B,IAAM,eAAe;AACrB,IAAM,gBAAgB;AAQtB,IAAM,WAAW,CAAC,aAChB,SAAS,MAAM,OAAO,EAAE,IAAI,KAAK;AAEnC,IAAM,SAAS,CAAC,SAAyB,KAAK,QAAQ,eAAe,EAAE;AAEvE,IAAMC,aAAY,CAAC,SAAyB;AAC1C,MAAI,aAAa;AACjB,aAAW,CAAC,SAAS,WAAW,KAAK,mBAAmB;AACtD,iBAAa,WAAW,QAAQ,SAAS,WAAW;AAAA,EACtD;AACA,SAAO,WAAW,QAAQ,mBAAmB,GAAG,EAAE,YAAY;AAChE;AAEA,IAAM,uBAAuB,CAAC,SAC5B,SAAS,SACR,KAAK,SAAS,8BAAe,2BAC5B,KAAK,SAAS,8BAAe;AAIjC,IAAM,oBAAoB,CACxB,SACkB;AAClB,MAAI,KAAK,aAAa,WAAW,EAAG,QAAO;AAC3C,QAAM,CAAC,UAAU,IAAI,KAAK;AAC1B,MAAI,eAAe,OAAW,QAAO;AACrC,MAAI,WAAW,GAAG,SAAS,8BAAe,WAAY,QAAO;AAC7D,MAAI,CAAC,qBAAqB,WAAW,IAAI,EAAG,QAAO;AACnD,SAAO,WAAW,GAAG;AACvB;AAEA,IAAM,mBAAmB,CAAC,SAA8D;AACtF,MAAI,QAAQ;AACZ,MAAI,cAAc;AAClB,MAAI,YAA0D;AAE9D,QAAM,eAAe,CAAC,MAAc,SAA8B;AAChE,aAAS;AACT,gBAAY,EAAE,MAAM,KAAK;AAAA,EAC3B;AAEA,aAAW,aAAa,MAAM;AAC5B,YAAQ,UAAU,MAAM;AAAA,MACtB,KAAK,8BAAe;AAClB,sBAAc;AACd;AAAA,MACF,KAAK,8BAAe,0BAA0B;AAC5C,iBAAS;AACT,cAAM,OAAO,UAAU;AACvB,YACE,KAAK,SAAS,8BAAe,uBAC7B,KAAK,OAAO,MACZ;AACA,sBAAY,EAAE,MAAM,KAAK,GAAG,MAAM,MAAM,UAAU;AAAA,QACpD,WACE,KAAK,SAAS,8BAAe,oBAC7B,KAAK,OAAO,MACZ;AACA,sBAAY,EAAE,MAAM,KAAK,GAAG,MAAM,MAAM,UAAU;AAAA,QACpD;AACA;AAAA,MACF;AAAA,MACA,KAAK,8BAAe,wBAAwB;AAC1C,YAAI,UAAU,WAAW,MAAM;AAC7B,wBAAc;AACd;AAAA,QACF;AACA,cAAM,OAAO,UAAU;AACvB,YAAI,SAAS,MAAM;AACjB,mBAAS,UAAU,WAAW;AAC9B;AAAA,QACF;AACA,gBAAQ,KAAK,MAAM;AAAA,UACjB,KAAK,8BAAe;AAClB,gBAAI,KAAK,OAAO,KAAM,cAAa,KAAK,GAAG,MAAM,SAAS;AAAA,gBACrD,UAAS;AACd;AAAA,UACF,KAAK,8BAAe;AAClB,gBAAI,KAAK,OAAO,KAAM,cAAa,KAAK,GAAG,MAAM,SAAS;AAAA,gBACrD,UAAS;AACd;AAAA,UACF,KAAK,8BAAe,qBAAqB;AACvC,kBAAM,SAAS,kBAAkB,IAAI;AACrC,gBAAI,WAAW,QAAQ,KAAK,aAAa,WAAW,GAAG;AACrD,2BAAa,QAAQ,SAAS;AAAA,YAChC,OAAO;AACL,uBAAS,KAAK,aAAa;AAAA,YAC7B;AACA;AAAA,UACF;AAAA,UACA;AACE,qBAAS;AAAA,QACb;AACA;AAAA,MACF;AAAA,MACA;AACE;AAAA,IACJ;AAAA,EACF;AAEA,SAAO,EAAE,OAAO,aAAa,UAAU;AACzC;AAEA,IAAO,+BAAQ,2BAAY;AAAA,EACzB,CAAC,SACC,gFAAgF,IAAI;AACxF,EAAuB;AAAA,EACrB,MAAM;AAAA,EACN,MAAM;AAAA,IACJ,MAAM;AAAA,IACN,MAAM;AAAA,MACJ,aACE;AAAA,IACJ;AAAA,IACA,QAAQ,CAAC;AAAA,IACT,UAAU;AAAA,MACR,kBACE;AAAA,IACJ;AAAA,EACF;AAAA,EACA,gBAAgB,CAAC;AAAA,EACjB,OAAO,SAAS;AACd,UAAM,OAAO,SAAS,QAAQ,QAAQ;AAEtC,QAAI,KAAK,SAAS,OAAO,EAAG,QAAO,CAAC;AACpC,QAAI,aAAa,KAAK,IAAI,EAAG,QAAO,CAAC;AAErC,UAAM,OAAO,OAAO,IAAI;AACxB,QAAI,CAAC,kBAAkB,IAAI,KAAK,YAAY,CAAC,EAAG,QAAO,CAAC;AAExD,WAAO;AAAA,MACL,QAAQ,MAA8B;AACpC,cAAM,EAAE,OAAO,aAAa,UAAU,IAAI,iBAAiB,KAAK,IAAI;AACpE,YAAI,YAAa;AACjB,YAAI,UAAU,KAAK,cAAc,KAAM;AACvC,YAAI,4BAA4B,IAAI,UAAU,IAAI,EAAG;AAErD,cAAM,WAAWA,WAAU,UAAU,IAAI;AACzC,YAAI,SAAS,SAAU;AAEvB,gBAAQ,OAAO;AAAA,UACb,MAAM,UAAU;AAAA,UAChB,WAAW;AAAA,UACX,MAAM,EAAE,MAAM,MAAM,UAAU,MAAM,SAAS;AAAA,QAC/C,CAAC;AAAA,MACH;AAAA,IACF;AAAA,EACF;AACF,CAAC;;;ACzLD,IAAAC,iBAA2C;;;ACV3C,IAAAC,iBAA6D;AAYtD,SAAS,cAAc,MAAsB;AAClD,QAAM,MAAM,CAAC,GAAG,IAAI;AACpB,QAAM,IAAI,KAAK;AACf,MAAI,IAAI;AACR,SAAO,IAAI,GAAG;AACZ,UAAM,KAAK,KAAK,CAAC;AACjB,QAAI,OAAO,OAAO,OAAO,KAAK;AAC5B,UAAI,CAAC,IAAI;AACT,WAAK;AACL,aAAO,IAAI,GAAG;AACZ,cAAM,IAAI,KAAK,CAAC;AAChB,YAAI,MAAM,IAAI;AACZ,cAAI,IAAI,IAAI,KAAK,KAAK,IAAI,CAAC,MAAM,IAAI;AACnC,gBAAI,CAAC,IAAI;AACT,gBAAI,IAAI,CAAC,IAAI;AACb,iBAAK;AACL;AAAA,UACF;AACA,cAAI,CAAC,IAAI;AACT,eAAK;AACL;AAAA,QACF;AACA,YAAI,MAAM,MAAM;AACd,cAAI,CAAC,IAAI;AAAA,QACX;AACA,aAAK;AAAA,MACP;AACA;AAAA,IACF;AACA,QAAI,OAAO,OAAO,KAAK,IAAI,CAAC,MAAM,KAAK;AACrC,aAAO,IAAI,KAAK,KAAK,CAAC,MAAM,MAAM;AAChC,YAAI,CAAC,IAAI;AACT,aAAK;AAAA,MACP;AACA;AAAA,IACF;AACA,QAAI,OAAO,OAAO,KAAK,IAAI,CAAC,MAAM,KAAK;AACrC,UAAI,CAAC,IAAI;AACT,UAAI,IAAI,CAAC,IAAI;AACb,WAAK;AACL,aAAO,IAAI,KAAK,EAAE,KAAK,CAAC,MAAM,OAAO,KAAK,IAAI,CAAC,MAAM,MAAM;AACzD,YAAI,KAAK,CAAC,MAAM,MAAM;AACpB,cAAI,CAAC,IAAI;AAAA,QACX;AACA,aAAK;AAAA,MACP;AACA,UAAI,IAAI,GAAG;AACT,YAAI,CAAC,IAAI;AACT,YAAI,IAAI,CAAC,IAAI;AACb,aAAK;AAAA,MACP;AACA;AAAA,IACF;AACA,SAAK;AAAA,EACP;AACA,SAAO,IAAI,KAAK,EAAE;AACpB;AAGA,IAAM,sBAAsB;AAQrB,SAAS,UAAU,MAAoC;AAC5D,UAAQ,KAAK,MAAM;AAAA,IACjB,KAAK,8BAAe;AAClB,aAAO,OAAO,KAAK,UAAU,WAAW,KAAK,QAAQ;AAAA,IACvD,KAAK,8BAAe;AAClB,aAAO,KAAK,OAAO,IAAI,CAAC,MAAM,EAAE,MAAM,UAAU,EAAE,MAAM,GAAG,EAAE,KAAK,mBAAmB;AAAA,IACvF,KAAK,8BAAe;AAClB,aAAO,UAAU,KAAK,KAAK;AAAA,IAC7B,KAAK,8BAAe,kBAAkB;AACpC,UAAI,KAAK,aAAa,KAAK;AACzB,eAAO;AAAA,MACT;AACA,YAAM,OAAO,UAAU,KAAK,IAAI;AAChC,YAAM,QAAQ,UAAU,KAAK,KAAK;AAClC,aAAO,SAAS,QAAQ,UAAU,OAAO,OAAO,QAAQ;AAAA,IAC1D;AAAA,IACA,KAAK,8BAAe,iBAAiB;AACnC,YAAM,QAAkB,CAAC;AACzB,iBAAW,WAAW,KAAK,UAAU;AACnC,YAAI,YAAY,MAAM;AACpB,iBAAO;AAAA,QACT;AACA,cAAM,OAAO,UAAU,OAAO;AAC9B,YAAI,SAAS,MAAM;AACjB,iBAAO;AAAA,QACT;AACA,cAAM,KAAK,IAAI;AAAA,MACjB;AACA,aAAO,MAAM,SAAS,IAAI,MAAM,KAAK,GAAG,IAAI;AAAA,IAC9C;AAAA,IACA;AACE,aAAO;AAAA,EACX;AACF;AAQA,SAAS,sBAAsB,MAAyC;AACtE,QAAM,SAAS,KAAK;AACpB,SACE,QAAQ,SAAS,8BAAe,oBAChC,OAAO,WAAW,QAClB,CAAC,OAAO,YACR,OAAO,SAAS,SAAS,8BAAe,cACxC,OAAO,SAAS,SAAS,UACzB,OAAO,QAAQ,SAAS,8BAAe;AAE3C;AAGA,SAAS,aAAa,MAAqB,UAAwC;AACjF,WAAS,IAAI,IAAI;AACjB,aAAW,OAAO,OAAO,KAAK,IAAI,GAAG;AACnC,QAAI,QAAQ,UAAU;AACpB;AAAA,IACF;AACA,UAAM,QAAS,KAA4C,GAAG;AAC9D,eAAW,SAAS,MAAM,QAAQ,KAAK,IAAI,QAAQ,CAAC,KAAK,GAAG;AAC1D,UAAI,UAAU,QAAQ,OAAO,UAAU,YAAY,UAAU,OAAO;AAClE,qBAAa,OAAwB,QAAQ;AAAA,MAC/C;AAAA,IACF;AAAA,EACF;AACF;AAUO,SAAS,kBACd,SACuB;AACvB,QAAM,WAAW,oBAAI,QAAuB;AAE5C,QAAM,QAAQ,CAAC,SAA8B;AAC3C,QAAI,SAAS,IAAI,IAAI,GAAG;AACtB;AAAA,IACF;AACA,UAAM,OAAO,UAAU,IAAI;AAC3B,QAAI,SAAS,MAAM;AACjB;AAAA,IACF;AACA,iBAAa,MAAM,QAAQ;AAC3B,YAAQ,cAAc,IAAI,GAAG,IAAI;AAAA,EACnC;AAEA,SAAO;AAAA,IACL,kBAAkB,CAAC,SAA0C;AAC3D,YAAM,IAAI;AAAA,IACZ;AAAA,IACA,iBAAiB,CAAC,SAAyC;AACzD,UAAI,sBAAsB,IAAI,GAAG;AAC/B,cAAM,IAAI;AAAA,MACZ;AAAA,IACF;AAAA,IACA,iBAAiB,CAAC,SAAyC;AACzD,YAAM,IAAI;AAAA,IACZ;AAAA,IACA,SAAS,CAAC,SAAiC;AACzC,YAAM,IAAI;AAAA,IACZ;AAAA,EACF;AACF;;;AD1KA,IAAM,oBAAoB;AAG1B,IAAM,cAAc;AAEpB,IAAO,+BAAQ,2BAAY;AAAA,EACzB,CAAC,SACC,gFAAgF,IAAI;AACxF,EAAuB;AAAA,EACrB,MAAM;AAAA,EACN,MAAM;AAAA,IACJ,MAAM;AAAA,IACN,MAAM;AAAA,MACJ,aACE;AAAA,IACJ;AAAA,IACA,QAAQ,CAAC;AAAA,IACT,UAAU;AAAA,MACR,oBACE;AAAA,IACJ;AAAA,EACF;AAAA,EACA,gBAAgB,CAAC;AAAA,EACjB,OAAO,SAAS;AACd,QAAI,WAAW,QAAQ,QAAQ,KAAK,CAAC,YAAY,KAAK,QAAQ,WAAW,IAAI,GAAG;AAC9E,aAAO,CAAC;AAAA,IACV;AACA,WAAO,kBAAkB,CAAC,KAAa,SAA8B;AACnE,UAAI,CAAC,kBAAkB,KAAK,GAAG,GAAG;AAChC;AAAA,MACF;AACA,cAAQ,OAAO,EAAE,MAAM,WAAW,qBAAqB,CAAC;AAAA,IAC1D,CAAC;AAAA,EACH;AACF,CAAC;;;AExCD,IAAAC,iBAA2D;AAK3D,IAAM,eAAe;AAGrB,IAAM,kBAAuC,oBAAI,IAAI,CAAC,WAAW,eAAe,SAAS,CAAC;AAG1F,SAAS,gBAAgB,MAAsD;AAC7E,MAAI,KAAK,SAAS,8BAAe,aAAa;AAC5C,WAAO;AAAA,EACT;AACA,MACE,KAAK,SAAS,8BAAe,mBAC7B,KAAK,SAAS,SAAS,8BAAe,cACtC,gBAAgB,IAAI,KAAK,SAAS,IAAI,GACtC;AACA,UAAM,WAAW,KAAK,eAAe,OAAO,CAAC;AAC7C,WAAO,aAAa,SAAY,OAAO,gBAAgB,QAAQ;AAAA,EACjE;AACA,SAAO;AACT;AAGA,SAAS,eAAe,YAA0D,MAA6B;AAC7G,SAAO,WAAW,QAAQ,IAAI,EAAE,WAAW,QAAQ,GAAG,EAAE,KAAK;AAC/D;AAMA,SAAS,iBACP,OACA,YACS;AACT,QAAM,WAAW,MAAM;AACvB,MAAI,SAAS,SAAS,cAAc;AAClC,WAAO;AAAA,EACT;AACA,MAAI,SAAS,KAAK,CAAC,YAAY,QAAQ,SAAS,8BAAe,UAAU,GAAG;AAC1E,WAAO;AAAA,EACT;AACA,MAAI,SAAS,KAAK,CAAC,YAAY,QAAQ,SAAS,8BAAe,kBAAkB,GAAG;AAClF,WAAO;AAAA,EACT;AACA,MAAI,SAAS,CAAC,GAAG,SAAS,8BAAe,eAAe;AACtD,WAAO;AAAA,EACT;AACA,QAAM,QAAQ,IAAI,IAAI,SAAS,IAAI,CAAC,YAAY,eAAe,YAAY,OAAO,CAAC,CAAC;AACpF,SAAO,MAAM,SAAS;AACxB;AAGA,SAAS,aAAa,MAAoC;AACxD,MAAI,KAAK,SAAS,8BAAe,qBAAqB;AACpD,WAAO,KAAK,IAAI,QAAQ;AAAA,EAC1B;AACA,QAAM,SAAS,KAAK;AACpB,MAAI,QAAQ,SAAS,8BAAe,sBAAsB,OAAO,GAAG,SAAS,8BAAe,YAAY;AACtG,WAAO,OAAO,GAAG;AAAA,EACnB;AACA,OACG,QAAQ,SAAS,8BAAe,oBAC/B,QAAQ,SAAS,8BAAe,sBAChC,QAAQ,SAAS,8BAAe,aAClC,OAAO,IAAI,SAAS,8BAAe,YACnC;AACA,WAAO,OAAO,IAAI;AAAA,EACpB;AACA,SAAO;AACT;AAOA,SAAS,WAAW,MAA8B;AAChD,WAAS,UAA4C,MAAM,WAAW,MAAM,UAAU,QAAQ,QAAQ;AACpG,UAAM,SAAS,QAAQ;AACvB,QACE,QAAQ,SAAS,8BAAe,0BAChC,QAAQ,SAAS,8BAAe,0BAChC;AACA,aAAO;AAAA,IACT;AAAA,EACF;AACA,SAAO;AACT;AAEA,IAAO,qCAAQ,2BAAY;AAAA,EACzB,CAAC,SACC,gFAAgF,IAAI;AACxF,EAAuB;AAAA,EACrB,MAAM;AAAA,EACN,MAAM;AAAA,IACJ,MAAM;AAAA,IACN,MAAM;AAAA,MACJ,aACE;AAAA,IACJ;AAAA,IACA,QAAQ,CAAC;AAAA,IACT,UAAU;AAAA,MACR,yBACE;AAAA,IACJ;AAAA,EACF;AAAA,EACA,gBAAgB,CAAC;AAAA,EACjB,OAAO,SAAS;AACd,UAAM,QAAQ,CACZ,SAIS;AACT,YAAM,aAAa,KAAK,YAAY;AACpC,UAAI,eAAe,QAAW;AAC5B;AAAA,MACF;AACA,YAAM,QAAQ,gBAAgB,UAAU;AACxC,UAAI,UAAU,QAAQ,iBAAiB,OAAO,QAAQ,UAAU,GAAG;AACjE;AAAA,MACF;AACA,YAAM,OAAO,aAAa,IAAI;AAC9B,UAAI,SAAS,QAAQ,KAAK,WAAW,GAAG,KAAK,YAAY,KAAK,IAAI,GAAG;AACnE;AAAA,MACF;AACA,UAAI,CAAC,WAAW,IAAI,GAAG;AACrB;AAAA,MACF;AACA,cAAQ,OAAO;AAAA,QACb,MAAM;AAAA,QACN,WAAW;AAAA,QACX,MAAM,EAAE,MAAM,OAAO,OAAO,MAAM,aAAa,MAAM,EAAE;AAAA,MACzD,CAAC;AAAA,IACH;AACA,WAAO;AAAA,MACL,qBAAqB;AAAA,MACrB,oBAAoB;AAAA,MACpB,yBAAyB;AAAA,IAC3B;AAAA,EACF;AACF,CAAC;;;AChJD,IAAAC,iBAA2D;AAO3D,IAAM,aAAa;AACnB,IAAM,kBAAkB;AACxB,IAAM,sBAAsB;AAC5B,IAAM,iBAAiB;AAGvB,IAAM,iBACJ;AACF,IAAM,gBAAgB;AAEtB,IAAM,iBAA8C,oBAAI,IAAI;AAAA,EAC1D,8BAAe;AAAA,EACf,8BAAe;AAAA,EACf,8BAAe;AACjB,CAAC;AAGD,SAAS,aAAa,OAAwB;AAC5C,SAAO,MAAM,SAAS,IAAI,KAAK,eAAe,KAAK,KAAK,KAAK,cAAc,KAAK,KAAK;AACvF;AAEA,SAAS,QAAQ,OAAuB;AACtC,QAAM,UAAU,MAAM,WAAW,MAAM,GAAG,EAAE,KAAK;AACjD,SAAO,QAAQ,UAAU,iBAAiB,UAAU,GAAG,QAAQ,MAAM,GAAG,cAAc,CAAC;AACzF;AAGA,SAAS,kBAAkB,MAA2C;AACpE,WAAS,UAAU,KAAK,QAAQ,WAAW,MAAM,UAAU,QAAQ,QAAQ;AACzE,QAAI,eAAe,IAAI,QAAQ,IAAI,GAAG;AACpC,aAAO;AAAA,IACT;AAAA,EACF;AACA,SAAO;AACT;AAOA,SAAS,cAAc,MAA8B;AACnD,QAAM,SAAS,KAAK;AACpB,MAAI,WAAW,QAAW;AACxB,WAAO;AAAA,EACT;AACA,SACE,OAAO,SAAS,8BAAe,qBAC/B,OAAO,SAAS,8BAAe,0BAC/B,OAAO,SAAS,8BAAe,wBAC/B,OAAO,SAAS,8BAAe,gBAC/B,OAAO,SAAS,8BAAe,gBAC/B,OAAO,SAAS,8BAAe;AAEnC;AAEA,IAAO,qCAAQ,2BAAY;AAAA,EACzB,CAAC,SACC,gFAAgF,IAAI;AACxF,EAAuB;AAAA,EACrB,MAAM;AAAA,EACN,MAAM;AAAA,IACJ,MAAM;AAAA,IACN,MAAM;AAAA,MACJ,aACE;AAAA,IACJ;AAAA,IACA,QAAQ,CAAC;AAAA,IACT,UAAU;AAAA,MACR,yBACE;AAAA,IACJ;AAAA,EACF;AAAA,EACA,gBAAgB,CAAC;AAAA,EACjB,OAAO,SAAS;AACd,QAAI,WAAW,QAAQ,QAAQ,GAAG;AAChC,aAAO,CAAC;AAAA,IACV;AACA,UAAM,cAAc,oBAAI,IAA6B;AACrD,UAAM,SAAS,oBAAI,QAA6C;AAEhE,UAAM,SAAS,CAAC,OAAe,SAA8B;AAC3D,UAAI,MAAM,SAAS,cAAc,CAAC,aAAa,KAAK,KAAK,cAAc,IAAI,GAAG;AAC5E;AAAA,MACF;AACA,YAAM,WAAW,YAAY,IAAI,KAAK;AACtC,UAAI,aAAa,QAAW;AAC1B,oBAAY,IAAI,OAAO,CAAC,IAAI,CAAC;AAAA,MAC/B,OAAO;AACL,iBAAS,KAAK,IAAI;AAAA,MACpB;AACA,aAAO,IAAI,MAAM,kBAAkB,IAAI,CAAC;AAAA,IAC1C;AAEA,WAAO;AAAA,MACL,QAAQ,MAA8B;AACpC,YAAI,OAAO,KAAK,UAAU,UAAU;AAClC,iBAAO,KAAK,OAAO,IAAI;AAAA,QACzB;AAAA,MACF;AAAA,MACA,gBAAgB,MAAsC;AACpD,cAAM,CAAC,IAAI,IAAI,KAAK;AACpB,YAAI,KAAK,YAAY,WAAW,KAAK,SAAS,QAAW;AACvD,iBAAO,KAAK,MAAM,UAAU,KAAK,MAAM,KAAK,IAAI;AAAA,QAClD;AAAA,MACF;AAAA,MACA,gBAAgB,MAAY;AAC1B,mBAAW,CAAC,OAAO,KAAK,KAAK,aAAa;AACxC,cAAI,MAAM,SAAS,iBAAiB;AAClC;AAAA,UACF;AACA,gBAAM,iBAAiB,IAAI;AAAA,YACzB,MAAM,IAAI,CAAC,SAAS,OAAO,IAAI,IAAI,CAAC,EAAE,OAAO,CAAC,UAAU,SAAS,IAAI;AAAA,UACvE;AACA,cAAI,eAAe,OAAO,qBAAqB;AAC7C;AAAA,UACF;AACA,gBAAM,CAAC,OAAO,GAAG,OAAO,IAAI;AAC5B,cAAI,UAAU,QAAW;AACvB;AAAA,UACF;AACA,qBAAW,QAAQ,SAAS;AAC1B,oBAAQ,OAAO;AAAA,cACb;AAAA,cACA,WAAW;AAAA,cACX,MAAM,EAAE,SAAS,QAAQ,KAAK,GAAG,MAAM,OAAO,MAAM,IAAI,MAAM,IAAI,EAAE;AAAA,YACtE,CAAC;AAAA,UACH;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF,CAAC;;;ACtJD,IAAAC,iBAA2C;AAS3C,IAAM,cAAc;AACpB,IAAM,iBAAiB;AACvB,IAAM,eAAe;AACrB,IAAM,gBAAgB;AAEtB,IAAM,mBAAmB;AAGzB,IAAM,cAAc;AASpB,SAAS,iBAAiB,KAAa,KAAsB;AAC3D,MAAI,iBAAiB,KAAK,IAAI,MAAM,GAAG,GAAG,CAAC,GAAG;AAC5C,WAAO;AAAA,EACT;AACA,MAAI,SAAS,MAAM;AACnB,SAAO,UAAU,KAAK,KAAK,KAAK,IAAI,MAAM,KAAK,EAAE,GAAG;AAClD,cAAU;AAAA,EACZ;AACA,MAAI,QAAQ,MAAM;AAClB,SAAO,QAAQ,IAAI,UAAU,KAAK,KAAK,IAAI,KAAK,KAAK,EAAE,GAAG;AACxD,aAAS;AAAA,EACX;AACA,QAAM,aAAa,UAAU,IAAK,IAAI,MAAM,KAAK,KAAM;AACvD,QAAM,YAAY,QAAQ,IAAI,SAAU,IAAI,KAAK,KAAK,KAAM;AAC5D,QAAM,aACJ,cAAc,MAAM,cAAc,OAAO,cAAc,OAAO,aAAa,KAAK,IAAI,MAAM,KAAK,CAAC;AAClG,MAAI,CAAC,YAAY;AACf,WAAO;AAAA,EACT;AACA,SAAO,EAAE,eAAe,OAAO,cAAc;AAC/C;AAGA,SAAS,kBAAkB,KAAsB;AAC/C,QAAM,UAAU,CAAC,GAAG,IAAI,SAAS,cAAc,CAAC,EAAE,IAAI,CAAC,MAAM,EAAE,KAAK;AACpE,WAAS,MAAM,GAAG,MAAM,IAAI,QAAQ,OAAO;AACzC,QAAI,IAAI,GAAG,MAAM,OAAO,CAAC,iBAAiB,KAAK,GAAG,GAAG;AACnD;AAAA,IACF;AACA,UAAM,SAAS,QAAQ,OAAO,CAAC,UAAU,QAAQ,GAAG,EAAE,GAAG,EAAE;AAC3D,QAAI,WAAW,UAAa,CAAC,cAAc,KAAK,IAAI,MAAM,GAAG,MAAM,CAAC,GAAG;AACrE,aAAO;AAAA,IACT;AAAA,EACF;AACA,SAAO;AACT;AAEA,IAAO,yBAAQ,2BAAY;AAAA,EACzB,CAAC,SACC,gFAAgF,IAAI;AACxF,EAAuB;AAAA,EACrB,MAAM;AAAA,EACN,MAAM;AAAA,IACJ,MAAM;AAAA,IACN,MAAM;AAAA,MACJ,aACE;AAAA,IACJ;AAAA,IACA,QAAQ,CAAC;AAAA,IACT,UAAU;AAAA,MACR,cACE;AAAA,IACJ;AAAA,EACF;AAAA,EACA,gBAAgB,CAAC;AAAA,EACjB,OAAO,SAAS;AACd,QAAI,WAAW,QAAQ,QAAQ,KAAK,CAAC,YAAY,KAAK,QAAQ,WAAW,IAAI,GAAG;AAC9E,aAAO,CAAC;AAAA,IACV;AACA,WAAO,kBAAkB,CAAC,KAAa,SAA8B;AACnE,UAAI,CAAC,YAAY,KAAK,GAAG,KAAK,CAAC,kBAAkB,GAAG,GAAG;AACrD;AAAA,MACF;AACA,cAAQ,OAAO,EAAE,MAAM,WAAW,eAAe,CAAC;AAAA,IACpD,CAAC;AAAA,EACH;AACF,CAAC;;;AClFD,IAAAC,iBAA2D;AAQ3D,IAAM,gBAAqC,oBAAI,IAAI,CAAC,SAAS,SAAS,QAAQ,OAAO,CAAC;AAGtF,IAAM,eAAoC,oBAAI,IAAI;AAAA,EAChD;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAED,IAAMC,kBAA8C,oBAAI,IAAI;AAAA,EAC1D,8BAAe;AAAA,EACf,8BAAe;AAAA,EACf,8BAAe;AACjB,CAAC;AAGD,SAAS,wBAAwB,MAA0C;AACzE,SAAO,MAAM,SAAS,8BAAe,WAAW,OAAO,KAAK,UAAU,YAAY,KAAK,UAAU;AACnG;AAGA,SAAS,kBAAkB,MAA8B;AACvD,SACE,KAAK,SAAS,8BAAe,kBAC7B,KAAK,OAAO,SAAS,8BAAe,cACpC,KAAK,OAAO,SAAS,gBACrB,KAAK,UAAU,UAAU,KACzB,wBAAwB,KAAK,UAAU,CAAC,CAAC;AAE7C;AAMA,SAAS,eAAe,MAAuC;AAC7D,MAAI,KAAK,OAAO,SAAS,8BAAe,cAAc,KAAK,OAAO,SAAS,WAAW;AACpF,WAAO;AAAA,EACT;AACA,QAAM,WAAW,KAAK,UAAU,CAAC;AACjC,MACE,UAAU,SAAS,8BAAe,2BAClC,UAAU,SAAS,8BAAe,oBAClC;AACA,WAAO;AAAA,EACT;AACA,QAAM,OAAO,SAAS;AACtB,MAAI,KAAK,SAAS,8BAAe,gBAAgB;AAC/C,WAAO,kBAAkB,IAAI;AAAA,EAC/B;AACA,SAAO,KAAK,KAAK;AAAA,IACf,CAAC,SAAS,KAAK,SAAS,8BAAe,uBAAuB,kBAAkB,KAAK,UAAU;AAAA,EACjG;AACF;AAGA,SAAS,cAAc,MAAwC;AAC7D,SACE,KAAK,OAAO,SAAS,8BAAe,cACpC,cAAc,IAAI,KAAK,OAAO,IAAI,KAClC,KAAK,UAAU,UAAU,KACzB,wBAAwB,KAAK,UAAU,CAAC,CAAC;AAE7C;AAGA,SAAS,yBAAyB,MAA2C;AAC3E,WAAS,UAAU,KAAK,QAAQ,WAAW,MAAM,UAAU,QAAQ,QAAQ;AACzE,QAAI,CAACA,gBAAe,IAAI,QAAQ,IAAI,GAAG;AACrC;AAAA,IACF;AACA,UAAM,cAAc,QAAQ;AAC5B,UAAM,oBACJ,aAAa,SAAS,8BAAe,iBAAiB,eAAe,WAAW;AAClF,QAAI,CAAC,mBAAmB;AACtB,aAAO;AAAA,IACT;AAAA,EACF;AACA,SAAO;AACT;AAGA,SAAS,eAAe,QAAsC;AAC5D,MAAI,OAAO,SAAS,8BAAe,YAAY;AAC7C,WAAO,OAAO;AAAA,EAChB;AACA,MAAI,OAAO,SAAS,8BAAe,kBAAkB;AACnD,WAAO,eAAe,OAAO,MAAM;AAAA,EACrC;AACA,MAAI,OAAO,SAAS,8BAAe,gBAAgB;AACjD,WAAO,eAAe,OAAO,MAAM;AAAA,EACrC;AACA,MAAI,OAAO,SAAS,8BAAe,0BAA0B;AAC3D,WAAO,eAAe,OAAO,GAAG;AAAA,EAClC;AACA,SAAO;AACT;AAGA,SAAS,WAAW,IAA4B;AAC9C,QAAM,OAAO,GAAG;AAChB,MACE,MAAM,SAAS,8BAAe,kBAC9B,CAAC,KAAK,UAAU,KAAK,CAAC,aAAa,aAAa,EAAE,GAClD;AACA,WAAO;AAAA,EACT;AACA,QAAM,OAAO,eAAe,KAAK,MAAM;AACvC,SAAO,SAAS,QAAQ,aAAa,IAAI,IAAI;AAC/C;AAEA,IAAO,gCAAQ,2BAAY;AAAA,EACzB,CAAC,SACC,gFAAgF,IAAI;AACxF,EAAuB;AAAA,EACrB,MAAM;AAAA,EACN,MAAM;AAAA,IACJ,MAAM;AAAA,IACN,MAAM;AAAA,MACJ,aACE;AAAA,IACJ;AAAA,IACA,QAAQ,CAAC;AAAA,IACT,UAAU;AAAA,MACR,mBACE;AAAA,IACJ;AAAA,EACF;AAAA,EACA,gBAAgB,CAAC;AAAA,EACjB,OAAO,SAAS;AACd,QAAI,CAAC,WAAW,QAAQ,QAAQ,GAAG;AACjC,aAAO,CAAC;AAAA,IACV;AACA,UAAM,SAAS,CAAC,SAA8B;AAC5C,YAAM,YAAY,yBAAyB,IAAI;AAC/C,UAAI,cAAc,QAAQ,CAAC,WAAW,SAAS,GAAG;AAChD;AAAA,MACF;AACA,cAAQ,OAAO,EAAE,MAAM,WAAW,oBAAoB,CAAC;AAAA,IACzD;AACA,WAAO;AAAA,MACL,cAAc,MAAoC;AAChD,YAAI,eAAe,IAAI,GAAG;AACxB,iBAAO,IAAI;AAAA,QACb;AAAA,MACF;AAAA,MACA,eAAe,MAAqC;AAClD,YAAI,cAAc,IAAI,GAAG;AACvB,iBAAO,IAAI;AAAA,QACb;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF,CAAC;;;ACjKD,IAAAC,iBAA2D;AAQ3D,IAAM,qBAA0C,oBAAI,IAAI,CAAC,OAAO,OAAO,MAAM,IAAI,CAAC;AAQlF,IAAM,uBAA4C,oBAAI,IAAI,CAAC,aAAa,KAAK,CAAC;AAQ9E,IAAM,iBAAiB;AAcvB,SAAS,oBAAoB,YAA6B;AACxD,MAAI,iBAAiB,UAAU,KAAK,CAAC,eAAe,KAAK,UAAU,EAAG,QAAO;AAC7E,SAAO,eAAe,WAAW,YAAY,KAAK,WAAW,KAAK,UAAU;AAC9E;AAOA,SAAS,kBAAkB,MAA8B;AACvD,UAAQ,KAAK,MAAM;AAAA,IACjB,KAAK,8BAAe;AAClB,aAAO;AAAA,IACT,KAAK,8BAAe;AAClB,aAAO,KAAK,YAAY,WAAW;AAAA,IACrC,KAAK,8BAAe;AAClB,aAAO,qBAAqB,IAAI,KAAK,IAAI,KAAK,oBAAoB,KAAK,IAAI;AAAA,IAC7E,KAAK,8BAAe;AAClB,aACE,CAAC,KAAK,YACN,KAAK,SAAS,SAAS,8BAAe,cACtC,oBAAoB,KAAK,SAAS,IAAI;AAAA,IAE1C;AACE,aAAO;AAAA,EACX;AACF;AAGA,SAAS,YAAY,MAAoC;AACvD,MAAI,KAAK,SAAS,8BAAe,YAAY;AAC3C,WAAO,KAAK;AAAA,EACd;AACA,MACE,KAAK,SAAS,8BAAe,oBAC7B,CAAC,KAAK,YACN,KAAK,SAAS,SAAS,8BAAe,YACtC;AACA,WAAO,KAAK,SAAS;AAAA,EACvB;AACA,SAAO;AACT;AAUA,SAAS,gBAAgB,MAA8B;AACrD,MAAI,KAAK,SAAS,8BAAe,iBAAiB;AAChD,WAAO,KAAK,YAAY,KAAK,CAAC,eAAe,gBAAgB,UAAU,CAAC;AAAA,EAC1E;AACA,QAAM,OAAO,YAAY,IAAI;AAC7B,SAAO,SAAS,QAAQ,iBAAiB,IAAI;AAC/C;AAGA,SAAS,aAAa,MAAoC;AACxD,MAAI,KAAK,SAAS,8BAAe,iBAAiB;AAChD,eAAW,cAAc,KAAK,aAAa;AACzC,YAAM,SAAS,aAAa,UAAU;AACtC,UAAI,WAAW,MAAM;AACnB,eAAO;AAAA,MACT;AAAA,IACF;AACA,WAAO;AAAA,EACT;AACA,SAAO,YAAY,IAAI;AACzB;AAEA,IAAO,8CAAQ,2BAAY;AAAA,EACzB,CAAC,SACC,gFAAgF,IAAI;AACxF,EAAuB;AAAA,EACrB,MAAM;AAAA,EACN,MAAM;AAAA,IACJ,MAAM;AAAA,IACN,MAAM;AAAA,MACJ,aACE;AAAA,IACJ;AAAA,IACA,QAAQ,CAAC;AAAA,IACT,UAAU;AAAA,MACR,iCACE;AAAA,IACJ;AAAA,EACF;AAAA,EACA,gBAAgB,CAAC;AAAA,EACjB,OAAO,SAAS;AACd,QAAI,WAAW,QAAQ,QAAQ,GAAG;AAChC,aAAO,CAAC;AAAA,IACV;AACA,WAAO;AAAA,MACL,iBAAiB,MAAuC;AACtD,YAAI,CAAC,mBAAmB,IAAI,KAAK,QAAQ,GAAG;AAC1C;AAAA,QACF;AACA,cAAM,EAAE,MAAM,MAAM,IAAI;AACxB,YAAI,kBAAkB,IAAI,KAAK,kBAAkB,KAAK,GAAG;AACvD;AAAA,QACF;AACA,cAAM,SAAS,CAAC,MAAM,KAAK,EAAE,KAAK,CAAC,YAAY,gBAAgB,OAAO,CAAC;AACvE,YAAI,WAAW,QAAW;AACxB;AAAA,QACF;AACA,gBAAQ,OAAO;AAAA,UACb;AAAA,UACA,WAAW;AAAA,UACX,MAAM,EAAE,UAAU,KAAK,UAAU,MAAM,aAAa,MAAM,KAAK,GAAG;AAAA,QACpE,CAAC;AAAA,MACH;AAAA,IACF;AAAA,EACF;AACF,CAAC;;;AC3JD,IAAAC,iBAA2C;AAiB3C,IAAM,eACJ;AAGF,IAAM,mBAAmB;AAQzB,IAAM,cAAc;AAEpB,IAAO,4CAAQ,2BAAY;AAAA,EACzB,CAAC,SACC,gFAAgF,IAAI;AACxF,EAAuB;AAAA,EACrB,MAAM;AAAA,EACN,MAAM;AAAA,IACJ,MAAM;AAAA,IACN,MAAM;AAAA,MACJ,aACE;AAAA,IACJ;AAAA,IACA,QAAQ,CAAC;AAAA,IACT,UAAU;AAAA,MACR,+BACE;AAAA,IACJ;AAAA,EACF;AAAA,EACA,gBAAgB,CAAC;AAAA,EACjB,OAAO,SAAS;AACd,QAAI,WAAW,QAAQ,QAAQ,KAAK,CAAC,YAAY,KAAK,QAAQ,WAAW,IAAI,GAAG;AAC9E,aAAO,CAAC;AAAA,IACV;AACA,WAAO,kBAAkB,CAAC,KAAa,SAA8B;AACnE,UAAI,CAAC,aAAa,KAAK,GAAG,KAAK,iBAAiB,KAAK,GAAG,GAAG;AACzD;AAAA,MACF;AACA,cAAQ,OAAO,EAAE,MAAM,WAAW,gCAAgC,CAAC;AAAA,IACrE,CAAC;AAAA,EACH;AACF,CAAC;;;AC5DD,IAAAC,iBAA2D;AAW3D,IAAM,kBAAqC,CAAC,WAAW,QAAQ,OAAO;AAGtE,IAAM,mBAAmB;AAOzB,SAAS,iBAAiB,YAA0C;AAClE,MAAI,WAAW,SAAS,8BAAe,YAAY;AACjD,WAAO,iBAAiB,KAAK,WAAW,IAAI;AAAA,EAC9C;AACA,MACE,WAAW,SAAS,8BAAe,oBACnC,CAAC,WAAW,YACZ,WAAW,SAAS,SAAS,8BAAe,YAC5C;AACA,WAAO,iBAAiB,KAAK,WAAW,SAAS,IAAI;AAAA,EACvD;AACA,MAAI,WAAW,SAAS,8BAAe,SAAS;AAC9C,WAAO,OAAO,WAAW,UAAU;AAAA,EACrC;AACA,SAAO;AACT;AAGA,SAAS,sBACP,UACuB;AACvB,SAAO,SAAS,YAAY;AAAA,IAC1B,CAAC,eAAe,CAAC,iBAAiB,UAAU;AAAA,EAC9C;AACF;AAMA,SAAS,eAAe,MAAkD;AACxE,MAAI,KAAK,SAAS,8BAAe,oBAAoB,KAAK,aAAa,KAAK;AAC1E,WAAO,CAAC,GAAG,eAAe,KAAK,IAAI,GAAG,GAAG,eAAe,KAAK,KAAK,CAAC;AAAA,EACrE;AACA,SAAO,CAAC,IAAI;AACd;AAQA,SAAS,sBAAsB,MAA4C;AACzE,MAAI,KAAK,SAAS,8BAAe,oBAAoB,KAAK,aAAa,KAAK;AAC1E,WAAO,CAAC;AAAA,EACV;AACA,QAAM,WAAW,eAAe,IAAI;AACpC,QAAM,mBAAmB,SAAS;AAAA,IAChC,CAAC,YACC,QAAQ,SAAS,8BAAe,WAChC,OAAO,QAAQ,UAAU;AAAA,EAC7B;AACA,MAAI,CAAC,kBAAkB;AACrB,WAAO,CAAC;AAAA,EACV;AACA,SAAO,SAAS;AAAA,IACd,CAAC,YACC,QAAQ,SAAS,8BAAe,WAAW,CAAC,iBAAiB,OAAO;AAAA,EACxE;AACF;AAGA,SAAS,oBACP,MACA,SACe;AACf,QAAM,SAAS,KAAK;AACpB,MACE,OAAO,SAAS,8BAAe,oBAC/B,OAAO,YACP,OAAO,SAAS,SAAS,8BAAe,YACxC;AACA,WAAO;AAAA,EACT;AACA,QAAM,OAAO,OAAO,SAAS;AAC7B,SAAO,QAAQ,IAAI,IAAI,IAAI,OAAO;AACpC;AAEA,IAAO,yBAAQ,2BAAY;AAAA,EACzB,CAAC,SACC,gFAAgF,IAAI;AACxF,EAAuB;AAAA,EACrB,MAAM;AAAA,EACN,MAAM;AAAA,IACJ,MAAM;AAAA,IACN,MAAM;AAAA,MACJ,aACE;AAAA,IACJ;AAAA,IACA,QAAQ;AAAA,MACN;AAAA,QACE,MAAM;AAAA,QACN,YAAY;AAAA,UACV,SAAS;AAAA,YACP,MAAM;AAAA,YACN,OAAO,EAAE,MAAM,SAAS;AAAA,YACxB,aACE;AAAA,UACJ;AAAA,QACF;AAAA,QACA,sBAAsB;AAAA,MACxB;AAAA,IACF;AAAA,IACA,UAAU;AAAA,MACR,YACE;AAAA,IACJ;AAAA,EACF;AAAA,EACA,gBAAgB,CAAC,CAAC,CAAC;AAAA,EACnB,OAAO,SAAS,CAAC,OAAO,GAAG;AACzB,UAAM,UAAU,IAAI,IAAI,SAAS,WAAW,eAAe;AAE3D,WAAO;AAAA,MACL,eAAe,MAAqC;AAClD,cAAM,SAAS,oBAAoB,MAAM,OAAO;AAChD,YAAI,WAAW,MAAM;AACnB;AAAA,QACF;AAEA,cAAM,YAAY,KAAK,UAAU,CAAC;AAClC,YAAI,cAAc,QAAW;AAC3B;AAAA,QACF;AAEA,cAAM,YACJ,UAAU,SAAS,8BAAe,kBAC9B,sBAAsB,SAAS,IAC/B,sBAAsB,SAAS;AAErC,mBAAW,YAAY,WAAW;AAChC,kBAAQ,OAAO;AAAA,YACb,MAAM;AAAA,YACN,WAAW;AAAA,YACX,MAAM,EAAE,OAAO;AAAA,UACjB,CAAC;AAAA,QACH;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF,CAAC;;;ACjKD,IAAAC,iBAA2C;AAe3C,IAAM,gBAAmC;AAAA,EACvC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAGA,IAAM,mBAAwC,oBAAI,IAAI;AAAA,EACpD;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAGD,SAAS,kBAAkB,MAAwC;AACjE,QAAM,SAAS,KAAK;AAEpB,MAAI,OAAO,SAAS,cAAc;AAChC,WAAO,OAAO,SAAS;AAAA,EACzB;AAEA,MACE,OAAO,SAAS,sBAChB,CAAC,OAAO,YACR,OAAO,SAAS,SAAS,gBACzB,OAAO,SAAS,SAAS,WACzB,OAAO,OAAO,SAAS,cACvB;AACA,WAAO,iBAAiB,IAAI,OAAO,OAAO,IAAI;AAAA,EAChD;AAEA,SAAO;AACT;AAOA,SAAS,QAAQ,UAAuC;AACtD,QAAM,WAAqB,CAAC;AAC5B,aAAW,WAAW,UAAU;AAC9B,QAAI;AACF,eAAS,KAAK,IAAI,OAAO,OAAO,CAAC;AAAA,IACnC,QAAQ;AAAA,IAER;AAAA,EACF;AACA,SAAO;AACT;AAEA,IAAO,uCAAQ,2BAAY;AAAA,EACzB,CAAC,SACC,gFAAgF,IAAI;AACxF,EAAuB;AAAA,EACrB,MAAM;AAAA,EACN,MAAM;AAAA,IACJ,MAAM;AAAA,IACN,MAAM;AAAA,MACJ,aACE;AAAA,IACJ;AAAA,IACA,QAAQ;AAAA,MACN;AAAA,QACE,MAAM;AAAA,QACN,YAAY;AAAA,UACV,OAAO;AAAA,YACL,MAAM;AAAA,YACN,OAAO,EAAE,MAAM,SAAS;AAAA,YACxB,aACE;AAAA,UACJ;AAAA,QACF;AAAA,QACA,sBAAsB;AAAA,MACxB;AAAA,IACF;AAAA,IACA,UAAU;AAAA,MACR,UACE;AAAA,IACJ;AAAA,EACF;AAAA,EACA,gBAAgB,CAAC,CAAC,CAAC;AAAA,EACnB,OAAO,SAAS,CAAC,OAAO,GAAG;AACzB,UAAM,WAAW,SAAS,SAAS;AACnC,UAAM,UAAU,QAAQ,QAAQ;AAChC,UAAM,WAAW,QAAQ;AAEzB,QAAI,QAAQ,KAAK,CAAC,OAAO,GAAG,KAAK,QAAQ,CAAC,GAAG;AAC3C,aAAO,CAAC;AAAA,IACV;AAEA,WAAO;AAAA,MACL,eAAe,MAAqC;AAClD,YAAI,kBAAkB,IAAI,GAAG;AAC3B,kBAAQ,OAAO,EAAE,MAAM,WAAW,WAAW,CAAC;AAAA,QAChD;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF,CAAC;;;AChHD,IAAAC,iBAA2D;AAa3D,IAAMC,mBAAqC;AAAA,EACzC;AAAA,EACA;AAAA,EACA;AACF;AAOA,IAAM,gBAA6C,oBAAI,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;AAGvE,SAASC,SAAQ,UAAuC;AACtD,QAAM,WAAqB,CAAC;AAC5B,aAAW,WAAW,UAAU;AAC9B,QAAI;AACF,eAAS,KAAK,IAAI,OAAO,OAAO,CAAC;AAAA,IACnC,QAAQ;AAAA,IAER;AAAA,EACF;AACA,SAAO;AACT;AAGA,SAAS,kBACP,MACA,SACe;AACf,QAAM,SAAS,KAAK;AACpB,MACE,OAAO,SAAS,8BAAe,oBAC/B,OAAO,YACP,OAAO,SAAS,SAAS,8BAAe,YACxC;AACA,WAAO;AAAA,EACT;AACA,QAAM,OAAO,OAAO,SAAS;AAC7B,MAAI,CAAC,QAAQ,IAAI,IAAI,GAAG;AACtB,WAAO;AAAA,EACT;AACA,MAAI,KAAK,UAAU,UAAU,cAAc,IAAI,IAAI,KAAK,IAAI;AAC1D,WAAO;AAAA,EACT;AACA,SAAO;AACT;AAEA,IAAO,0CAAQ,2BAAY;AAAA,EACzB,CAAC,SACC,gFAAgF,IAAI;AACxF,EAAuB;AAAA,EACrB,MAAM;AAAA,EACN,MAAM;AAAA,IACJ,MAAM;AAAA,IACN,MAAM;AAAA,MACJ,aACE;AAAA,IACJ;AAAA,IACA,QAAQ;AAAA,MACN;AAAA,QACE,MAAM;AAAA,QACN,YAAY;AAAA,UACV,SAAS;AAAA,YACP,MAAM;AAAA,YACN,OAAO,EAAE,MAAM,SAAS;AAAA,YACxB,aACE;AAAA,UACJ;AAAA,UACA,SAAS;AAAA,YACP,MAAM;AAAA,YACN,OAAO,EAAE,MAAM,SAAS;AAAA,YACxB,aAAa;AAAA,UACf;AAAA,QACF;AAAA,QACA,sBAAsB;AAAA,MACxB;AAAA,IACF;AAAA,IACA,UAAU;AAAA,MACR,0BACE;AAAA,IACJ;AAAA,EACF;AAAA,EACA,gBAAgB,CAAC,CAAC,CAAC;AAAA,EACnB,OAAO,SAAS,CAAC,OAAO,GAAG;AACzB,UAAM,UAAU,SAAS,WAAW,CAAC;AACrC,QAAI,QAAQ,WAAW,GAAG;AACxB,aAAO,CAAC;AAAA,IACV;AAEA,UAAM,SAASA,SAAQ,OAAO;AAC9B,QAAI,CAAC,OAAO,KAAK,CAAC,OAAO,GAAG,KAAK,QAAQ,QAAQ,CAAC,GAAG;AACnD,aAAO,CAAC;AAAA,IACV;AAEA,UAAM,UAAU,IAAI,IAAI,SAAS,WAAWD,gBAAe;AAE3D,WAAO;AAAA,MACL,eAAe,MAAqC;AAClD,cAAM,SAAS,kBAAkB,MAAM,OAAO;AAC9C,YAAI,WAAW,MAAM;AACnB,kBAAQ,OAAO;AAAA,YACb;AAAA,YACA,WAAW;AAAA,YACX,MAAM,EAAE,OAAO;AAAA,UACjB,CAAC;AAAA,QACH;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF,CAAC;;;AC1HD,IAAAE,iBAMO;AACP,IAAAC,MAAoB;AAKpB,IAAMC,mBAAqC;AAAA,EACzC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAEA,SAASC,eAAc,UAAkB,YAA6B;AACpE,MAAID,iBAAgB,KAAK,CAAC,OAAO,GAAG,KAAK,QAAQ,CAAC,GAAG;AACnD,WAAO;AAAA,EACT;AACA,SAAO,eAAe,KAAK,WAAW,MAAM,GAAG,IAAI,CAAC;AACtD;AAGA,SAAS,YAAY,QAAyB;AAC5C,SAAO,uBAAuB,KAAK,MAAM;AAC3C;AAGA,SAASE,QAAO,MAAgD;AAC9D,MACE,KAAK,SAAS,8BAAe,kBAC7B,KAAK,SAAS,8BAAe,uBAC7B;AACA,WAAOA,QAAO,KAAK,UAAU;AAAA,EAC/B;AACA,SAAO;AACT;AAQA,SAAS,iBACP,MACA,YACiB;AACjB,QAAM,QAAkB,CAAC;AACzB,aAAW,QAAQ,KAAK,YAAY;AAClC,QAAI,KAAK,SAAS,8BAAe,UAAU;AACzC,aAAO;AAAA,IACT;AACA,QAAI,KAAK,YAAY,KAAK,aAAa,KAAK,UAAU,KAAK,SAAS,QAAQ;AAC1E,aAAO;AAAA,IACT;AACA,UAAM,QAAQ,KAAK;AACnB,QACE,MAAM,SAAS,8BAAe,WAC9B,OAAO,MAAM,UAAU,UACvB;AACA,aAAO;AAAA,IACT;AACA,UAAM,OAAO,WAAW,QAAQ,KAAK;AACrC,QAAI,CAAC,MAAM,SAAS,IAAI,GAAG;AACzB,YAAM,KAAK,IAAI;AAAA,IACjB;AAAA,EACF;AACA,SAAO,MAAM,SAAS,IAAI,QAAQ;AACpC;AAGA,SAAS,oBACP,MACA,OACS;AACT,MAAI,UAAuC;AAC3C,SAAO,YAAY,MAAM;AACvB,UAAM,WAAW,QAAQ,UAAU,KAAK,CAAC,MAAM,EAAE,SAAS,KAAK,IAAI;AACnE,QAAI,aAAa,QAAW;AAC1B,aAAO,SAAS,KAAK;AAAA,QACnB,CAAC,QAAQ,IAAI,KAAK,SAAS,8BAAe;AAAA,MAC5C;AAAA,IACF;AACA,cAAU,QAAQ;AAAA,EACpB;AACA,SAAO;AACT;AAEA,IAAM,oBACD,gBAAY,cAAiB,gBAAY,YAAe,gBAAY;AAOzE,SAAS,uBACP,MACA,UACS;AACT,QAAM,UAAU,SAAS,QAAQ,eAAe;AAChD,QAAM,SAAS,SAAS,sBAAsB,IAAI,IAAI;AACtD,MAAI,SAAS,QAAQ,oBAAoB,MAAM;AAC/C,MAAI,WAAW,QAAW;AACxB,WAAO;AAAA,EACT;AACA,OAAK,OAAO,QAAW,gBAAY,WAAW,GAAG;AAC/C,aAAS,QAAQ,iBAAiB,MAAM;AAAA,EAC1C;AACA,UAAQ,OAAO,QAAQ,uBAAuB;AAChD;AAEA,IAAO,6BAAQ,2BAAY;AAAA,EACzB,CAAC,SACC,8EAA8E,IAAI;AACtF,EAAuB;AAAA,EACrB,MAAM;AAAA,EACN,MAAM;AAAA,IACJ,MAAM;AAAA,IACN,SAAS;AAAA,IACT,MAAM;AAAA,MACJ,aACE;AAAA,IACJ;AAAA,IACA,QAAQ,CAAC;AAAA,IACT,UAAU;AAAA,MACR,YACE;AAAA,MACF,cACE;AAAA,IACJ;AAAA,EACF;AAAA,EACA,gBAAgB,CAAC;AAAA,EACjB,OAAO,SAAS;AACd,UAAM,aAAa,QAAQ;AAC3B,QAAID,eAAc,QAAQ,UAAU,WAAW,QAAQ,CAAC,GAAG;AACzD,aAAO,CAAC;AAAA,IACV;AAEA,QAAI;AACJ,QAAI;AACF,iBAAW,2BAAY,kBAAkB,OAAO;AAAA,IAClD,QAAQ;AACN,iBAAW;AAAA,IACb;AAGA,UAAM,mBAAmB,oBAAI,IAAoB;AAEjD,aAAS,gBAAgB,MAA+B,KAAsB;AAC5E,YAAM,SAAS,KAAK;AACpB,UACE,OAAO,SAAS,8BAAe,oBAC/B,CAAC,OAAO,YACR,OAAO,SAAS,SAAS,8BAAe,YACxC;AACA,eAAO,OAAO,SAAS,SAAS;AAAA,MAClC;AACA,UAAI,OAAO,SAAS,8BAAe,YAAY;AAC7C,eAAO,iBAAiB,IAAI,OAAO,IAAI,MAAM;AAAA,MAC/C;AACA,aAAO;AAAA,IACT;AAEA,aAAS,SACP,MACmC;AAKnC,YAAM,SAAS,KAAK;AACpB,UACE,OAAO,SAAS,8BAAe,oBAC/B,OAAO,SAAS,SAAS,8BAAe,YACxC;AACA,eAAO;AAAA,MACT;AACA,YAAM,MAAM,KAAK,UAAU,CAAC;AAC5B,UACE,QAAQ,UACR,KAAK,UAAU,WAAW,KAC1B,IAAI,SAAS,8BAAe,eAC5B;AACA,eAAO;AAAA,MACT;AACA,YAAM,QAAQC,QAAO,GAAG;AACxB,UAAI,MAAM,SAAS,8BAAe,kBAAkB;AAClD,eAAO;AAAA,MACT;AACA,YAAM,SAAS,iBAAiB,OAAO,UAAU;AACjD,UAAI,WAAW,MAAM;AACnB,eAAO;AAAA,MACT;AACA,YAAM,WAAW,OAAO;AACxB,YAAM,iBAAiB,IAAI,OAAO,KAAK,IAAI,CAAC;AAC5C,aAAO,CAAC,UAAU;AAAA,QAChB,MAAM,YAAY,UAAU,MAAM;AAAA,QAClC,MAAM,YAAY,KAAK,cAAc;AAAA,MACvC;AAAA,IACF;AAEA,WAAO;AAAA,MACL,kBAAkB,MAAwC;AACxD,YAAI,CAAC,YAAY,KAAK,OAAO,KAAK,GAAG;AACnC;AAAA,QACF;AACA,mBAAW,QAAQ,KAAK,YAAY;AAClC,cACE,KAAK,SAAS,8BAAe,mBAC7B,KAAK,SAAS,SAAS,8BAAe,YACtC;AACA,6BAAiB,IAAI,KAAK,MAAM,MAAM,KAAK,SAAS,IAAI;AAAA,UAC1D;AAAA,QACF;AAAA,MACF;AAAA,MAEA,eAAe,MAAqC;AAClD,YAAI,gBAAgB,MAAM,YAAY,GAAG;AACvC,gBAAM,MAAM,SAAS,IAAI;AACzB,kBAAQ,OAAO;AAAA,YACb;AAAA,YACA,WAAW;AAAA,YACX,GAAI,QAAQ,OAAO,CAAC,IAAI,EAAE,IAAI;AAAA,UAChC,CAAC;AACD;AAAA,QACF;AAEA,YAAI,CAAC,gBAAgB,MAAM,MAAM,GAAG;AAClC;AAAA,QACF;AACA,cAAM,MAAM,KAAK,UAAU,CAAC;AAC5B,YAAI,QAAQ,UAAa,IAAI,SAAS,8BAAe,YAAY;AAC/D;AAAA,QACF;AACA,cAAM,SACJ,oBAAoB,KAAK,WAAW,SAAS,GAAG,CAAC,KAChD,aAAa,QAAQ,uBAAuB,KAAK,QAAQ;AAC5D,YAAI,QAAQ;AACV,kBAAQ,OAAO;AAAA,YACb;AAAA,YACA,WAAW;AAAA,YACX,MAAM,EAAE,MAAM,IAAI,KAAK;AAAA,UACzB,CAAC;AAAA,QACH;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF,CAAC;;;ACzND,IAAAC,iBAIO;AAYP,IAAM,uBAAuB;AAG7B,IAAM,oBAAoB;AAE1B,IAAMC,mBAAqC;AAAA,EACzC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAEA,IAAM,qBAAwC;AAAA,EAC5C;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAMA,IAAM,mBAAwC,oBAAI,IAAI;AAAA;AAAA,EAEpD;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA;AAAA,EAEA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA;AAAA,EAEA;AACF,CAAC;AAED,IAAMC,kBAA8C,oBAAI,IAAI;AAAA,EAC1D,8BAAe;AAAA,EACf,8BAAe;AAAA,EACf,8BAAe;AACjB,CAAC;AAED,IAAM,0BAA+C,oBAAI,IAAI,CAAC,OAAO,KAAK,CAAC;AAE3E,SAASC,eAAc,UAAkB,YAA6B;AACpE,MAAIF,iBAAgB,KAAK,CAAC,OAAO,GAAG,KAAK,QAAQ,CAAC,GAAG;AACnD,WAAO;AAAA,EACT;AACA,SAAO,eAAe,KAAK,WAAW,MAAM,GAAG,IAAI,CAAC;AACtD;AAEA,SAASG,YAAW,UAA2B;AAC7C,SAAO,mBAAmB,KAAK,CAAC,OAAO,GAAG,KAAK,QAAQ,CAAC;AAC1D;AAGA,SAASC,QAAO,MAAoC;AAClD,MACE,KAAK,SAAS,8BAAe,kBAC7B,KAAK,SAAS,8BAAe,yBAC7B,KAAK,SAAS,8BAAe,qBAC7B;AACA,WAAOA,QAAO,KAAK,UAAU;AAAA,EAC/B;AACA,SAAO;AACT;AAEA,SAAS,eAAe,MAAqD;AAC3E,SACE,KAAK,SAAS,8BAAe,WAC7B,WAAW,QACX,KAAK,UAAU;AAEnB;AAQA,SAAS,cAAc,MAAqB,OAAwB;AAClE,MAAI,QAAQ,mBAAmB;AAC7B,WAAO;AAAA,EACT;AACA,QAAM,QAAQA,QAAO,IAAI;AACzB,UAAQ,MAAM,MAAM;AAAA,IAClB,KAAK,8BAAe,SAAS;AAC3B,aAAO;AAAA,IACT;AAAA,IACA,KAAK,8BAAe,iBAAiB;AACnC,aAAO,MAAM,YAAY,WAAW;AAAA,IACtC;AAAA,IACA,KAAK,8BAAe,iBAAiB;AACnC,cACG,MAAM,aAAa,OAAO,MAAM,aAAa,QAC9C,MAAM,SAAS,SAAS,8BAAe,WACvC,OAAO,MAAM,SAAS,UAAU;AAAA,IAEpC;AAAA,IACA,KAAK,8BAAe,iBAAiB;AACnC,aAAO,MAAM,SAAS;AAAA,QACpB,CAAC,OACC,OAAO,QACP,GAAG,SAAS,8BAAe,iBAC3B,cAAc,IAAI,QAAQ,CAAC;AAAA,MAC/B;AAAA,IACF;AAAA,IACA,KAAK,8BAAe,kBAAkB;AACpC,aAAO,MAAM,WAAW,MAAM,CAAC,SAAS;AACtC,YAAI,KAAK,SAAS,8BAAe,UAAU;AACzC,iBAAO;AAAA,QACT;AACA,YAAI,KAAK,aAAa,KAAK,UAAU,KAAK,SAAS,QAAQ;AACzD,iBAAO;AAAA,QACT;AACA,YAAI,KAAK,YAAY,KAAK,IAAI,SAAS,8BAAe,SAAS;AAC7D,iBAAO;AAAA,QACT;AACA,eAAO,cAAc,KAAK,OAAO,QAAQ,CAAC;AAAA,MAC5C,CAAC;AAAA,IACH;AAAA,IACA,SAAS;AACP,aAAO;AAAA,IACT;AAAA,EACF;AACF;AAGA,SAAS,mBAAmB,MAAoC;AAC9D,QAAM,QAAQA,QAAO,IAAI;AACzB,MACE,MAAM,SAAS,8BAAe,kBAC9B,MAAM,OAAO,SAAS,8BAAe,oBACrC,CAAC,MAAM,OAAO,YACd,MAAM,OAAO,OAAO,SAAS,8BAAe,cAC5C,MAAM,OAAO,OAAO,SAAS,YAC7B,MAAM,OAAO,SAAS,SAAS,8BAAe,cAC9C,MAAM,OAAO,SAAS,SAAS,YAC/B,MAAM,UAAU,WAAW,KAC3B,MAAM,UAAU,CAAC,MAAM,UACvB,MAAM,UAAU,CAAC,EAAE,SAAS,8BAAe,eAC3C;AACA,WAAOA,QAAO,MAAM,UAAU,CAAC,CAAC;AAAA,EAClC;AACA,SAAO;AACT;AAUA,SAAS,SAAS,MAAqB,YAAuC;AAC5E,QAAM,OAAO,mBAAmB,IAAI;AAEpC,MAAI,eAAe,IAAI,GAAG;AACxB,QAAI,CAAC,YAAY;AACf,aAAO;AAAA,IACT;AAEA,QAAI,OAAO,KAAK,KAAK,MAAM,KAAK,GAAG;AACjC,aAAO;AAAA,IACT;AACA,WAAO,EAAE,MAAM,SAAS,MAAM,EAAE;AAAA,EAClC;AAEA,MAAI,KAAK,SAAS,8BAAe,iBAAiB;AAChD,WAAO,cAAc,MAAM,CAAC,IACxB,EAAE,MAAM,SAAS,MAAM,KAAK,SAAS,OAAO,IAC5C;AAAA,EACN;AAEA,MAAI,KAAK,SAAS,8BAAe,kBAAkB;AACjD,WAAO,cAAc,MAAM,CAAC,IACxB,EAAE,MAAM,UAAU,MAAM,KAAK,WAAW,OAAO,IAC/C;AAAA,EACN;AAEA,MACE,KAAK,SAAS,8BAAe,iBAC7B,KAAK,OAAO,SAAS,8BAAe,cACpC,wBAAwB,IAAI,KAAK,OAAO,IAAI,GAC5C;AACA,UAAM,MAAM,KAAK,UAAU,CAAC;AAC5B,QACE,KAAK,UAAU,WAAW,KAC1B,QAAQ,UACR,IAAI,SAAS,8BAAe,eAC5B;AACA,aAAO;AAAA,IACT;AACA,UAAM,UAAUA,QAAO,GAAG;AAC1B,QAAI,QAAQ,SAAS,8BAAe,iBAAiB;AACnD,aAAO;AAAA,IACT;AACA,WAAO,cAAc,SAAS,CAAC,IAC3B,EAAE,MAAM,KAAK,OAAO,SAAS,QAAQ,QAAQ,OAAO,MAAM,QAAQ,SAAS,OAAO,IAClF;AAAA,EACN;AAEA,SAAO;AACT;AAGA,SAASC,mBAAkB,MAA2C;AACpE,MAAI,UAA4C,KAAK;AACrD,SAAO,YAAY,UAAa,YAAY,MAAM;AAChD,QAAIJ,gBAAe,IAAI,QAAQ,IAAI,GAAG;AACpC,aAAO;AAAA,IACT;AACA,cAAU,QAAQ;AAAA,EACpB;AACA,SAAO;AACT;AAMA,IAAM,yBAAmE,oBAAI;AAAA,EAC3E;AAAA,IACE;AAAA,MACE;AAAA,MACA,oBAAI,IAAI,CAAC,QAAQ,UAAU,WAAW,UAAU,eAAe,QAAQ,CAAC;AAAA,IAC1E;AAAA,IACA,CAAC,SAAS,oBAAI,IAAI,CAAC,QAAQ,SAAS,CAAC,CAAC;AAAA,IACtC,CAAC,QAAQ,oBAAI,IAAI,CAAC,WAAW,CAAC,CAAC;AAAA,EACjC;AACF;AAEA,SAAS,0BACP,MACA,UACS;AACT,QAAM,SAAS,KAAK;AACpB,MACE,OAAO,SAAS,8BAAe,cAC/B,OAAO,SAAS,mBAChB;AACA,WAAO;AAAA,EACT;AACA,MACE,OAAO,SAAS,8BAAe,oBAC/B,OAAO,YACP,OAAO,OAAO,SAAS,8BAAe,cACtC,OAAO,SAAS,SAAS,8BAAe,YACxC;AACA,WAAO;AAAA,EACT;AACA,QAAM,UAAU,uBAAuB,IAAI,OAAO,OAAO,IAAI;AAC7D,MAAI,YAAY,UAAa,CAAC,QAAQ,IAAI,OAAO,SAAS,IAAI,GAAG;AAC/D,WAAO;AAAA,EACT;AAGA,MAAI,OAAO,OAAO,SAAS,YAAY,OAAO,SAAS,SAAS,UAAU;AACxE,WAAO,KAAK,UAAU,CAAC,MAAM;AAAA,EAC/B;AACA,SAAO;AACT;AAOA,SAAS,WAAW,YAA0C;AAC5D,QAAM,SAAS,WAAW;AAE1B,MAAI,OAAO,SAAS,8BAAe,kBAAkB;AACnD,QAAI,OAAO,WAAW,YAAY;AAEhC,aAAO;AAAA,IACT;AACA,UAAM,cAAc,OAAO;AAE3B,QACE,YAAY,SAAS,8BAAe,wBACpC,YAAY,SAAS,QACrB;AACA,aAAO;AAAA,IACT;AAEA,QAAI,YAAY,SAAS,8BAAe,kBAAkB;AACxD,aAAO;AAAA,IACT;AAEA,QACE,YAAY,SAAS,8BAAe,mBACpC,YAAY,aAAa,UACzB;AACA,aAAO;AAAA,IACT;AAEA,QACE,CAAC,OAAO,YACR,OAAO,SAAS,SAAS,8BAAe,cACxC,iBAAiB,IAAI,OAAO,SAAS,IAAI,KACzC,YAAY,SAAS,8BAAe,kBACpC,YAAY,WAAW,QACvB;AACA,aAAO;AAAA,IACT;AAIA,WAAO;AAAA,EACT;AAGA,MACE,OAAO,SAAS,8BAAe,kBAC/B,OAAO,UAAU,YACjB;AACA,WAAO;AAAA,EACT;AAIA,MAAI,OAAO,SAAS,8BAAe,eAAe;AAChD,WAAO;AAAA,EACT;AAGA,MAAI,OAAO,SAAS,8BAAe,kBAAkB;AACnD,WAAO;AAAA,EACT;AAKA,MACE,OAAO,SAAS,8BAAe,kBAC/B,OAAO,UAAU,SAAS,UAAU,KACpC,0BAA0B,QAAQ,UAAU,GAC5C;AACA,WAAO;AAAA,EACT;AAGA,MACE,OAAO,SAAS,8BAAe,mBAC/B,OAAO,aAAa,UACpB;AACA,WAAO;AAAA,EACT;AAEA,SAAO;AACT;AAEA,IAAO,uCAAQ,2BAAY;AAAA,EACzB,CAAC,SACC,8EAA8E,IAAI;AACtF,EAAuB;AAAA,EACrB,MAAM;AAAA,EACN,MAAM;AAAA,IACJ,MAAM;AAAA,IACN,MAAM;AAAA,MACJ,aACE;AAAA,IACJ;AAAA,IACA,QAAQ;AAAA,MACN;AAAA,QACE,MAAM;AAAA,QACN,sBAAsB;AAAA,QACtB,YAAY;AAAA,UACV,aAAa,EAAE,MAAM,UAAU,SAAS,EAAE;AAAA,UAC1C,YAAY,EAAE,MAAM,UAAU;AAAA,UAC9B,iBAAiB,EAAE,MAAM,UAAU;AAAA,QACrC;AAAA,MACF;AAAA,IACF;AAAA,IACA,UAAU;AAAA,MACR,iBACE;AAAA,MACF,YACE;AAAA,IACJ;AAAA,EACF;AAAA,EACA,gBAAgB,CAAC,CAAC,CAAC;AAAA,EACnB,OAAO,SAAS,CAAC,UAAU,GAAG;AAC5B,UAAM,UAAU,cAAc,CAAC;AAC/B,UAAM,cAAc,QAAQ,eAAe;AAC3C,UAAM,aAAa,QAAQ,cAAc;AACzC,UAAM,kBAAkB,QAAQ,mBAAmB;AAEnD,UAAM,aAAa,QAAQ;AAC3B,UAAM,WAAW,QAAQ;AAEzB,QAAIC,eAAc,UAAU,WAAW,QAAQ,CAAC,GAAG;AACjD,aAAO,CAAC;AAAA,IACV;AACA,QAAI,mBAAmBC,YAAW,QAAQ,GAAG;AAC3C,aAAO,CAAC;AAAA,IACV;AAEA,aAAS,0BACP,YACS;AACT,YAAM,YAAY,WAAW,qBAAqB,UAAU;AAC5D,YAAM,WAAW,UAAU,CAAC;AAC5B,UAAI,aAAa,QAAW;AAC1B,eAAO;AAAA,MACT;AACA,iBAAW,aAAa,SAAS,YAAY;AAE3C,YAAI,UAAU,SAAS,MAAM;AAC3B;AAAA,QACF;AACA,YAAI,UAAU,QAAQ,GAAG;AACvB,iBAAO;AAAA,QACT;AAGA,YAAI,UAAU,WAAW,SAAS,8BAAe,YAAY;AAC3D,iBAAO;AAAA,QACT;AACA,YAAI,CAAC,WAAW,UAAU,UAAU,GAAG;AACrC,iBAAO;AAAA,QACT;AAAA,MACF;AACA,aAAO;AAAA,IACT;AAEA,WAAO;AAAA,MACL,mBAAmB,MAAyC;AAC1D,cAAM,cAAc,KAAK;AACzB,YACE,YAAY,SAAS,8BAAe,uBACpC,YAAY,SAAS,WACrB,YAAY,YAAY,MACxB;AACA;AAAA,QACF;AACA,YAAI,KAAK,GAAG,SAAS,8BAAe,cAAc,KAAK,SAAS,MAAM;AACpE;AAAA,QACF;AACA,YAAIE,mBAAkB,IAAI,MAAM,MAAM;AACpC;AAAA,QACF;AAEA,cAAM,YAAY,SAAS,KAAK,MAAM,UAAU;AAChD,YAAI,cAAc,MAAM;AACtB;AAAA,QACF;AACA,YAAI,UAAU,SAAS,WAAW,UAAU,OAAO,aAAa;AAC9D;AAAA,QACF;AACA,YAAI,CAAC,0BAA0B,IAAI,GAAG;AACpC;AAAA,QACF;AAEA,gBAAQ,OAAO;AAAA,UACb,MAAM,KAAK;AAAA,UACX,WACE,UAAU,SAAS,UAAU,eAAe;AAAA,UAC9C,MAAM,EAAE,MAAM,KAAK,GAAG,MAAM,MAAM,UAAU,KAAK;AAAA,QACnD,CAAC;AAAA,MACH;AAAA,IACF;AAAA,EACF;AACF,CAAC;;;A/C/gBD,IAAM,QAAQ;AAAA,EACZ,0BAA0B;AAAA,EAC1B,gCAAgC;AAAA,EAChC,oBAAoB;AAAA,EACpB,WAAW;AAAA,EACX,yBAAyB;AAAA,EACzB,2BAA2B;AAAA,EAC3B,qBAAqB;AAAA,EACrB,cAAc;AAAA,EACd,+BAA+B;AAAA,EAC/B,uBAAuB;AAAA,EACvB,4BAA4B;AAAA,EAC5B,6BAA6B;AAAA,EAC7B,8BAA8B;AAAA,EAC9B,iCAAiC;AAAA,EACjC,0BAA0B;AAAA,EAC1B,yBAAyB;AAAA,EACzB,iBAAiB;AAAA,EACjB,wBAAwB;AAAA,EACxB,+BAA+B;AAAA,EAC/B,yBAAyB;AAAA,EACzB,qCAAqC;AAAA,EACrC,qBAAqB;AAAA,EACrB,oBAAoB;AAAA,EACpB,kBAAkB;AAAA,EAClB,+BAA+B;AAAA,EAC/B,wBAAwB;AAAA,EACxB,2BAA2B;AAAA,EAC3B,yBAAyB;AAAA,EACzB,kCAAkC;AAAA,EAClC,wBAAwB;AAAA,EACxB,8BAA8B;AAAA,EAC9B,8BAA8B;AAAA,EAC9B,kBAAkB;AAAA,EAClB,yBAAyB;AAAA,EACzB,uCAAuC;AAAA,EACvC,qCAAqC;AAAA,EACrC,kBAAkB;AAAA,EAClB,gCAAgC;AAAA,EAChC,mCAAmC;AAAA,EACnC,sBAAsB;AAAA,EACtB,gCAAgC;AAClC;AAEA,IAAM,SAAS;AAAA,EACb,MAAM;AAAA,IACJ,MAAM;AAAA,IACN,SAAS;AAAA,EACX;AAAA,EACA;AAAA,EACA,SAAS;AAAA,IACP,aAAa;AAAA,MACX,SAAS,CAAC,OAAO;AAAA,MACjB,OAAO;AAAA,QACL,+BAA+B;AAAA,QAC/B,8BAA8B;AAAA,QAC9B,qCAAqC;AAAA,QACrC,gCAAgC;AAAA,QAChC,sCAAsC;AAAA,QACtC,+BAA+B;AAAA,QAC/B,mCAAmC;AAAA,QACnC,uCAAuC;AAAA;AAAA,QAEvC,6BAA6B;AAAA,QAC7B,qCAAqC;AAAA,QACrC,2BAA2B;AAAA,QAC3B,+BAA+B;AAAA,QAC/B,iCAAiC;AAAA,QACjC,kCAAkC;AAAA,QAClC,oCAAoC;AAAA,QACpC,0BAA0B;AAAA;AAAA,QAE1B,gCAAgC;AAAA;AAAA,QAEhC,2BAA2B;AAAA,QAC3B,2CAA2C;AAAA,QAC3C,0BAA0B;AAAA,QAC1B,wBAAwB;AAAA,QACxB,8BAA8B;AAAA,QAC9B,qCAAqC;AAAA;AAAA,QAErC,+BAA+B;AAAA,QAC/B,iCAAiC;AAAA,QACjC,wCAAwC;AAAA;AAAA;AAAA;AAAA;AAAA,QAKxC,6CAA6C;AAAA,QAC7C,2CAA2C;AAAA,QAC3C,8BAA8B;AAAA,QAC9B,wBAAwB;AAAA,QACxB,+BAA+B;AAAA,QAC/B,oCAAoC;AAAA,QACpC,oCAAoC;AAAA;AAAA,QAEpC,wBAAwB;AAAA;AAAA;AAAA,QAGxB,4BAA4B;AAAA;AAAA;AAAA;AAAA,QAI5B,sCAAsC;AAAA,MACxC;AAAA,IACF;AAAA,IACA,QAAQ;AAAA,MACN,SAAS,CAAC,OAAO;AAAA,MACjB,OAAO;AAAA,QACL,+BAA+B;AAAA,QAC/B,8BAA8B;AAAA,QAC9B,qCAAqC;AAAA,QACrC,gCAAgC;AAAA,QAChC,oBAAoB;AAAA,QACpB,uBAAuB;AAAA,QACvB,iBAAiB;AAAA,QACjB,sCAAsC;AAAA,QACtC,+BAA+B;AAAA,QAC/B,mCAAmC;AAAA,QACnC,uCAAuC;AAAA;AAAA,QAEvC,6BAA6B;AAAA,QAC7B,qCAAqC;AAAA,QACrC,2BAA2B;AAAA,QAC3B,+BAA+B;AAAA,QAC/B,iCAAiC;AAAA,QACjC,kCAAkC;AAAA,QAClC,oCAAoC;AAAA,QACpC,0BAA0B;AAAA;AAAA;AAAA,QAG1B,gCAAgC;AAAA;AAAA,QAEhC,2BAA2B;AAAA,QAC3B,2CAA2C;AAAA,QAC3C,0BAA0B;AAAA,QAC1B,wBAAwB;AAAA,QACxB,8BAA8B;AAAA;AAAA,QAE9B,qCAAqC;AAAA;AAAA,QAErC,+BAA+B;AAAA,QAC/B,iCAAiC;AAAA,QACjC,wCAAwC;AAAA;AAAA,QAExC,6CAA6C;AAAA,QAC7C,2CAA2C;AAAA,QAC3C,8BAA8B;AAAA,QAC9B,wBAAwB;AAAA,QACxB,+BAA+B;AAAA,QAC/B,oCAAoC;AAAA;AAAA;AAAA;AAAA,QAIpC,oCAAoC;AAAA,QACpC,wBAAwB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,QAOxB,sCAAsC;AAAA,QACtC,yCAAyC;AAAA;AAAA,QAEzC,4BAA4B;AAAA,QAC5B,sCAAsC;AAAA,MACxC;AAAA,IACF;AAAA,EACF;AACF;AAEA,IAAO,gBAAQ;","names":["import_utils","import_utils","import_utils","import_utils","import_utils","propName","import_utils","import_utils","DEFAULT_IGNORE_PATTERNS","import_utils","import_utils","import_utils","isNode","calleeName","import_utils","import_utils","import_utils","import_utils","findVariable","import_utils","import_utils","propName","keyName","import_utils","import_utils","import_utils","import_utils","import_utils","isNode","calleeName","import_utils","import_utils","matchesAnyPattern","isGlobalFetchCall","import_utils","import_utils","isNode","unwrap","import_utils","propertyKeyName","keyName","import_utils","import_utils","import_utils","kebabCase","import_utils","import_utils","import_utils","import_utils","import_utils","import_utils","FUNCTION_TYPES","import_utils","import_utils","import_utils","import_utils","import_utils","DEFAULT_METHODS","compile","import_utils","ts","IGNORE_PATTERNS","isIgnoredFile","unwrap","import_utils","IGNORE_PATTERNS","FUNCTION_TYPES","isIgnoredFile","isTestFile","unwrap","enclosingFunction"]}
|