@slip-stream-kit/eslint-plugin 0.44.0 → 0.45.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/dist/index.js.map CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
- "sources": ["../src/utils/path-match.ts", "../src/rules/atom-naming/atom-naming.ts", "../src/utils/component.ts", "../src/rules/component-arrow-function/component-arrow-function.ts", "../src/utils/package-root.ts", "../../config/src/lib/package-type/package-type.ts", "../src/utils/package-type-reader.ts", "../src/utils/component-file-scope.ts", "../src/utils/exported-components.ts", "../src/rules/component-classname/component-classname.ts", "../src/rules/component-file-order/component-file-order.ts", "../src/rules/component-name-matches-file/component-name-matches-file.ts", "../src/rules/dumb-component-purity/dumb-component-purity.ts", "../src/utils/playwright-call.ts", "../src/rules/e2e-describe-order/e2e-describe-order.ts", "../src/rules/e2e-file-layout/e2e-file-layout.ts", "../src/utils/attached-comments.ts", "../src/rules/e2e-file-order/e2e-file-order.ts", "../src/rules/e2e-page-object-member-order/e2e-page-object-member-order.ts", "../src/rules/e2e-test-tags/e2e-test-tags.ts", "../src/rules/e2e-test-title/e2e-test-title.ts", "../src/rules/e2e-top-level-describe/e2e-top-level-describe.ts", "../src/rules/feature-files/feature-files.ts", "../src/utils/import-target.ts", "../src/rules/feature-public-api/feature-public-api.ts", "../src/rules/layer-imports/layer-imports.ts", "../src/rules/max-components-per-file/max-components-per-file.ts", "../src/rules/max-jsdoc-lines/max-jsdoc-lines.ts", "../src/rules/max-jsdoc-summary-lines/max-jsdoc-summary-lines.ts", "../src/rules/max-jsx-return-size/max-jsx-return-size.ts", "../src/rules/no-feature-self-import/no-feature-self-import.ts", "../src/rules/no-hooks-in-services/no-hooks-in-services.ts", "../src/rules/package-structure/package-structure.ts", "../src/rules/props-destructuring-blank-line/props-destructuring-blank-line.ts", "../src/rules/props-destructuring-newline/props-destructuring-newline.ts", "../src/rules/props-type-name/props-type-name.ts", "../src/rules/props-type-reference/props-type-reference.ts", "../src/rules/require-component-stories/require-component-stories.ts", "../src/utils/story-path.ts", "../src/utils/cognitive-complexity.ts", "../src/rules/require-jsdoc-example/require-jsdoc-example.ts", "../src/rules/test-location/test-location.ts", "../src/rules/index.ts", "../src/index.ts"],
4
- "sourcesContent": ["// Characters that must be escaped when embedded literally into a RegExp source.\nconst REGEX_METACHARS = new Set(['\\\\', '^', '$', '.', '|', '+', '(', ')', '[', ']', '{', '}'])\n\n/**\n * Convert a glob pattern to an (unanchored) RegExp.\n *\n * - `**` matches any characters, including path separators.\n * - `*` matches any characters except a path separator.\n * - `?` matches a single non-separator character.\n *\n * The result is intentionally unanchored so a pattern matches anywhere in the\n * path (e.g. `features/**` matches `/repo/src/features/x/comp.tsx`).\n */\nconst globToRegExp = (glob: string): RegExp => {\n let source = ''\n\n for (let index = 0; index < glob.length; index++) {\n const char = glob[index]!\n\n if (char === '*') {\n if (glob[index + 1] === '*') {\n source += '.*'\n index++\n\n // Consume a trailing slash so `**/foo` also matches a bare `foo`.\n if (glob[index + 1] === '/') {\n index++\n }\n } else {\n source += '[^/]*'\n }\n } else if (char === '?') {\n source += '[^/]'\n } else if (REGEX_METACHARS.has(char)) {\n source += `\\\\${char}`\n } else {\n source += char\n }\n }\n\n return new RegExp(source)\n}\n\n/** Whether `filename` matches at least one of the provided glob `patterns`. */\nexport const matchesAnyGlob = (filename: string, patterns: readonly string[]): boolean => {\n const normalized = filename.split('\\\\').join('/')\n\n return patterns.some((pattern) => {\n return globToRegExp(pattern).test(normalized)\n })\n}\n", "import type { Rule } from 'eslint'\nimport type * as ESTree from 'estree'\n\nimport { matchesAnyGlob } from '../../utils/path-match'\n\ninterface Options {\n asyncSuffix?: string\n syncSuffix?: string\n argsSuffix?: string\n readablePrefix?: string\n paths?: string[]\n ignore?: string[]\n}\n\nconst ATOM_FACTORIES = new Set([\n 'atom',\n 'atomWithStorage',\n 'atomWithReset',\n 'atomWithDefault',\n 'atomFamily',\n 'loadable',\n 'selectAtom',\n 'splitAtom',\n 'focusAtom',\n])\n\n// TS-only nodes are not modelled by estree.\ninterface TypedPattern {\n typeAnnotation?: {\n typeAnnotation?: { type: string; typeName?: { type: string; name?: string } }\n }\n}\n\nconst isWriteOnly = (call: ESTree.CallExpression): boolean => {\n const [read, write] = call.arguments\n\n // `atom<T | null>(null)` is a primitive atom; only a `null` read paired with a write is write-only.\n return (\n call.callee.type === 'Identifier' &&\n call.callee.name === 'atom' &&\n read?.type === 'Literal' &&\n read.value === null &&\n write !== undefined\n )\n}\n\nconst asFunction = (\n node: ESTree.Node | undefined,\n): ESTree.ArrowFunctionExpression | ESTree.FunctionExpression | null => {\n return node?.type === 'ArrowFunctionExpression' || node?.type === 'FunctionExpression' ? node : null\n}\n\nconst isNamedArgsType = (param: ESTree.Pattern, argsSuffix: string): boolean => {\n const target = param.type === 'AssignmentPattern' ? param.left : param\n\n if (target.type === 'RestElement') {\n return false\n }\n\n const annotation = (target as TypedPattern).typeAnnotation?.typeAnnotation\n\n // Unannotated args are typed through the `atom<\u2026>` generics or are implicit `any`; tsc owns both.\n if (annotation === undefined) {\n return true\n }\n\n return (\n annotation.type === 'TSTypeReference' &&\n annotation.typeName?.type === 'Identifier' &&\n annotation.typeName.name!.endsWith(argsSuffix)\n )\n}\n\n/** `toggleOpenedCardAtom` \u2192 `ToggleOpenedCardArgs`, for the message's example. */\nconst exampleArgsType = (name: string, suffixes: string[], argsSuffix: string): string => {\n const suffix = suffixes.find((candidate) => {\n return name.endsWith(candidate) && name.length > candidate.length\n })\n\n const base = (suffix === undefined ? name : name.slice(0, -suffix.length)).replace(/^\\$+/, '')\n\n return `${base.charAt(0).toUpperCase()}${base.slice(1)}${argsSuffix}`\n}\n\nexport const atomNaming: Rule.RuleModule = {\n meta: {\n type: 'suggestion',\n docs: {\n description:\n 'Require readable Jotai atoms to start with `$`, write-only atoms to end with `Fx` (async) or `Atom` (sync), and write-only atoms to take a single `*Args` object.',\n recommended: true,\n url: 'https://github.com/ArthurSaenz/infra-kit/tree/main/apps/infra-kit/eslint-plugin#atom-naming',\n },\n schema: [\n {\n type: 'object',\n properties: {\n asyncSuffix: {\n type: 'string',\n minLength: 1,\n description: \"Suffix of an async write-only atom (default 'Fx').\",\n },\n syncSuffix: {\n type: 'string',\n minLength: 1,\n description: \"Suffix of a sync write-only atom (default 'Atom').\",\n },\n argsSuffix: {\n type: 'string',\n minLength: 1,\n description: \"Suffix of the type naming a write-only atom's argument (default 'Args').\",\n },\n readablePrefix: {\n type: 'string',\n minLength: 1,\n description: \"Prefix of a readable atom (default '$').\",\n },\n paths: {\n type: 'array',\n items: { type: 'string' },\n description:\n 'Optional glob patterns. When provided, the rule only runs for files whose path matches one of them.',\n },\n ignore: {\n type: 'array',\n items: { type: 'string' },\n description:\n 'Optional glob patterns. The rule is skipped for files whose path matches one of them, even if it also matches `paths`.',\n },\n },\n additionalProperties: false,\n },\n ],\n messages: {\n readablePrefix: 'Readable atom \"{{name}}\" must start with \"{{prefix}}\" (e.g. \"{{expected}}\").',\n writeOnlyPrefix: 'Write-only atom \"{{name}}\" must not start with \"{{prefix}}\": that prefix marks readable atoms.',\n writeOnlySuffix: 'Write-only atom \"{{name}}\" must end with {{expected}}.',\n argsNotNamed:\n 'Write-only atom \"{{name}}\" must take a single argument typed with a named `*{{suffix}}` type (e.g. `args: {{example}}`).',\n },\n },\n\n create(context) {\n const options = (context.options[0] ?? {}) as Options\n const paths = options.paths ?? []\n const ignore = options.ignore ?? []\n\n if (ignore.length > 0 && matchesAnyGlob(context.filename, ignore)) {\n return {}\n }\n\n if (paths.length > 0 && !matchesAnyGlob(context.filename, paths)) {\n return {}\n }\n\n const asyncSuffix = options.asyncSuffix ?? 'Fx'\n const syncSuffix = options.syncSuffix ?? 'Atom'\n const argsSuffix = options.argsSuffix ?? 'Args'\n const prefix = options.readablePrefix ?? '$'\n\n const checkWriteOnly = (id: ESTree.Identifier, call: ESTree.CallExpression): void => {\n const { name } = id\n const write = asFunction(call.arguments[1])\n\n if (name.startsWith(prefix)) {\n context.report({ node: id, messageId: 'writeOnlyPrefix', data: { name, prefix } })\n }\n\n // A write function passed by reference cannot be seen to be async, so either suffix passes.\n const asyncForm = { suffix: asyncSuffix, kind: 'async' }\n const syncForm = { suffix: syncSuffix, kind: 'sync' }\n let accepted = [asyncForm, syncForm]\n\n if (write !== null) {\n accepted = [write.async ? asyncForm : syncForm]\n }\n\n const hasSuffix = accepted.some((form) => {\n return name.endsWith(form.suffix)\n })\n\n if (!hasSuffix) {\n const expected = accepted\n .map((form) => {\n return `\"${form.suffix}\" (${form.kind})`\n })\n .join(' or ')\n\n context.report({ node: id, messageId: 'writeOnlySuffix', data: { name, expected } })\n }\n\n // Jotai's write signature is `(get, set, ...args)`: everything past `set` is the caller's input.\n const inputs = write?.params.slice(2) ?? []\n\n if (inputs.length === 0) {\n return\n }\n\n if (inputs.length > 1 || !isNamedArgsType(inputs[0]!, argsSuffix)) {\n context.report({\n node: inputs[0]!,\n messageId: 'argsNotNamed',\n data: { name, suffix: argsSuffix, example: exampleArgsType(name, [asyncSuffix, syncSuffix], argsSuffix) },\n })\n }\n }\n\n const check = (node: ESTree.VariableDeclarator): void => {\n const { id, init } = node\n\n if (\n id.type !== 'Identifier' ||\n init?.type !== 'CallExpression' ||\n init.callee.type !== 'Identifier' ||\n !ATOM_FACTORIES.has(init.callee.name)\n ) {\n return\n }\n\n if (isWriteOnly(init)) {\n checkWriteOnly(id, init)\n\n return\n }\n\n // Everything else is readable: primitive, derived, read-write, and `atomFamily(...)`, whose\n // members are read through the family even when they are write-only themselves.\n if (!id.name.startsWith(prefix)) {\n context.report({\n node: id,\n messageId: 'readablePrefix',\n data: { name: id.name, prefix, expected: `${prefix}${id.name}` },\n })\n }\n }\n\n return {\n 'Program > VariableDeclaration > VariableDeclarator': check,\n 'Program > ExportNamedDeclaration > VariableDeclaration > VariableDeclarator': check,\n }\n },\n}\n", "import type * as ESTree from 'estree'\n\nexport type ComponentFunction = ESTree.ArrowFunctionExpression | ESTree.FunctionDeclaration | ESTree.FunctionExpression\n\n// Minimal structural view over the `parent` back-reference ESLint adds to every node.\ninterface WithParent {\n parent?: ESTree.Node\n}\n\n// Calls that wrap a component while preserving its identity (memo, forwardRef, observer, ...).\nconst COMPONENT_WRAPPER_CALLEES = new Set(['memo', 'forwardRef', 'observer', 'React.memo', 'React.forwardRef'])\n\n// Node types that introduce a new function scope \u2014 their returns are not the outer component's.\nconst NESTED_SCOPES = new Set(['FunctionDeclaration', 'FunctionExpression', 'ArrowFunctionExpression'])\n\nconst isPascalCase = (name: string): boolean => {\n return /^[A-Z]/.test(name)\n}\n\nexport const isJsxNode = (node: ESTree.Node | null | undefined): boolean => {\n if (!node) {\n return false\n }\n\n const type = node.type as string\n\n return type === 'JSXElement' || type === 'JSXFragment'\n}\n\nconst getParent = (node: ESTree.Node | undefined): ESTree.Node | undefined => {\n return (node as (WithParent & ESTree.Node) | undefined)?.parent\n}\n\n/** Best-effort name of a call's callee: `memo` for `memo(...)`, `React.memo` for `React.memo(...)`. */\nconst getCalleeName = (callee: ESTree.CallExpression['callee']): string | null => {\n if (callee.type === 'Identifier') {\n return callee.name\n }\n\n if (\n callee.type === 'MemberExpression' &&\n callee.object.type === 'Identifier' &&\n callee.property.type === 'Identifier'\n ) {\n return `${callee.object.name}.${callee.property.name}`\n }\n\n return null\n}\n\n/**\n * Resolve the declared name of a function, looking through component wrappers\n * such as `memo`/`forwardRef` so that `const Comp = memo(({ a }) => ...)` is\n * still recognised by its PascalCase variable name.\n */\nexport const getComponentName = (node: ComponentFunction): string | null => {\n if (node.type === 'FunctionDeclaration') {\n return node.id?.name ?? null\n }\n\n let current = getParent(node)\n\n // Walk through wrapping call expressions (memo, forwardRef, React.memo, ...).\n while (current?.type === 'CallExpression') {\n const calleeName = getCalleeName(current.callee)\n\n if (!calleeName || !COMPONENT_WRAPPER_CALLEES.has(calleeName)) {\n break\n }\n\n current = getParent(current)\n }\n\n if (current?.type === 'VariableDeclarator' && current.id.type === 'Identifier') {\n return current.id.name\n }\n\n return null\n}\n\n/**\n * Collect every *own* return argument of a function \u2014 the expression of each\n * `return <expr>` reachable without entering a nested function scope, plus the\n * implicit-return body of an expression-bodied arrow.\n *\n * Bare `return;` (a null argument) contributes nothing, so callers never receive\n * a null and can safely walk each result. This is the multi-return counterpart\n * to the boolean `returnsJsx`, which is defined in terms of it; the deliberate\n * \"skip nested scopes\" behaviour answers *which* returns belong to this function\n * (a `return` inside an inline `.map`/IIFE callback is that callback's return,\n * not this one's).\n */\nexport const collectOwnReturnArguments = (node: ComponentFunction): ESTree.Expression[] => {\n if (node.body.type !== 'BlockStatement') {\n return [node.body]\n }\n\n const args: ESTree.Expression[] = []\n\n const visit = (current: ESTree.Node | null | undefined): void => {\n if (!current || NESTED_SCOPES.has(current.type)) {\n return\n }\n\n if (current.type === 'ReturnStatement') {\n if (current.argument) {\n args.push(current.argument)\n }\n\n return\n }\n\n if (current.type === 'IfStatement') {\n visit(current.consequent)\n visit(current.alternate)\n\n return\n }\n\n if (current.type === 'BlockStatement') {\n for (const statement of current.body) {\n visit(statement)\n }\n\n return\n }\n\n if (current.type === 'SwitchStatement') {\n const statements = current.cases.flatMap((switchCase) => {\n return switchCase.consequent\n })\n\n for (const statement of statements) {\n visit(statement)\n }\n\n return\n }\n\n if (current.type === 'TryStatement') {\n visit(current.block)\n visit(current.handler?.body)\n visit(current.finalizer)\n\n return\n }\n\n if (\n current.type === 'ForStatement' ||\n current.type === 'ForInStatement' ||\n current.type === 'ForOfStatement' ||\n current.type === 'WhileStatement' ||\n current.type === 'DoWhileStatement'\n ) {\n visit(current.body)\n }\n }\n\n for (const statement of node.body.body) {\n visit(statement)\n }\n\n return args\n}\n\n/** Whether a function returns JSX, scanning its own body without descending into nested functions. */\nconst returnsJsx = (node: ComponentFunction): boolean => {\n return collectOwnReturnArguments(node).some(isJsxNode)\n}\n\n/** A function is treated as a React component when it is PascalCase-named or returns JSX. */\nexport const isComponent = (node: ComponentFunction): boolean => {\n const name = getComponentName(node)\n\n if (name && isPascalCase(name)) {\n return true\n }\n\n return returnsJsx(node)\n}\n\nconst isComponentFunctionNode = (node: ESTree.Node): node is ComponentFunction => {\n return (\n node.type === 'ArrowFunctionExpression' || node.type === 'FunctionExpression' || node.type === 'FunctionDeclaration'\n )\n}\n\n/**\n * Extract the component function from an expression, unwrapping a single layer of\n * component wrappers (`memo(fn)`, `forwardRef(fn)`, `React.memo(fn)`, ...). Returns\n * null when no function is found.\n */\nexport const getComponentFunction = (node: ESTree.Node | null | undefined): ComponentFunction | null => {\n if (!node) {\n return null\n }\n\n if (isComponentFunctionNode(node)) {\n return node\n }\n\n if (node.type === 'CallExpression') {\n for (const argument of node.arguments) {\n if (argument.type === 'SpreadElement') {\n continue\n }\n\n const found = getComponentFunction(argument)\n\n if (found) {\n return found\n }\n }\n }\n\n return null\n}\n\n// TS-only nodes are not modelled by estree. A parameter's `typeAnnotation` wraps the type node;\n// for a named type that inner node is a `TSTypeReference` whose `typeName` is the referenced\n// identifier (`Props`, `ButtonProps`, ...). Inline object types, qualified names (`NS.Props`) and\n// generics surface a different `typeName` shape and are intentionally left unresolved.\ninterface TypeReferenceNode {\n type?: string\n typeName?: { type?: string; name?: string }\n}\n\ninterface AnnotatedParam {\n typeAnnotation?: {\n typeAnnotation?: TypeReferenceNode\n }\n}\n\n/**\n * The parameter that actually carries the props type annotation. A default value wraps the\n * parameter in an `AssignmentPattern` (`(props: Props = {})`), moving the annotation onto its\n * `.left`; unwrap one layer so the annotation is found either way.\n */\nexport const getAnnotatedParam = (param: ESTree.Pattern): ESTree.Pattern => {\n return param.type === 'AssignmentPattern' ? param.left : param\n}\n\n/** The named type referenced by a component function's first parameter (`Props`), or null. */\nexport const getPropsTypeNameFromFunction = (node: ComponentFunction): string | null => {\n const firstParam = node.params[0]\n\n if (!firstParam) {\n return null\n }\n\n const inner = (getAnnotatedParam(firstParam) as AnnotatedParam).typeAnnotation?.typeAnnotation\n\n if (inner?.type !== 'TSTypeReference' || inner.typeName?.type !== 'Identifier') {\n return null\n }\n\n return inner.typeName.name ?? null\n}\n\n/**\n * Resolve the props type name a component *uses* \u2014 the named type on its first parameter \u2014\n * looking through component wrappers (`memo`/`forwardRef`). Returns null when the component is\n * anonymous of props (no parameter) or its props type is not a simple named reference (inline\n * object, qualified name, generic). Mirrors `getDeclaredComponentName`'s node dispatch so a\n * `const`-declared arrow component resolves through its `init`, not the `VariableDeclaration`.\n */\nexport const getComponentPropsTypeName = (node: ESTree.Node | null): string | null => {\n if (!node) {\n return null\n }\n\n if (node.type === 'FunctionDeclaration') {\n return isComponent(node) ? getPropsTypeNameFromFunction(node) : null\n }\n\n if (node.type === 'VariableDeclaration') {\n for (const declaration of node.declarations) {\n const fn = getComponentFunction(declaration.init)\n\n if (fn && isComponent(fn)) {\n return getPropsTypeNameFromFunction(fn)\n }\n }\n\n return null\n }\n\n const fn = getComponentFunction(node)\n\n return fn && isComponent(fn) ? getPropsTypeNameFromFunction(fn) : null\n}\n\n/** Unwrap an `export ...` statement to the declaration it wraps (or the statement itself). */\nexport const unwrapExport = (statement: ESTree.Statement | ESTree.ModuleDeclaration): ESTree.Node | null => {\n if (statement.type === 'ExportNamedDeclaration' || statement.type === 'ExportDefaultDeclaration') {\n return (statement.declaration as ESTree.Node | null) ?? null\n }\n\n return statement\n}\n\n/** Whether a single top-level declaration declares a React component. */\nexport const declaresComponent = (node: ESTree.Node | null): boolean => {\n if (!node) {\n return false\n }\n\n if (node.type === 'FunctionDeclaration') {\n return isComponent(node)\n }\n\n if (node.type === 'VariableDeclaration') {\n return node.declarations.some((declaration) => {\n const fn = getComponentFunction(declaration.init)\n\n return fn ? isComponent(fn) : false\n })\n }\n\n const fn = getComponentFunction(node)\n\n return fn ? isComponent(fn) : false\n}\n\n/**\n * Resolve the name of the React component declared by a single top-level declaration,\n * or null when the declaration is not a component or the component is anonymous\n * (e.g. `export default () => <div />`). Mirrors `declaresComponent`'s node dispatch and\n * resolves the name through component wrappers (`memo`/`forwardRef`).\n */\nexport const getDeclaredComponentName = (node: ESTree.Node | null): string | null => {\n if (!node) {\n return null\n }\n\n if (node.type === 'FunctionDeclaration') {\n return isComponent(node) ? getComponentName(node) : null\n }\n\n if (node.type === 'VariableDeclaration') {\n for (const declaration of node.declarations) {\n const fn = getComponentFunction(declaration.init)\n\n if (fn && isComponent(fn)) {\n return getComponentName(fn)\n }\n }\n\n return null\n }\n\n const fn = getComponentFunction(node)\n\n return fn && isComponent(fn) ? getComponentName(fn) : null\n}\n\n/** Whether any top-level statement in a program body declares a React component. */\nexport const bodyDeclaresComponent = (body: Array<ESTree.Statement | ESTree.ModuleDeclaration>): boolean => {\n return body.some((statement) => {\n return declaresComponent(unwrapExport(statement))\n })\n}\n", "import type { Rule } from 'eslint'\nimport type * as ESTree from 'estree'\n\nimport { getComponentFunction, getComponentName, isComponent, unwrapExport } from '../../utils/component'\nimport type { ComponentFunction } from '../../utils/component'\nimport { matchesAnyGlob } from '../../utils/path-match'\n\ninterface Options {\n paths?: string[]\n ignore?: string[]\n}\n\n// Fallback used when a component is anonymous (e.g. `export default memo(function () { ... })`),\n// since `getComponentName` returns null rather than a placeholder in that case.\nconst ANONYMOUS_NAME = 'component'\n\ntype MessageId = 'functionDeclaration' | 'functionExpression'\n\ninterface Violation {\n node: ESTree.Node\n messageId: MessageId\n name: string\n}\n\nconst reportName = (fn: ComponentFunction): string => {\n return getComponentName(fn) ?? ANONYMOUS_NAME\n}\n\n/**\n * Violation for a single non-`VariableDeclaration` top-level declaration:\n * - a `function Foo() {}` component declaration (incl. exported/default/anonymous), or\n * - an expression that resolves to a function-expression component\n * (e.g. `export default memo(function () { ... })`).\n */\nconst nonVariableViolation = (declaration: ESTree.Node): Violation | null => {\n if (declaration.type === 'FunctionDeclaration') {\n return isComponent(declaration)\n ? { node: declaration, messageId: 'functionDeclaration', name: reportName(declaration) }\n : null\n }\n\n const fn = getComponentFunction(declaration)\n\n return fn?.type === 'FunctionExpression' && isComponent(fn)\n ? { node: fn, messageId: 'functionExpression', name: reportName(fn) }\n : null\n}\n\n/** Function-expression component violations across every declarator in a `const`/`let`/`var`. */\nconst variableViolations = (declaration: ESTree.VariableDeclaration): Violation[] => {\n const violations: Violation[] = []\n\n for (const declarator of declaration.declarations) {\n const fn = getComponentFunction(declarator.init)\n\n if (fn?.type === 'FunctionExpression' && isComponent(fn)) {\n violations.push({ node: declarator, messageId: 'functionExpression', name: reportName(fn) })\n }\n }\n\n return violations\n}\n\n/** Every non-arrow component declared at the top level of the program body. */\nconst collectViolations = (body: Array<ESTree.Statement | ESTree.ModuleDeclaration>): Violation[] => {\n const violations: Violation[] = []\n\n for (const statement of body) {\n const declaration = unwrapExport(statement)\n\n if (!declaration) {\n continue\n }\n\n if (declaration.type === 'VariableDeclaration') {\n violations.push(...variableViolations(declaration))\n\n continue\n }\n\n const violation = nonVariableViolation(declaration)\n\n if (violation) {\n violations.push(violation)\n }\n }\n\n return violations\n}\n\nexport const componentArrowFunction: Rule.RuleModule = {\n meta: {\n type: 'suggestion',\n docs: {\n description:\n 'Enforce that React components are declared as arrow functions, not `function` declarations or function expressions.',\n recommended: true,\n url: 'https://github.com/ArthurSaenz/infra-kit/tree/main/apps/infra-kit/eslint-plugin#component-arrow-function',\n },\n schema: [\n {\n type: 'object',\n properties: {\n paths: {\n type: 'array',\n items: { type: 'string' },\n description:\n 'Optional glob patterns. When provided, the rule only runs for files whose path matches one of them.',\n },\n ignore: {\n type: 'array',\n items: { type: 'string' },\n description:\n 'Optional glob patterns. The rule is skipped for files whose path matches one of them, even if it also matches `paths`. Use this to exclude pages and routes (e.g. `**/pages/**`, `**/routes/**`).',\n },\n },\n additionalProperties: false,\n },\n ],\n messages: {\n functionDeclaration:\n 'React components must be arrow functions; convert the `function {{name}}` declaration to `const {{name}} = () => { \u2026 }`.',\n functionExpression:\n 'React components must be arrow functions; replace the `function` expression for `{{name}}` with an arrow function.',\n },\n },\n\n create(context) {\n const options = (context.options[0] ?? {}) as Options\n const paths = options.paths ?? []\n const ignore = options.ignore ?? []\n\n // `ignore` takes precedence: skip excluded files even when they also match `paths`.\n if (ignore.length > 0 && matchesAnyGlob(context.filename, ignore)) {\n return {}\n }\n\n if (paths.length > 0 && !matchesAnyGlob(context.filename, paths)) {\n return {}\n }\n\n return {\n Program(program) {\n for (const { node, messageId, name } of collectViolations(program.body)) {\n context.report({ node, messageId, data: { name } })\n }\n },\n }\n },\n}\n", "import fs from 'node:fs'\nimport path from 'node:path'\n\nexport const CONFIG_FILENAME = 'infra-kit.config.ts'\nconst PACKAGE_MARKERS = [CONFIG_FILENAME, 'package.json']\nconst REPO_MARKERS = ['pnpm-workspace.yaml']\n\nconst hasAnyMarker = (dir: string, markers: readonly string[]): boolean => {\n return markers.some((marker) => {\n return fs.existsSync(path.posix.join(dir, marker))\n })\n}\n\n// The steady-state cost of the rule is one `statSync` per linted file (see package-type-reader), so\n// the directory walk must not add a stat per ancestor per file: every dirname seen resolves to its\n// package root once per lint process.\nconst rootCache = new Map<string, string | null>()\n\n/** Nearest ancestor of `startDir` (inclusive) that holds one of `markers`, or null at the fs root. */\nconst findUp = (startDir: string, markers: readonly string[]): string | null => {\n let current = startDir\n\n while (!hasAnyMarker(current, markers)) {\n const parent = path.posix.dirname(current)\n\n if (parent === current) {\n return null\n }\n\n current = parent\n }\n\n return current\n}\n\n/**\n * The package directory a linted file belongs to: the nearest ancestor holding `infra-kit.config.ts`\n * or `package.json`. Null for virtual / relative filenames, which have no place on disk to walk from.\n */\nexport const findPackageRoot = (filename: string): string | null => {\n // ESLint hands rules `<input>` / `<text>` for virtual sources; there is nothing to walk up from.\n if (!path.posix.isAbsolute(filename)) {\n return null\n }\n\n const dir = path.posix.dirname(filename)\n const cached = rootCache.get(dir)\n\n if (cached !== undefined) {\n return cached\n }\n\n const root = findUp(dir, PACKAGE_MARKERS)\n\n rootCache.set(dir, root)\n\n return root\n}\n\n/**\n * The directory names between `<packageRoot>/src/` and `filename`, outermost first \u2014 `[]` for a\n * file directly in `src/`, null when the file is not under `src/` at all (so `dist/src/x/...`,\n * built output a consumer ships, is null too).\n */\nexport const dirsUnderSrc = (packageRoot: string, filename: string): string[] | null => {\n const srcPrefix = `${packageRoot}/src/`\n\n if (!filename.startsWith(srcPrefix)) {\n return null\n }\n\n return filename.slice(srcPrefix.length).split('/').slice(0, -1)\n}\n\n/** Nearest ancestor of `packageRoot` (inclusive) that is a pnpm workspace root, or null outside one. */\nexport const findRepoRoot = (packageRoot: string): string | null => {\n return findUp(packageRoot, REPO_MARKERS)\n}\n\n/** Drops the dirname \u2192 root memo; only tests that build and tear down fixture trees need this. */\nexport const resetPackageRootCache = (): void => {\n rootCache.clear()\n}\n", "import path from 'node:path'\n\n/**\n * The kind of workspace package a guidance block is written for. The repo root\n * has its own body and is deliberately not a `PackageType`.\n */\nexport type PackageType = 'frontend' | 'backend' | 'lib' | 'e2e' | 'mobile'\n\n/** Every package type, in registry order. Useful for exhaustive table-driven tests. */\nexport const PACKAGE_TYPES: readonly PackageType[] = ['frontend', 'backend', 'lib', 'e2e', 'mobile']\n\n/** The `package.json` fields package-type detection reads. */\nexport interface PackageTypeManifest {\n scripts?: Record<string, string>\n dependencies?: Record<string, string>\n devDependencies?: Record<string, string>\n peerDependencies?: Record<string, string>\n}\n\nexport interface DetectPackageTypeArgs {\n /** Absolute path to the package directory. */\n packageDir: string\n /** Absolute path to the repo root the directory convention is measured against. */\n repoRoot: string\n /** The package's parsed `package.json` (an empty object when it is missing or unreadable). */\n pkgJson: PackageTypeManifest\n /** `type` declared in the package's `infra-kit.config.ts`. Wins over every detected signal. */\n declaredType?: PackageType\n}\n\n/** Directory names under `apps/<app>/` that carry declared semantics inside infra-kit. */\nconst APP_DIRECTORY_TYPES: Readonly<Record<string, PackageType>> = {\n ui: 'frontend',\n api: 'backend',\n tests: 'e2e',\n}\n\n/** A directory with this basename is a Capacitor shell wherever it sits in the tree. */\nconst MOBILE_BASENAME = 'mobile-app'\n\n/**\n * Dependency signals, first match wins. `react` alone is deliberately absent:\n * component libraries carry it too, so `vite` + `react` + a `dev` script is what\n * separates an app from a library (handled separately below).\n */\nconst DEPENDENCY_SIGNALS: ReadonlyArray<{ type: PackageType; packages: readonly string[] }> = [\n { type: 'e2e', packages: ['@playwright/test'] },\n { type: 'mobile', packages: ['@capacitor/core', '@capacitor/cli'] },\n // `aws-lambda` / `@types/aws-lambda` are deliberately NOT signals: every consumer backend already\n // lives at `apps/<app>/api` (row 2), while the only packages those two deps would catch are\n // libraries (`packages/lib-core` in both consumers, the infra-kit CLI itself) \u2014 a lambda types\n // dependency alone never means backend, exactly as `react` alone never means frontend.\n { type: 'backend', packages: ['serverless'] },\n]\n\n/**\n * Type implied by where the package sits, or `null` when the path carries no\n * declared semantics. `apps/<app>/{ui,api,tests}` is already load-bearing inside\n * infra-kit (`infra-kit dev --target` keys must be `<app>/api` or `<app>/ui`), so this\n * is the repo's own convention rather than a heuristic \u2014 which is why it beats\n * the dependency signals.\n *\n * @example\n * fromDirectory('/repo/apps/client/ui', '/repo') // => 'frontend'\n * fromDirectory('/repo/packages/mobile-app', '/repo') // => 'mobile'\n */\nconst fromDirectory = (packageDir: string, repoRoot: string): PackageType | null => {\n const segments = path\n .relative(repoRoot, packageDir)\n .split(path.sep)\n .filter((segment) => {\n return segment !== '' && segment !== '.'\n })\n\n const [first, , third] = segments\n\n if (segments.length === 3 && first === 'apps' && third !== undefined) {\n const appType = APP_DIRECTORY_TYPES[third]\n\n if (appType) return appType\n }\n\n return segments.at(-1) === MOBILE_BASENAME ? 'mobile' : null\n}\n\n/**\n * Type implied by the merged `dependencies` / `devDependencies` / `peerDependencies`\n * plus the `dev` script, or `null` when nothing matches.\n *\n * @example\n * fromDependencies({ dependencies: { '@playwright/test': '^1' } }) // => 'e2e'\n * fromDependencies({ dependencies: { react: '^19' } }) // => null (react alone is not a frontend)\n */\nconst fromDependencies = (pkgJson: PackageTypeManifest): PackageType | null => {\n const deps = new Set([\n ...Object.keys(pkgJson.dependencies ?? {}),\n ...Object.keys(pkgJson.devDependencies ?? {}),\n ...Object.keys(pkgJson.peerDependencies ?? {}),\n ])\n\n for (const signal of DEPENDENCY_SIGNALS) {\n if (\n signal.packages.some((name) => {\n return deps.has(name)\n })\n )\n return signal.type\n }\n\n const isViteReactApp = deps.has('vite') && deps.has('react') && Boolean(pkgJson.scripts?.dev)\n\n return isViteReactApp ? 'frontend' : null\n}\n\n/**\n * Resolve a package's type by the \u00A73.2 precedence: an explicit `type` in\n * `infra-kit.config.ts` beats the directory convention, which beats the\n * dependency signals, which fall back to `lib`. There is no `unknown` \u2014 the\n * fallback is the least opinionated body, so an unrecognised package still gets\n * a usable block rather than a failing check.\n *\n * @example\n * detectPackageType({\n * packageDir: '/repo/apps/client/ui',\n * repoRoot: '/repo',\n * pkgJson: { dependencies: { '@playwright/test': '^1' } },\n * })\n * // => 'frontend' (the directory convention beats the dependency signal)\n */\nexport const detectPackageType = ({\n packageDir,\n repoRoot,\n pkgJson,\n declaredType,\n}: DetectPackageTypeArgs): PackageType => {\n return declaredType ?? fromDirectory(packageDir, repoRoot) ?? fromDependencies(pkgJson) ?? 'lib'\n}\n", "import type { PackageType, PackageTypeManifest } from '@slip-stream-kit/config/package-type'\nimport { PACKAGE_TYPES, detectPackageType } from '@slip-stream-kit/config/package-type'\nimport fs from 'node:fs'\nimport path from 'node:path'\n\nimport { CONFIG_FILENAME, findRepoRoot } from './package-root'\n\nconst BLOCK_COMMENT = /\\/\\*[\\s\\S]*?\\*\\//g\n// Full-line `//` comments only: a trailing `//` after code is left alone so the `https://` inside\n// every consumer's `templates.cloud` string value survives the strip. Indentation is `[ \\t]`, not\n// `\\s`, because under the `m` flag `\\s*` spans line breaks and backtracks super-linearly.\nconst FULL_LINE_COMMENT = /^[ \\t]*\\/\\/.*$/gm\n// Built from PACKAGE_TYPES so a sixth type added to the config package cannot escape the reader.\nconst DECLARED_TYPE = new RegExp(`(?:^|[\\\\s{,])type:\\\\s*['\"](${PACKAGE_TYPES.join('|')})['\"]`, 'm')\n\n/**\n * The literal `type` declared in an `infra-kit.config.ts` source text, or undefined when it is\n * absent, computed, or not one of the known types.\n *\n * The config is read as text rather than imported: `require(esm)` is cached by the ESM loader, so a\n * rewritten config would keep returning its old value, and importing it would execute consumer code\n * (and its zod import) inside the ESLint process. Comments are stripped first so a commented-out\n * `// type: 'backend'` above the live literal cannot win; the first live match does.\n */\nexport const readDeclaredType = (text: string): PackageType | undefined => {\n const stripped = text.replace(BLOCK_COMMENT, '').replace(FULL_LINE_COMMENT, '')\n const literal = DECLARED_TYPE.exec(stripped)?.[1]\n\n return PACKAGE_TYPES.find((candidate) => {\n return candidate === literal\n })\n}\n\ninterface CachedType {\n /** `-1` when the config file is absent, so its later creation is a cache miss like any edit. */\n mtimeMs: number\n type: PackageType\n}\n\nconst typeCache = new Map<string, CachedType>()\n\nconst configMtimeMs = (configPath: string): number => {\n try {\n return fs.statSync(configPath).mtimeMs\n } catch {\n return -1\n }\n}\n\nconst readManifest = (manifestPath: string): PackageTypeManifest => {\n try {\n return JSON.parse(fs.readFileSync(manifestPath, 'utf8')) as PackageTypeManifest\n } catch {\n return {}\n }\n}\n\n/**\n * The package's type: the literal declared in its `infra-kit.config.ts` when there is one, else the\n * CLI's inference from directory and dependency signals.\n *\n * One `statSync` on the config per call is the steady-state cost; the text is re-read only when the\n * mtime moved, so a config edit is seen by the next lint of any file in the package \u2014 in a CLI run\n * or a long-lived IDE server alike. `package.json` is read once per root and never revalidated: it\n * only feeds the dependency fallback, and a dependency change is a `pnpm install` event, not an\n * edit-lint loop.\n */\nexport const resolvePackageType = (packageRoot: string): PackageType => {\n const configPath = path.posix.join(packageRoot, CONFIG_FILENAME)\n const mtimeMs = configMtimeMs(configPath)\n const hit = typeCache.get(packageRoot)\n\n if (hit !== undefined && hit.mtimeMs === mtimeMs) {\n return hit.type\n }\n\n const declaredType = mtimeMs >= 0 ? readDeclaredType(fs.readFileSync(configPath, 'utf8')) : undefined\n\n const type = detectPackageType({\n packageDir: packageRoot,\n repoRoot: findRepoRoot(packageRoot) ?? packageRoot,\n pkgJson: readManifest(path.posix.join(packageRoot, 'package.json')),\n declaredType,\n })\n\n typeCache.set(packageRoot, { mtimeMs, type })\n\n return type\n}\n\n/** Drops the root \u2192 type memo; only tests that build and tear down fixture trees need this. */\nexport const resetPackageTypeCache = (): void => {\n typeCache.clear()\n}\n", "import { findPackageRoot } from './package-root'\nimport { resolvePackageType } from './package-type-reader'\nimport { matchesAnyGlob } from './path-match'\n\n/** Where a feature's dumb components live \u2014 the default scope of the dumb-component rules. */\nexport const DUMB_COMPONENT_PATHS = ['**/features/*/components/**/*.tsx', '**/*-component.tsx']\n\n// Backends and Playwright suites render no React, so a `.tsx` there is never a UI component.\nconst NON_UI_TYPES = new Set(['backend', 'e2e'])\n\nconst STORY_OR_TEST_DIR = /(?:^|\\/)(?:__tests__|__stories__)\\//\nconst STORY_OR_TEST_EXT = /\\.(?:stories|test|spec)\\.[cm]?[jt]sx?$/\n\n/** Whether `filename` is a story or test file, which renders components without being one. */\nexport const isStoryOrTestFile = (filename: string): boolean => {\n return STORY_OR_TEST_DIR.test(filename) || STORY_OR_TEST_EXT.test(filename)\n}\n\n/** Whether `filename` sits in a package that can hold UI components (virtual filenames count). */\nexport const isUiPackageFile = (filename: string): boolean => {\n const packageRoot = findPackageRoot(filename)\n\n return packageRoot === null || !NON_UI_TYPES.has(resolvePackageType(packageRoot))\n}\n\n/** The shared `paths`/`ignore` gate: ignore wins, an empty `paths` matches everything. */\nexport const isInScope = (filename: string, paths: readonly string[], ignore: readonly string[]): boolean => {\n if (ignore.length > 0 && matchesAnyGlob(filename, ignore)) {\n return false\n }\n\n return paths.length === 0 || matchesAnyGlob(filename, paths)\n}\n", "import type * as ESTree from 'estree'\n\nimport type { ComponentFunction } from './component'\nimport { getComponentFunction, isComponent } from './component'\n\nexport interface ExportedComponent {\n /** Local (declared) name, or null for an anonymous default export. */\n name: string | null\n /** The identifier that declares the name, or null for an anonymous default export. */\n id: ESTree.Identifier | null\n /** The node a variable lookup resolves the declaration from (`getDeclaredVariables`). */\n declaration: ESTree.FunctionDeclaration | ESTree.VariableDeclarator | null\n fn: ComponentFunction\n}\n\ntype TopLevelStatement = ESTree.Statement | ESTree.ModuleDeclaration\n\nconst fromFunctionDeclaration = (node: ESTree.FunctionDeclaration): ExportedComponent | null => {\n if (!isComponent(node)) {\n return null\n }\n\n return { name: node.id?.name ?? null, id: node.id ?? null, declaration: node.id ? node : null, fn: node }\n}\n\nconst fromVariableDeclaration = (node: ESTree.VariableDeclaration): ExportedComponent[] => {\n return node.declarations.flatMap((declarator) => {\n const fn = getComponentFunction(declarator.init)\n\n if (!fn || declarator.id.type !== 'Identifier' || !isComponent(fn)) {\n return []\n }\n\n return [{ name: declarator.id.name, id: declarator.id, declaration: declarator, fn }]\n })\n}\n\nconst fromDeclaration = (node: ESTree.Node | null | undefined): ExportedComponent[] => {\n if (node?.type === 'FunctionDeclaration') {\n const component = fromFunctionDeclaration(node)\n\n return component ? [component] : []\n }\n\n if (node?.type === 'VariableDeclaration') {\n return fromVariableDeclaration(node)\n }\n\n return []\n}\n\n/** Top-level, non-exported component declarations by name, for resolving `export { X }`. */\nconst collectLocalComponents = (body: TopLevelStatement[]): Map<string, ExportedComponent> => {\n const local = new Map<string, ExportedComponent>()\n\n for (const statement of body) {\n for (const component of fromDeclaration(statement)) {\n if (component.name !== null) {\n local.set(component.name, component)\n }\n }\n }\n\n return local\n}\n\nconst fromDefaultExport = (\n declaration: ESTree.ExportDefaultDeclaration['declaration'],\n local: Map<string, ExportedComponent>,\n): ExportedComponent[] => {\n if (declaration.type === 'Identifier') {\n const component = local.get(declaration.name)\n\n return component ? [component] : []\n }\n\n const node = declaration as ESTree.Node\n\n if (node.type === 'FunctionDeclaration' && node.id) {\n return fromDeclaration(node)\n }\n\n const fn = getComponentFunction(node)\n\n return fn && isComponent(fn) ? [{ name: null, id: null, declaration: null, fn }] : []\n}\n\nconst fromStatement = (statement: TopLevelStatement, local: Map<string, ExportedComponent>): ExportedComponent[] => {\n if (statement.type === 'ExportDefaultDeclaration') {\n return fromDefaultExport(statement.declaration, local)\n }\n\n if (statement.type !== 'ExportNamedDeclaration') {\n return []\n }\n\n if (statement.declaration) {\n return fromDeclaration(statement.declaration)\n }\n\n // `export { X } from './x'` is declared in another module.\n if (statement.source) {\n return []\n }\n\n return statement.specifiers.flatMap((specifier) => {\n const component = specifier.local.type === 'Identifier' ? local.get(specifier.local.name) : undefined\n\n return component ? [component] : []\n })\n}\n\n/**\n * The React components a module exports: `export const X = ...`, `export function X`,\n * `export default function X`, and `export { X }` / `export default X` of a local component.\n */\nexport const collectExportedComponents = (program: ESTree.Program): ExportedComponent[] => {\n const local = collectLocalComponents(program.body)\n\n const found = program.body.flatMap((statement) => {\n return fromStatement(statement, local)\n })\n\n return [...new Set(found)]\n}\n", "import type { Rule, SourceCode } from 'eslint'\nimport type * as ESTree from 'estree'\n\nimport type { ComponentFunction } from '../../utils/component'\nimport { collectOwnReturnArguments, getAnnotatedParam } from '../../utils/component'\nimport { DUMB_COMPONENT_PATHS, isInScope, isStoryOrTestFile, isUiPackageFile } from '../../utils/component-file-scope'\nimport type { ExportedComponent } from '../../utils/exported-components'\nimport { collectExportedComponents } from '../../utils/exported-components'\n\ninterface Options {\n paths?: string[]\n ignore?: string[]\n}\n\n// TS and JSX nodes are not modelled by estree; these are the minimal structural views the rule reads.\ninterface TsMember {\n type: string\n computed?: boolean\n key?: { type: string; name?: string; value?: unknown }\n range: [number, number]\n loc: ESTree.SourceLocation\n}\n\ninterface TsType {\n type: string\n members?: TsMember[]\n types?: TsType[]\n typeName?: { type: string; name?: string }\n typeArguments?: unknown\n range: [number, number]\n loc: ESTree.SourceLocation\n}\n\ninterface TsDeclaration {\n type: string\n id?: { name?: string }\n body?: { body: TsMember[]; range: [number, number]; loc: ESTree.SourceLocation }\n extends?: unknown[]\n typeAnnotation?: TsType\n}\n\ninterface JsxNode {\n type: string\n name?: JsxNode & { name?: string | JsxNode }\n property?: JsxNode & { name?: string }\n openingElement?: JsxNode\n attributes?: JsxNode[]\n value?: { type: string; expression?: ESTree.Node } | null\n}\n\n/** Where `className?: string` can be appended: the member list and the braces around it. */\ninterface MemberContainer {\n members: TsMember[]\n body: { range: [number, number]; loc: ESTree.SourceLocation }\n}\n\n/** What is known about a props type: null when it cannot be resolved in this file. */\ntype PropsShape = { hasClassName: boolean; container: MemberContainer | null } | null\n\n/** How the root element can reach the prop: the `className` binding or `<object>.className`. */\ntype ClassNameBinding = { kind: 'identifier'; name: string } | { kind: 'member'; object: string }\n\nconst MAX_ALIAS_DEPTH = 5\n\nconst isClassNameMember = (member: TsMember): boolean => {\n if (member.type !== 'TSPropertySignature' || member.computed) {\n return false\n }\n\n return member.key?.name === 'className' || member.key?.value === 'className'\n}\n\nconst findTypeDeclaration = (program: ESTree.Program, name: string): TsDeclaration | null => {\n for (const statement of program.body) {\n const node = (\n statement.type === 'ExportNamedDeclaration' ? statement.declaration : statement\n ) as TsDeclaration | null\n\n if (\n (node?.type === 'TSInterfaceDeclaration' || node?.type === 'TSTypeAliasDeclaration') &&\n node.id?.name === name\n ) {\n return node\n }\n }\n\n return null\n}\n\nconst fromMembers = (members: TsMember[], body: MemberContainer['body']): PropsShape => {\n return { hasClassName: members.some(isClassNameMember), container: { members, body } }\n}\n\nconst fromIntersection = (shapes: PropsShape[]): PropsShape => {\n if (\n shapes.some((shape) => {\n return shape?.hasClassName\n })\n ) {\n return { hasClassName: true, container: null }\n }\n\n // An unresolved part (an imported base type) may well declare `className`.\n if (shapes.includes(null)) {\n return null\n }\n\n return {\n hasClassName: false,\n container:\n shapes.findLast((shape) => {\n return shape?.container\n })?.container ?? null,\n }\n}\n\nconst resolveShape = (program: ESTree.Program, type: TsType | undefined, depth: number): PropsShape => {\n if (!type || depth > MAX_ALIAS_DEPTH) {\n return null\n }\n\n if (type.type === 'TSTypeLiteral') {\n return fromMembers(type.members ?? [], type)\n }\n\n if (type.type === 'TSIntersectionType') {\n return fromIntersection(\n (type.types ?? []).map((part) => {\n return resolveShape(program, part, depth + 1)\n }),\n )\n }\n\n if (type.type !== 'TSTypeReference' || type.typeName?.type !== 'Identifier' || type.typeArguments) {\n return null\n }\n\n const declaration = findTypeDeclaration(program, type.typeName.name!)\n\n if (declaration?.type === 'TSTypeAliasDeclaration') {\n return resolveShape(program, declaration.typeAnnotation, depth + 1)\n }\n\n if (!declaration?.body) {\n return null\n }\n\n const shape = fromMembers(declaration.body.body, declaration.body)\n\n // An inherited `className` is invisible here; only an interface with no `extends` is conclusive.\n return shape?.hasClassName || !declaration.extends?.length ? shape : null\n}\n\nconst bindingFromObjectPattern = (pattern: ESTree.ObjectPattern): ClassNameBinding | null => {\n const destructured = pattern.properties.find((property) => {\n return (\n property.type === 'Property' &&\n !property.computed &&\n property.key.type === 'Identifier' &&\n property.key.name === 'className'\n )\n }) as ESTree.AssignmentProperty | undefined\n\n if (destructured) {\n const value = destructured.value.type === 'AssignmentPattern' ? destructured.value.left : destructured.value\n\n return value.type === 'Identifier' ? { kind: 'identifier', name: value.name } : null\n }\n\n const rest = pattern.properties.find((property) => {\n return property.type === 'RestElement'\n })\n\n return rest?.argument.type === 'Identifier' ? { kind: 'member', object: rest.argument.name } : null\n}\n\n/** `const { className } = props` statements at the top of the component body. */\nconst bindingsFromBody = (fn: ComponentFunction, propsName: string): ClassNameBinding[] => {\n const statements = fn.body.type === 'BlockStatement' ? fn.body.body : []\n\n return statements.flatMap((statement) => {\n if (statement.type !== 'VariableDeclaration') {\n return []\n }\n\n return statement.declarations.flatMap((declarator) => {\n const isPropsDestructure =\n declarator.id.type === 'ObjectPattern' &&\n declarator.init?.type === 'Identifier' &&\n declarator.init.name === propsName\n\n const binding = isPropsDestructure ? bindingFromObjectPattern(declarator.id as ESTree.ObjectPattern) : null\n\n return binding ? [binding] : []\n })\n })\n}\n\nconst getClassNameBindings = (fn: ComponentFunction): ClassNameBinding[] => {\n const param = fn.params[0]\n const pattern = param ? getAnnotatedParam(param) : null\n\n if (pattern?.type === 'Identifier') {\n return [{ kind: 'member', object: pattern.name }, ...bindingsFromBody(fn, pattern.name)]\n }\n\n const binding = pattern?.type === 'ObjectPattern' ? bindingFromObjectPattern(pattern) : null\n\n return binding ? [binding] : []\n}\n\nconst matchesBinding = (node: ESTree.Node, binding: ClassNameBinding): boolean => {\n if (binding.kind === 'identifier') {\n return node.type === 'Identifier' && node.name === binding.name\n }\n\n return (\n node.type === 'MemberExpression' &&\n !node.computed &&\n node.object.type === 'Identifier' &&\n node.object.name === binding.object &&\n node.property.type === 'Identifier' &&\n node.property.name === 'className'\n )\n}\n\nconst referencesBinding = (\n node: ESTree.Node,\n binding: ClassNameBinding,\n visitorKeys: SourceCode.VisitorKeys,\n): boolean => {\n if (matchesBinding(node, binding)) {\n return true\n }\n\n // A non-computed property name (`styles.className`, `{ className: x }`) is a label, not the binding.\n const label = node.type === 'MemberExpression' ? 'property' : 'key'\n\n const keys = (visitorKeys[node.type] ?? []).filter((key) => {\n return !(key === label && 'computed' in node && !node.computed)\n })\n\n return keys.some((key) => {\n const child = (node as unknown as Record<string, unknown>)[key]\n const children = (Array.isArray(child) ? child : [child]) as Array<ESTree.Node | null>\n\n return children.some((item) => {\n return item !== null && typeof item?.type === 'string' && referencesBinding(item, binding, visitorKeys)\n })\n })\n}\n\nconst isFragment = (element: JsxNode): boolean => {\n const name = element.openingElement?.name\n\n if (name?.type === 'JSXIdentifier') {\n return name.name === 'Fragment'\n }\n\n return name?.type === 'JSXMemberExpression' && name.property?.name === 'Fragment'\n}\n\n/** The single JSX element a component returns, or null when the root is not one plain element. */\nconst getRootElement = (fn: ComponentFunction): JsxNode | null => {\n const returns = collectOwnReturnArguments(fn)\n const root = returns.length === 1 ? (returns[0] as unknown as JsxNode) : null\n\n return root?.type === 'JSXElement' && !isFragment(root) ? root : null\n}\n\nconst buildMemberFix = (sourceCode: SourceCode, container: MemberContainer): Rule.ReportFixer => {\n return (fixer) => {\n const last = container.members.at(-1)\n\n if (!last) {\n return fixer.replaceTextRange(container.body.range, '{ className?: string }')\n }\n\n const separator = /[;,]$/.exec(sourceCode.text.slice(...last.range))?.[0] ?? ''\n\n if (container.body.loc.start.line === container.body.loc.end.line) {\n return fixer.insertTextAfterRange(\n last.range,\n separator ? ` className?: string${separator}` : '; className?: string',\n )\n }\n\n const indent = /^\\s*/.exec(sourceCode.lines[last.loc.start.line - 1]!)![0]\n\n return fixer.insertTextAfterRange(last.range, `\\n${indent}className?: string${separator}`)\n }\n}\n\nexport const componentClassname: Rule.RuleModule = {\n meta: {\n type: 'suggestion',\n fixable: 'code',\n docs: {\n description:\n 'Require a dumb component to declare a `className` prop and merge it into its root element (`className={cn(..., className)}`).',\n recommended: true,\n url: 'https://github.com/ArthurSaenz/infra-kit/tree/main/apps/infra-kit/eslint-plugin#component-classname',\n },\n schema: [\n {\n type: 'object',\n properties: {\n paths: {\n type: 'array',\n items: { type: 'string' },\n description: `Glob patterns of the files to check. Replaces the default (${DUMB_COMPONENT_PATHS.join(', ')}).`,\n },\n ignore: {\n type: 'array',\n items: { type: 'string' },\n description:\n 'Glob patterns of files to skip (e.g. svg sprites, icons), even if they also match `paths`. Stories and tests are always skipped.',\n },\n },\n additionalProperties: false,\n },\n ],\n messages: {\n missingClassNameProp:\n '`{{name}}` must accept a `className` prop: declare `className?: string` on its props type so callers can position it.',\n rootMissingClassName:\n \"The root element of `{{name}}` must merge the `className` prop, e.g. `className={cn('\u2026', className)}`.\",\n },\n },\n\n create(context) {\n const options = (context.options[0] ?? {}) as Options\n const filename = context.filename.split('\\\\').join('/')\n\n if (\n isStoryOrTestFile(filename) ||\n !isInScope(filename, options.paths ?? DUMB_COMPONENT_PATHS, options.ignore ?? []) ||\n !isUiPackageFile(filename)\n ) {\n return {}\n }\n\n const { sourceCode } = context\n\n const checkProps = (program: ESTree.Program, component: ExportedComponent, name: string): void => {\n const param = component.fn.params[0]\n\n if (!param) {\n context.report({ node: component.id ?? component.fn, messageId: 'missingClassNameProp', data: { name } })\n\n return\n }\n\n const annotation = (getAnnotatedParam(param) as { typeAnnotation?: { typeAnnotation?: TsType } }).typeAnnotation\n ?.typeAnnotation\n\n const shape = annotation ? resolveShape(program, annotation, 0) : null\n\n if (shape && !shape.hasClassName) {\n context.report({\n node: param,\n messageId: 'missingClassNameProp',\n data: { name },\n fix: shape.container ? buildMemberFix(sourceCode, shape.container) : null,\n })\n }\n }\n\n const checkRoot = (component: ExportedComponent, name: string): void => {\n const root = getRootElement(component.fn)\n const attributes = root?.openingElement?.attributes ?? []\n\n // A spread (`{...rest}`) may carry `className` through; it cannot be told apart statically.\n if (\n !root ||\n attributes.some((attribute) => {\n return attribute.type === 'JSXSpreadAttribute'\n })\n ) {\n return\n }\n\n const attribute = attributes.find((candidate) => {\n return candidate.type === 'JSXAttribute' && candidate.name?.name === 'className'\n })\n\n const bindings = getClassNameBindings(component.fn)\n\n const expression =\n attribute?.value?.type === 'JSXExpressionContainer' ? (attribute.value.expression ?? null) : null\n\n const merged =\n expression !== null &&\n bindings.some((binding) => {\n return referencesBinding(expression, binding, sourceCode.visitorKeys)\n })\n\n if (!merged) {\n context.report({\n node: (attribute ?? root.openingElement!.name!) as unknown as ESTree.Node,\n messageId: 'rootMissingClassName',\n data: { name },\n })\n }\n }\n\n return {\n Program(program) {\n for (const component of collectExportedComponents(program)) {\n const name = component.name ?? 'this component'\n\n checkProps(program, component, name)\n checkRoot(component, name)\n }\n },\n }\n },\n}\n", "import type { Rule } from 'eslint'\nimport type * as ESTree from 'estree'\n\nimport {\n declaresComponent,\n getComponentPropsTypeName,\n getDeclaredComponentName,\n unwrapExport,\n} from '../../utils/component'\nimport { matchesAnyGlob } from '../../utils/path-match'\n\ninterface Options {\n paths?: string[]\n ignore?: string[]\n}\n\n// TS-only nodes are not modelled by estree; access their identifier structurally.\ninterface NamedDeclaration {\n type: string\n id?: { name?: string } | null\n}\n\nconst PROPS_SUFFIX = 'Props'\n\n/**\n * Count the directive prologue \u2014 the leading run of string-literal expression statements\n * (`'use client'`, `'use server'`, `'use strict'`) at the top of the file. They are\n * legitimate file-leading content (like imports) and must not count as \"stray\" before the\n * props interface. Per the ECMAScript spec a directive is only one that *precedes* any other\n * statement, so we stop at the first non-string-literal statement rather than matching any\n * bare string anywhere in the body.\n */\nconst getDirectivePrologueCount = (body: Array<ESTree.Statement | ESTree.ModuleDeclaration>): number => {\n let count = 0\n\n for (const statement of body) {\n const isStringExpression =\n statement.type === 'ExpressionStatement' &&\n statement.expression.type === 'Literal' &&\n typeof statement.expression.value === 'string'\n\n if (!isStringExpression) {\n break\n }\n\n count += 1\n }\n\n return count\n}\n\n/**\n * The name of a top-level interface or type-alias declaration, or null when it is neither.\n * Unlike the props lookup, this is name-agnostic: any local type declaration is indexed so a\n * component can be matched against the type it actually references, whatever that type is called.\n */\nconst getTypeDeclName = (node: ESTree.Node | null): string | null => {\n if (!node) {\n return null\n }\n\n const named = node as NamedDeclaration\n\n if (named.type !== 'TSInterfaceDeclaration' && named.type !== 'TSTypeAliasDeclaration') {\n return null\n }\n\n return named.id?.name ?? null\n}\n\ninterface ComponentRef {\n index: number\n name: string | null\n // The type name the component uses for its props \u2014 resolved from its parameter annotation, or\n // the `<Name>Props` convention when the parameter carries no resolvable named type. Null when\n // neither is available (e.g. an anonymous component with no typed props parameter).\n propsName: string | null\n}\n\ninterface TopLevel {\n importIndices: number[]\n components: ComponentRef[]\n // First index of each top-level type declaration, keyed by its name.\n declIndexByName: Map<string, number>\n // Local binding names introduced by imports \u2014 used to detect a props type that is\n // imported (e.g. `import type { CompProps }`) rather than declared in the file.\n importedNames: Set<string>\n}\n\n/** Classify each top-level statement into imports, components, local type declarations, and import bindings. */\nconst collectTopLevel = (body: Array<ESTree.Statement | ESTree.ModuleDeclaration>): TopLevel => {\n const importIndices: number[] = []\n const components: ComponentRef[] = []\n const declIndexByName = new Map<string, number>()\n const importedNames = new Set<string>()\n\n for (const [index, statement] of body.entries()) {\n if (statement.type === 'ImportDeclaration') {\n importIndices.push(index)\n\n for (const specifier of statement.specifiers) {\n importedNames.add(specifier.local.name)\n }\n\n continue\n }\n\n const declaration = unwrapExport(statement)\n\n const declName = getTypeDeclName(declaration)\n\n if (declName !== null && !declIndexByName.has(declName)) {\n declIndexByName.set(declName, index)\n }\n\n if (declaresComponent(declaration)) {\n const name = getDeclaredComponentName(declaration)\n // Prefer the type the component's parameter actually references; fall back to the\n // `<Name>Props` convention only when no named parameter type is resolvable.\n const propsName = getComponentPropsTypeName(declaration) ?? (name === null ? null : `${name}${PROPS_SUFFIX}`)\n\n components.push({ index, name, propsName })\n }\n }\n\n return { importIndices, components, declIndexByName, importedNames }\n}\n\n/**\n * Whether any top-level statement in the half-open range `[directiveCount, boundary)` is a stray \u2014\n * i.e. not an import and not part of the leading directive prologue. `skipIndex` excludes a single\n * known-good statement (the component itself, when scanning the gap before its props interface).\n */\nconst hasStrayBefore = (\n body: Array<ESTree.Statement | ESTree.ModuleDeclaration>,\n boundary: number,\n directiveCount: number,\n skipIndex?: number,\n): boolean => {\n return body.some((statement, index) => {\n return index < boundary && index >= directiveCount && index !== skipIndex && statement.type !== 'ImportDeclaration'\n })\n}\n\ntype MessageId =\n | 'importsFirst'\n | 'interfaceImmediatelyBeforeComponent'\n | 'interfaceImmediatelyAfterImports'\n | 'componentImmediatelyAfterImports'\n\n// A pending report, expressed as a body index plus the message to raise against it. `data`\n// carries the identifier names interpolated into the message so an AI fix loop reads the\n// concrete interface/component to move \u2014 omitted for `importsFirst`, which stays generic.\ninterface Violation {\n index: number\n messageId: MessageId\n data?: Record<string, string>\n}\n\n// Fallback when a component is anonymous (e.g. `export default (props: Props) => \u2026`), matching\n// the `ANONYMOUS_NAME` convention the sibling rules use for a name-less component.\nconst ANONYMOUS_COMPONENT = 'component'\n\n/** Imports that sit after the first component (or its props interface) must move up. */\nconst findImportOrderViolations = (importIndices: number[], importBoundary: number): Violation[] => {\n return importIndices\n .filter((importIndex) => {\n return importIndex > importBoundary\n })\n .map((importIndex) => {\n return { index: importIndex, messageId: 'importsFirst' }\n })\n}\n\n/**\n * Each component's props type, when declared locally, must sit immediately before the component.\n * The type is matched by the name the component's parameter actually references, so an interface\n * named anything (`Props`, `UserCardProps`, ...) is judged \u2014 not just the `<Name>Props` convention.\n * A type referenced by more than one component is skipped: a single declaration cannot sit\n * immediately before two components, so adjacency is unenforceable and would misfire.\n */\nconst findAdjacencyViolations = (components: ComponentRef[], declIndexByName: Map<string, number>): Violation[] => {\n const violations: Violation[] = []\n\n const referenceCount = new Map<string, number>()\n\n for (const component of components) {\n if (component.propsName !== null) {\n referenceCount.set(component.propsName, (referenceCount.get(component.propsName) ?? 0) + 1)\n }\n }\n\n for (const component of components) {\n const propsName = component.propsName\n\n if (propsName === null || (referenceCount.get(propsName) ?? 0) > 1) {\n continue\n }\n\n const propsIndex = declIndexByName.get(propsName)\n\n if (propsIndex !== undefined && propsIndex !== component.index - 1) {\n violations.push({\n index: propsIndex,\n messageId: 'interfaceImmediatelyBeforeComponent',\n data: { interface: propsName, component: component.name ?? ANONYMOUS_COMPONENT },\n })\n }\n }\n\n return violations\n}\n\n/**\n * The first component is anchored to the import block: no stray top-level definition may wedge\n * between the imports and the props interface \u2014 or, when the props type is *imported* rather than\n * declared in the file, between the imports and the component itself. Only the first component is\n * anchored; later interfaces are governed solely by the adjacency check. Each `every` guard skips\n * when an import sits after its anchor, since that misorder is already reported by `importsFirst`.\n */\nconst findAnchorViolations = (\n body: Array<ESTree.Statement | ESTree.ModuleDeclaration>,\n directiveCount: number,\n importIndices: number[],\n first: ComponentRef,\n firstPropsName: string | null,\n firstPropsIndex: number | undefined,\n importedNames: Set<string>,\n): Violation[] => {\n const violations: Violation[] = []\n\n const importsBeforeInterface =\n firstPropsIndex !== undefined &&\n importIndices.every((importIndex) => {\n return importIndex < firstPropsIndex\n })\n\n if (importsBeforeInterface && hasStrayBefore(body, firstPropsIndex!, directiveCount, first.index)) {\n violations.push({\n index: firstPropsIndex!,\n messageId: 'interfaceImmediatelyAfterImports',\n // `firstPropsIndex !== undefined` implies `firstPropsName !== null` (it is derived from it).\n data: { interface: firstPropsName!, component: first.name ?? ANONYMOUS_COMPONENT },\n })\n }\n\n const firstPropsImported =\n firstPropsIndex === undefined && firstPropsName !== null && importedNames.has(firstPropsName)\n\n const importsBeforeComponent = importIndices.every((importIndex) => {\n return importIndex < first.index\n })\n\n if (firstPropsImported && importsBeforeComponent && hasStrayBefore(body, first.index, directiveCount)) {\n violations.push({\n index: first.index,\n messageId: 'componentImmediatelyAfterImports',\n // `firstPropsImported` requires `firstPropsName !== null`.\n data: { interface: firstPropsName!, component: first.name ?? ANONYMOUS_COMPONENT },\n })\n }\n\n return violations\n}\n\nexport const componentFileOrder: Rule.RuleModule = {\n meta: {\n type: 'suggestion',\n docs: {\n description:\n 'Enforce a strict top-level order in React component files: imports first, then \u2014 for each component \u2014 its props interface/type declared immediately before the component.',\n recommended: true,\n url: 'https://github.com/ArthurSaenz/infra-kit/tree/main/apps/infra-kit/eslint-plugin#component-file-order',\n },\n schema: [\n {\n type: 'object',\n properties: {\n paths: {\n type: 'array',\n items: { type: 'string' },\n description:\n 'Optional glob patterns. When provided, the rule only runs for files whose path matches one of them.',\n },\n ignore: {\n type: 'array',\n items: { type: 'string' },\n description:\n 'Optional glob patterns. The rule is skipped for files whose path matches one of them, even if it also matches `paths`.',\n },\n },\n additionalProperties: false,\n },\n ],\n messages: {\n // Generic on purpose: fires on a misplaced import, and the constraint is \"before *every*\n // component\", so naming a single component would mislead in a multi-component file.\n importsFirst: 'Imports must come before the component interface and declaration.',\n // \"props type\" (not \"interface\"): the rule matches both `interface` and `type` alias props\n // declarations, so the neutral term reads correctly for either.\n interfaceImmediatelyBeforeComponent:\n 'Declare the props type `{{interface}}` immediately before component `{{component}}` (no declarations between them).',\n interfaceImmediatelyAfterImports:\n 'Declare the props type `{{interface}}` (for component `{{component}}`) immediately after the imports, with no other declarations in between.',\n componentImmediatelyAfterImports:\n 'Props type `{{interface}}` is imported, so declare component `{{component}}` immediately after the imports, with no other declarations in between.',\n },\n },\n\n create(context) {\n const options = (context.options[0] ?? {}) as Options\n const paths = options.paths ?? []\n const ignore = options.ignore ?? []\n\n // `ignore` takes precedence: skip excluded files even when they also match `paths`.\n if (ignore.length > 0 && matchesAnyGlob(context.filename, ignore)) {\n return {}\n }\n\n if (paths.length > 0 && !matchesAnyGlob(context.filename, paths)) {\n return {}\n }\n\n return {\n Program(program) {\n const body = program.body\n\n // Leading directive prologue (`'use client'`, ...) \u2014 excluded from the stray checks.\n const directiveCount = getDirectivePrologueCount(body)\n\n const { importIndices, components, declIndexByName, importedNames } = collectTopLevel(body)\n\n // The rule only governs files that actually contain a component.\n if (components.length === 0) {\n return\n }\n\n const first = components[0]!\n const firstPropsName = first.propsName\n const firstPropsIndex = firstPropsName === null ? undefined : declIndexByName.get(firstPropsName)\n // `importBoundary` is intentionally directive-insensitive: a leading directive prologue\n // shifts every subsequent index up uniformly, so it never crosses this boundary. The\n // prologue is excluded only from the stray checks, where the raw index matters.\n const importBoundary = Math.min(first.index, firstPropsIndex ?? first.index)\n\n const violations = [\n ...findImportOrderViolations(importIndices, importBoundary),\n ...findAdjacencyViolations(components, declIndexByName),\n ...findAnchorViolations(\n body,\n directiveCount,\n importIndices,\n first,\n firstPropsName,\n firstPropsIndex,\n importedNames,\n ),\n ]\n\n for (const violation of violations) {\n context.report({ node: body[violation.index]!, messageId: violation.messageId, data: violation.data })\n }\n },\n }\n },\n}\n", "import type { Rule, Scope } from 'eslint'\nimport type * as ESTree from 'estree'\nimport path from 'node:path'\n\nimport { isInScope, isStoryOrTestFile, isUiPackageFile } from '../../utils/component-file-scope'\nimport type { ExportedComponent } from '../../utils/exported-components'\nimport { collectExportedComponents } from '../../utils/exported-components'\n\ninterface Options {\n paths?: string[]\n ignore?: string[]\n}\n\n// Route/page entry files and design-system primitives follow their framework's naming, not the\n// feature `*-component` / `*-container` convention.\n// Shared libraries (ui-kit, `lib/`) name files by concept, not by component; the convention binds\n// feature code and any file that already opts in with the suffix.\nexport const DEFAULT_PATHS = ['**/features/**', '**/*-component.tsx', '**/*-container.tsx']\n\nexport const DEFAULT_IGNORE = ['**/pages/**', '**/routes/**', '**/renderer/**', '**/primitives/**']\n\nconst SUFFIX_BY_DIR: Record<string, string> = {\n components: '-component',\n containers: '-container',\n}\n\nconst toPascalCase = (basename: string): string => {\n return basename\n .split(/[-_.]/)\n .filter(Boolean)\n .map((part) => {\n return part[0]!.toUpperCase() + part.slice(1)\n })\n .join('')\n}\n\n/**\n * The suffix the nearest `components/` or `containers/` folder inside a feature requires, or null elsewhere. Shared\n * `src/components/<name>/<name>.tsx` libraries follow their own folder-per-component layout.\n */\nconst requiredSuffix = (dirs: readonly string[]): { dir: string; suffix: string } | null => {\n const featureRoot = dirs.indexOf('features') + 2\n\n const index = dirs.findLastIndex((name, position) => {\n return name in SUFFIX_BY_DIR && featureRoot > 1 && position >= featureRoot\n })\n\n if (index === -1) {\n return null\n }\n\n const dir = dirs[index]!\n\n return { dir, suffix: SUFFIX_BY_DIR[dir]! }\n}\n\nconst findVariable = (sourceCode: Rule.RuleContext['sourceCode'], component: ExportedComponent) => {\n return sourceCode.getDeclaredVariables(component.declaration!).find((variable) => {\n return variable.name === component.name\n })\n}\n\nconst renameFix = (variable: Scope.Variable, expected: string): Rule.ReportFixer => {\n return (fixer) => {\n const nodes = [\n ...variable.identifiers,\n ...variable.references.map((reference) => {\n return reference.identifier\n }),\n ]\n\n // `export { X }` parses local and exported as two nodes over one range; one edit covers both.\n const ranges = new Map(\n nodes.map((node) => {\n return [node.range!.join(':'), node.range!] as const\n }),\n )\n\n return [...ranges.values()].map((range) => {\n return fixer.replaceTextRange(range, expected)\n })\n }\n}\n\nexport const componentNameMatchesFile: Rule.RuleModule = {\n meta: {\n type: 'suggestion',\n hasSuggestions: true,\n docs: {\n description:\n \"Require a `.tsx` file's exported component to be named after the file (`abroad-slider-component.tsx` \u2192 `AbroadSliderComponent`), and files under `components/` / `containers/` to end with `-component` / `-container`.\",\n recommended: true,\n url: 'https://github.com/ArthurSaenz/infra-kit/tree/main/apps/infra-kit/eslint-plugin#component-name-matches-file',\n },\n schema: [\n {\n type: 'object',\n properties: {\n paths: {\n type: 'array',\n items: { type: 'string' },\n description: `Glob patterns of files to check. Replaces the default (${DEFAULT_PATHS.join(', ')}).`,\n },\n ignore: {\n type: 'array',\n items: { type: 'string' },\n description: `Glob patterns of files to skip, even if they also match \\`paths\\`. Replaces the default (${DEFAULT_IGNORE.join(', ')}).`,\n },\n },\n additionalProperties: false,\n },\n ],\n messages: {\n nameMismatch: 'The exported component in `{{file}}` must be named `{{expected}}`, but it is named `{{actual}}`.',\n wrongSuffix: 'A file under `{{dir}}/` must be named `*{{suffix}}.tsx`, but it is `{{file}}`.',\n renameComponent: 'Rename `{{actual}}` to `{{expected}}`.',\n },\n },\n\n create(context) {\n const options = (context.options[0] ?? {}) as Options\n const filename = context.filename.split('\\\\').join('/')\n const file = path.posix.basename(filename)\n\n if (\n !file.endsWith('.tsx') ||\n file === 'index.tsx' ||\n isStoryOrTestFile(filename) ||\n !isInScope(filename, options.paths ?? DEFAULT_PATHS, options.ignore ?? DEFAULT_IGNORE) ||\n !isUiPackageFile(filename)\n ) {\n return {}\n }\n\n const basename = file.slice(0, -'.tsx'.length)\n const expected = toPascalCase(basename)\n\n return {\n Program(program) {\n const suffixRule = requiredSuffix(path.posix.dirname(filename).split('/'))\n\n if (suffixRule && !basename.endsWith(suffixRule.suffix)) {\n context.report({\n node: program,\n loc: { line: 1, column: 0 },\n messageId: 'wrongSuffix',\n data: { ...suffixRule, file },\n })\n }\n\n const named = collectExportedComponents(program).filter((component) => {\n return component.name !== null\n })\n\n // With several exports the intended one is ambiguous; `max-components-per-file` owns that case.\n if (named.length !== 1 || named[0]!.name === expected) {\n return\n }\n\n const component = named[0]!\n const actual = component.name!\n const variable = findVariable(context.sourceCode, component)\n const moduleScope = context.sourceCode.getScope(program).childScopes[0] ?? context.sourceCode.getScope(program)\n const nameTaken = moduleScope.set.has(expected)\n\n context.report({\n node: component.id as ESTree.Node,\n messageId: 'nameMismatch',\n data: { file, expected, actual },\n suggest:\n variable && !nameTaken\n ? [{ messageId: 'renameComponent', data: { actual, expected }, fix: renameFix(variable, expected) }]\n : [],\n })\n },\n }\n },\n}\n", "import type { Rule } from 'eslint'\nimport type * as ESTree from 'estree'\n\nimport { DUMB_COMPONENT_PATHS, isInScope, isStoryOrTestFile, isUiPackageFile } from '../../utils/component-file-scope'\n\ninterface Options {\n paths?: string[]\n ignore?: string[]\n allowHooks?: string[]\n}\n\n// React's local-state and DOM hooks: everything a dumb component needs without knowing about data.\nexport const DEFAULT_ALLOWED_HOOKS = [\n 'useState',\n 'useRef',\n 'useMemo',\n 'useCallback',\n 'useId',\n 'useEffect',\n 'useLayoutEffect',\n 'useImperativeHandle',\n]\n\nconst EFFECT_HOOKS = new Set(['useEffect', 'useLayoutEffect'])\nconst HOOK_NAME = /^use[A-Z]/\nconst ANALYTICS = /analytics/i\n\n/** `useX` for `useX(...)` and `React.useX(...)`, else null. */\nconst getHookName = (callee: ESTree.CallExpression['callee']): string | null => {\n if (callee.type === 'Identifier') {\n return HOOK_NAME.test(callee.name) ? callee.name : null\n }\n\n if (\n callee.type === 'MemberExpression' &&\n callee.object.type === 'Identifier' &&\n callee.object.name === 'React' &&\n callee.property.type === 'Identifier' &&\n HOOK_NAME.test(callee.property.name)\n ) {\n return callee.property.name\n }\n\n return null\n}\n\n/** Every identifier name along a callee chain: `window.analytics.track` \u2192 window, analytics, track. */\nconst calleeNames = (node: ESTree.Node): string[] => {\n if (node.type === 'Identifier') {\n return [node.name]\n }\n\n if (node.type === 'MemberExpression') {\n const property = !node.computed && node.property.type === 'Identifier' ? [node.property.name] : []\n\n return [...calleeNames(node.object), ...property]\n }\n\n return []\n}\n\nconst rootObjectName = (node: ESTree.Node): string | null => {\n if (node.type === 'Identifier') {\n return node.name\n }\n\n return node.type === 'MemberExpression' ? rootObjectName(node.object) : null\n}\n\nconst isSideEffectCall = (callee: ESTree.CallExpression['callee']): boolean => {\n if (callee.type === 'Identifier' && callee.name === 'fetch') {\n return true\n }\n\n if (callee.type === 'MemberExpression' && rootObjectName(callee) === 'httpClient') {\n return true\n }\n\n return calleeNames(callee).some((name) => {\n return ANALYTICS.test(name)\n })\n}\n\nexport const dumbComponentPurity: Rule.RuleModule = {\n meta: {\n type: 'problem',\n docs: {\n description:\n \"Keep dumb components pure: only React's local-state hooks are allowed, and effects may not fetch, call `httpClient` or send analytics.\",\n recommended: true,\n url: 'https://github.com/ArthurSaenz/infra-kit/tree/main/apps/infra-kit/eslint-plugin#dumb-component-purity',\n },\n schema: [\n {\n type: 'object',\n properties: {\n paths: {\n type: 'array',\n items: { type: 'string' },\n description: `Glob patterns of the files to check. Replaces the default (${DUMB_COMPONENT_PATHS.join(', ')}).`,\n },\n ignore: {\n type: 'array',\n items: { type: 'string' },\n description:\n 'Glob patterns of files to skip, even if they also match `paths`. Stories and tests are always skipped.',\n },\n allowHooks: {\n type: 'array',\n items: { type: 'string' },\n description: `Hooks allowed on top of the defaults (${DEFAULT_ALLOWED_HOOKS.join(', ')}), e.g. UI-library hooks like \\`useMediaQuery\\`.`,\n },\n },\n additionalProperties: false,\n },\n ],\n messages: {\n forbiddenHook:\n '\"{{hook}}\" is not in the allowed hook list for dumb components. Call it in the container and pass the value as a prop.',\n sideEffectInEffect:\n '`{{call}}` is a side effect a dumb component must not run. Move it to the container and pass a callback or the result as a prop.',\n },\n },\n\n create(context) {\n const options = (context.options[0] ?? {}) as Options\n const filename = context.filename.split('\\\\').join('/')\n\n if (\n isStoryOrTestFile(filename) ||\n !isInScope(filename, options.paths ?? DUMB_COMPONENT_PATHS, options.ignore ?? []) ||\n !isUiPackageFile(filename)\n ) {\n return {}\n }\n\n const allowed = new Set([...DEFAULT_ALLOWED_HOOKS, ...(options.allowHooks ?? [])])\n const effectCallbacks = new Set<ESTree.Node>()\n\n return {\n CallExpression(node) {\n const hook = getHookName(node.callee)\n\n if (hook !== null && !allowed.has(hook)) {\n context.report({ node: node.callee, messageId: 'forbiddenHook', data: { hook } })\n }\n\n if (hook !== null && EFFECT_HOOKS.has(hook) && node.arguments[0]) {\n effectCallbacks.add(node.arguments[0])\n }\n\n if (!isSideEffectCall(node.callee)) {\n return\n }\n\n // Effects are entered before their body is visited, so an enclosing callback is already registered.\n const inEffect = context.sourceCode.getAncestors(node).some((ancestor) => {\n return effectCallbacks.has(ancestor)\n })\n\n if (inEffect) {\n context.report({\n node: node.callee,\n messageId: 'sideEffectInEffect',\n data: { call: context.sourceCode.getText(node.callee) },\n })\n }\n },\n }\n },\n}\n", "import type { Rule } from 'eslint'\nimport type { CallExpression, Expression, Node, ObjectExpression, SpreadElement } from 'estree'\n\nimport { findPackageRoot } from './package-root'\nimport { resolvePackageType } from './package-type-reader'\n\nexport type PlaywrightCallKind = 'test' | 'describe'\n\n// Modifiers that keep a call a test / describe declaration; `step`, `use`, `beforeEach` and the\n// rest are not declarations and carry no title or tags of their own.\nconst TEST_MODIFIERS = new Set(['only', 'skip', 'fixme', 'fail'])\nconst DESCRIBE_MODIFIERS = new Set(['only', 'skip', 'fixme', 'serial', 'parallel'])\n\n/** `test.describe.serial` \u2192 `['test', 'describe', 'serial']`; null for anything but a plain name chain. */\nexport const calleeNames = (callee: Expression | Node): string[] | null => {\n if (callee.type === 'Identifier') {\n return [callee.name]\n }\n\n if (callee.type !== 'MemberExpression' || callee.computed || callee.property.type !== 'Identifier') {\n return null\n }\n\n const head = calleeNames(callee.object)\n\n return head === null ? null : [...head, callee.property.name]\n}\n\n/**\n * Whether `node` declares a Playwright test or describe block, read from its callee alone.\n *\n * @example\n * playwrightCallKind(parse(\"test.describe.serial('Checkout', () => {})\")) // => 'describe'\n */\nexport const playwrightCallKind = (node: CallExpression): PlaywrightCallKind | null => {\n const names = calleeNames(node.callee)\n\n if (names === null || names[0] !== 'test') {\n return null\n }\n\n const [, second, ...rest] = names\n\n if (second === undefined) {\n return 'test'\n }\n\n if (second === 'describe') {\n const isDescribe = rest.every((name) => {\n return DESCRIBE_MODIFIERS.has(name)\n })\n\n return isDescribe ? 'describe' : null\n }\n\n return rest.length === 0 && TEST_MODIFIERS.has(second) ? 'test' : null\n}\n\n/** The `{ tag, annotation }` details object, present only in the three-argument form. */\nexport const detailsArgument = (node: CallExpression): ObjectExpression | null => {\n const details: Expression | SpreadElement | undefined = node.arguments[1]\n\n return node.arguments.length >= 3 && details?.type === 'ObjectExpression' ? details : null\n}\n\n/** A title that is a plain string: a literal, or a template without expressions. */\nexport const staticTitle = (node: CallExpression): string | null => {\n const title = node.arguments[0]\n\n if (title?.type === 'Literal' && typeof title.value === 'string') {\n return title.value\n }\n\n if (title?.type === 'TemplateLiteral' && title.expressions.length === 0) {\n return title.quasis[0]?.value.cooked ?? null\n }\n\n return null\n}\n\n/** True when the linted file belongs to a package whose type resolves to `e2e`. */\n/** The callee chain of a top-level `test.*(\u2026)` statement, e.g. `['test', 'describe', 'configure']`. */\nexport const testStatementNames = (statement: Node): string[] | null => {\n if (statement.type !== 'ExpressionStatement' || statement.expression.type !== 'CallExpression') {\n return null\n }\n\n const names = calleeNames(statement.expression.callee)\n\n return names?.[0] === 'test' ? names : null\n}\n\nexport const isInE2ePackage = (context: Rule.RuleContext): boolean => {\n const packageRoot = findPackageRoot(context.filename.split('\\\\').join('/'))\n\n return packageRoot !== null && resolvePackageType(packageRoot) === 'e2e'\n}\n", "import type { Rule } from 'eslint'\nimport type * as ESTree from 'estree'\n\nimport { matchesAnyGlob } from '../../utils/path-match'\nimport { isInE2ePackage, playwrightCallKind, staticTitle, testStatementNames } from '../../utils/playwright-call'\n\nexport interface Options {\n /** Globs; the rule is skipped for matching files. */\n ignore?: string[]\n}\n\nconst SPEC_FILE = /\\.spec\\.[cm]?[jt]sx?$/\n\nconst SETUP_RANK = 0\nconst BODY_RANK = 5\nconst HOOK_RANK: Record<string, number> = { beforeAll: 1, beforeEach: 2, afterEach: 3, afterAll: 4 }\nconst SETUP_CALLS = new Set(['use', 'configure', 'setTimeout', 'slow'])\n// Without a test callback these annotate the block (`test.skip(isMobile, '\u2026')`) instead of declaring a test.\nconst ANNOTATION_CALLS = new Set(['skip', 'fixme', 'fail'])\n\nconst RANK_NAMES = ['setup', 'beforeAll hook', 'beforeEach hook', 'afterEach hook', 'afterAll hook', 'test']\n\ninterface Ranked {\n rank: number\n label: string\n}\n\nconst isFunction = (node: ESTree.Node | undefined): boolean => {\n return node?.type === 'ArrowFunctionExpression' || node?.type === 'FunctionExpression'\n}\n\nconst rankFor = (method: string, call: ESTree.CallExpression): number => {\n if (method in HOOK_RANK) {\n return HOOK_RANK[method]!\n }\n\n const declaresTest = call.arguments.slice(1).some(isFunction)\n\n return SETUP_CALLS.has(method) || (ANNOTATION_CALLS.has(method) && !declaresTest) ? SETUP_RANK : BODY_RANK\n}\n\n/** A statement's slot in a describe body, or null when it is not a `test.*` call. */\nconst rankOf = (statement: ESTree.Statement): Ranked | null => {\n const names = testStatementNames(statement)\n\n if (names === null) {\n return null\n }\n\n const call = (statement as ESTree.ExpressionStatement).expression as ESTree.CallExpression\n const rank = rankFor(names.at(-1)!, call)\n const title = rank === BODY_RANK ? staticTitle(call) : null\n const label = title === null ? `\\`${names.join('.')}\\`` : `\\`${names.join('.')}('${title}')\\``\n\n return { rank, label: `${label} (${RANK_NAMES[rank]})` }\n}\n\nconst describeBody = (call: ESTree.CallExpression): ESTree.Statement[] | null => {\n const callback = call.arguments.at(-1)\n\n if (callback?.type !== 'ArrowFunctionExpression' && callback?.type !== 'FunctionExpression') {\n return null\n }\n\n return callback.body.type === 'BlockStatement' ? callback.body.body : null\n}\n\nexport const e2eDescribeOrder: Rule.RuleModule = {\n meta: {\n type: 'suggestion',\n docs: {\n description:\n 'Order an e2e `test.describe` body: `test.use` / `configure` / annotations, then hooks beforeAll \u2192 beforeEach \u2192 afterEach \u2192 afterAll, then tests and nested describes.',\n recommended: true,\n url: 'https://github.com/ArthurSaenz/infra-kit/tree/main/apps/infra-kit/eslint-plugin#e2e-describe-order',\n },\n schema: [\n {\n type: 'object',\n properties: {\n ignore: {\n type: 'array',\n items: { type: 'string' },\n description: 'Optional globs; the rule is skipped for matching files.',\n },\n },\n additionalProperties: false,\n },\n ],\n messages: {\n outOfOrder:\n '{{label}} comes after {{afterLabel}} in describe {{describe}}. Order a describe body: `test.use` / `test.describe.configure` / annotations, then hooks beforeAll \u2192 beforeEach \u2192 afterEach \u2192 afterAll, then tests and nested describes.',\n },\n },\n\n create(context) {\n const options = (context.options[0] ?? {}) as Options\n const filename = context.filename.split('\\\\').join('/')\n\n if (!SPEC_FILE.test(filename) || (options.ignore?.length && matchesAnyGlob(filename, options.ignore))) {\n return {}\n }\n\n if (!isInE2ePackage(context)) {\n return {}\n }\n\n return {\n CallExpression(node) {\n const body = playwrightCallKind(node) === 'describe' ? describeBody(node) : null\n\n if (body === null) {\n return\n }\n\n const title = staticTitle(node)\n const describe = title === null ? 'block' : `'${title}'`\n let latest: Ranked | null = null\n\n for (const statement of body) {\n const ranked = rankOf(statement)\n\n if (ranked === null) {\n continue\n }\n\n if (latest !== null && ranked.rank < latest.rank) {\n context.report({\n node: statement,\n messageId: 'outOfOrder',\n data: {\n label: ranked.label,\n afterLabel: latest.label,\n describe,\n },\n })\n } else {\n latest = ranked\n }\n }\n },\n }\n },\n}\n", "import type { Rule } from 'eslint'\n\nimport { dirsUnderSrc, findPackageRoot } from '../../utils/package-root'\nimport { resolvePackageType } from '../../utils/package-type-reader'\nimport { matchesAnyGlob } from '../../utils/path-match'\n\nexport interface Options {\n /** Globs; the rule is skipped for matching files. */\n ignore?: string[]\n}\n\nconst TEST_FILE = /\\.(?:test|spec)\\.[cm]?[jt]sx?$/\nconst LEGACY_TEST_SUFFIX = /\\.test(\\.[cm]?[jt]sx?)$/\nconst SPEC_LAYERS = new Set(['tests', 'visual'])\n\n/** Support-file suffix \u2192 the domain subfolder it belongs in; anything unmatched is a domain helper. */\nconst SUBFOLDER_BY_SUFFIX: readonly (readonly [RegExp, string])[] = [\n [/\\.(?:page|component)\\.[cm]?[jt]sx?$/, 'pages'],\n [/\\.fixture\\.[cm]?[jt]sx?$/, 'fixtures'],\n [/\\.mock\\.[cm]?[jt]sx?$/, 'mocks'],\n [/\\.data\\.[cm]?[jt]sx?$/, 'data'],\n]\n\ntype MessageId = 'legacyTestSuffix' | 'specOutsideDomain' | 'nestedSpec' | 'supportInDomainRoot'\n\ninterface Violation {\n messageId: MessageId\n data: Record<string, string>\n}\n\nconst subfolderFor = (basename: string): string => {\n const match = SUBFOLDER_BY_SUFFIX.find(([pattern]) => {\n return pattern.test(basename)\n })\n\n return match ? match[1] : 'lib'\n}\n\nconst specViolation = (dirs: readonly string[], basename: string): Violation | null => {\n if (LEGACY_TEST_SUFFIX.test(basename)) {\n return {\n messageId: 'legacyTestSuffix',\n data: { basename, target: basename.replace(LEGACY_TEST_SUFFIX, '.spec$1') },\n }\n }\n\n const [layer, domain] = dirs\n\n if (layer === undefined || !SPEC_LAYERS.has(layer) || domain === undefined) {\n return { messageId: 'specOutsideDomain', data: { basename, path: ['src', ...dirs, basename].join('/') } }\n }\n\n if (dirs.length > 2) {\n return {\n messageId: 'nestedSpec',\n data: { basename, path: ['src', ...dirs, basename].join('/'), target: `src/${layer}/${domain}/${basename}` },\n }\n }\n\n return null\n}\n\nconst supportViolation = (dirs: readonly string[], basename: string): Violation | null => {\n const [layer, domain] = dirs\n\n if (dirs.length !== 2 || layer === undefined || !SPEC_LAYERS.has(layer) || domain === undefined) {\n return null\n }\n\n const subfolder = subfolderFor(basename)\n\n return {\n messageId: 'supportInDomainRoot',\n data: { basename, domain, subfolder, target: `src/${layer}/${domain}/${subfolder}/${basename}` },\n }\n}\n\n/** The layout problem with `filename`, or null when it is fine or not an e2e source file. */\nconst findViolation = (filename: string, ignore: readonly string[]): Violation | null => {\n if (ignore.length > 0 && matchesAnyGlob(filename, ignore)) {\n return null\n }\n\n const packageRoot = findPackageRoot(filename)\n\n if (packageRoot === null || resolvePackageType(packageRoot) !== 'e2e') {\n return null\n }\n\n const dirs = dirsUnderSrc(packageRoot, filename)\n\n if (dirs === null) {\n return null\n }\n\n const basename = filename.slice(filename.lastIndexOf('/') + 1)\n\n return TEST_FILE.test(basename) ? specViolation(dirs, basename) : supportViolation(dirs, basename)\n}\n\nexport const e2eFileLayout: Rule.RuleModule = {\n meta: {\n type: 'problem',\n docs: {\n description:\n 'Require e2e packages to keep `*.spec.ts` files at the root of `src/tests/<domain>/` and every other file in a domain subfolder.',\n recommended: true,\n url: 'https://github.com/ArthurSaenz/infra-kit/tree/main/apps/infra-kit/eslint-plugin#e2e-file-layout',\n },\n schema: [\n {\n type: 'object',\n properties: {\n ignore: {\n type: 'array',\n items: { type: 'string' },\n description: 'Optional globs; the rule is skipped for matching files.',\n },\n },\n additionalProperties: false,\n },\n ],\n messages: {\n legacyTestSuffix:\n '`{{basename}}` uses `.test`. Rename it to `{{target}}` \u2014 every Playwright spec in an e2e package is `*.spec.ts`.',\n specOutsideDomain:\n '`{{path}}` is a spec outside a domain folder. Move it into `src/tests/<domain>/`, where `<domain>` is the business domain it covers.',\n nestedSpec:\n '`{{path}}` nests a spec below its domain folder. Move it to `{{target}}`, or split the domain into two sibling domains if it holds too many specs.',\n supportInDomainRoot:\n '`{{basename}}` sits in the root of domain `{{domain}}`, which holds only `*.spec.ts`. Move it to `{{target}}`.',\n },\n },\n\n create(context) {\n const options = (context.options[0] ?? {}) as Options\n const violation = findViolation(context.filename.split('\\\\').join('/'), options.ignore ?? [])\n\n if (violation === null) {\n return {}\n }\n\n return {\n // Reported on Program: the violation is the file's location, not any node inside it.\n Program(program) {\n context.report({ node: program, messageId: violation.messageId, data: violation.data })\n },\n }\n },\n}\n", "import type { SourceCode } from 'eslint'\nimport type * as ESTree from 'estree'\n\n/**\n * Where `node` starts once its attached leading comments are included: the unbroken run of comments\n * directly above it, each on the line after the previous one ends. A comment separated by a blank\n * line (a file overview, a section banner) stays behind when the node moves.\n *\n * @example\n * attachedStart(sourceCode, node) // => range start of the JSDoc right above `node`, else of `node`\n */\nexport const attachedStart = (sourceCode: SourceCode, node: ESTree.Node): number => {\n const previousEndLine = sourceCode.getTokenBefore(node)?.loc.end.line ?? 0\n let start = node.range![0]\n let startLine = node.loc!.start.line\n\n for (const comment of sourceCode.getCommentsBefore(node).toReversed()) {\n if (comment.loc!.end.line < startLine - 1 || comment.loc!.start.line <= previousEndLine) {\n break\n }\n\n start = comment.range![0]\n startLine = comment.loc!.start.line\n }\n\n return start\n}\n", "import type { Rule, Scope, SourceCode } from 'eslint'\nimport type * as ESTree from 'estree'\n\nimport { attachedStart } from '../../utils/attached-comments'\nimport { matchesAnyGlob } from '../../utils/path-match'\nimport { isInE2ePackage, playwrightCallKind } from '../../utils/playwright-call'\n\nexport interface Options {\n /** Globs; the rule is skipped for matching files. */\n ignore?: string[]\n}\n\ntype Statement = ESTree.Statement | ESTree.ModuleDeclaration\ntype FileKind = 'pageObject' | 'fixture' | 'spec' | 'mock' | 'lib'\ntype AnchorKind = Exclude<FileKind, 'lib'>\n\n// TS-only nodes are not modelled by estree; read them structurally.\ninterface TsNode {\n type: string\n id?: { name?: string } | null\n static?: boolean\n value?: unknown\n typeArguments?: { params: TsNode[] }\n typeName?: { type: string; name?: string }\n types?: TsNode[]\n}\n\ninterface Anchor {\n index: number\n label: string\n /** Type names the anchor is declared with (a fixture's `extend<\u2026>` argument); they may precede it. */\n headerTypes: Set<string>\n}\n\nconst FILE_KIND: readonly (readonly [RegExp, FileKind])[] = [\n [/\\.(?:page|component)\\.[cm]?[jt]sx?$/, 'pageObject'],\n [/\\.fixture\\.[cm]?[jt]sx?$/, 'fixture'],\n [/\\.spec\\.[cm]?[jt]sx?$/, 'spec'],\n [/\\.mock\\.[cm]?[jt]sx?$/, 'mock'],\n]\n\nconst LIB_DIR = /\\/lib\\//\n// Fixed-content files with no single main declaration to lead with.\nconst UNORDERED_FILE = /\\.data\\.[cm]?[jt]sx?$/\n\nconst KIND_OPENING: Record<FileKind, string> = {\n pageObject: 'a page object file opens with its imports, then the class',\n fixture: 'a fixture file opens with its imports, then the fixtures type and the `extend` call',\n spec: 'a spec file opens with its imports, then its `test.*` calls',\n mock: 'a mock file opens with its imports, then the exported mock function',\n lib: 'a lib file opens with its imports, then its exports',\n}\n\nconst fileKindOf = (filename: string): FileKind | null => {\n const match = FILE_KIND.find(([pattern]) => {\n return pattern.test(filename)\n })\n\n if (match) {\n return match[1]\n }\n\n return LIB_DIR.test(filename) && !UNORDERED_FILE.test(filename) ? 'lib' : null\n}\n\nconst unwrapExport = (statement: Statement): ESTree.Node => {\n const isExport = statement.type === 'ExportNamedDeclaration' || statement.type === 'ExportDefaultDeclaration'\n\n return isExport && statement.declaration ? (statement.declaration as ESTree.Node) : statement\n}\n\n/** The root identifier of a call chain: `test` for `test.describe.configure(\u2026)`. */\nconst calleeRoot = (callee: ESTree.Node): string | null => {\n if (callee.type === 'Identifier') {\n return callee.name\n }\n\n if (callee.type === 'MemberExpression') {\n return calleeRoot(callee.object)\n }\n\n return callee.type === 'CallExpression' ? calleeRoot(callee.callee) : null\n}\n\nconst typeNamesOf = (node: TsNode | undefined): string[] => {\n if (node === undefined) {\n return []\n }\n\n if (node.type === 'TSTypeReference' && node.typeName?.type === 'Identifier') {\n return [node.typeName.name!]\n }\n\n return (node.types ?? []).flatMap(typeNamesOf)\n}\n\nconst pageObjectAnchor = (declaration: ESTree.Node, index: number): Anchor | null => {\n if (declaration.type !== 'ClassDeclaration') {\n return null\n }\n\n return { index, label: `class \\`${declaration.id?.name ?? 'default'}\\``, headerTypes: new Set() }\n}\n\nconst fixtureAnchor = (declaration: ESTree.Node, index: number): Anchor | null => {\n if (declaration.type !== 'VariableDeclaration') {\n return null\n }\n\n const [declarator] = declaration.declarations\n const init = declarator?.init\n\n if (init?.type !== 'CallExpression' || init.callee.type !== 'MemberExpression') {\n return null\n }\n\n const property = init.callee.property\n\n if (property.type !== 'Identifier' || property.name !== 'extend') {\n return null\n }\n\n const name = declarator!.id.type === 'Identifier' ? declarator!.id.name : 'test'\n const typeArguments = (init as unknown as TsNode).typeArguments?.params ?? []\n\n return { index, label: `fixture \\`${name}\\``, headerTypes: new Set(typeArguments.flatMap(typeNamesOf)) }\n}\n\nconst specAnchor = (statement: Statement, index: number): Anchor | null => {\n if (statement.type !== 'ExpressionStatement' || statement.expression.type !== 'CallExpression') {\n return null\n }\n\n if (calleeRoot(statement.expression.callee) !== 'test') {\n return null\n }\n\n return { index, label: 'the first `test.*` call', headerTypes: new Set() }\n}\n\nconst isFunctionValue = (node: ESTree.Node | null | undefined): boolean => {\n return node?.type === 'ArrowFunctionExpression' || node?.type === 'FunctionExpression'\n}\n\nconst mockAnchor = (statement: Statement, index: number): Anchor | null => {\n if (statement.type !== 'ExportNamedDeclaration' && statement.type !== 'ExportDefaultDeclaration') {\n return null\n }\n\n const declaration = unwrapExport(statement)\n\n if (declaration.type === 'FunctionDeclaration') {\n return { index, label: `mock \\`${declaration.id?.name ?? 'default'}\\``, headerTypes: new Set() }\n }\n\n const declarator = declaration.type === 'VariableDeclaration' ? declaration.declarations[0] : undefined\n\n if (declarator?.id.type !== 'Identifier' || !isFunctionValue(declarator.init)) {\n return null\n }\n\n return { index, label: `mock \\`${declarator.id.name}\\``, headerTypes: new Set() }\n}\n\nconst ANCHOR_FINDERS: Record<AnchorKind, (statement: Statement, index: number) => Anchor | null> = {\n pageObject: (statement, index) => {\n return pageObjectAnchor(unwrapExport(statement), index)\n },\n fixture: (statement, index) => {\n return fixtureAnchor(unwrapExport(statement), index)\n },\n spec: specAnchor,\n mock: mockAnchor,\n}\n\nconst findAnchor = (body: Statement[], kind: AnchorKind): Anchor | null => {\n for (const [index, statement] of body.entries()) {\n const anchor = ANCHOR_FINDERS[kind](statement, index)\n\n if (anchor !== null) {\n return anchor\n }\n }\n\n return null\n}\n\nconst isDirective = (statement: Statement): boolean => {\n return (\n statement.type === 'ExpressionStatement' &&\n statement.expression.type === 'Literal' &&\n typeof statement.expression.value === 'string'\n )\n}\n\ninterface Misplaced {\n candidates: number[]\n /** What the misplaced statements must follow, as the report names it. */\n target: string\n}\n\nconst anchoredCandidates = (body: Statement[], kind: AnchorKind): Misplaced | null => {\n const anchor = findAnchor(body, kind)\n\n if (anchor === null) {\n return null\n }\n\n const candidates = body.slice(0, anchor.index).flatMap((statement, index) => {\n const declaration = unwrapExport(statement) as TsNode\n\n const isHeader =\n statement.type === 'ImportDeclaration' ||\n isDirective(statement) ||\n (declaration.id?.name !== undefined && anchor.headerTypes.has(declaration.id.name))\n\n return isHeader ? [] : [index]\n })\n\n return { candidates, target: anchor.label }\n}\n\n/** Names a local `export { a, b as c }` list exports, so `const a` below counts as an export. */\nconst locallyExportedNames = (body: Statement[]): Set<string> => {\n const names = body.flatMap((statement) => {\n if (statement.type !== 'ExportNamedDeclaration' || statement.source) {\n return []\n }\n\n return statement.specifiers.flatMap((specifier) => {\n return specifier.local.type === 'Identifier' ? [specifier.local.name] : []\n })\n })\n\n return new Set(names)\n}\n\nconst declaredNames = (statement: Statement): string[] => {\n const declaration = unwrapExport(statement) as TsNode & ESTree.Node\n\n if (declaration.type === 'VariableDeclaration') {\n return declaration.declarations.flatMap((declarator) => {\n return declarator.id.type === 'Identifier' ? [declarator.id.name] : []\n })\n }\n\n return declaration.id?.name ? [declaration.id.name] : []\n}\n\n/** A lib file's private statements that sit above one of its exports. */\nconst libCandidates = (body: Statement[]): Misplaced | null => {\n const exportedNames = locallyExportedNames(body)\n\n const isExported = (statement: Statement): boolean => {\n return (\n statement.type.startsWith('Export') ||\n declaredNames(statement).some((name) => {\n return exportedNames.has(name)\n })\n )\n }\n\n const lastExport = body.findLastIndex(isExported)\n\n if (lastExport === -1) {\n return null\n }\n\n const candidates = body.slice(0, lastExport).flatMap((statement, index) => {\n return statement.type === 'ImportDeclaration' || isDirective(statement) || isExported(statement) ? [] : [index]\n })\n\n return { candidates, target: 'the exports' }\n}\n\nconst misplacedStatements = (body: Statement[], kind: FileKind): Misplaced | null => {\n return kind === 'lib' ? libCandidates(body) : anchoredCandidates(body, kind)\n}\n\n/**\n * Whether a function passed to \u2014 or invoked as \u2014 `call` runs as part of it. Playwright runs every\n * `test.*` callback later, except a `describe` body; any other callback (`forEach`, `map`, an IIFE)\n * is assumed to run on the spot.\n */\nconst runsWithCall = (fn: ESTree.Node, call: ESTree.CallExpression): boolean => {\n if (call.callee === fn || playwrightCallKind(call) === 'describe') {\n return true\n }\n\n return calleeRoot(call.callee) !== 'test'\n}\n\nconst isFunctionNode = (node: ESTree.Node): boolean => {\n return (\n node.type === 'ArrowFunctionExpression' || node.type === 'FunctionExpression' || node.type === 'FunctionDeclaration'\n )\n}\n\n/** Whether `node` is evaluated while the module loads, rather than later from a function or instance. */\nconst runsAtLoad = (node: ESTree.Node): boolean => {\n let child: ESTree.Node = node\n let parent = (node as Rule.Node).parent as ESTree.Node | null | undefined\n\n while (parent) {\n if (isFunctionNode(child)) {\n if (parent.type !== 'CallExpression' || !runsWithCall(child, parent)) {\n return false\n }\n }\n\n const tsParent = parent as unknown as TsNode\n\n if (tsParent.type === 'PropertyDefinition' && tsParent.value === child && !tsParent.static) {\n return false\n }\n\n child = parent\n parent = (parent as Rule.Node).parent as ESTree.Node | null | undefined\n }\n\n return true\n}\n\nconst topLevelIndex = (node: ESTree.Node, body: Statement[]): number => {\n let current = node as Rule.Node\n\n while (current.parent && current.parent.type !== 'Program') {\n current = current.parent\n }\n\n return body.indexOf(current as Statement)\n}\n\nconst valueReferences = (sourceCode: SourceCode, statement: Statement): Scope.Reference[] => {\n return sourceCode.getDeclaredVariables(unwrapExport(statement)).flatMap((variable) => {\n return variable.references.filter((reference) => {\n const tsReference = reference as Scope.Reference & { isValueReference?: boolean }\n\n return tsReference.isValueReference !== false && reference.identifier !== variable.identifiers[0]\n })\n })\n}\n\n/**\n * Narrows the stray candidates to the ones that can move to the end of the file. A binding stays\n * put when it is read while the module loads \u2014 a `describe` title, `test.use({\u2026})`, a loop inside\n * `describe`, a `static` field, an `extend` option \u2014 since a `const` below that point is in its TDZ.\n * Any read from a statement that stays counts, so a kept helper keeps what it closes over.\n */\nconst movableStrays = (sourceCode: SourceCode, body: Statement[], candidates: number[]): Set<number> => {\n const movable = new Set(candidates)\n let changed = true\n\n while (changed) {\n changed = false\n\n for (const index of movable) {\n const pinned = valueReferences(sourceCode, body[index]!).some((reference) => {\n const from = topLevelIndex(reference.identifier as ESTree.Node, body)\n\n return !movable.has(from) && (candidates.includes(from) || runsAtLoad(reference.identifier as ESTree.Node))\n })\n\n if (pinned) {\n movable.delete(index)\n changed = true\n }\n }\n }\n\n return movable\n}\n\nconst describeStatement = (statement: Statement): string => {\n const names = declaredNames(statement)\n\n if (names.length > 0) {\n return names\n .map((name) => {\n return `\\`${name}\\``\n })\n .join(', ')\n }\n\n return `a ${unwrapExport(statement).type} statement`\n}\n\n/** The statement's source range, widened over its attached comments and a same-line trailing one. */\nconst statementSpan = (sourceCode: SourceCode, statement: Statement): [number, number] => {\n const trailing = sourceCode.getCommentsAfter(statement).filter((comment) => {\n return comment.loc!.start.line === statement.loc!.end.line\n })\n\n return [attachedStart(sourceCode, statement), (trailing.at(-1) ?? statement).range![1]]\n}\n\nconst buildFix = (sourceCode: SourceCode, body: Statement[], movable: number[]): Rule.ReportFixer => {\n return (fixer) => {\n const spans = movable.map((index) => {\n return statementSpan(sourceCode, body[index]!)\n })\n\n const moved = spans.map(([start, end]) => {\n return sourceCode.text.slice(start, end)\n })\n\n const end = sourceCode.text.length\n const separator = sourceCode.text.endsWith('\\n') ? '\\n' : '\\n\\n'\n\n return [\n ...spans.map(([start, stop]) => {\n const next = sourceCode.text.slice(stop).search(/\\S/)\n\n return fixer.removeRange([start, next === -1 ? end : stop + next])\n }),\n fixer.insertTextAfterRange([end, end], `${separator}${moved.join('\\n\\n')}\\n`),\n ]\n }\n}\n\nexport const e2eFileOrder: Rule.RuleModule = {\n meta: {\n type: 'suggestion',\n fixable: 'code',\n docs: {\n description:\n 'Require e2e page objects, fixtures, specs, mocks and lib files to open with their imports followed by the class, the `extend` call, the `test.*` calls, the mock function or the exports \u2014 helpers and constants go below.',\n recommended: true,\n url: 'https://github.com/ArthurSaenz/infra-kit/tree/main/apps/infra-kit/eslint-plugin#e2e-file-order',\n },\n schema: [\n {\n type: 'object',\n properties: {\n ignore: {\n type: 'array',\n items: { type: 'string' },\n description: 'Optional globs; the rule is skipped for matching files.',\n },\n },\n additionalProperties: false,\n },\n ],\n messages: {\n strayBeforeAnchor:\n '{{name}} sits between the imports and {{anchor}}. Move it below {{anchor}}: {{opening}}. The autofix moves it to the end of the file.',\n },\n },\n\n create(context) {\n const options = (context.options[0] ?? {}) as Options\n const filename = context.filename.split('\\\\').join('/')\n const kind = fileKindOf(filename)\n\n if (kind === null || (options.ignore?.length && matchesAnyGlob(filename, options.ignore))) {\n return {}\n }\n\n if (!isInE2ePackage(context)) {\n return {}\n }\n\n return {\n Program(program) {\n const body = program.body as Statement[]\n const misplaced = misplacedStatements(body, kind)\n\n if (misplaced === null) {\n return\n }\n\n const movable = [...movableStrays(context.sourceCode, body, misplaced.candidates)].toSorted((a, b) => {\n return a - b\n })\n\n if (movable.length === 0) {\n return\n }\n\n const fix = buildFix(context.sourceCode, body, movable)\n\n for (const index of movable) {\n context.report({\n node: body[index]!,\n messageId: 'strayBeforeAnchor',\n data: { name: describeStatement(body[index]!), anchor: misplaced.target, opening: KIND_OPENING[kind] },\n fix,\n })\n }\n },\n }\n },\n}\n", "import type { Rule, SourceCode } from 'eslint'\nimport type * as ESTree from 'estree'\n\nimport { attachedStart } from '../../utils/attached-comments'\nimport { matchesAnyGlob } from '../../utils/path-match'\nimport { isInE2ePackage } from '../../utils/playwright-call'\n\nexport interface Options {\n /** Globs; the rule is skipped for matching files. */\n ignore?: string[]\n}\n\ntype Member = ESTree.MethodDefinition | ESTree.PropertyDefinition | ESTree.StaticBlock\n\n// TS-only member fields are not modelled by estree; read them structurally.\ninterface TsMember {\n type: string\n kind?: string\n accessibility?: 'public' | 'protected' | 'private'\n key?: ESTree.Node\n}\n\nconst PAGE_OBJECT_FILE = /\\.(?:page|component)\\.[cm]?[jt]sx?$/\n\nconst GROUPS = ['field', 'constructor', 'getter', 'public method', 'private method'] as const\n\ntype Group = (typeof GROUPS)[number]\n\nconst isPrivate = (member: TsMember): boolean => {\n return (\n member.accessibility === 'private' ||\n member.accessibility === 'protected' ||\n member.key?.type === 'PrivateIdentifier'\n )\n}\n\n/**\n * A member's group. A property is a field even when it holds an arrow function: properties initialize\n * in source order, so moving one past another could break an initializer that reads it.\n */\nconst groupOf = (member: TsMember): Group => {\n if (member.kind === 'constructor') {\n return 'constructor'\n }\n\n if (member.type !== 'MethodDefinition') {\n return 'field'\n }\n\n if (isPrivate(member)) {\n return 'private method'\n }\n\n return member.kind === 'get' || member.kind === 'set' ? 'getter' : 'public method'\n}\n\nconst memberName = (member: TsMember): string => {\n if (member.kind === 'constructor') {\n return 'the constructor'\n }\n\n const key = member.key\n\n if (key?.type === 'Identifier') {\n return `\\`${key.name}\\``\n }\n\n return key?.type === 'PrivateIdentifier' ? `\\`#${key.name}\\`` : 'a computed member'\n}\n\n/**\n * Reorders the members into the group order. Each member keeps its own comments; the text between\n * members (blank lines, indentation) stays where it was. Sorting is stable, so fields keep their\n * relative order and field initializers see the same `this` they did before.\n */\nconst buildFix = (sourceCode: SourceCode, members: Member[]): Rule.ReportFixer => {\n return (fixer) => {\n const spans = members.map((_, index) => {\n return [attachedStart(sourceCode, members[index]!), members[index]!.range![1]] as [number, number]\n })\n\n const texts = spans.map(([start, end]) => {\n return sourceCode.text.slice(start, end)\n })\n\n const order = members\n .map((member, index) => {\n return { index, rank: GROUPS.indexOf(groupOf(member as TsMember)) }\n })\n .toSorted((a, b) => {\n return a.rank - b.rank || a.index - b.index\n })\n\n return spans.map((span, slot) => {\n return fixer.replaceTextRange(span, texts[order[slot]!.index]!)\n })\n }\n}\n\ninterface Violation {\n member: Member\n group: Group\n after: Member\n afterGroup: Group\n}\n\nconst findViolations = (members: Member[]): Violation[] => {\n const violations: Violation[] = []\n let latest: { member: Member; group: Group } | null = null\n\n for (const member of members) {\n const group = groupOf(member as TsMember)\n\n if (latest !== null && GROUPS.indexOf(group) < GROUPS.indexOf(latest.group)) {\n violations.push({ member, group, after: latest.member, afterGroup: latest.group })\n } else {\n latest = { member, group }\n }\n }\n\n return violations\n}\n\nexport const e2ePageObjectMemberOrder: Rule.RuleModule = {\n meta: {\n type: 'suggestion',\n fixable: 'code',\n docs: {\n description:\n 'Order the members of an e2e page object: fields, the constructor, getters, public methods, then private methods.',\n recommended: true,\n url: 'https://github.com/ArthurSaenz/infra-kit/tree/main/apps/infra-kit/eslint-plugin#e2e-page-object-member-order',\n },\n schema: [\n {\n type: 'object',\n properties: {\n ignore: {\n type: 'array',\n items: { type: 'string' },\n description: 'Optional globs; the rule is skipped for matching files.',\n },\n },\n additionalProperties: false,\n },\n ],\n messages: {\n outOfOrder:\n 'The {{group}} {{name}} comes after the {{afterGroup}} {{afterName}} in class `{{className}}`. Order a page object: fields, constructor, getters, public methods, private methods.',\n },\n },\n\n create(context) {\n const options = (context.options[0] ?? {}) as Options\n const filename = context.filename.split('\\\\').join('/')\n\n if (!PAGE_OBJECT_FILE.test(filename) || (options.ignore?.length && matchesAnyGlob(filename, options.ignore))) {\n return {}\n }\n\n if (!isInE2ePackage(context)) {\n return {}\n }\n\n const check = (node: ESTree.ClassDeclaration | ESTree.ClassExpression): void => {\n const members = node.body.body as Member[]\n const violations = findViolations(members)\n\n if (violations.length === 0) {\n return\n }\n\n const fix = buildFix(context.sourceCode, members)\n\n for (const violation of violations) {\n context.report({\n node: violation.member,\n messageId: 'outOfOrder',\n data: {\n group: violation.group,\n name: memberName(violation.member as TsMember),\n afterGroup: violation.afterGroup,\n afterName: memberName(violation.after as TsMember),\n className: node.id?.name ?? 'anonymous',\n },\n fix,\n })\n }\n }\n\n return {\n ClassDeclaration: check,\n ClassExpression: check,\n }\n },\n}\n", "import type { Rule } from 'eslint'\nimport type { Expression, Node, ObjectExpression, SpreadElement } from 'estree'\n\nimport { detailsArgument, isInE2ePackage, playwrightCallKind } from '../../utils/playwright-call'\n\nexport interface Options {\n /** The only tags a test or describe may carry. */\n allowed?: string[]\n}\n\nexport const DEFAULT_ALLOWED_TAGS = ['@smoke', '@readonly', '@mocked', '@slow']\n\n/** The `tag` property's value node, or null when the details object has none. */\nconst tagValue = (details: ObjectExpression): Expression | null => {\n for (const property of details.properties) {\n if (\n property.type === 'Property' &&\n !property.computed &&\n property.key.type === 'Identifier' &&\n property.key.name === 'tag'\n ) {\n return property.value as Expression\n }\n }\n\n return null\n}\n\n/** String-literal tags with their nodes; non-literal entries (a shared constant) are not judged. */\nconst literalTags = (value: Expression): { tag: string; node: Node }[] => {\n const entries: (Expression | SpreadElement | null)[] = value.type === 'ArrayExpression' ? value.elements : [value]\n\n return entries.flatMap((entry) => {\n return entry?.type === 'Literal' && typeof entry.value === 'string' ? [{ tag: entry.value, node: entry }] : []\n })\n}\n\nexport const e2eTestTags: Rule.RuleModule = {\n meta: {\n type: 'problem',\n docs: {\n description: 'Restrict Playwright test and describe tags in e2e packages to an allowed set.',\n recommended: true,\n url: 'https://github.com/ArthurSaenz/infra-kit/tree/main/apps/infra-kit/eslint-plugin#e2e-test-tags',\n },\n schema: [\n {\n type: 'object',\n properties: {\n allowed: {\n type: 'array',\n items: { type: 'string', pattern: '^@' },\n uniqueItems: true,\n description: 'The only tags allowed; defaults to @smoke, @readonly, @mocked, @slow.',\n },\n },\n additionalProperties: false,\n },\n ],\n messages: {\n unknownTag:\n 'Tag `{{tag}}` is not an allowed e2e tag. Use one of {{allowed}}; browsers, devices and environments are Playwright projects, not tags.',\n },\n },\n\n create(context) {\n if (!isInE2ePackage(context)) {\n return {}\n }\n\n const options = (context.options[0] ?? {}) as Options\n const allowed = new Set(options.allowed ?? DEFAULT_ALLOWED_TAGS)\n\n const allowedList = [...allowed]\n .map((tag) => {\n return `\\`${tag}\\``\n })\n .join(', ')\n\n return {\n CallExpression(node) {\n const details = playwrightCallKind(node) === null ? null : detailsArgument(node)\n const value = details === null ? null : tagValue(details)\n\n if (value === null) {\n return\n }\n\n for (const { tag, node: tagNode } of literalTags(value)) {\n if (!allowed.has(tag)) {\n context.report({ node: tagNode, messageId: 'unknownTag', data: { tag, allowed: allowedList } })\n }\n }\n },\n }\n },\n}\n", "import type { Rule } from 'eslint'\n\nimport { isInE2ePackage, playwrightCallKind, staticTitle } from '../../utils/playwright-call'\n\nconst SHOULD_PREFIX = /^should\\s+/i\n\nexport const e2eTestTitle: Rule.RuleModule = {\n meta: {\n type: 'suggestion',\n docs: {\n description: 'Require e2e test titles to state the behaviour directly, without a leading `should`.',\n recommended: true,\n url: 'https://github.com/ArthurSaenz/infra-kit/tree/main/apps/infra-kit/eslint-plugin#e2e-test-title',\n },\n schema: [],\n messages: {\n shouldPrefix:\n 'Test title \"{{title}}\" starts with `should`. State the behaviour and its observable outcome directly: \"{{suggested}}\".',\n },\n },\n\n create(context) {\n if (!isInE2ePackage(context)) {\n return {}\n }\n\n return {\n CallExpression(node) {\n const title = playwrightCallKind(node) === 'test' ? staticTitle(node) : null\n\n if (title === null || !SHOULD_PREFIX.test(title)) {\n return\n }\n\n context.report({\n node: node.arguments[0] ?? node,\n messageId: 'shouldPrefix',\n data: { title, suggested: title.replace(SHOULD_PREFIX, '') },\n })\n },\n }\n },\n}\n", "import type { Rule, SourceCode } from 'eslint'\nimport type * as ESTree from 'estree'\n\nimport { attachedStart } from '../../utils/attached-comments'\nimport { matchesAnyGlob } from '../../utils/path-match'\nimport { isInE2ePackage, playwrightCallKind, staticTitle, testStatementNames } from '../../utils/playwright-call'\n\nexport interface Options {\n /** Globs; the rule is skipped for matching files. */\n ignore?: string[]\n /** Top-level `test.describe` blocks a spec may hold. */\n max?: number\n}\n\nconst SPEC_FILE = /\\.spec\\.[cm]?[jt]sx?$/\nconst DEFAULT_MAX = 1\n\ntype Statement = ESTree.Statement | ESTree.ModuleDeclaration\n\ninterface TopLevelCall {\n statement: ESTree.ExpressionStatement\n call: ESTree.CallExpression\n names: string[]\n}\n\nconst topLevelCalls = (body: Statement[]): TopLevelCall[] => {\n return body.flatMap((statement) => {\n const names = testStatementNames(statement)\n\n if (names === null) {\n return []\n }\n\n const expressionStatement = statement as ESTree.ExpressionStatement\n\n return [{ statement: expressionStatement, call: expressionStatement.expression as ESTree.CallExpression, names }]\n })\n}\n\nconst describeLabel = (call: ESTree.CallExpression): string => {\n const title = staticTitle(call)\n\n return title === null ? 'the `test.describe` block' : `\\`test.describe('${title}')\\``\n}\n\nconst callbackBlock = (call: ESTree.CallExpression): ESTree.BlockStatement | null => {\n const callback = call.arguments.at(-1)\n\n if (callback?.type !== 'ArrowFunctionExpression' && callback?.type !== 'FunctionExpression') {\n return null\n }\n\n return callback.body.type === 'BlockStatement' ? callback.body : null\n}\n\n/** The statement's range, widened over its attached comments and the whitespace that follows it. */\nconst removalRange = (sourceCode: SourceCode, statement: Statement): [number, number] => {\n const end = statement.range![1]\n const next = sourceCode.text.slice(end).search(/\\S/)\n\n return [attachedStart(sourceCode, statement), next === -1 ? sourceCode.text.length : end + next]\n}\n\n/**\n * Moves every top-level `test.use` / `configure` / hook / annotation into the one describe, at the\n * start of its body and in source order. Equivalent while the spec has a single describe: each of\n * them then applies to exactly the tests it applied to before.\n */\nconst buildFix = (sourceCode: SourceCode, moved: TopLevelCall[], block: ESTree.BlockStatement): Rule.ReportFixer => {\n return (fixer) => {\n // The describe is top-level, so an empty body indents one level from column 0.\n const indent = ' '.repeat(block.body[0]?.loc?.start.column ?? 2)\n\n const texts = moved.map(({ statement }) => {\n const [start] = removalRange(sourceCode, statement)\n\n return sourceCode.text\n .slice(start, statement.range![1])\n .split('\\n')\n .map((line) => {\n return line === '' ? line : `${indent}${line}`\n })\n .join('\\n')\n })\n\n return [\n ...moved.map(({ statement }) => {\n return fixer.removeRange(removalRange(sourceCode, statement))\n }),\n fixer.insertTextAfterRange([block.range![0], block.range![0] + 1], `\\n${texts.join('\\n\\n')}\\n`),\n ]\n }\n}\n\nexport const e2eTopLevelDescribe: Rule.RuleModule = {\n meta: {\n type: 'suggestion',\n fixable: 'code',\n docs: {\n description:\n 'Require an e2e spec to hold one top-level `test.describe`, with its `test.use`, `configure`, hooks and tests inside it.',\n recommended: true,\n url: 'https://github.com/ArthurSaenz/infra-kit/tree/main/apps/infra-kit/eslint-plugin#e2e-top-level-describe',\n },\n schema: [\n {\n type: 'object',\n properties: {\n ignore: {\n type: 'array',\n items: { type: 'string' },\n description: 'Optional globs; the rule is skipped for matching files.',\n },\n max: {\n type: 'integer',\n minimum: 1,\n description: 'Top-level `test.describe` blocks a spec may hold.',\n },\n },\n additionalProperties: false,\n },\n ],\n messages: {\n extraDescribe:\n '{{describe}} is top-level describe number {{count}} in this spec; the limit is {{max}}. Move it to its own spec file, or nest it inside {{first}}.',\n outsideDescribe:\n '`{{call}}` sits at the top level of the spec. Move it inside {{describe}}: a spec holds one top-level describe, and its setup, hooks and tests live inside it.',\n testOutsideDescribe:\n 'Test {{test}} sits at the top level of the spec. Wrap the spec\u2019s tests in a `test.describe` named after the feature they cover.',\n },\n },\n\n create(context) {\n const options = (context.options[0] ?? {}) as Options\n const filename = context.filename.split('\\\\').join('/')\n\n if (!SPEC_FILE.test(filename) || (options.ignore?.length && matchesAnyGlob(filename, options.ignore))) {\n return {}\n }\n\n if (!isInE2ePackage(context)) {\n return {}\n }\n\n const max = options.max ?? DEFAULT_MAX\n\n return {\n Program(program) {\n const calls = topLevelCalls(program.body as Statement[])\n\n const describes = calls.filter(({ call }) => {\n return playwrightCallKind(call) === 'describe'\n })\n\n const tests = calls.filter(({ call }) => {\n return (\n playwrightCallKind(call) === 'test' &&\n call.arguments.slice(1).some((argument) => {\n return argument.type === 'ArrowFunctionExpression' || argument.type === 'FunctionExpression'\n })\n )\n })\n\n const setup = calls.filter((entry) => {\n return !describes.includes(entry) && !tests.includes(entry)\n })\n\n for (const [index, extra] of describes.slice(max).entries()) {\n context.report({\n node: extra.statement,\n messageId: 'extraDescribe',\n data: {\n describe: describeLabel(extra.call),\n count: String(max + index + 1),\n max: String(max),\n first: describeLabel(describes[0]!.call),\n },\n })\n }\n\n for (const test of tests) {\n const title = staticTitle(test.call)\n\n context.report({\n node: test.statement,\n messageId: 'testOutsideDescribe',\n data: { test: title === null ? `\\`${test.names.join('.')}\\`` : `'${title}'` },\n })\n }\n\n const [only] = describes\n const block = describes.length === 1 && only ? callbackBlock(only.call) : null\n const fix = block === null ? undefined : buildFix(context.sourceCode, setup, block)\n\n for (const entry of setup) {\n context.report({\n node: entry.statement,\n messageId: 'outsideDescribe',\n data: {\n call: entry.names.join('.'),\n describe: only ? describeLabel(only.call) : 'a `test.describe` block',\n },\n fix,\n })\n }\n },\n }\n },\n}\n", "import type { Rule } from 'eslint'\nimport fs from 'node:fs'\nimport path from 'node:path'\n\nimport { isUiPackageFile } from '../../utils/component-file-scope'\nimport { fileDirsUnderSrc, srcDirOf } from '../../utils/import-target'\nimport { matchesAnyGlob } from '../../utils/path-match'\n\ninterface Options {\n /** File names (without extension) allowed directly in a feature root, on top of the defaults. */\n extraRootFiles?: string[]\n /** File names (without extension) allowed directly in a feature's `services/`, on top of the defaults. */\n extraServiceFiles?: string[]\n paths?: string[]\n ignore?: string[]\n}\n\nexport const ROOT_FILES = ['index', 'types', 'services', 'analytics', 'constants', 'translates']\nexport const SERVICE_FILES = ['main', 'api', 'libs', 'index', 'types', 'constants']\n\nconst SERVICES = 'services'\nconst TEST_OR_STORY_DIR = /\\/__(?:tests|stories)__\\//\nconst EXEMPT_FILE = /\\.(?:(?:test|spec|stories)\\.[cm]?[jt]sx?|d\\.[cm]?ts)$/\n\nconst stemOf = (basename: string): string => {\n return basename.slice(0, basename.length - path.posix.extname(basename).length)\n}\n\nconst describeAllowed = (stems: readonly string[]): string => {\n return stems\n .map((stem) => {\n return `${stem}.ts`\n })\n .join(', ')\n}\n\ninterface Violation {\n messageId: 'unknownRootFile' | 'unknownServiceFile' | 'servicesFileAndFolder'\n data: Record<string, string>\n}\n\n/** `features/<feature>/services.*` or anything under `features/<feature>/services/`. */\nconst isServiceFile = (filename: string, dirs: readonly string[]): boolean => {\n return dirs[2] === SERVICES || (dirs.length === 2 && stemOf(path.posix.basename(filename)) === SERVICES)\n}\n\n/** `dirs` are the file's directories under `src/`, starting `['features', <feature>]`. */\nconst findNameViolation = (filename: string, dirs: readonly string[], options: Options): Violation | null => {\n const basename = path.posix.basename(filename)\n const stem = stemOf(basename)\n\n if (dirs.length === 2) {\n const allowed = [...ROOT_FILES, ...(options.extraRootFiles ?? [])]\n\n if (!allowed.includes(stem)) {\n return { messageId: 'unknownRootFile', data: { file: basename, allowed: describeAllowed(allowed) } }\n }\n\n // A rule sees one file at a time, so the sibling folder is only visible on disk.\n if (stem === SERVICES && fs.existsSync(path.posix.join(path.posix.dirname(filename), SERVICES))) {\n return { messageId: 'servicesFileAndFolder', data: { feature: dirs[1]! } }\n }\n\n return null\n }\n\n // Deeper folders under `services/` are not judged; other segments are package-structure's concern.\n if (dirs.length === 3 && dirs[2] === SERVICES) {\n const allowed = [...SERVICE_FILES, ...(options.extraServiceFiles ?? [])]\n\n if (!allowed.includes(stem)) {\n return { messageId: 'unknownServiceFile', data: { file: basename, allowed: describeAllowed(allowed) } }\n }\n }\n\n return null\n}\n\nexport const featureFiles: Rule.RuleModule = {\n meta: {\n type: 'problem',\n docs: {\n description:\n 'Allow only the conventional files in a feature root and its `services/`, one of `services.ts` or `services/`, and no JSX in services.',\n recommended: true,\n url: 'https://github.com/ArthurSaenz/infra-kit/tree/main/apps/infra-kit/eslint-plugin#feature-files',\n },\n schema: [\n {\n type: 'object',\n properties: {\n extraRootFiles: {\n type: 'array',\n items: { type: 'string', minLength: 1 },\n uniqueItems: true,\n description: `File names without extension allowed in a feature root besides ${ROOT_FILES.join(', ')}.`,\n },\n extraServiceFiles: {\n type: 'array',\n items: { type: 'string', minLength: 1 },\n uniqueItems: true,\n description: `File names without extension allowed in \\`services/\\` besides ${SERVICE_FILES.join(', ')}.`,\n },\n paths: {\n type: 'array',\n items: { type: 'string' },\n description:\n 'Optional glob patterns. When provided, the rule only runs for files whose path matches one of them.',\n },\n ignore: {\n type: 'array',\n items: { type: 'string' },\n description:\n 'Optional glob patterns. The rule is skipped for files whose path matches one of them, even if it also matches `paths`.',\n },\n },\n additionalProperties: false,\n },\n ],\n messages: {\n unknownRootFile: '\"{{file}}\" is not an allowed feature-root file. Allowed: {{allowed}}.',\n unknownServiceFile: '\"{{file}}\" is not an allowed file in `services/`. Allowed: {{allowed}}.',\n servicesFileAndFolder:\n 'Feature \"{{feature}}\" has both `services.ts` and a `services/` folder. Keep one: move this file into `services/main.ts`, or fold the folder into this file.',\n jsxInService: 'Services hold atoms and pure functions; JSX belongs in a component or container.',\n },\n },\n\n create(context) {\n const options = (context.options[0] ?? {}) as Options\n const filename = context.filename.split('\\\\').join('/')\n const paths = options.paths ?? []\n const ignore = options.ignore ?? []\n\n if (ignore.length > 0 && matchesAnyGlob(filename, ignore)) {\n return {}\n }\n\n if (paths.length > 0 && !matchesAnyGlob(filename, paths)) {\n return {}\n }\n\n if (TEST_OR_STORY_DIR.test(filename) || EXEMPT_FILE.test(filename)) {\n return {}\n }\n\n const srcDir = srcDirOf(filename)\n\n if (srcDir === null) {\n return {}\n }\n\n const dirs = fileDirsUnderSrc(filename, srcDir)\n\n if (dirs[0] !== 'features' || dirs.length < 2 || !isUiPackageFile(filename)) {\n return {}\n }\n\n const violation = findNameViolation(filename, dirs, options)\n const listeners: Rule.RuleListener = {}\n\n if (violation !== null) {\n // Reported on Program, like package-structure: the file's name is the problem, not a line in it.\n listeners.Program = (program) => {\n context.report({ ...violation, node: program })\n }\n }\n\n if (isServiceFile(filename, dirs)) {\n let reported = false\n\n const reportJsx = (node: Rule.Node): void => {\n if (!reported) {\n reported = true\n context.report({ node, messageId: 'jsxInService' })\n }\n }\n\n Object.assign(listeners, { JSXElement: reportJsx, JSXFragment: reportJsx })\n }\n\n return listeners\n },\n}\n", "import type { Rule } from 'eslint'\nimport path from 'node:path'\n\nimport { findPackageRoot } from './package-root'\nimport { resolvePackageType } from './package-type-reader'\nimport { matchesAnyGlob } from './path-match'\n\nexport const DEFAULT_ROOT_ALIAS = '#root'\n\nconst INDEX_FILE = /^index(?:\\.[cm]?[jt]sx?)?$/\n\n/** An import-like node whose module path is a string literal, with the literal node to report on. */\nexport interface ImportSource {\n specifier: string\n node: Rule.Node\n typeOnly: boolean\n}\n\ninterface SourceLiteral {\n type: string\n value?: unknown\n literal?: { value?: unknown }\n}\n\nconst literalValue = (source: SourceLiteral | null | undefined): string | null => {\n if (source === null || source === undefined) {\n return null\n }\n\n // `typeof import('x')` wraps the literal in a TSLiteralType; every other carrier holds it directly.\n const value = source.type === 'TSLiteralType' ? source.literal?.value : source.value\n\n return typeof value === 'string' ? value : null\n}\n\ninterface SpecifierLike {\n importKind?: string\n exportKind?: string\n}\n\nconst allSpecifiersAreTypes = (specifiers: readonly SpecifierLike[] | undefined, key: keyof SpecifierLike): boolean => {\n return (\n specifiers !== undefined &&\n specifiers.length > 0 &&\n specifiers.every((specifier) => {\n return specifier[key] === 'type'\n })\n )\n}\n\ninterface ImportLikeNode {\n type: string\n source?: SourceLiteral | null\n argument?: SourceLiteral\n importKind?: string\n exportKind?: string\n specifiers?: SpecifierLike[]\n}\n\n/**\n * The module path an import-like node names, or null for a node without a static string path\n * (`import(name)`, a template literal, a local `export { a }`). `typeof import('x')` counts and is\n * type-only: hulyo reaches into feature internals that way, past every import-statement rule.\n */\nexport const readImportSource = (node: Rule.Node): ImportSource | null => {\n const candidate = node as unknown as ImportLikeNode\n // typescript-eslint 8 moved TSImportType's path from `argument` to `source`; read either.\n const sourceNode = candidate.type === 'TSImportType' ? (candidate.source ?? candidate.argument) : candidate.source\n const specifier = literalValue(sourceNode)\n\n if (specifier === null || sourceNode === null || sourceNode === undefined) {\n return null\n }\n\n const typeOnly =\n candidate.type === 'TSImportType' ||\n candidate.importKind === 'type' ||\n candidate.exportKind === 'type' ||\n allSpecifiersAreTypes(candidate.specifiers, candidate.type === 'ImportDeclaration' ? 'importKind' : 'exportKind')\n\n return { specifier, node: sourceNode as unknown as Rule.Node, typeOnly }\n}\n\n/** The `src` directory of the package `filename` lives in, or null when it is not under one. */\nexport const srcDirOf = (filename: string): string | null => {\n const packageRoot = findPackageRoot(filename)\n\n if (packageRoot !== null) {\n return filename.startsWith(`${packageRoot}/src/`) ? `${packageRoot}/src` : null\n }\n\n // Virtual filenames (RuleTester, `<input>`) have no package on disk: the innermost `src/` stands in.\n const index = filename.lastIndexOf('/src/')\n\n return index >= 0 ? filename.slice(0, index + '/src'.length) : null\n}\n\n/**\n * Where `specifier` points, as the path segments under `srcDir` \u2014 `['features', 'user']` for\n * `#root/features/user` or `../../features/user`. Null for a package import, another alias, or a\n * relative path that climbs out of `src/`: those have no layer.\n */\nexport const resolveUnderSrc = (\n filename: string,\n srcDir: string,\n specifier: string,\n rootAlias: string,\n): string[] | null => {\n let absolute: string\n\n if (specifier === rootAlias || specifier.startsWith(`${rootAlias}/`)) {\n absolute = path.posix.join(srcDir, specifier.slice(rootAlias.length))\n } else if (specifier.startsWith('.')) {\n absolute = path.posix.resolve(path.posix.dirname(filename), specifier)\n } else {\n return null\n }\n\n if (!absolute.startsWith(`${srcDir}/`)) {\n return null\n }\n\n return absolute.slice(srcDir.length + 1).split('/')\n}\n\n/** Path segments of `filename`'s directory under `srcDir`. */\nexport const fileDirsUnderSrc = (filename: string, srcDir: string): string[] => {\n return filename\n .slice(srcDir.length + 1)\n .split('/')\n .slice(0, -1)\n}\n\n/** `features/<name>` or `features/<name>/index.*` \u2014 the only paths that form a feature's public API. */\nexport const isFeaturePublicApi = (target: readonly string[]): boolean => {\n return target.length === 2 || (target.length === 3 && INDEX_FILE.test(target[2]!))\n}\n\n/** The feature name a src-relative path sits in (`features/<name>/\u2026`), or null outside `features/`. */\nexport const featureNameOf = (segments: readonly string[]): string | null => {\n return segments[0] === 'features' && segments.length >= 2 ? segments[1]! : null\n}\n\n/**\n * Every node kind that names a module: static imports, re-exports, dynamic `import('x')` and the\n * type-level `typeof import('x')`. A rule registers one handler for all of them.\n */\nexport const IMPORT_SELECTORS = [\n 'ImportDeclaration',\n 'ExportNamedDeclaration',\n 'ExportAllDeclaration',\n 'ImportExpression',\n 'TSImportType',\n] as const\n\n// Backends and Playwright suites have no UI layering; their `src/` folders mean something else.\nconst UNLAYERED_TYPES = new Set(['backend', 'e2e'])\n\n/** Whether the src-layout import rules apply to `filename`: not ignored, not in a backend or e2e package. */\nexport const isLayeredFile = (filename: string, ignore: readonly string[]): boolean => {\n if (ignore.length > 0 && matchesAnyGlob(filename, ignore)) {\n return false\n }\n\n const packageRoot = findPackageRoot(filename)\n\n return packageRoot === null || !UNLAYERED_TYPES.has(resolvePackageType(packageRoot))\n}\n", "import type { Rule } from 'eslint'\n\nimport {\n DEFAULT_ROOT_ALIAS,\n IMPORT_SELECTORS,\n featureNameOf,\n fileDirsUnderSrc,\n isFeaturePublicApi,\n isLayeredFile,\n readImportSource,\n resolveUnderSrc,\n srcDirOf,\n} from '../../utils/import-target'\n\nexport interface Options {\n /** The alias that maps to the package's `src/`. */\n rootAlias?: string\n /** Globs; the rule is skipped for matching files. */\n ignore?: string[]\n}\n\nexport const featurePublicApi: Rule.RuleModule = {\n meta: {\n type: 'problem',\n docs: {\n description:\n 'Require code outside a feature to import it only through its public API (`features/<name>` / its `index`), whatever the path form.',\n recommended: true,\n url: 'https://github.com/ArthurSaenz/infra-kit/tree/main/apps/infra-kit/eslint-plugin#feature-public-api',\n },\n schema: [\n {\n type: 'object',\n properties: {\n rootAlias: { type: 'string', description: 'The alias that maps to `src/` (default `#root`).' },\n ignore: {\n type: 'array',\n items: { type: 'string' },\n description: 'Optional globs; the rule is skipped for matching files.',\n },\n },\n additionalProperties: false,\n },\n ],\n messages: {\n deepImport:\n '`{{specifier}}` reaches into the internals of feature `{{feature}}`. Import from its public API `{{publicApi}}` instead, exporting what you need from `features/{{feature}}/index.ts`.',\n },\n },\n\n create(context) {\n const options = (context.options[0] ?? {}) as Options\n const filename = context.filename.split('\\\\').join('/')\n const srcDir = srcDirOf(filename)\n\n if (srcDir === null || !isLayeredFile(filename, options.ignore ?? [])) {\n return {}\n }\n\n const rootAlias = options.rootAlias ?? DEFAULT_ROOT_ALIAS\n const ownFeature = featureNameOf(fileDirsUnderSrc(filename, srcDir))\n\n const check = (node: Rule.Node): void => {\n const source = readImportSource(node)\n const target = source === null ? null : resolveUnderSrc(filename, srcDir, source.specifier, rootAlias)\n const feature = target === null ? null : featureNameOf(target)\n\n if (source === null || feature === null || feature === ownFeature || isFeaturePublicApi(target!)) {\n return\n }\n\n context.report({\n node: source.node,\n messageId: 'deepImport',\n data: { specifier: source.specifier, feature, publicApi: `${rootAlias}/features/${feature}` },\n })\n }\n\n return Object.fromEntries(\n IMPORT_SELECTORS.map((selector) => {\n return [selector, check]\n }),\n )\n },\n}\n", "import type { Rule } from 'eslint'\n\nimport {\n DEFAULT_ROOT_ALIAS,\n IMPORT_SELECTORS,\n fileDirsUnderSrc,\n isLayeredFile,\n readImportSource,\n resolveUnderSrc,\n srcDirOf,\n} from '../../utils/import-target'\n\nexport interface Options {\n /** Folders under `src/`, lowest level first; folders in one inner array share a level. */\n layers?: string[][]\n /** Type-only imports carry no runtime edge, so they may point at any level. */\n allowTypeImports?: boolean\n /** The alias that maps to the package's `src/`. */\n rootAlias?: string\n /** Globs; the rule is skipped for matching files. */\n ignore?: string[]\n /** Folders whose subfolders may not import each other (`commands/a` \u2192 `commands/b`). */\n isolate?: string[]\n}\n\n// `renderer` and `mobile` are entry points like `app`: they mount pages, nothing imports them.\n// A test assembles its own environment (global styles, app providers) the way an entry point does,\n// and it is not part of the runtime graph the layers protect.\nconst TEST_FILE = /\\.(?:test|spec)\\.[cm]?[jt]sx?$/\n\nconst isTestFile = (filename: string): boolean => {\n return filename.includes('/__tests__/') || TEST_FILE.test(filename)\n}\n\nexport const DEFAULT_LAYERS: string[][] = [\n ['lib', 'components', 'shared', 'assets', 'styles', 'data'],\n ['core', 'entities'],\n ['features'],\n ['pages', 'routes'],\n ['app', 'renderer', 'mobile'],\n]\n\nconst levelIndex = (layers: readonly string[][]): Map<string, number> => {\n return new Map(\n layers.flatMap((level, index) => {\n return level.map((layer): [string, number] => {\n return [layer, index]\n })\n }),\n )\n}\n\nconst describeOrder = (layers: readonly string[][]): string => {\n return layers\n .map((level) => {\n return level.join(', ')\n })\n .join(' \u2192 ')\n}\n\nexport const layerImports: Rule.RuleModule = {\n meta: {\n type: 'problem',\n docs: {\n description:\n 'Allow imports only to the same or a lower layer of `src/` (lib/components \u2192 entities \u2192 features \u2192 pages/routes \u2192 app).',\n recommended: true,\n url: 'https://github.com/ArthurSaenz/infra-kit/tree/main/apps/infra-kit/eslint-plugin#layer-imports',\n },\n schema: [\n {\n type: 'object',\n properties: {\n layers: {\n type: 'array',\n items: { type: 'array', items: { type: 'string' }, minItems: 1 },\n minItems: 1,\n description: 'Folders under `src/`, lowest level first; folders in one inner array share a level.',\n },\n allowTypeImports: {\n type: 'boolean',\n description: 'Whether type-only imports may point at a higher layer (default true).',\n },\n rootAlias: { type: 'string', description: 'The alias that maps to `src/` (default `#root`).' },\n ignore: {\n type: 'array',\n items: { type: 'string' },\n description: 'Optional globs; the rule is skipped for matching files.',\n },\n isolate: {\n type: 'array',\n items: { type: 'string' },\n description: 'Folders whose subfolders may not import each other (`commands/a` \u2192 `commands/b`).',\n },\n },\n additionalProperties: false,\n },\n ],\n messages: {\n upward:\n '`{{fromLayer}}` cannot import `{{specifier}}` from the higher layer `{{toLayer}}`. Layers import only their own level or below: {{order}}. Move the shared code down into a lower layer, or pass it in from above.',\n sibling:\n '`{{fromLayer}}/{{fromUnit}}` cannot import `{{specifier}}` from its sibling `{{fromLayer}}/{{toUnit}}`: folders under `{{fromLayer}}/` are isolated from each other. Move the shared code down into a lower layer, or pass it in from above.',\n },\n },\n\n create(context) {\n const options = (context.options[0] ?? {}) as Options\n const filename = context.filename.split('\\\\').join('/')\n const srcDir = srcDirOf(filename)\n\n if (srcDir === null || isTestFile(filename) || !isLayeredFile(filename, options.ignore ?? [])) {\n return {}\n }\n\n const layers = options.layers ?? DEFAULT_LAYERS\n const levels = levelIndex(layers)\n const [fromLayer, fromUnit] = fileDirsUnderSrc(filename, srcDir)\n const fromLevel = fromLayer === undefined ? undefined : levels.get(fromLayer)\n\n // A file directly in `src/` (main.tsx) or in an unlisted folder has no level to compare against.\n if (fromLayer === undefined || fromLevel === undefined) {\n return {}\n }\n\n const allowTypeImports = options.allowTypeImports ?? true\n const rootAlias = options.rootAlias ?? DEFAULT_ROOT_ALIAS\n const isolated = fromUnit !== undefined && (options.isolate ?? []).includes(fromLayer)\n\n const check = (node: Rule.Node): void => {\n const source = readImportSource(node)\n\n if (source === null || (allowTypeImports && source.typeOnly)) {\n return\n }\n\n const [toLayer, toUnit] = resolveUnderSrc(filename, srcDir, source.specifier, rootAlias) ?? []\n const toLevel = toLayer === undefined ? undefined : levels.get(toLayer)\n\n if (isolated && toLayer === fromLayer && toUnit !== undefined && toUnit !== fromUnit) {\n context.report({\n node: source.node,\n messageId: 'sibling',\n data: { fromLayer, fromUnit: fromUnit!, toUnit, specifier: source.specifier },\n })\n\n return\n }\n\n if (toLevel === undefined || toLevel <= fromLevel) {\n return\n }\n\n context.report({\n node: source.node,\n messageId: 'upward',\n data: { fromLayer, toLayer: toLayer!, specifier: source.specifier, order: describeOrder(layers) },\n })\n }\n\n return Object.fromEntries(\n IMPORT_SELECTORS.map((selector) => {\n return [selector, check]\n }),\n )\n },\n}\n", "import type { Rule } from 'eslint'\nimport type * as ESTree from 'estree'\n\nimport { getComponentFunction, getComponentName, isComponent, unwrapExport } from '../../utils/component'\nimport type { ComponentFunction } from '../../utils/component'\nimport { matchesAnyGlob } from '../../utils/path-match'\n\ninterface Options {\n maxComponents?: number\n paths?: string[]\n ignore?: string[]\n}\n\n// Default ceiling on component declarations in a single file. Tunable via the\n// `maxComponents` option; the value is a convention nudge (\"split this file\"),\n// not a hard truth.\nconst DEFAULT_MAX_COMPONENTS = 4\n\n// Fallback used when the offending component is anonymous (e.g.\n// `export default () => <div />`), since `getComponentName` returns null rather\n// than a placeholder in that case.\nconst ANONYMOUS_NAME = 'component'\n\n/** The component function(s) declared by a single top-level declaration. */\nconst componentFunctionsIn = (declaration: ESTree.Node): ComponentFunction[] => {\n if (declaration.type === 'FunctionDeclaration') {\n return isComponent(declaration) ? [declaration] : []\n }\n\n if (declaration.type === 'VariableDeclaration') {\n return declaration.declarations\n .map((declarator) => {\n return getComponentFunction(declarator.init)\n })\n .filter((fn): fn is ComponentFunction => {\n return fn !== null && isComponent(fn)\n })\n }\n\n // e.g. `export default memo(() => \u2026)`.\n const fn = getComponentFunction(declaration)\n\n return fn && isComponent(fn) ? [fn] : []\n}\n\n/**\n * Every component declared at the TOP LEVEL of the program body (mirrors\n * `max-jsx-return-size` and `component-arrow-function`). Multi-declarator\n * declarations (`const A = \u2026, B = \u2026`) count each component separately;\n * re-exports (`export { X } from './x'`) declare nothing and are not counted.\n * Nested/in-render components are deliberately out of scope \u2014 that is a\n * different concern (component identity/perf), not file organisation.\n *\n * Returns the component *functions* (not just a count) so a future export-aware\n * variant \u2014 count only non-exported helpers \u2014 is an additive change, not a\n * rewrite.\n */\nconst collectComponents = (body: Array<ESTree.Statement | ESTree.ModuleDeclaration>): ComponentFunction[] => {\n return body.flatMap((statement) => {\n const declaration = unwrapExport(statement)\n\n return declaration ? componentFunctionsIn(declaration) : []\n })\n}\n\nexport const maxComponentsPerFile: Rule.RuleModule = {\n meta: {\n type: 'suggestion',\n docs: {\n description:\n 'Limit the number of React components declared in a single file; move extra components into their own files.',\n recommended: true,\n url: 'https://github.com/ArthurSaenz/infra-kit/tree/main/apps/infra-kit/eslint-plugin#max-components-per-file',\n },\n schema: [\n {\n type: 'object',\n properties: {\n maxComponents: {\n type: 'integer',\n minimum: 1,\n description: 'Maximum number of component declarations a single file may contain before the rule reports.',\n },\n paths: {\n type: 'array',\n items: { type: 'string' },\n description:\n 'Optional glob patterns. When provided, the rule only runs for files whose path matches one of them.',\n },\n ignore: {\n type: 'array',\n items: { type: 'string' },\n description:\n 'Optional glob patterns. The rule is skipped for files whose path matches one of them, even if it also matches `paths`.',\n },\n },\n additionalProperties: false,\n },\n ],\n messages: {\n // File-scoped problem \u2192 reported once, anchored to the first component over\n // the limit so a human or AI fix loop has a concrete node to move out.\n tooManyComponents:\n 'This file declares {{count}} components (max {{max}}); move components such as {{name}} into separate files.',\n },\n },\n\n create(context) {\n const options = (context.options[0] ?? {}) as Options\n const max = options.maxComponents ?? DEFAULT_MAX_COMPONENTS\n const paths = options.paths ?? []\n const ignore = options.ignore ?? []\n\n // `ignore` takes precedence: skip excluded files even when they also match `paths`.\n if (ignore.length > 0 && matchesAnyGlob(context.filename, ignore)) {\n return {}\n }\n\n if (paths.length > 0 && !matchesAnyGlob(context.filename, paths)) {\n return {}\n }\n\n return {\n Program(program) {\n const components = collectComponents(program.body)\n\n if (components.length <= max) {\n return\n }\n\n // The first component beyond the limit: a real, moveable node, and the\n // single report keeps one file-scoped problem from emitting N squiggles\n // (there is no autofix to justify multiplicity). `length > max` guarantees\n // this index exists; the guard satisfies `noUncheckedIndexedAccess`.\n const offender = components[max]\n\n if (!offender) {\n return\n }\n\n const name = getComponentName(offender) ?? ANONYMOUS_NAME\n\n context.report({\n node: offender,\n messageId: 'tooManyComponents',\n data: { count: components.length, max, name },\n })\n },\n }\n },\n}\n", "import type { Rule } from 'eslint'\nimport type * as ESTree from 'estree'\n\ninterface Options {\n maxLines?: number\n maxExampleLines?: number\n exemptTags?: string[]\n}\n\n// Prose budget = total lines MINUS `@example` body lines. Simulated against the real rule\n// semantics over the linted corpus (6108 blocks across the source repo + its five sync\n// targets; evidence brief \u00A74c): 15 \u2192 125 reports / 113 unique / 2.12% of linted blocks \u2014\n// a normal lint-rule yield, roughly one sprint of cleanup. 20 \u2192 47 reports, too thin to\n// change behaviour; 12 \u2192 235, more than one sprint.\n// NOTE: the brief's \u00A72 figure (\"183 at cap 15\") measures raw BLOCK length, not this budget.\nconst DEFAULT_MAX_LINES = 15\n\n// `@example` body length across the 637 example-carrying blocks (brief \u00A74b):\n// p50=4, p90=9, p95=12, p99=23, max=35. 10 \u2248 p90 \u2192 48 reports / 28 unique (\u00A74c).\n// 20 would reach only 10 blocks corpus-wide \u2014 too loose to justify the rule's strongest half.\nconst DEFAULT_MAX_EXAMPLE_LINES = 10\n\n// Zero existing usages of any of these tags corpus-wide (\u00A74), so adopting them costs nothing.\n// This is the ONLY exemption mechanism: there is deliberately no positional fallback, because\n// position exempts by luck \u2014 the corpus's `stdin-ref.ts:3` is a 39-line file-level block whose\n// next statement is `let readers = 0`, so no \"precedes the first import\" spelling would reach it.\nconst DEFAULT_EXEMPT_TAGS = ['fileoverview', 'module', 'packageDocumentation']\n\n/** A JSDoc block: the house idiom, shared verbatim with `require-jsdoc-example`. */\nconst isJsdocBlock = (comment: ESTree.Comment): boolean => {\n return comment.type === 'Block' && comment.value.startsWith('*')\n}\n\n/**\n * The block's lines with the leading whitespace and `*` gutter removed, so tag\n * detection sees `@example` rather than ` * @example`. One entry per source line the\n * block occupies (`comment.value` keeps every newline between `/**` and the closer).\n */\nconst strippedLines = (comment: ESTree.Comment): string[] => {\n return comment.value.split('\\n').map((line) => {\n return line.replace(/^\\s*\\*+/, '').trim()\n })\n}\n\n/**\n * The JSDoc tag a stripped line opens (`@example \u2026` \u2192 `example`), or null for body/prose.\n *\n * Lower-cased on the way out: the match is case-insensitive, so every comparison against it\n * must be too. Without this, `@Example` parses as a tag but matches neither the example scan\n * nor `exemptTags` \u2014 the author gets a prose violation and a `@Fileoverview` escape hatch that\n * silently does not work.\n */\nconst tagNameOf = (line: string): string | null => {\n return line.match(/^@([A-Z][\\w-]*)/i)?.[1]?.toLowerCase() ?? null\n}\n\n// KNOWN PARSER HAZARD: any line opening with `@` ends the body, so a decorator (`@Injectable`)\n// written inside an `@example` truncates it early. The effect is worse than an under-count: the\n// truncated lines are recharged to PROSE, so the block reports `tooManyLines` and advises\n// `@fileoverview` \u2014 misleading advice for a block whose real problem is a long example. A scan of\n// all 637 example bodies in the corpus found ZERO lines starting with `@` that were not real tags,\n// so this is correct today \u2014 measured, not assumed, and not future-proof. A real JSDoc parser is\n// the fix if that ever stops holding.\n/**\n * Total lines occupied by the block's `@example` bodies.\n *\n * A scan enters example mode on an `@example` line (the tag line itself counts) and leaves\n * it at the next line opening any tag. An `@example` that is the block's last tag therefore\n * runs through the closing `*` + `/` line \u2014 which is how the corpus was measured, and what\n * makes `prose + example === total` exact. Bodies from multiple `@example` tags sum.\n */\nconst countExampleLines = (lines: string[]): number => {\n let inExample = false\n let count = 0\n\n for (const line of lines) {\n const tag = tagNameOf(line)\n\n if (tag) {\n inExample = tag === 'example'\n }\n\n if (inExample) {\n count += 1\n }\n }\n\n return count\n}\n\n/**\n * Whether the block declares any exempt tag \u2014 the rule's one and only escape hatch.\n *\n * `exemptTags` is normalised here rather than at the call site so a configured\n * `['FileOverview']` behaves the same as `['fileoverview']`; `tagNameOf` already lower-cases.\n */\nconst hasExemptTag = (lines: string[], exemptTags: string[]): boolean => {\n const normalized = exemptTags.map((tag) => {\n return tag.toLowerCase()\n })\n\n return lines.some((line) => {\n const tag = tagNameOf(line)\n\n return tag !== null && normalized.includes(tag)\n })\n}\n\nexport const maxJsdocLines: Rule.RuleModule = {\n meta: {\n type: 'suggestion',\n docs: {\n description:\n 'Cap the height of a JSDoc block, budgeting its prose and its `@example` bodies separately so a rule-mandated example never consumes the prose budget.',\n recommended: true,\n url: 'https://github.com/ArthurSaenz/infra-kit/tree/main/apps/infra-kit/eslint-plugin#max-jsdoc-lines',\n },\n // Deliberately NOT fixable. Any fixer would have to delete sentences, and the longest\n // blocks in the corpus are the most valuable documentation in it. The part of this\n // problem that IS mechanically fixable \u2014 blank-line padding and `{type}` annotations \u2014\n // is already handled upstream by `jsdoc/tag-lines` and `jsdoc/no-types`.\n schema: [\n {\n type: 'object',\n properties: {\n maxLines: {\n type: 'integer',\n minimum: 1,\n description:\n 'Maximum lines a JSDoc block may span, excluding its `@example` bodies, before the rule reports.',\n },\n maxExampleLines: {\n type: 'integer',\n minimum: 1,\n description:\n \"Maximum lines the block's `@example` bodies may span in total. Budgeted separately from `maxLines` so a rule-mandated example never consumes the prose budget.\",\n },\n exemptTags: {\n type: 'array',\n items: { type: 'string' },\n description:\n 'Tag names (without `@`) that exempt a block from every check. The only exemption mechanism; intended for module-level blocks whose length is the point.',\n },\n },\n additionalProperties: false,\n },\n ],\n messages: {\n // Names `@fileoverview` inline: with no positional exemption, this message is the only\n // thing standing between a long file-level rationale block and an author's delete key.\n tooManyLines:\n 'This JSDoc block spans {{lines}} lines of prose (max {{max}}; `@example` bodies are budgeted separately). Keep the contract \u2014 what it does and what a caller must know \u2014 and move rationale into a `//` note or the file-level block. If this IS module-level rationale, tag the block `@fileoverview` to exempt it.',\n exampleTooLong:\n 'The `@example` bodies in this JSDoc block span {{lines}} lines (max {{max}}). Show the smallest call that teaches usage; a full walkthrough belongs in a test or the readme.',\n },\n },\n\n create(context) {\n const options = (context.options[0] ?? {}) as Options\n const maxLines = options.maxLines ?? DEFAULT_MAX_LINES\n const maxExampleLines = options.maxExampleLines ?? DEFAULT_MAX_EXAMPLE_LINES\n const exemptTags = options.exemptTags ?? DEFAULT_EXEMPT_TAGS\n\n const { sourceCode } = context\n\n return {\n Program() {\n // EOF guard (NOT symbol attachment \u2014 this rule deliberately never resolves the symbol\n // a block documents): the start offset of the last token, so a trailing block with no\n // token after it can be skipped as degenerate input.\n const lastTokenStart = sourceCode.ast.tokens.at(-1)?.range[0] ?? -1\n\n // Comment-driven, not node-driven: every JSDoc-shaped block in the file is linted and\n // exemptions are explicit. A node-driven walk needs an anchor-type allowlist, which is\n // exactly how `jsdoc/match-description` ends up not covering `type`/`interface`. It also\n // avoids `SourceCode#getJSDocComment`, which ESLint 10 removed outright.\n for (const comment of sourceCode.getAllComments()) {\n if (!isJsdocBlock(comment) || !comment.loc || !comment.range) {\n continue\n }\n\n if (lastTokenStart <= comment.range[1]) {\n continue\n }\n\n const lines = strippedLines(comment)\n\n if (hasExemptTag(lines, exemptTags)) {\n continue\n }\n\n const totalLines = comment.loc.end.line - comment.loc.start.line + 1\n const exampleLines = countExampleLines(lines)\n const proseLines = totalLines - exampleLines\n\n // Two independent budgets: both can report on the same block.\n if (proseLines > maxLines) {\n context.report({\n loc: comment.loc,\n messageId: 'tooManyLines',\n data: { lines: proseLines, max: maxLines },\n })\n }\n\n if (exampleLines > maxExampleLines) {\n context.report({\n loc: comment.loc,\n messageId: 'exampleTooLong',\n data: { lines: exampleLines, max: maxExampleLines },\n })\n }\n }\n },\n }\n },\n}\n", "import type { Rule } from 'eslint'\nimport type * as ESTree from 'estree'\n\ninterface Options {\n maxSummaryLines?: number\n exemptTags?: string[]\n}\n\n// The user's stated requirement: a reader should grasp the essence of a comment in 3 to 5 lines.\n// 5 is the loose end of that range, so it is the default \u2014 the rule enforces the ceiling the user\n// named, not a tighter one invented here.\n//\n// Calibration: 51 of 2,171 JSDoc blocks in `apps/infra-kit/cli/src` exceed 5 summary lines (static\n// script, 2026-09-05, `docs/comment-review-skill-plan.md` \u00A79). That is 2.3% of linted blocks \u2014 the\n// same order as `max-jsdoc-lines`'s 2.12%, i.e. a normal lint-rule yield rather than a sweep.\nconst DEFAULT_MAX_SUMMARY_LINES = 5\n\n// COMPOSES WITH `max-jsdoc-lines`, does not overlap it: that rule caps the WHOLE block at 15 lines\n// (prose and `@example` bodies budgeted separately); this one caps only the FIRST PARAGRAPH at 5.\n// A block can satisfy either and fail the other \u2014 a 40-line block whose summary is two lines is a\n// well-shaped long block, and a 7-line block that is one unbroken paragraph is a badly-shaped short\n// one. Do not unify them: the second number is about whether a reader can skim, not about height.\n//\n// Same list as `max-jsdoc-lines` deliberately, so one `@fileoverview` tag exempts a module-level\n// block from both rules rather than requiring two different escape hatches.\nconst DEFAULT_EXEMPT_TAGS = ['fileoverview', 'module', 'packageDocumentation']\n\n/** A JSDoc block: the house idiom, shared verbatim with `max-jsdoc-lines`. */\nconst isJsdocBlock = (comment: ESTree.Comment): boolean => {\n return comment.type === 'Block' && comment.value.startsWith('*')\n}\n\n/**\n * The block's lines with the leading whitespace and `*` gutter removed, so a gutter-only line\n * reads as `''` and tag detection sees `@param` rather than ` * @param`. One entry per source\n * line the block occupies (`comment.value` keeps every newline between `/**` and the closer).\n */\nconst strippedLines = (comment: ESTree.Comment): string[] => {\n return comment.value.split('\\n').map((line) => {\n return line.replace(/^\\s*\\*+/, '').trim()\n })\n}\n\n/**\n * The JSDoc tag a stripped line opens (`@param \u2026` \u2192 `param`), or null for body/prose.\n *\n * Lower-cased on the way out so every comparison against it can be case-insensitive; without\n * this a `@Fileoverview` would parse as a tag but match neither the paragraph boundary check nor\n * `exemptTags`, giving the author an escape hatch that silently does not work.\n */\nconst tagNameOf = (line: string): string | null => {\n return line.match(/^@([A-Z][\\w-]*)/i)?.[1]?.toLowerCase() ?? null\n}\n\n/**\n * The height of the summary paragraph, in PROSE lines.\n *\n * The scan skips leading gutter-only lines (the `/**` opener strips to `''`, and so does a block\n * that opens with a blank gutter line), then counts prose until the first blank line or the first\n * line opening any tag, whichever comes first. A block with neither is one paragraph end to end,\n * so its whole prose body is the summary.\n *\n * Delimiter lines are NOT counted: the opener and the closing line carry no prose, and charging them\n * would make every block read two lines longer than what a reader actually reads. This is the one\n * place the count differs from `max-jsdoc-lines`, which measures visual height and so counts them.\n *\n * A block whose first non-empty line already opens a tag has a zero-line summary and can never\n * report \u2014 intentional, since `@param`-only blocks are a contract, not a description.\n */\nconst summaryLineCount = (lines: string[]): number => {\n let count = 0\n\n for (const line of lines) {\n const isBlank = line === ''\n\n if (tagNameOf(line) !== null || (isBlank && count > 0)) {\n break\n }\n\n if (!isBlank) {\n count += 1\n }\n }\n\n return count\n}\n\n/**\n * Whether the block declares any exempt tag \u2014 the rule's one and only escape hatch.\n *\n * `exemptTags` is normalised here rather than at the call site so a configured `['FileOverview']`\n * behaves the same as `['fileoverview']`; `tagNameOf` already lower-cases.\n */\nconst hasExemptTag = (lines: string[], exemptTags: string[]): boolean => {\n const normalized = exemptTags.map((tag) => {\n return tag.toLowerCase()\n })\n\n return lines.some((line) => {\n const tag = tagNameOf(line)\n\n return tag !== null && normalized.includes(tag)\n })\n}\n\nexport const maxJsdocSummaryLines: Rule.RuleModule = {\n meta: {\n type: 'suggestion',\n docs: {\n description:\n 'Cap the height of a JSDoc summary paragraph, so the first thing a reader sees is graspable at a glance and the detail sits below a blank line.',\n recommended: true,\n url: 'https://github.com/ArthurSaenz/infra-kit/tree/main/apps/infra-kit/eslint-plugin#max-jsdoc-summary-lines',\n },\n // Deliberately NOT fixable, for the same reason `max-jsdoc-lines` is not: the mechanical fix\n // (insert a blank line after line 5) splits a paragraph at an arbitrary point and produces a\n // summary that reads as truncated. Deciding what the first glance must contain is judgement.\n schema: [\n {\n type: 'object',\n properties: {\n maxSummaryLines: {\n type: 'integer',\n minimum: 1,\n description:\n 'Maximum prose lines the summary paragraph may span before the rule reports. The summary runs from the first prose line to the first blank line or first tag.',\n },\n exemptTags: {\n type: 'array',\n items: { type: 'string' },\n description:\n 'Tag names (without `@`) that exempt a block from the check. The only exemption mechanism; intended for module-level blocks whose length is the point.',\n },\n },\n additionalProperties: false,\n },\n ],\n messages: {\n // Names the offending count, the cap, and the escape hatch inline. No `suggest`: a suggestion\n // is host-UI-only and therefore invisible to the text-reading agents that are half this\n // rule's audience.\n summaryTooLong:\n 'This JSDoc summary paragraph runs {{lines}} lines (max {{max}}). Keep the first paragraph to what a reader needs in one glance, then a blank line, then the detail. If this IS module-level rationale, tag the block `@fileoverview` to exempt it.',\n },\n },\n\n create(context) {\n const options = (context.options[0] ?? {}) as Options\n const maxSummaryLines = options.maxSummaryLines ?? DEFAULT_MAX_SUMMARY_LINES\n const exemptTags = options.exemptTags ?? DEFAULT_EXEMPT_TAGS\n\n const { sourceCode } = context\n\n return {\n Program() {\n // EOF guard (NOT symbol attachment \u2014 this rule deliberately never resolves the symbol a\n // block documents): the start offset of the last token, so a trailing block with no token\n // after it is skipped as degenerate input. Mirrors `max-jsdoc-lines`.\n const lastTokenStart = sourceCode.ast.tokens.at(-1)?.range[0] ?? -1\n\n // Comment-driven, not node-driven: every JSDoc-shaped block in the file is linted and\n // exemptions are explicit. `//` line comments and plain `/* */` blocks are not JSDoc and\n // are never measured \u2014 `isJsdocBlock` is the whole filter.\n for (const comment of sourceCode.getAllComments()) {\n if (!isJsdocBlock(comment) || !comment.loc || !comment.range) {\n continue\n }\n\n if (lastTokenStart <= comment.range[1]) {\n continue\n }\n\n const lines = strippedLines(comment)\n\n if (hasExemptTag(lines, exemptTags)) {\n continue\n }\n\n const summaryLines = summaryLineCount(lines)\n\n if (summaryLines > maxSummaryLines) {\n context.report({\n loc: comment.loc,\n messageId: 'summaryTooLong',\n data: { lines: summaryLines, max: maxSummaryLines },\n })\n }\n }\n },\n }\n },\n}\n", "import type { Rule, SourceCode } from 'eslint'\nimport type * as ESTree from 'estree'\n\nimport {\n collectOwnReturnArguments,\n getComponentFunction,\n getComponentName,\n isComponent,\n unwrapExport,\n} from '../../utils/component'\nimport type { ComponentFunction } from '../../utils/component'\nimport { matchesAnyGlob } from '../../utils/path-match'\n\ninterface Options {\n maxElements?: number\n paths?: string[]\n ignore?: string[]\n}\n\n// Default ceiling on JSX elements rendered by a single return. Tunable via the\n// `maxElements` option; the value is a starting estimate, not a hard truth.\nconst DEFAULT_MAX_ELEMENTS = 20\n\n// Fallback used when a component is anonymous (e.g. `export default () => <div />`),\n// since `getComponentName` returns null rather than a placeholder in that case.\nconst ANONYMOUS_NAME = 'component'\n\ntype VisitorKeys = SourceCode.VisitorKeys\n\nconst isNode = (value: unknown): value is ESTree.Node => {\n return typeof value === 'object' && value !== null && typeof (value as { type?: unknown }).type === 'string'\n}\n\n// estree does not model JSX, so child traversal is driven by the parser-provided\n// `visitorKeys` (real child keys only \u2014 excludes `parent`/`loc`/`range`), falling\n// back to `Object.keys`; `parent` is skipped explicitly to guard recursion.\nconst childNodes = (node: ESTree.Node, visitorKeys: VisitorKeys): ESTree.Node[] => {\n const children: ESTree.Node[] = []\n const keys = visitorKeys[node.type as string] ?? Object.keys(node)\n\n for (const key of keys) {\n if (key === 'parent') {\n continue\n }\n\n const value = (node as unknown as Record<string, unknown>)[key]\n\n if (Array.isArray(value)) {\n children.push(...value.filter(isNode))\n } else if (isNode(value)) {\n children.push(value)\n }\n }\n\n return children\n}\n\n/**\n * Count the `JSXElement` nodes in an expression subtree. `JSXElement` counts 1;\n * `JSXFragment` counts 0 (a no-op wrapper) but still recurses. The walk descends\n * into nested function scopes, so inline-callback JSX (`.map(() => <li/>)`) is\n * counted once within its enclosing return \u2014 the counterpart to\n * `collectOwnReturnArguments`, which skips those scopes.\n */\nconst countJsxElements = (node: ESTree.Node, visitorKeys: VisitorKeys): number => {\n const self = (node.type as string) === 'JSXElement' ? 1 : 0\n\n return childNodes(node, visitorKeys).reduce((total, child) => {\n return total + countJsxElements(child, visitorKeys)\n }, self)\n}\n\n// Structural views over JSX nodes estree does not type. A JSX element's tag name\n// is on `openingElement.name`, which is an identifier (`name` is a string), a\n// member expression (`Foo.Bar`), or a namespaced name (`svg:rect`) \u2014 so the\n// child slots are read as `unknown` and narrowed per node type.\ninterface JsxNameNode {\n type?: string\n name?: unknown\n object?: unknown\n property?: unknown\n namespace?: unknown\n}\n\ninterface JsxElementNode {\n openingElement?: { name?: unknown }\n loc?: { start: { line: number } }\n}\n\nconst jsxNameToString = (node: unknown): string => {\n const name = node as JsxNameNode | null | undefined\n\n switch (name?.type) {\n case 'JSXIdentifier':\n return typeof name.name === 'string' ? name.name : 'element'\n case 'JSXMemberExpression':\n return `${jsxNameToString(name.object)}.${jsxNameToString(name.property)}`\n case 'JSXNamespacedName':\n return `${jsxNameToString(name.namespace)}:${jsxNameToString(name.name)}`\n default:\n return 'element'\n }\n}\n\n// The JSXElements directly under `root` (descending only through non-element\n// wrappers like fragments, expression containers, conditionals, and `.map`\n// callbacks). A parent always out-counts its children, so the largest of these\n// is the single biggest block a reader could lift out of the return.\nconst topLevelElements = (root: ESTree.Node, visitorKeys: VisitorKeys): ESTree.Node[] => {\n const elements: ESTree.Node[] = []\n\n const walk = (node: ESTree.Node, isRoot: boolean): void => {\n if (!isRoot && (node.type as string) === 'JSXElement') {\n elements.push(node)\n\n return\n }\n\n for (const child of childNodes(node, visitorKeys)) {\n walk(child, false)\n }\n }\n\n walk(root, true)\n\n return elements\n}\n\ninterface LargestBlock {\n name: string\n line: number\n count: number\n}\n\n/** The biggest extractable JSX block inside a return, for an actionable message. */\nconst largestBlock = (root: ESTree.Node, visitorKeys: VisitorKeys): LargestBlock | null => {\n let best: { node: ESTree.Node; count: number } | null = null\n\n for (const element of topLevelElements(root, visitorKeys)) {\n const count = countJsxElements(element, visitorKeys)\n\n if (!best || count > best.count) {\n best = { node: element, count }\n }\n }\n\n if (!best) {\n return null\n }\n\n const element = best.node as unknown as JsxElementNode\n\n return { name: jsxNameToString(element.openingElement?.name), line: element.loc?.start.line ?? 0, count: best.count }\n}\n\n/** The component function(s) declared by a single top-level declaration. */\nconst componentFunctionsIn = (declaration: ESTree.Node): ComponentFunction[] => {\n if (declaration.type === 'FunctionDeclaration') {\n return isComponent(declaration) ? [declaration] : []\n }\n\n if (declaration.type === 'VariableDeclaration') {\n return declaration.declarations\n .map((declarator) => {\n return getComponentFunction(declarator.init)\n })\n .filter((fn): fn is ComponentFunction => {\n return fn !== null && isComponent(fn)\n })\n }\n\n // e.g. `export default memo(() => \u2026)`.\n const fn = getComponentFunction(declaration)\n\n return fn && isComponent(fn) ? [fn] : []\n}\n\n/**\n * Every component declared at the TOP LEVEL of the program body (mirrors\n * `component-arrow-function`). Anonymous inline callbacks are never collected, so\n * a single oversized return can never be reported twice.\n */\nconst collectComponents = (body: Array<ESTree.Statement | ESTree.ModuleDeclaration>): ComponentFunction[] => {\n return body.flatMap((statement) => {\n const declaration = unwrapExport(statement)\n\n return declaration ? componentFunctionsIn(declaration) : []\n })\n}\n\nexport const maxJsxReturnSize: Rule.RuleModule = {\n meta: {\n type: 'suggestion',\n docs: {\n description:\n 'Warn when a component return renders too many JSX elements; extract parts into variables or sub-components.',\n recommended: true,\n url: 'https://github.com/ArthurSaenz/infra-kit/tree/main/apps/infra-kit/eslint-plugin#max-jsx-return-size',\n },\n schema: [\n {\n type: 'object',\n properties: {\n maxElements: {\n type: 'integer',\n minimum: 1,\n description: 'Maximum number of JSX elements a single return may render before the rule reports.',\n },\n paths: {\n type: 'array',\n items: { type: 'string' },\n description:\n 'Optional glob patterns. When provided, the rule only runs for files whose path matches one of them.',\n },\n ignore: {\n type: 'array',\n items: { type: 'string' },\n description:\n 'Optional glob patterns. The rule is skipped for files whose path matches one of them, even if it also matches `paths`.',\n },\n },\n additionalProperties: false,\n },\n ],\n messages: {\n // Points at the single biggest block so a human or AI fix loop knows\n // exactly what to lift out.\n tooManyElements:\n '{{name}} renders {{count}} JSX elements in one return (max {{max}}). Extract the largest block \u2014 <{{largest}}> at line {{line}} ({{largestCount}} elements) \u2014 into a variable or a sub-component.',\n // Fallback when no single block dominates (e.g. many flat siblings): there is\n // nothing meaningful to point at, so advise splitting.\n tooManyElementsFlat:\n '{{name}} renders {{count}} JSX elements in one return (max {{max}}). Split it into smaller sub-components or extract groups of elements into variables.',\n },\n },\n\n create(context) {\n const options = (context.options[0] ?? {}) as Options\n const max = options.maxElements ?? DEFAULT_MAX_ELEMENTS\n const paths = options.paths ?? []\n const ignore = options.ignore ?? []\n\n // `ignore` takes precedence: skip excluded files even when they also match `paths`.\n if (ignore.length > 0 && matchesAnyGlob(context.filename, ignore)) {\n return {}\n }\n\n if (paths.length > 0 && !matchesAnyGlob(context.filename, paths)) {\n return {}\n }\n\n const visitorKeys = context.sourceCode.visitorKeys\n\n // Measure one declared component: count each of its own return arguments\n // (nested scopes skipped by `collectOwnReturnArguments`; arrow implicit body\n // included) and report once per return that exceeds `max`.\n const checkComponent = (fn: ComponentFunction): void => {\n const name = getComponentName(fn) ?? ANONYMOUS_NAME\n\n for (const argument of collectOwnReturnArguments(fn)) {\n const count = countJsxElements(argument, visitorKeys)\n\n if (count <= max) {\n continue\n }\n\n const largest = largestBlock(argument, visitorKeys)\n\n if (largest && largest.count >= 2) {\n context.report({\n node: argument,\n messageId: 'tooManyElements',\n data: { count, max, name, largest: largest.name, line: largest.line, largestCount: largest.count },\n })\n } else {\n context.report({ node: argument, messageId: 'tooManyElementsFlat', data: { count, max, name } })\n }\n }\n }\n\n return {\n Program(program) {\n for (const component of collectComponents(program.body)) {\n checkComponent(component)\n }\n },\n }\n },\n}\n", "import type { Rule } from 'eslint'\n\nimport {\n DEFAULT_ROOT_ALIAS,\n IMPORT_SELECTORS,\n featureNameOf,\n fileDirsUnderSrc,\n isFeaturePublicApi,\n isLayeredFile,\n readImportSource,\n resolveUnderSrc,\n srcDirOf,\n} from '../../utils/import-target'\n\nexport interface Options {\n /** The alias that maps to the package's `src/`. */\n rootAlias?: string\n /** Globs; the rule is skipped for matching files. */\n ignore?: string[]\n}\n\n// Tests and stories exercise the feature from outside, so its public API is the right entry for them.\nconst CONSUMER_DIRS = new Set(['__tests__', '__stories__'])\n\nexport const noFeatureSelfImport: Rule.RuleModule = {\n meta: {\n type: 'problem',\n docs: {\n description:\n 'Forbid a feature from importing itself through its own public API, which closes an import cycle through `index.ts`.',\n recommended: true,\n url: 'https://github.com/ArthurSaenz/infra-kit/tree/main/apps/infra-kit/eslint-plugin#no-feature-self-import',\n },\n schema: [\n {\n type: 'object',\n properties: {\n rootAlias: { type: 'string', description: 'The alias that maps to `src/` (default `#root`).' },\n ignore: {\n type: 'array',\n items: { type: 'string' },\n description: 'Optional globs; the rule is skipped for matching files.',\n },\n },\n additionalProperties: false,\n },\n ],\n messages: {\n selfImport:\n '`{{specifier}}` imports feature `{{feature}}` through its own public API from inside it, which makes an import cycle via `index.ts`. Import the module that defines it with a relative path instead.',\n selfTypeImport:\n '`{{specifier}}` reads types of feature `{{feature}}` through its own public API from inside it. Import them from the module that defines them with a relative path; the public API is for code outside the feature.',\n },\n },\n\n create(context) {\n const options = (context.options[0] ?? {}) as Options\n const filename = context.filename.split('\\\\').join('/')\n const srcDir = srcDirOf(filename)\n\n if (srcDir === null || !isLayeredFile(filename, options.ignore ?? [])) {\n return {}\n }\n\n const dirs = fileDirsUnderSrc(filename, srcDir)\n const ownFeature = featureNameOf(dirs)\n\n const isConsumer = dirs.some((dir) => {\n return CONSUMER_DIRS.has(dir)\n })\n\n if (ownFeature === null || isConsumer) {\n return {}\n }\n\n const rootAlias = options.rootAlias ?? DEFAULT_ROOT_ALIAS\n\n const check = (node: Rule.Node): void => {\n const source = readImportSource(node)\n const target = source === null ? null : resolveUnderSrc(filename, srcDir, source.specifier, rootAlias)\n\n if (source === null || target === null || featureNameOf(target) !== ownFeature || !isFeaturePublicApi(target)) {\n return\n }\n\n context.report({\n node: source.node,\n // A type-only import is erased at build time, so it closes no runtime cycle.\n messageId: source.typeOnly ? 'selfTypeImport' : 'selfImport',\n data: { specifier: source.specifier, feature: ownFeature },\n })\n }\n\n return Object.fromEntries(\n IMPORT_SELECTORS.map((selector) => {\n return [selector, check]\n }),\n )\n },\n}\n", "import type { Rule } from 'eslint'\nimport type * as ESTree from 'estree'\n\nimport { isUiPackageFile } from '../../utils/component-file-scope'\nimport { matchesAnyGlob } from '../../utils/path-match'\n\ninterface Options {\n paths?: string[]\n ignore?: string[]\n}\n\n// A leading `/` rather than `**/`: path-match's `**/` also matches a bare suffix, so `**/services.ts`\n// would catch `lib/use-services.ts`, the very place a hook belongs.\nexport const DEFAULT_PATHS = [\n '/services/',\n '/services.ts',\n '/services.tsx',\n '/service.ts',\n '/service.tsx',\n '/entities/**/model.ts',\n '/entities/**/model.tsx',\n]\n\nconst HOOK_NAME = /^use[A-Z0-9]/\nconst TEST_OR_STORY_DIR = /\\/__(?:tests|stories)__\\//\nconst TEST_OR_STORY_FILE = /\\.(?:test|spec|stories)\\.[cm]?[jt]sx?$/\n\nexport const noHooksInServices: Rule.RuleModule = {\n meta: {\n type: 'problem',\n docs: {\n description:\n 'Disallow declaring React hooks in services and entity models: they hold atoms and pure functions, the hook belongs in a container or `lib/`.',\n recommended: true,\n url: 'https://github.com/ArthurSaenz/infra-kit/tree/main/apps/infra-kit/eslint-plugin#no-hooks-in-services',\n },\n schema: [\n {\n type: 'object',\n properties: {\n paths: {\n type: 'array',\n items: { type: 'string' },\n description: `Glob patterns of service files; replaces the default (${DEFAULT_PATHS.join(', ')}).`,\n },\n ignore: {\n type: 'array',\n items: { type: 'string' },\n description:\n 'Optional glob patterns. The rule is skipped for files whose path matches one of them, even if it also matches `paths`.',\n },\n },\n additionalProperties: false,\n },\n ],\n messages: {\n hookInService:\n '\"{{name}}\" is a hook, and services hold only atoms and pure functions. Move it to a container or to `lib/`.',\n },\n },\n\n create(context) {\n const options = (context.options[0] ?? {}) as Options\n const filename = context.filename.split('\\\\').join('/')\n const ignore = options.ignore ?? []\n\n if (ignore.length > 0 && matchesAnyGlob(filename, ignore)) {\n return {}\n }\n\n if (\n !matchesAnyGlob(filename, options.paths ?? DEFAULT_PATHS) ||\n TEST_OR_STORY_DIR.test(filename) ||\n TEST_OR_STORY_FILE.test(filename) ||\n // Backend packages have `src/services/` too, where `use*` means something else.\n !isUiPackageFile(filename)\n ) {\n return {}\n }\n\n const report = (id: ESTree.Identifier): void => {\n if (HOOK_NAME.test(id.name)) {\n context.report({ node: id, messageId: 'hookInService', data: { name: id.name } })\n }\n }\n\n return {\n FunctionDeclaration(node) {\n if (node.id) {\n report(node.id)\n }\n },\n VariableDeclarator(node) {\n if (\n node.id.type === 'Identifier' &&\n (node.init?.type === 'ArrowFunctionExpression' || node.init?.type === 'FunctionExpression')\n ) {\n report(node.id)\n }\n },\n }\n },\n}\n", "import type { Rule } from 'eslint'\n\nimport { dirsUnderSrc, findPackageRoot } from '../../utils/package-root'\nimport { resolvePackageType } from '../../utils/package-type-reader'\nimport { matchesAnyGlob } from '../../utils/path-match'\n\n// Declared locally rather than imported: this type reaches the plugin's public `dist/index.d.ts`,\n// and a `@slip-stream-kit/config` specifier there would make every consumer's tsc resolve a package\n// the plugin does not ship. A unit test binds the members to the config package's PACKAGE_TYPES.\nexport const PACKAGE_TYPE_VALUES = ['frontend', 'backend', 'lib', 'e2e', 'mobile'] as const\n\nexport type PackageType = (typeof PACKAGE_TYPE_VALUES)[number]\n\nexport interface LayerEntry {\n /** First-level directories allowed under `src/`. */\n layers: string[]\n /**\n * Allowed directories one level further down, keyed by where they sit: `features/*` means \"inside\n * every folder of `features/`\" (each folder is a unit of any name), `services` means \"directly\n * inside `services/`\". A layer without a key is not inspected below its first level.\n */\n segments?: Record<string, string[]>\n /** Skill or doc that owns this layout, appended to the message. `''` or absent \u2192 no \"See \u2026\" sentence. */\n skill?: string\n}\n\nexport interface Options extends Partial<Record<PackageType, LayerEntry>> {\n /** Globs; the rule is skipped for matching files. */\n ignore?: string[]\n}\n\n/**\n * Built-in entries per package type. A present option key replaces the whole entry (layers,\n * segments AND skill) \u2014 the same absent\u2192default / set\u2192replace semantics as every other option in\n * the plugin. `mobile` and `lib` have no entry until their layouts settle, so they are silent.\n */\nexport const DEFAULT_ENTRIES: Partial<Record<PackageType, LayerEntry>> = {\n frontend: {\n // `__tests__` holds the tests of files that sit directly in `src/` (see `test-location`).\n layers: ['app', 'features', 'lib', 'components', 'pages', 'routes', '__tests__'],\n segments: {\n 'features/*': ['containers', 'components', 'services', '__stories__', '__tests__'],\n },\n skill: '/infra-kit:fe-architect',\n },\n backend: {\n layers: ['controllers', 'services', 'lib', 'config', '__tests__'],\n segments: {\n 'services/*': ['__tests__'],\n },\n // The skill does not exist yet; the user adds `plugins/infra-kit/skills/be-architect/SKILL.md`\n // and accepted the dangling pointer until then.\n skill: '/infra-kit:be-architect',\n },\n e2e: {\n layers: ['tests', 'visual', 'setup', 'pages', 'config', 'lib', 'components', 'mocks', 'fixtures'],\n // A domain folder's root holds only specs; its support files always sit in one of these.\n segments: {\n 'tests/*': ['pages', 'fixtures', 'mocks', 'data', 'lib'],\n 'visual/*': ['pages', 'fixtures', 'mocks', 'data', 'lib'],\n },\n skill: '/infra-kit:e2e-architect',\n },\n}\n\nexport const resolveEntry = (type: PackageType, options: Options): LayerEntry | undefined => {\n return options[type] ?? DEFAULT_ENTRIES[type]\n}\n\nconst UNIT_KEY_SUFFIX = '/*'\n\n/**\n * A `segments` key that names a layer outside `layers` can never match a file, so it is a typo in\n * the consumer's config rather than a policy \u2014 surfaced as a config error, not silently ignored.\n */\nconst assertSegmentKeysNameLayers = (type: PackageType, entry: LayerEntry): void => {\n for (const key of Object.keys(entry.segments ?? {})) {\n const layer = key.endsWith(UNIT_KEY_SUFFIX) ? key.slice(0, -UNIT_KEY_SUFFIX.length) : key\n\n if (!entry.layers.includes(layer)) {\n throw new Error(\n `@wl/package-structure: \\`${type}.segments\\` key \"${key}\" names a layer that is not in \\`${type}.layers\\` (${entry.layers.join(', ')}).`,\n )\n }\n }\n}\n\nconst LAYER_ENTRY_SCHEMA = {\n type: 'object',\n properties: {\n layers: {\n type: 'array',\n items: { type: 'string', minLength: 1 },\n uniqueItems: true,\n description: 'First-level directories allowed under `src/`.',\n },\n segments: {\n type: 'object',\n propertyNames: { pattern: '^[^/]+(/\\\\*)?$' },\n additionalProperties: {\n type: 'array',\n items: { type: 'string', minLength: 1 },\n uniqueItems: true,\n },\n description:\n 'Allowed directories one level down, keyed by `<layer>` (directly inside it) or `<layer>/*` (inside each of its folders).',\n },\n skill: {\n type: 'string',\n description: 'Skill or doc that owns this layout, appended to the message; `\"\"` drops the sentence.',\n },\n },\n required: ['layers'],\n additionalProperties: false,\n} as const\n\ninterface Violation {\n messageId: 'unknownLayer' | 'unknownSegment'\n /** The offending directory name. */\n name: string\n /** Where it sits, as the message names it: the layer, or `features/<unit>`. */\n scope: string\n allowed: string[]\n}\n\n/**\n * The directory `dirs[1]` or `dirs[2]` that `entry.segments` forbids, or null. Files directly inside\n * a layer or a unit (`features/<unit>/index.ts`) are not a segment and are never reported.\n */\nconst findSegmentViolation = (dirs: string[], entry: LayerEntry): Violation | null => {\n const [layer, second, third] = dirs\n const segments = entry.segments ?? {}\n const perUnit = segments[`${layer}${UNIT_KEY_SUFFIX}`]\n\n if (perUnit !== undefined) {\n return second !== undefined && third !== undefined && !perUnit.includes(third)\n ? { messageId: 'unknownSegment', name: third, scope: `${layer}/${second}`, allowed: perUnit }\n : null\n }\n\n const direct = segments[layer!]\n\n if (direct !== undefined && second !== undefined && !direct.includes(second)) {\n return { messageId: 'unknownSegment', name: second, scope: layer!, allowed: direct }\n }\n\n return null\n}\n\nconst findViolation = (dirs: string[], entry: LayerEntry): Violation | null => {\n const layer = dirs[0]!\n\n if (!entry.layers.includes(layer)) {\n return { messageId: 'unknownLayer', name: layer, scope: 'src', allowed: entry.layers }\n }\n\n return findSegmentViolation(dirs, entry)\n}\n\n/** The violation `filename` commits under its package's entry, or null when exempt or allowed. */\nconst inspect = (\n filename: string,\n options: Options,\n): { violation: Violation; type: PackageType; entry: LayerEntry } | null => {\n const packageRoot = findPackageRoot(filename)\n\n if (packageRoot === null) {\n return null\n }\n\n const dirs = dirsUnderSrc(packageRoot, filename)\n\n if (dirs === null || dirs.length === 0) {\n return null\n }\n\n const type = resolvePackageType(packageRoot)\n const entry = resolveEntry(type, options)\n\n if (entry === undefined) {\n return null\n }\n\n assertSegmentKeysNameLayers(type, entry)\n\n const violation = findViolation(dirs, entry)\n\n return violation === null ? null : { violation, type, entry }\n}\n\nexport const packageStructure: Rule.RuleModule = {\n meta: {\n type: 'problem',\n docs: {\n description: 'Allow only the `src/` layers, and the segments inside them, that belong to the package type.',\n recommended: true,\n url: 'https://github.com/ArthurSaenz/infra-kit/tree/main/apps/infra-kit/eslint-plugin#package-structure',\n },\n schema: [\n {\n type: 'object',\n properties: {\n frontend: LAYER_ENTRY_SCHEMA,\n backend: LAYER_ENTRY_SCHEMA,\n lib: LAYER_ENTRY_SCHEMA,\n e2e: LAYER_ENTRY_SCHEMA,\n mobile: LAYER_ENTRY_SCHEMA,\n ignore: {\n type: 'array',\n items: { type: 'string' },\n description: 'Optional globs; the rule is skipped for matching files.',\n },\n },\n additionalProperties: false,\n },\n ],\n messages: {\n unknownLayer:\n '`{{name}}` is not an allowed `src/` layer for package type `{{type}}` (allowed: {{allowed}}).{{seeSkill}}',\n unknownSegment:\n '`{{name}}` is not an allowed segment of `{{scope}}` for package type `{{type}}` (allowed: {{allowed}}).{{seeSkill}}',\n },\n },\n\n create(context) {\n const options = (context.options[0] ?? {}) as Options\n const ignore = options.ignore ?? []\n\n if (ignore.length > 0 && matchesAnyGlob(context.filename, ignore)) {\n return {}\n }\n\n const found = inspect(context.filename, options)\n\n if (found === null) {\n return {}\n }\n\n const { violation, type, entry } = found\n\n return {\n // Reported on Program so the IDE marks the file from line 1: every file under the offending\n // directory carries the same message, which is how a \"red folder\" surfaces in the explorer.\n Program(program) {\n context.report({\n node: program,\n messageId: violation.messageId,\n data: {\n name: violation.name,\n scope: violation.scope,\n type,\n allowed: violation.allowed.join(', '),\n // Message templates have no conditionals, so the optional sentence is assembled here.\n seeSkill: entry.skill ? ` See ${entry.skill} for the ${type} layout.` : '',\n },\n })\n },\n }\n },\n}\n", "import type { Rule } from 'eslint'\nimport type * as ESTree from 'estree'\n\nimport type { ComponentFunction } from '../../utils/component'\nimport { isComponent } from '../../utils/component'\n\n/** Whether a statement is `const { ... } = props` (destructuring the `props` identifier). */\nconst isPropsDestructuring = (statement: ESTree.Statement): boolean => {\n if (statement.type !== 'VariableDeclaration') {\n return false\n }\n\n return statement.declarations.some((declaration) => {\n return (\n declaration.id.type === 'ObjectPattern' &&\n declaration.init?.type === 'Identifier' &&\n declaration.init.name === 'props'\n )\n })\n}\n\nexport const propsDestructuringBlankLine: Rule.RuleModule = {\n meta: {\n type: 'suggestion',\n docs: {\n description:\n 'Require a blank line after the `const { ... } = props` destructuring statement at the top of a React component body.',\n recommended: true,\n url: 'https://github.com/ArthurSaenz/infra-kit/tree/main/apps/infra-kit/eslint-plugin#props-destructuring-blank-line',\n },\n fixable: 'whitespace',\n schema: [],\n messages: {\n blankLineAfterProps: 'Add a blank line after destructuring props.',\n },\n },\n\n create(context) {\n const sourceCode = context.sourceCode\n\n const check = (node: ComponentFunction): void => {\n if (node.body.type !== 'BlockStatement') {\n return\n }\n\n if (!isComponent(node)) {\n return\n }\n\n const statements = node.body.body\n const index = statements.findIndex(isPropsDestructuring)\n\n if (index === -1) {\n return\n }\n\n const propsStatement = statements[index]\n const nextStatement = statements[index + 1]\n\n // `propsStatement` is defined because `index !== -1`; the guard also narrows the type.\n // Nothing follows the destructuring \u2014 no separation needed.\n if (!propsStatement || !nextStatement) {\n return\n }\n\n // The token/comment that follows the destructuring statement; a comment on the\n // next line still counts as \"no blank line\" until it is pushed down.\n const tokenAfter = sourceCode.getTokenAfter(propsStatement, { includeComments: true })\n const referenceLine = (tokenAfter ?? nextStatement).loc!.start.line\n\n if (referenceLine - propsStatement.loc!.end.line >= 2) {\n return\n }\n\n context.report({\n node: propsStatement,\n messageId: 'blankLineAfterProps',\n fix(fixer) {\n return fixer.insertTextAfter(propsStatement, '\\n')\n },\n })\n }\n\n return {\n ArrowFunctionExpression: check,\n FunctionDeclaration: check,\n FunctionExpression: check,\n }\n },\n}\n", "import type { Rule } from 'eslint'\nimport type * as ESTree from 'estree'\n\nimport type { ComponentFunction } from '../../utils/component'\nimport { isComponent } from '../../utils/component'\n\n// Minimal structural views over nodes that estree's types do not fully model:\n// the optional TS type annotation and `range` that the parser attaches to params.\ninterface WithRange {\n range?: [number, number]\n}\ntype AnnotatedPattern = ESTree.ObjectPattern & { typeAnnotation?: ESTree.Node & WithRange } & WithRange\n\n// Recursively collect every identifier a destructuring pattern binds, so we can detect\n// whether it already introduces a `props` binding (e.g. a `...props` rest).\nconst collectBoundNames = (node: ESTree.Node | null, names: Set<string>): void => {\n if (!node) {\n return\n }\n\n switch (node.type) {\n case 'Identifier':\n names.add(node.name)\n break\n case 'ObjectPattern':\n for (const property of node.properties) collectBoundNames(property, names)\n break\n case 'ArrayPattern':\n for (const element of node.elements) collectBoundNames(element, names)\n break\n case 'Property':\n collectBoundNames(node.value, names)\n break\n case 'RestElement':\n collectBoundNames(node.argument, names)\n break\n case 'AssignmentPattern':\n collectBoundNames(node.left, names)\n break\n default:\n break\n }\n}\n\nexport const propsDestructuringNewline: Rule.RuleModule = {\n meta: {\n type: 'suggestion',\n docs: {\n description:\n 'Require React components to accept a single props parameter and destructure it on its own line in the body, rather than destructuring inline in the parameter list.',\n recommended: true,\n url: 'https://github.com/ArthurSaenz/infra-kit/tree/main/apps/infra-kit/eslint-plugin#props-destructuring-newline',\n },\n fixable: 'code',\n schema: [],\n messages: {\n destructureOnNewLine:\n 'Accept a single `props` parameter and destructure it on its own line in the component body instead of destructuring in the parameter list.',\n },\n },\n\n create(context) {\n const sourceCode = context.sourceCode\n\n const check = (node: ComponentFunction): void => {\n const firstParam = node.params[0]\n\n if (!firstParam || firstParam.type !== 'ObjectPattern') {\n return\n }\n\n if (!isComponent(node)) {\n return\n }\n\n // The fix renames the parameter to `props` and re-destructures it in the body\n // (`const <pattern> = props`). If the pattern already binds `props` (e.g. a\n // `...props` rest, a `{ props }` shorthand, or a `{ data: props }` rename), that\n // body binding collides with the new parameter and yields an invalid \"Duplicate\n // declaration props\". No safe rename keeps the `props` name the rule mandates \u2014\n // and an ESLint fixer cannot scope-rename the downstream `props.*` usages a rename\n // would require \u2014 so these patterns are still reported (the inline destructuring is\n // a violation regardless) but WITHOUT an autofix; the developer resolves them by hand.\n const boundNames = new Set<string>()\n\n collectBoundNames(firstParam, boundNames)\n\n const bindsProps = boundNames.has('props')\n\n const objectPattern = firstParam as AnnotatedPattern\n\n context.report({\n node: firstParam,\n messageId: 'destructureOnNewLine',\n fix: bindsProps\n ? undefined\n : (fixer) => {\n const text = sourceCode.getText()\n const annotation = objectPattern.typeAnnotation\n\n const patternStart = objectPattern.range![0]\n const patternEnd = annotation ? annotation.range![0] : objectPattern.range![1]\n const fullEnd = annotation ? annotation.range![1] : objectPattern.range![1]\n\n const patternText = text.slice(patternStart, patternEnd).trim()\n const annotationText = annotation ? sourceCode.getText(annotation) : ''\n\n const fixes = [fixer.replaceTextRange([patternStart, fullEnd], `props${annotationText}`)]\n\n const destructureStatement = `const ${patternText} = props`\n\n // Indentation of the line the component is declared on, used as the base for inserted code.\n const lines = sourceCode.getLines()\n const declarationLine = lines[node.loc!.start.line - 1] ?? ''\n const baseIndent = declarationLine.slice(0, declarationLine.length - declarationLine.trimStart().length)\n const innerIndent = `${baseIndent} `\n\n if (node.body.type === 'BlockStatement') {\n const [firstStatement] = node.body.body\n\n if (firstStatement) {\n const indent = ' '.repeat(firstStatement.loc!.start.column)\n\n fixes.push(fixer.insertTextBefore(firstStatement, `${destructureStatement}\\n\\n${indent}`))\n } else {\n const openBrace = sourceCode.getFirstToken(node.body)!\n\n fixes.push(fixer.insertTextAfter(openBrace, `\\n${innerIndent}${destructureStatement}\\n${baseIndent}`))\n }\n\n return fixes\n }\n\n // Expression-bodied arrow (implicit return) \u2014 wrap it in a block.\n const bodyText = sourceCode.getText(node.body)\n\n fixes.push(\n fixer.replaceText(\n node.body,\n `{\\n${innerIndent}${destructureStatement}\\n\\n${innerIndent}return ${bodyText}\\n${baseIndent}}`,\n ),\n )\n\n return fixes\n },\n })\n }\n\n return {\n ArrowFunctionExpression: check,\n FunctionDeclaration: check,\n FunctionExpression: check,\n }\n },\n}\n", "import type { Rule } from 'eslint'\n\nimport type { ComponentFunction } from '../../utils/component'\nimport { getAnnotatedParam, getComponentName, getPropsTypeNameFromFunction, isComponent } from '../../utils/component'\nimport { matchesAnyGlob } from '../../utils/path-match'\n\ninterface Options {\n paths?: string[]\n ignore?: string[]\n}\n\nconst PROPS_SUFFIX = 'Props'\n\nexport const propsTypeName: Rule.RuleModule = {\n meta: {\n type: 'suggestion',\n docs: {\n description:\n \"Require a React component's props type to be named `<ComponentName>Props` (e.g. `ButtonProps` for `Button`).\",\n recommended: true,\n url: 'https://github.com/ArthurSaenz/infra-kit/tree/main/apps/infra-kit/eslint-plugin#props-type-name',\n },\n schema: [\n {\n type: 'object',\n properties: {\n paths: {\n type: 'array',\n items: { type: 'string' },\n description:\n 'Optional glob patterns. When provided, the rule only runs for files whose path matches one of them.',\n },\n ignore: {\n type: 'array',\n items: { type: 'string' },\n description:\n 'Optional glob patterns. The rule is skipped for files whose path matches one of them, even if it also matches `paths`.',\n },\n },\n additionalProperties: false,\n },\n ],\n messages: {\n propsTypeNameMismatch: \"A component's props type must be named `{{expected}}`, but it is named `{{actual}}`.\",\n },\n },\n\n create(context) {\n const options = (context.options[0] ?? {}) as Options\n const paths = options.paths ?? []\n const ignore = options.ignore ?? []\n\n // `ignore` takes precedence: skip excluded files even when they also match `paths`.\n if (ignore.length > 0 && matchesAnyGlob(context.filename, ignore)) {\n return {}\n }\n\n if (paths.length > 0 && !matchesAnyGlob(context.filename, paths)) {\n return {}\n }\n\n const check = (node: ComponentFunction): void => {\n if (!isComponent(node)) {\n return\n }\n\n // An anonymous component (e.g. `export default () => ...`) has no name to derive the\n // expected props type name from, so the convention cannot be checked.\n const componentName = getComponentName(node)\n\n if (componentName === null) {\n return\n }\n\n // Only a simple named type reference is checked. An inline object type is the\n // `props-type-reference` rule's concern; qualified names and generics are out of scope and\n // resolve to null. A component with no typed props parameter is likewise not constrained.\n const actual = getPropsTypeNameFromFunction(node)\n\n if (actual === null) {\n return\n }\n\n const expected = `${componentName}${PROPS_SUFFIX}`\n\n if (actual === expected) {\n return\n }\n\n // `getPropsTypeNameFromFunction` only returns non-null when the first parameter carries a\n // named type reference, so an annotated parameter is guaranteed to exist here.\n context.report({\n node: getAnnotatedParam(node.params[0]!),\n messageId: 'propsTypeNameMismatch',\n data: { expected, actual },\n })\n }\n\n return {\n ArrowFunctionExpression: check,\n FunctionDeclaration: check,\n FunctionExpression: check,\n }\n },\n}\n", "import type { Rule } from 'eslint'\n\nimport type { ComponentFunction } from '../../utils/component'\nimport { getAnnotatedParam, getComponentName, isComponent } from '../../utils/component'\nimport { matchesAnyGlob } from '../../utils/path-match'\n\ninterface Options {\n paths?: string[]\n ignore?: string[]\n}\n\n// TS-only nodes are not modelled by estree, so we view them through a minimal two-level\n// structural interface: the `TSTypeAnnotation` wrapper a parser attaches to a parameter, and\n// its inner type node. An inline object type is `TSTypeLiteral`; a named type is `TSTypeReference`.\ninterface AnnotatedNode {\n typeAnnotation?: {\n typeAnnotation?: { type?: string }\n }\n}\n\nconst INLINE_OBJECT_TYPE = 'TSTypeLiteral'\n\nexport const propsTypeReference: Rule.RuleModule = {\n meta: {\n type: 'suggestion',\n docs: {\n description:\n \"Require a React component's props parameter to use a named type (e.g. `ButtonProps`) instead of an inline object type literal.\",\n recommended: true,\n url: 'https://github.com/ArthurSaenz/infra-kit/tree/main/apps/infra-kit/eslint-plugin#props-type-reference',\n },\n schema: [\n {\n type: 'object',\n properties: {\n paths: {\n type: 'array',\n items: { type: 'string' },\n description:\n 'Optional glob patterns. When provided, the rule only runs for files whose path matches one of them.',\n },\n ignore: {\n type: 'array',\n items: { type: 'string' },\n description:\n 'Optional glob patterns. The rule is skipped for files whose path matches one of them, even if it also matches `paths`.',\n },\n },\n additionalProperties: false,\n },\n ],\n messages: {\n useNamedPropsType:\n \"Use a named props type (e.g. `{{name}}Props`) instead of an inline object type for this component's props.\",\n useNamedPropsTypeAnonymous: \"Use a named props type instead of an inline object type for this component's props.\",\n },\n },\n\n create(context) {\n const options = (context.options[0] ?? {}) as Options\n const paths = options.paths ?? []\n const ignore = options.ignore ?? []\n\n // `ignore` takes precedence: skip excluded files even when they also match `paths`.\n if (ignore.length > 0 && matchesAnyGlob(context.filename, ignore)) {\n return {}\n }\n\n if (paths.length > 0 && !matchesAnyGlob(context.filename, paths)) {\n return {}\n }\n\n const check = (node: ComponentFunction): void => {\n const firstParam = node.params[0]\n\n if (!firstParam || !isComponent(node)) {\n return\n }\n\n const annotatedParam = getAnnotatedParam(firstParam)\n const innerType = (annotatedParam as AnnotatedNode).typeAnnotation?.typeAnnotation?.type\n\n if (innerType !== INLINE_OBJECT_TYPE) {\n return\n }\n\n const name = getComponentName(node)\n\n context.report(\n name === null\n ? { node: annotatedParam, messageId: 'useNamedPropsTypeAnonymous' }\n : { node: annotatedParam, messageId: 'useNamedPropsType', data: { name } },\n )\n }\n\n return {\n ArrowFunctionExpression: check,\n FunctionDeclaration: check,\n FunctionExpression: check,\n }\n },\n}\n", "import type { Rule } from 'eslint'\nimport { existsSync } from 'node:fs'\nimport path from 'node:path'\n\nimport { bodyDeclaresComponent } from '../../utils/component'\nimport { matchesAnyGlob } from '../../utils/path-match'\nimport type { ExtraTarget, StoryPathOptions } from '../../utils/story-path'\nimport { DEFAULT_STORY_PATH_OPTIONS, classifyComponent, deriveExpectedStoryPaths } from '../../utils/story-path'\n\ninterface Options {\n paths?: string[]\n ignore?: string[]\n storiesDir?: string\n storySuffix?: string\n storyExtensions?: string[]\n componentSuffix?: string\n requireComponentAst?: boolean\n extraTargets?: ExtraTarget[]\n}\n\n/** Pick the story-path knobs out of the rule options, leaving defaults to the helper. */\nconst toStoryPathOptions = (options: Options): Partial<StoryPathOptions> => {\n const picked: Partial<StoryPathOptions> = {}\n\n if (options.storiesDir !== undefined) {\n picked.storiesDir = options.storiesDir\n }\n\n if (options.storySuffix !== undefined) {\n picked.storySuffix = options.storySuffix\n }\n\n if (options.storyExtensions !== undefined) {\n picked.storyExtensions = options.storyExtensions\n }\n\n if (options.componentSuffix !== undefined) {\n picked.componentSuffix = options.componentSuffix\n }\n\n if (options.extraTargets !== undefined) {\n picked.extraTargets = options.extraTargets\n }\n\n return picked\n}\n\nexport const requireComponentStories: Rule.RuleModule = {\n meta: {\n type: 'problem',\n docs: {\n description: 'Require a co-located Storybook story for every dumb component.',\n recommended: true,\n url: 'https://github.com/ArthurSaenz/infra-kit/tree/main/apps/infra-kit/eslint-plugin#require-component-stories',\n },\n schema: [\n {\n type: 'object',\n properties: {\n paths: {\n type: 'array',\n items: { type: 'string' },\n description: 'Optional globs; when provided the rule only runs for files whose path matches one.',\n },\n ignore: {\n type: 'array',\n items: { type: 'string' },\n description: 'Optional globs; the rule is skipped for matching files, even if they also match `paths`.',\n },\n storiesDir: {\n type: 'string',\n description: `Story directory name (default '${DEFAULT_STORY_PATH_OPTIONS.storiesDir}').`,\n },\n storySuffix: {\n type: 'string',\n description: `Suffix inserted before the extension (default '${DEFAULT_STORY_PATH_OPTIONS.storySuffix}').`,\n },\n storyExtensions: {\n type: 'array',\n items: { type: 'string' },\n description: 'Extensions a satisfying story file may have, in priority order.',\n },\n componentSuffix: {\n type: 'string',\n description: `Basename suffix a component file must end with (default '${DEFAULT_STORY_PATH_OPTIONS.componentSuffix}'; '' disables).`,\n },\n requireComponentAst: {\n type: 'boolean',\n description: 'When true (default), only require a story for files that actually declare a component.',\n },\n extraTargets: {\n type: 'array',\n items: {\n type: 'object',\n properties: {\n componentsDir: { type: 'string' },\n anchorParentDir: { type: 'string' },\n storyMode: { enum: ['feature-root', 'sibling'] },\n },\n required: ['componentsDir', 'storyMode'],\n additionalProperties: false,\n },\n description: 'Extra structured component layouts (componentsDir + optional anchorParentDir + storyMode).',\n },\n },\n additionalProperties: false,\n },\n ],\n messages: {\n missingStory: \"Dumb component '{{component}}' is missing a Storybook story (expected at '{{expected}}').\",\n },\n },\n\n create(context) {\n const options = (context.options[0] ?? {}) as Options\n const paths = options.paths ?? []\n const ignore = options.ignore ?? []\n const requireComponentAst = options.requireComponentAst ?? true\n const storyPathOptions = toStoryPathOptions(options)\n\n // `ignore` takes precedence: skip excluded files even when they also match `paths`.\n if (ignore.length > 0 && matchesAnyGlob(context.filename, ignore)) {\n return {}\n }\n\n if (paths.length > 0 && !matchesAnyGlob(context.filename, paths)) {\n return {}\n }\n\n return {\n Program(program) {\n // Is this file a dumb component that requires a story, and where would the story live?\n if (!classifyComponent(context.filename, storyPathOptions)) {\n return\n }\n\n // Only enforce on files that actually declare a component (avoids flagging stray\n // non-component files placed under a components/ directory).\n if (requireComponentAst && !bodyDeclaresComponent(program.body)) {\n return\n }\n\n const candidates = deriveExpectedStoryPaths(context.filename, storyPathOptions)\n\n // The story is satisfied if ANY candidate (by extension) exists on disk.\n const hasStory = candidates.some((candidate) => {\n return existsSync(candidate)\n })\n\n if (hasStory) {\n return\n }\n\n context.report({\n node: program,\n messageId: 'missingStory',\n data: {\n component: path.posix.basename(context.filename.split('\\\\').join('/')),\n expected: candidates[0] ?? '',\n },\n })\n },\n }\n },\n}\n", "import path from 'node:path'\n\n/** Where a story file lives relative to its component. */\nexport type StoryMode = 'feature-root' | 'sibling'\n\n/** A consumer-defined extra component layout (structured \u2014 never a glob). */\nexport interface ExtraTarget {\n /** Immediate parent directory name a component file must sit directly inside. */\n componentsDir: string\n /** Optional grandparent directory name gate (e.g. `features`). */\n anchorParentDir?: string\n /** Where the story is expected for files matched by this target. */\n storyMode: StoryMode\n}\n\nexport interface StoryPathOptions {\n /** Story directory name (default `__stories__`). */\n storiesDir: string\n /** Suffix inserted before the extension (default `.stories`). */\n storySuffix: string\n /** Extensions a satisfying story file may have, in priority order. */\n storyExtensions: string[]\n /** Extensions a file must have to be considered a component. */\n componentExtensions: string[]\n /** Basename suffix a component file must end with (default `-component`; `''` disables). */\n componentSuffix: string\n /** Additional structured component layouts beyond the two built-ins. */\n extraTargets: ExtraTarget[]\n}\n\nexport const DEFAULT_STORY_PATH_OPTIONS: StoryPathOptions = {\n storiesDir: '__stories__',\n storySuffix: '.stories',\n storyExtensions: ['.tsx', '.jsx', '.ts', '.js'],\n componentExtensions: ['.tsx', '.jsx'],\n componentSuffix: '-component',\n extraTargets: [],\n}\n\nconst resolveOptions = (opts?: Partial<StoryPathOptions>): StoryPathOptions => {\n return { ...DEFAULT_STORY_PATH_OPTIONS, ...opts }\n}\n\n/** Normalize OS-native separators to posix so all downstream path logic is deterministic. */\nconst toPosix = (filePath: string): string => {\n return filePath.split('\\\\').join('/')\n}\n\ninterface ParsedComponent {\n /** Posix directory of the file. */\n dir: string\n /** Basename without its extension. */\n base: string\n /** Original extension (e.g. `.tsx`). */\n ext: string\n /** Immediate parent directory name. */\n parent: string\n /** Grandparent directory name. */\n grandparent: string\n /** Great-grandparent directory name. */\n greatGrandparent: string\n}\n\n/** Parse a file path into the segment view the gate and derivation both need. */\nconst parse = (filePath: string): ParsedComponent => {\n const normalized = toPosix(filePath)\n const segments = normalized.split('/')\n const basename = segments[segments.length - 1] ?? ''\n const ext = path.posix.extname(basename)\n const base = ext ? basename.slice(0, -ext.length) : basename\n\n return {\n dir: path.posix.dirname(normalized),\n base,\n ext,\n parent: segments[segments.length - 2] ?? '',\n grandparent: segments[segments.length - 3] ?? '',\n greatGrandparent: segments[segments.length - 4] ?? '',\n }\n}\n\n/** Whether the file passes the component preconditions (extension + name suffix). */\nconst passesComponentPreconditions = (parsed: ParsedComponent, options: StoryPathOptions): boolean => {\n if (!options.componentExtensions.includes(parsed.ext)) {\n return false\n }\n\n return options.componentSuffix === '' || parsed.base.endsWith(options.componentSuffix)\n}\n\n/**\n * Classify a file as a dumb component requiring a story, resolving WHERE its story should live.\n * Returns null when the file is not a component-requiring-a-story under any branch.\n *\n * Exactly one admit-condition may hold:\n * - feature-root: direct child of `components/` whose chain is `features/<f>/components`.\n * - sibling: a `components/default/<name>-component` file (parent `default`, grandparent `components`).\n * - extraTargets: a structured consumer-defined layout.\n */\nexport const classifyComponent = (filePath: string, opts?: Partial<StoryPathOptions>): { mode: StoryMode } | null => {\n const options = resolveOptions(opts)\n const parsed = parse(filePath)\n\n if (!passesComponentPreconditions(parsed, options)) {\n return null\n }\n\n // (a) feature-root \u2014 immediate parent is `components` AND the chain is `features/<feature>/components`.\n if (parsed.parent === 'components' && parsed.greatGrandparent === 'features') {\n return { mode: 'feature-root' }\n }\n\n // (b) sibling \u2014 `components/default/<name>-component.*` (NOT a direct child of `components/`).\n if (parsed.parent === 'default' && parsed.grandparent === 'components') {\n return { mode: 'sibling' }\n }\n\n // (c) extraTargets \u2014 structured layouts (componentsDir + optional anchorParentDir).\n for (const target of options.extraTargets) {\n const parentMatches = parsed.parent === target.componentsDir\n const anchorMatches = target.anchorParentDir == null || parsed.grandparent === target.anchorParentDir\n\n if (parentMatches && anchorMatches) {\n return { mode: target.storyMode }\n }\n }\n\n return null\n}\n\n/**\n * Ordered candidate story paths for a component file. Empty when the file is not a\n * component-requiring-a-story (see {@link classifyComponent}). The story is considered present\n * when ANY candidate exists on disk.\n */\nexport const deriveExpectedStoryPaths = (filePath: string, opts?: Partial<StoryPathOptions>): string[] => {\n const options = resolveOptions(opts)\n const classification = classifyComponent(filePath, options)\n\n if (!classification) {\n return []\n }\n\n const parsed = parse(filePath)\n\n // feature-root: dirname(file) is `.../components`, so its parent is the feature root.\n // sibling: the story dir sits next to the component file itself.\n const storyBaseDir = classification.mode === 'feature-root' ? path.posix.dirname(parsed.dir) : parsed.dir\n const storyDir = path.posix.join(storyBaseDir, options.storiesDir)\n\n return options.storyExtensions.map((extension) => {\n return path.posix.join(storyDir, `${parsed.base}${options.storySuffix}${extension}`)\n })\n}\n", "import type * as ESTree from 'estree'\n\nexport type FunctionNode = ESTree.ArrowFunctionExpression | ESTree.FunctionDeclaration | ESTree.FunctionExpression\n\n// Keys that are never child AST nodes (back-reference + source positions + the discriminant).\nconst NON_CHILD_KEYS = new Set(['parent', 'loc', 'range', 'type'])\n\nconst LOOP_TYPES = new Set(['ForStatement', 'ForInStatement', 'ForOfStatement', 'WhileStatement', 'DoWhileStatement'])\nconst NESTED_FUNCTION_TYPES = new Set(['FunctionDeclaration', 'FunctionExpression', 'ArrowFunctionExpression'])\n\n// Mutable walk context: the running score plus the enclosing function's name (for recursion).\ninterface Ctx {\n score: number\n name: string | null\n}\n\nconst isNode = (value: unknown): value is ESTree.Node => {\n return typeof value === 'object' && value !== null && typeof (value as { type?: unknown }).type === 'string'\n}\n\n/**\n * The direct child AST nodes of `node`, read generically from its own enumerable\n * properties (skipping `parent`/`loc`/`range`). estree does not model JSX, but JSX\n * nodes still carry a string `type`, so embedded `&&`/ternaries are reached too.\n */\nconst childrenOf = (node: ESTree.Node): ESTree.Node[] => {\n const children: ESTree.Node[] = []\n\n for (const key of Object.keys(node)) {\n if (NON_CHILD_KEYS.has(key)) {\n continue\n }\n\n const value = (node as unknown as Record<string, unknown>)[key]\n\n if (Array.isArray(value)) {\n children.push(...value.filter(isNode))\n } else if (isNode(value)) {\n children.push(value)\n }\n }\n\n return children\n}\n\n// Flatten a logical chain into its operand leaves while collecting operators in order.\nconst flattenLogicalOperators = (node: ESTree.Node, operators: string[]): ESTree.Node[] => {\n if (node.type !== 'LogicalExpression') {\n return [node]\n }\n\n const left = flattenLogicalOperators(node.left, operators)\n\n operators.push(node.operator)\n\n const right = flattenLogicalOperators(node.right, operators)\n\n return [...left, ...right]\n}\n\n// Score = number of contiguous runs of the SAME operator (`a && b && c` \u2192 1, `a && b || c` \u2192 2).\nconst countOperatorRuns = (operators: string[]): number => {\n let runs = 0\n let previous: string | null = null\n\n for (const operator of operators) {\n if (operator !== previous) {\n runs += 1\n previous = operator\n }\n }\n\n return runs\n}\n\nconst recurseChildren = (ctx: Ctx, node: ESTree.Node, nesting: number): void => {\n for (const child of childrenOf(node)) {\n walk(ctx, child, nesting)\n }\n}\n\nconst handleLogical = (ctx: Ctx, node: ESTree.LogicalExpression, nesting: number): void => {\n const operators: string[] = []\n const operands = flattenLogicalOperators(node, operators)\n\n ctx.score += countOperatorRuns(operators)\n\n for (const operand of operands) {\n walk(ctx, operand, nesting)\n }\n}\n\nconst handleAlternate = (ctx: Ctx, alternate: ESTree.Statement | null | undefined, nesting: number): void => {\n if (!alternate) {\n return\n }\n\n // `else if` (the alternate IS another `if`): +1 with no nesting bump, processed\n // inline so the chained `if` does not also take its own structural increment.\n if (alternate.type === 'IfStatement') {\n ctx.score += 1\n walk(ctx, alternate.test, nesting)\n walk(ctx, alternate.consequent, nesting + 1)\n handleAlternate(ctx, alternate.alternate, nesting)\n\n return\n }\n\n // plain `else`: +1, body nested one level.\n ctx.score += 1\n walk(ctx, alternate, nesting + 1)\n}\n\nconst handleIf = (ctx: Ctx, node: ESTree.IfStatement, nesting: number): void => {\n ctx.score += 1 + nesting\n walk(ctx, node.test, nesting)\n walk(ctx, node.consequent, nesting + 1)\n handleAlternate(ctx, node.alternate, nesting)\n}\n\nconst handleTernary = (ctx: Ctx, node: ESTree.ConditionalExpression, nesting: number): void => {\n ctx.score += 1 + nesting\n walk(ctx, node.test, nesting)\n walk(ctx, node.consequent, nesting + 1)\n walk(ctx, node.alternate, nesting + 1)\n}\n\nconst handleSwitch = (ctx: Ctx, node: ESTree.SwitchStatement, nesting: number): void => {\n ctx.score += 1 + nesting\n walk(ctx, node.discriminant, nesting)\n\n for (const switchCase of node.cases) {\n if (switchCase.test) {\n walk(ctx, switchCase.test, nesting)\n }\n\n for (const statement of switchCase.consequent) {\n walk(ctx, statement, nesting + 1)\n }\n }\n}\n\nconst handleLoop = (ctx: Ctx, node: ESTree.Node, nesting: number): void => {\n ctx.score += 1 + nesting\n\n const body = (node as { body?: ESTree.Node }).body\n\n for (const child of childrenOf(node)) {\n // The loop body nests one level; conditions/headers stay at this level.\n walk(ctx, child, child === body ? nesting + 1 : nesting)\n }\n}\n\nconst handleTry = (ctx: Ctx, node: ESTree.TryStatement, nesting: number): void => {\n walk(ctx, node.block, nesting)\n\n if (node.handler) {\n ctx.score += 1 + nesting\n walk(ctx, node.handler.body, nesting + 1)\n }\n\n if (node.finalizer) {\n walk(ctx, node.finalizer, nesting)\n }\n}\n\nconst handleCall = (ctx: Ctx, node: ESTree.CallExpression, nesting: number): void => {\n if (ctx.name && node.callee.type === 'Identifier' && node.callee.name === ctx.name) {\n ctx.score += 1\n }\n\n recurseChildren(ctx, node, nesting)\n}\n\nfunction walk(ctx: Ctx, node: ESTree.Node, nesting: number): void {\n const type = node.type as string\n\n if (type === 'LogicalExpression') {\n handleLogical(ctx, node as ESTree.LogicalExpression, nesting)\n } else if (type === 'IfStatement') {\n handleIf(ctx, node as ESTree.IfStatement, nesting)\n } else if (type === 'ConditionalExpression') {\n handleTernary(ctx, node as ESTree.ConditionalExpression, nesting)\n } else if (type === 'SwitchStatement') {\n handleSwitch(ctx, node as ESTree.SwitchStatement, nesting)\n } else if (LOOP_TYPES.has(type)) {\n handleLoop(ctx, node, nesting)\n } else if (type === 'TryStatement') {\n handleTry(ctx, node as ESTree.TryStatement, nesting)\n } else if (NESTED_FUNCTION_TYPES.has(type)) {\n // Nested functions take no structural increment, but their bodies nest one level.\n walk(ctx, (node as FunctionNode).body, nesting + 1)\n } else if (type === 'CallExpression') {\n handleCall(ctx, node as ESTree.CallExpression, nesting)\n } else {\n recurseChildren(ctx, node, nesting)\n }\n}\n\n/**\n * Cognitive complexity of a function per the SonarSource white-paper model.\n *\n * Each `if`/ternary/switch/loop/`catch` adds 1 plus the current nesting level;\n * `else`/`else if` adds 1 with no nesting bump; each run of a logical operator\n * adds 1; recursion (a direct call to the enclosing function by name) adds 1.\n * Nesting deepens inside every branch, loop, switch, `catch`, and nested function.\n *\n * @example\n * cognitiveComplexity(node) // 0 for a flat function, 1 for a single `if`\n */\nexport const cognitiveComplexity = (fn: FunctionNode, enclosingName?: string | null): number => {\n const fallbackName = fn.type === 'FunctionDeclaration' ? (fn.id?.name ?? null) : null\n const ctx: Ctx = { score: 0, name: enclosingName ?? fallbackName }\n\n walk(ctx, fn.body, 0)\n\n return ctx.score\n}\n", "import type { Rule, SourceCode } from 'eslint'\nimport type * as ESTree from 'estree'\n\nimport { cognitiveComplexity } from '../../utils/cognitive-complexity'\nimport type { FunctionNode } from '../../utils/cognitive-complexity'\nimport { matchesAnyGlob } from '../../utils/path-match'\n\ninterface Options {\n minComplexity?: number\n exampleComplexity?: number\n paths?: string[]\n ignore?: string[]\n}\n\n// Defaults chosen so only genuinely \"substantial\" functions are flagged, and only the\n// most complex of those are pushed to also carry a worked `@example`.\nconst DEFAULT_MIN_COMPLEXITY = 8\nconst DEFAULT_EXAMPLE_COMPLEXITY = 12\n\ntype MessageId = 'missingExample' | 'missingJsdoc'\n\ninterface Settings {\n minComplexity: number\n exampleComplexity: number\n}\n\ninterface Target {\n fn: FunctionNode\n name: string\n // Nodes whose leading comments may carry the qualifying JSDoc (declaration + any `export` wrapper).\n anchors: ESTree.Node[]\n}\n\ninterface Violation {\n messageId: MessageId\n data: Record<string, number | string>\n}\n\nconst isTargetFn = (node: ESTree.Node | null | undefined): node is FunctionNode => {\n return node?.type === 'ArrowFunctionExpression' || node?.type === 'FunctionExpression'\n}\n\n/** Split a top-level statement into its inner declaration and any `export` wrapper. */\nconst getExportInfo = (\n statement: ESTree.Statement | ESTree.ModuleDeclaration,\n): { exportStmt: ESTree.Node | null; declaration: ESTree.Node | null } => {\n if (statement.type === 'ExportNamedDeclaration' || statement.type === 'ExportDefaultDeclaration') {\n return { exportStmt: statement, declaration: (statement.declaration as ESTree.Node | null) ?? null }\n }\n\n return { exportStmt: null, declaration: statement }\n}\n\n/** The named, definable functions declared by a single top-level declaration. */\nconst targetsFromDeclaration = (declaration: ESTree.Node, anchors: ESTree.Node[]): Target[] => {\n if (declaration.type === 'FunctionDeclaration') {\n return declaration.id ? [{ fn: declaration, name: declaration.id.name, anchors }] : []\n }\n\n if (declaration.type === 'VariableDeclaration') {\n return declaration.declarations.flatMap((declarator) => {\n return declarator.id.type === 'Identifier' && isTargetFn(declarator.init)\n ? [{ fn: declarator.init, name: declarator.id.name, anchors }]\n : []\n })\n }\n\n return []\n}\n\n/** Every named top-level function definition (bare or `export`/`export default` wrapped). */\nconst collectTargets = (body: Array<ESTree.Statement | ESTree.ModuleDeclaration>): Target[] => {\n return body.flatMap((statement) => {\n const { exportStmt, declaration } = getExportInfo(statement)\n\n if (!declaration) {\n return []\n }\n\n const anchors = exportStmt ? [exportStmt, declaration] : [declaration]\n\n return targetsFromDeclaration(declaration, anchors)\n })\n}\n\n/** Whether a `/** \u2026 *\\/` JSDoc block immediately precedes any anchor. */\nconst hasJsdocBlock = (sourceCode: SourceCode, anchors: ESTree.Node[]): boolean => {\n return anchors.some((anchor) => {\n return sourceCode.getCommentsBefore(anchor).some((comment) => {\n return comment.type === 'Block' && comment.value.startsWith('*')\n })\n })\n}\n\n/** Whether such a leading JSDoc block ALSO carries an `@example` tag. */\nconst hasJsdocExample = (sourceCode: SourceCode, anchors: ESTree.Node[]): boolean => {\n return anchors.some((anchor) => {\n return sourceCode.getCommentsBefore(anchor).some((comment) => {\n return comment.type === 'Block' && comment.value.startsWith('*') && comment.value.includes('@example')\n })\n })\n}\n\n/** Decide whether a target violates the rule and, if so, which message fits. */\nconst decideViolation = (target: Target, settings: Settings, sourceCode: SourceCode): Violation | null => {\n const complexity = cognitiveComplexity(target.fn, target.name)\n const { minComplexity, exampleComplexity } = settings\n\n // Below the floor: no documentation requirement at all.\n if (complexity < minComplexity) {\n return null\n }\n\n const { name } = target\n\n // A missing block always takes precedence over a missing `@example`.\n if (!hasJsdocBlock(sourceCode, target.anchors)) {\n return { messageId: 'missingJsdoc', data: { name, complexity, minComplexity } }\n }\n\n if (complexity >= exampleComplexity && !hasJsdocExample(sourceCode, target.anchors)) {\n return { messageId: 'missingExample', data: { name, complexity, exampleComplexity } }\n }\n\n return null\n}\n\nexport const requireJsdocExample: Rule.RuleModule = {\n meta: {\n type: 'suggestion',\n docs: {\n description:\n 'Graduated JSDoc requirement by cognitive complexity: at or above `minComplexity` a function must carry a leading JSDoc block, and at or above `exampleComplexity` that block must also include an `@example` tag.',\n recommended: true,\n url: 'https://github.com/ArthurSaenz/infra-kit/tree/main/apps/infra-kit/eslint-plugin#require-jsdoc-example',\n },\n schema: [\n {\n type: 'object',\n properties: {\n minComplexity: {\n type: 'integer',\n minimum: 1,\n description: 'Cognitive complexity at or above which a function must carry a leading JSDoc block.',\n },\n exampleComplexity: {\n type: 'integer',\n minimum: 1,\n description: 'Cognitive complexity at or above which the JSDoc block must also include an `@example` tag.',\n },\n paths: {\n type: 'array',\n items: { type: 'string' },\n description:\n 'Optional glob patterns. When provided, the rule only runs for files whose path matches one of them.',\n },\n ignore: {\n type: 'array',\n items: { type: 'string' },\n description:\n 'Optional glob patterns. The rule is skipped for files whose path matches one of them, even if it also matches `paths`.',\n },\n },\n additionalProperties: false,\n },\n ],\n messages: {\n missingJsdoc:\n 'function \"{{name}}\" has cognitive complexity {{complexity}} (>= {{minComplexity}}); add a JSDoc block documenting it.',\n missingExample:\n 'function \"{{name}}\" has cognitive complexity {{complexity}} (>= {{exampleComplexity}}); its JSDoc block needs an `@example` documenting usage.',\n },\n },\n\n create(context) {\n const options = (context.options[0] ?? {}) as Options\n const paths = options.paths ?? []\n const ignore = options.ignore ?? []\n\n // `ignore` takes precedence: skip excluded files even when they also match `paths`.\n if (ignore.length > 0 && matchesAnyGlob(context.filename, ignore)) {\n return {}\n }\n\n if (paths.length > 0 && !matchesAnyGlob(context.filename, paths)) {\n return {}\n }\n\n const settings: Settings = {\n minComplexity: options.minComplexity ?? DEFAULT_MIN_COMPLEXITY,\n exampleComplexity: options.exampleComplexity ?? DEFAULT_EXAMPLE_COMPLEXITY,\n }\n\n const { sourceCode } = context\n\n return {\n Program(program) {\n for (const target of collectTargets(program.body)) {\n const violation = decideViolation(target, settings, sourceCode)\n\n if (violation) {\n context.report({ node: target.fn, messageId: violation.messageId, data: violation.data })\n }\n }\n },\n }\n },\n}\n", "import type { Rule } from 'eslint'\n\nimport { findPackageRoot } from '../../utils/package-root'\nimport { resolvePackageType } from '../../utils/package-type-reader'\nimport { matchesAnyGlob } from '../../utils/path-match'\n\nexport interface Options {\n /** Globs; the rule is skipped for matching files. */\n ignore?: string[]\n}\n\nconst TEST_FILE = /\\.(?:test|spec)\\.[cm]?[jt]sx?$/\nconst SPEC_SUFFIX = /\\.spec(\\.[cm]?[jt]sx?)$/\nconst TESTS_DIR = '__tests__'\nconst FEATURES_DIR = 'features'\n\ntype MessageId = 'outsideTestsDir' | 'outsideFeatureTestsDir' | 'specSuffix'\n\ninterface Violation {\n messageId: MessageId\n data: Record<string, string>\n}\n\n/** Relative from `src/` keeps the message short and still unambiguous inside a package. */\nconst fromSrc = (dirs: readonly string[]): string[] => {\n const srcIndex = dirs.lastIndexOf('src')\n\n return srcIndex >= 0 ? dirs.slice(srcIndex) : dirs.slice(-1)\n}\n\n/**\n * The directory of the feature `dirs` sits in (`\u2026/src/\u2026/features/<name>`), or null outside a\n * feature. Only a `features/` below `src/` counts, so a checkout path that happens to contain one\n * cannot turn every test into a feature test; the innermost wins so a nested feature owns its tests.\n */\nconst featureRoot = (dirs: readonly string[]): string[] | null => {\n const srcIndex = dirs.lastIndexOf('src')\n const featuresIndex = dirs.lastIndexOf(FEATURES_DIR)\n\n return srcIndex >= 0 && featuresIndex > srcIndex && featuresIndex + 1 < dirs.length\n ? dirs.slice(0, featuresIndex + 2)\n : null\n}\n\nconst locationViolation = (dirs: readonly string[], basename: string): Violation | null => {\n const feature = featureRoot(dirs)\n\n // A feature keeps every test in its root `__tests__/` (the `/infra-kit:fe-architect` layout), so a\n // `services/__tests__/` inside it is as misplaced as a test next to its source.\n if (feature !== null) {\n if (dirs[feature.length] === TESTS_DIR) {\n return null\n }\n\n return {\n messageId: 'outsideFeatureTestsDir',\n data: { basename, target: [...fromSrc(feature), TESTS_DIR, basename].join('/') },\n }\n }\n\n if (dirs.includes(TESTS_DIR)) {\n return null\n }\n\n return {\n messageId: 'outsideTestsDir',\n data: { basename, target: [...fromSrc(dirs), TESTS_DIR, basename].join('/') },\n }\n}\n\nconst findViolations = (filename: string, ignore: readonly string[]): Violation[] => {\n if (!TEST_FILE.test(filename) || (ignore.length > 0 && matchesAnyGlob(filename, ignore))) {\n return []\n }\n\n // e2e packages keep specs under `tests/*` by their own layout (see `e2e-file-layout`).\n const packageRoot = findPackageRoot(filename)\n\n if (packageRoot !== null && resolvePackageType(packageRoot) === 'e2e') {\n return []\n }\n\n const dirs = filename.split('/')\n const basename = dirs.pop()!\n const location = locationViolation(dirs, basename)\n\n const suffix: Violation | null = SPEC_SUFFIX.test(basename)\n ? { messageId: 'specSuffix', data: { basename, target: basename.replace(SPEC_SUFFIX, '.test$1') } }\n : null\n\n return [location, suffix].filter((violation): violation is Violation => {\n return violation !== null\n })\n}\n\nexport const testLocation: Rule.RuleModule = {\n meta: {\n type: 'problem',\n docs: {\n description:\n 'Require unit tests to be `*.test.*` files in a `__tests__/` folder beside the code they test \u2014 the feature root\u2019s inside a frontend feature.',\n recommended: true,\n url: 'https://github.com/ArthurSaenz/infra-kit/tree/main/apps/infra-kit/eslint-plugin#test-location',\n },\n schema: [\n {\n type: 'object',\n properties: {\n ignore: {\n type: 'array',\n items: { type: 'string' },\n description: 'Optional globs; the rule is skipped for matching files.',\n },\n },\n additionalProperties: false,\n },\n ],\n messages: {\n outsideTestsDir:\n '`{{basename}}` sits next to its source. Move it to `{{target}}` \u2014 tests live in a `__tests__/` folder beside the code they test.',\n outsideFeatureTestsDir:\n '`{{basename}}` is a feature test outside the feature root. Move it to `{{target}}` \u2014 a feature keeps all its tests in one `__tests__/` at its root.',\n specSuffix:\n '`{{basename}}` uses `.spec`. Rename it to `{{target}}` \u2014 unit tests are `*.test.*`; `.spec` belongs to Playwright specs in an e2e package.',\n },\n },\n\n create(context) {\n const options = (context.options[0] ?? {}) as Options\n const violations = findViolations(context.filename.split('\\\\').join('/'), options.ignore ?? [])\n\n if (violations.length === 0) {\n return {}\n }\n\n return {\n // Reported on Program: the violation is the file's location, not any node inside it.\n Program(program) {\n for (const violation of violations) {\n context.report({ node: program, messageId: violation.messageId, data: violation.data })\n }\n },\n }\n },\n}\n", "import type { Rule } from 'eslint'\n\n// Each './<rule>' resolves to './<rule>/index.ts' (the rule's folder barrel) under\n// `moduleResolution: bundler`; a future switch to node16/nodenext would require explicit paths.\nimport { atomNaming } from './atom-naming'\nimport { componentArrowFunction } from './component-arrow-function'\nimport { componentClassname } from './component-classname'\nimport { componentFileOrder } from './component-file-order'\nimport { componentNameMatchesFile } from './component-name-matches-file'\nimport { dumbComponentPurity } from './dumb-component-purity'\nimport { e2eDescribeOrder } from './e2e-describe-order'\nimport { e2eFileLayout } from './e2e-file-layout'\nimport { e2eFileOrder } from './e2e-file-order'\nimport { e2ePageObjectMemberOrder } from './e2e-page-object-member-order'\nimport { e2eTestTags } from './e2e-test-tags'\nimport { e2eTestTitle } from './e2e-test-title'\nimport { e2eTopLevelDescribe } from './e2e-top-level-describe'\nimport { featureFiles } from './feature-files'\nimport { featurePublicApi } from './feature-public-api'\nimport { layerImports } from './layer-imports'\nimport { maxComponentsPerFile } from './max-components-per-file'\nimport { maxJsdocLines } from './max-jsdoc-lines'\nimport { maxJsdocSummaryLines } from './max-jsdoc-summary-lines'\nimport { maxJsxReturnSize } from './max-jsx-return-size'\nimport { noFeatureSelfImport } from './no-feature-self-import'\nimport { noHooksInServices } from './no-hooks-in-services'\nimport { packageStructure } from './package-structure'\nimport { propsDestructuringBlankLine } from './props-destructuring-blank-line'\nimport { propsDestructuringNewline } from './props-destructuring-newline'\nimport { propsTypeName } from './props-type-name'\nimport { propsTypeReference } from './props-type-reference'\nimport { requireComponentStories } from './require-component-stories'\nimport { requireJsdocExample } from './require-jsdoc-example'\nimport { testLocation } from './test-location'\n\nexport const rules: Record<string, Rule.RuleModule> = {\n 'props-destructuring-newline': propsDestructuringNewline,\n 'props-destructuring-blank-line': propsDestructuringBlankLine,\n 'props-type-reference': propsTypeReference,\n 'props-type-name': propsTypeName,\n 'component-file-order': componentFileOrder,\n 'component-arrow-function': componentArrowFunction,\n 'max-components-per-file': maxComponentsPerFile,\n 'max-jsx-return-size': maxJsxReturnSize,\n 'max-jsdoc-lines': maxJsdocLines,\n 'max-jsdoc-summary-lines': maxJsdocSummaryLines,\n 'require-component-stories': requireComponentStories,\n 'require-jsdoc-example': requireJsdocExample,\n 'package-structure': packageStructure,\n 'test-location': testLocation,\n 'layer-imports': layerImports,\n 'feature-public-api': featurePublicApi,\n 'no-feature-self-import': noFeatureSelfImport,\n 'e2e-file-layout': e2eFileLayout,\n 'e2e-file-order': e2eFileOrder,\n 'e2e-page-object-member-order': e2ePageObjectMemberOrder,\n 'e2e-describe-order': e2eDescribeOrder,\n 'e2e-top-level-describe': e2eTopLevelDescribe,\n 'e2e-test-tags': e2eTestTags,\n 'e2e-test-title': e2eTestTitle,\n 'atom-naming': atomNaming,\n 'no-hooks-in-services': noHooksInServices,\n 'feature-files': featureFiles,\n 'component-name-matches-file': componentNameMatchesFile,\n 'component-classname': componentClassname,\n 'dumb-component-purity': dumbComponentPurity,\n}\n", "import type { ESLint, Linter } from 'eslint'\n\nimport { rules } from './rules'\n\nconst PLUGIN_NAME = '@wl'\n\nconst plugin: ESLint.Plugin & { configs: Record<string, Linter.Config | Linter.Config[]> } = {\n meta: {\n name: '@wl/eslint-plugin',\n version: '0.44.0',\n },\n rules,\n configs: {},\n}\n\n/**\n * Flat-config preset that registers the plugin and turns every rule on, scoped to\n * the files each rule is meant for. It is an array of config blocks, so spread it:\n *\n * @example\n * import wl from '@wl/eslint-plugin'\n *\n * export default [...wl.configs.recommended]\n */\nplugin.configs.recommended = [\n {\n files: ['**/*.tsx'],\n plugins: {\n [PLUGIN_NAME]: plugin,\n },\n rules: {\n [`${PLUGIN_NAME}/props-destructuring-newline`]: 'error',\n [`${PLUGIN_NAME}/props-destructuring-blank-line`]: 'error',\n [`${PLUGIN_NAME}/props-type-reference`]: 'error',\n [`${PLUGIN_NAME}/props-type-name`]: 'error',\n [`${PLUGIN_NAME}/component-file-order`]: 'error',\n // Pages and routes are excluded: route/page modules commonly use `function`\n // declarations (and framework conventions like default-exported page functions).\n [`${PLUGIN_NAME}/component-arrow-function`]: ['error', { ignore: ['**/pages/**', '**/routes/**'] }],\n [`${PLUGIN_NAME}/require-component-stories`]: 'error',\n // Advisory: flags returns that render too many JSX elements; extract into a\n // variable or sub-component. Warn-class by nature (`type: 'suggestion'`);\n // severity confirmed against a repo-wide dry run at the default ceiling.\n [`${PLUGIN_NAME}/max-jsx-return-size`]: 'error',\n // Caps component declarations per file; extra components belong in their own\n // files. Pages and routes are excluded (framework conventions co-locate\n // route trees and default-exported page functions). Ceiling confirmed\n // against a repo-wide dry run at the default.\n [`${PLUGIN_NAME}/max-components-per-file`]: ['error', { ignore: ['**/pages/**', '**/routes/**'] }],\n },\n },\n // Storybook stories legitimately deviate from the component conventions: the\n // imports \u2192 *Props \u2192 component order (meta/args/decorators/render fns), and\n // named templates that reference the *component's* props type (e.g.\n // `const Template = (args: ButtonProps) => ...`) rather than their own\n // `<TemplateName>Props`. So both the ordering and the props-type-name rules\n // would only produce noise there. Every other rule stays enabled for stories.\n {\n files: ['**/*.stories.{ts,tsx}'],\n rules: {\n [`${PLUGIN_NAME}/component-file-order`]: 'off',\n [`${PLUGIN_NAME}/props-type-name`]: 'off',\n },\n },\n // Dumb presentational files (`*-component.tsx`) follow the one-component-per-file\n // convention the props/order/stories rules already assume, so they get a tighter\n // ceiling of 1. This MUST come AFTER the global `**/*.tsx` block: flat config\n // REPLACES rule options across matching blocks (it does not merge), and `ignore`\n // is re-declared here so pages/routes dumb-components keep their exemption.\n // A repo-wide dry run found zero `*-component.tsx` files declaring >1 component.\n {\n files: ['**/*-component.tsx'],\n rules: {\n [`${PLUGIN_NAME}/max-components-per-file`]: [\n 'error',\n { maxComponents: 1, ignore: ['**/pages/**', '**/routes/**'] },\n ],\n },\n },\n // `require-jsdoc-example` targets named functions, which overwhelmingly live in\n // plain `.ts` lib/util modules (not just `.tsx`), so it gets its OWN block scoped\n // to both extensions \u2014 the tsx-only blocks above would never reach where it\n // matters. Severity is `warn` (not `error`) so first adoption does not break\n // consumers' CI; the graduated defaults (minComplexity 8 \u2192 require a JSDoc block,\n // exampleComplexity 12 \u2192 also require `@example`) are left implicit. Flat config\n // REPLACES rule options across matching blocks, so this rule lives only here and\n // relies on no option merging.\n {\n files: ['**/*.ts', '**/*.tsx'],\n plugins: {\n [PLUGIN_NAME]: plugin,\n },\n rules: {\n [`${PLUGIN_NAME}/require-jsdoc-example`]: 'warn',\n },\n },\n // `package-structure` judges a file by its directory, not its contents, so it must reach every\n // source extension \u2014 the `**/*.tsx` block above would never see a `.ts` under `src/core/`. Its\n // own block (like `require-jsdoc-example`) with `plugins` re-declared keeps it self-contained.\n // `error` from day one: the per-type entries are overridable per package via `config({ rules })`.\n {\n files: ['**/*.{ts,tsx,js,jsx}'],\n plugins: {\n [PLUGIN_NAME]: plugin,\n },\n rules: {\n [`${PLUGIN_NAME}/package-structure`]: 'error',\n },\n },\n // Scoped by filename, so it never runs on non-test files. e2e packages are exempt inside the rule\n // (by package type); `*.e2e.test.*` covers e2e suites that sit in a package of another type.\n {\n files: ['**/*.{test,spec}.{ts,tsx,js,jsx,mts,cts,mjs,cjs}'],\n plugins: {\n [PLUGIN_NAME]: plugin,\n },\n rules: {\n [`${PLUGIN_NAME}/test-location`]: ['error', { ignore: ['**/*.e2e.test.*'] }],\n },\n },\n // Import-path rules read where a specifier lands under `src/`, so they reach every source extension.\n // They gate themselves on the package type (backend and e2e packages have no UI layering).\n {\n files: ['**/*.{ts,tsx,js,jsx,mts,cts,mjs,cjs}'],\n plugins: {\n [PLUGIN_NAME]: plugin,\n },\n rules: {\n [`${PLUGIN_NAME}/layer-imports`]: 'error',\n [`${PLUGIN_NAME}/feature-public-api`]: 'error',\n [`${PLUGIN_NAME}/no-feature-self-import`]: 'error',\n },\n },\n // fe-architect naming and purity rules. Each gates itself on path and package type (backend and e2e\n // packages are skipped), so one repo-wide block is enough.\n {\n files: ['**/*.{ts,tsx}'],\n plugins: {\n [PLUGIN_NAME]: plugin,\n },\n rules: {\n [`${PLUGIN_NAME}/atom-naming`]: 'error',\n [`${PLUGIN_NAME}/no-hooks-in-services`]: 'error',\n [`${PLUGIN_NAME}/feature-files`]: 'error',\n [`${PLUGIN_NAME}/component-name-matches-file`]: 'error',\n [`${PLUGIN_NAME}/component-classname`]: 'error',\n [`${PLUGIN_NAME}/dumb-component-purity`]: 'error',\n },\n },\n // The e2e rules gate themselves on the package type, so a repo-wide glob costs one cached type\n // lookup per file elsewhere.\n {\n files: ['**/*.{ts,tsx,js,jsx,mts,cts,mjs,cjs}'],\n plugins: {\n [PLUGIN_NAME]: plugin,\n },\n rules: {\n [`${PLUGIN_NAME}/e2e-file-layout`]: 'error',\n [`${PLUGIN_NAME}/e2e-file-order`]: 'error',\n [`${PLUGIN_NAME}/e2e-page-object-member-order`]: 'error',\n [`${PLUGIN_NAME}/e2e-describe-order`]: 'error',\n [`${PLUGIN_NAME}/e2e-top-level-describe`]: 'error',\n [`${PLUGIN_NAME}/e2e-test-tags`]: 'error',\n [`${PLUGIN_NAME}/e2e-test-title`]: 'error',\n },\n },\n]\n\nexport const meta: ESLint.Plugin['meta'] = plugin.meta\nexport const configs: Record<string, Linter.Config | Linter.Config[]> = plugin.configs\nexport { rules }\n\nexport default plugin\n"],
5
- "mappings": "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",
3
+ "sources": ["../src/utils/path-match.ts", "../src/rules/atom-naming/atom-naming.ts", "../src/utils/component.ts", "../src/rules/component-arrow-function/component-arrow-function.ts", "../src/utils/package-root.ts", "../../config/src/lib/package-type/package-type.ts", "../src/utils/package-type-reader.ts", "../src/utils/component-file-scope.ts", "../src/utils/exported-components.ts", "../src/rules/component-classname/component-classname.ts", "../src/rules/component-file-order/component-file-order.ts", "../src/rules/component-name-matches-file/component-name-matches-file.ts", "../src/rules/dumb-component-purity/dumb-component-purity.ts", "../src/utils/playwright-call.ts", "../src/rules/e2e-describe-order/e2e-describe-order.ts", "../src/rules/e2e-file-layout/e2e-file-layout.ts", "../src/utils/attached-comments.ts", "../src/rules/e2e-file-order/e2e-file-order.ts", "../src/rules/e2e-page-object-member-order/e2e-page-object-member-order.ts", "../src/rules/e2e-test-tags/e2e-test-tags.ts", "../src/rules/e2e-test-title/e2e-test-title.ts", "../src/rules/e2e-top-level-describe/e2e-top-level-describe.ts", "../src/rules/feature-files/feature-files.ts", "../src/utils/import-target.ts", "../src/rules/feature-public-api/feature-public-api.ts", "../src/rules/layer-imports/layer-imports.ts", "../src/rules/max-components-per-file/max-components-per-file.ts", "../src/rules/max-jsdoc-lines/max-jsdoc-lines.ts", "../src/rules/max-jsdoc-summary-lines/max-jsdoc-summary-lines.ts", "../src/rules/max-jsx-return-size/max-jsx-return-size.ts", "../src/rules/no-feature-self-import/no-feature-self-import.ts", "../src/rules/no-hooks-in-services/no-hooks-in-services.ts", "../src/rules/package-structure/package-structure.ts", "../src/rules/props-destructuring-blank-line/props-destructuring-blank-line.ts", "../src/rules/props-destructuring-newline/props-destructuring-newline.ts", "../src/rules/props-type-name/props-type-name.ts", "../src/rules/props-type-reference/props-type-reference.ts", "../src/rules/require-component-stories/require-component-stories.ts", "../src/utils/story-path.ts", "../src/utils/cognitive-complexity.ts", "../src/rules/require-jsdoc-example/require-jsdoc-example.ts", "../src/rules/services-namespace-import/services-namespace-import.ts", "../src/rules/test-location/test-location.ts", "../src/rules/index.ts", "../src/index.ts"],
4
+ "sourcesContent": ["// Characters that must be escaped when embedded literally into a RegExp source.\nconst REGEX_METACHARS = new Set(['\\\\', '^', '$', '.', '|', '+', '(', ')', '[', ']', '{', '}'])\n\n/**\n * Convert a glob pattern to an (unanchored) RegExp.\n *\n * - `**` matches any characters, including path separators.\n * - `*` matches any characters except a path separator.\n * - `?` matches a single non-separator character.\n *\n * The result is intentionally unanchored so a pattern matches anywhere in the\n * path (e.g. `features/**` matches `/repo/src/features/x/comp.tsx`).\n */\nconst globToRegExp = (glob: string): RegExp => {\n let source = ''\n\n for (let index = 0; index < glob.length; index++) {\n const char = glob[index]!\n\n if (char === '*') {\n if (glob[index + 1] === '*') {\n source += '.*'\n index++\n\n // Consume a trailing slash so `**/foo` also matches a bare `foo`.\n if (glob[index + 1] === '/') {\n index++\n }\n } else {\n source += '[^/]*'\n }\n } else if (char === '?') {\n source += '[^/]'\n } else if (REGEX_METACHARS.has(char)) {\n source += `\\\\${char}`\n } else {\n source += char\n }\n }\n\n return new RegExp(source)\n}\n\n/** Whether `filename` matches at least one of the provided glob `patterns`. */\nexport const matchesAnyGlob = (filename: string, patterns: readonly string[]): boolean => {\n const normalized = filename.split('\\\\').join('/')\n\n return patterns.some((pattern) => {\n return globToRegExp(pattern).test(normalized)\n })\n}\n", "import type { Rule } from 'eslint'\nimport type * as ESTree from 'estree'\n\nimport { matchesAnyGlob } from '../../utils/path-match'\n\ninterface Options {\n asyncSuffix?: string\n syncSuffix?: string\n argsSuffix?: string\n readablePrefix?: string\n paths?: string[]\n ignore?: string[]\n}\n\nconst ATOM_FACTORIES = new Set([\n 'atom',\n 'atomWithStorage',\n 'atomWithReset',\n 'atomWithDefault',\n 'atomFamily',\n 'loadable',\n 'selectAtom',\n 'splitAtom',\n 'focusAtom',\n])\n\n// TS-only nodes are not modelled by estree.\ninterface TypedPattern {\n typeAnnotation?: {\n typeAnnotation?: { type: string; typeName?: { type: string; name?: string } }\n }\n}\n\nconst isWriteOnly = (call: ESTree.CallExpression): boolean => {\n const [read, write] = call.arguments\n\n // `atom<T | null>(null)` is a primitive atom; only a `null` read paired with a write is write-only.\n return (\n call.callee.type === 'Identifier' &&\n call.callee.name === 'atom' &&\n read?.type === 'Literal' &&\n read.value === null &&\n write !== undefined\n )\n}\n\nconst asFunction = (\n node: ESTree.Node | undefined,\n): ESTree.ArrowFunctionExpression | ESTree.FunctionExpression | null => {\n return node?.type === 'ArrowFunctionExpression' || node?.type === 'FunctionExpression' ? node : null\n}\n\nconst isNamedArgsType = (param: ESTree.Pattern, argsSuffix: string): boolean => {\n const target = param.type === 'AssignmentPattern' ? param.left : param\n\n if (target.type === 'RestElement') {\n return false\n }\n\n const annotation = (target as TypedPattern).typeAnnotation?.typeAnnotation\n\n // Unannotated args are typed through the `atom<\u2026>` generics or are implicit `any`; tsc owns both.\n if (annotation === undefined) {\n return true\n }\n\n return (\n annotation.type === 'TSTypeReference' &&\n annotation.typeName?.type === 'Identifier' &&\n annotation.typeName.name!.endsWith(argsSuffix)\n )\n}\n\n/** `toggleOpenedCardAtom` \u2192 `ToggleOpenedCardArgs`, for the message's example. */\nconst exampleArgsType = (name: string, suffixes: string[], argsSuffix: string): string => {\n const suffix = suffixes.find((candidate) => {\n return name.endsWith(candidate) && name.length > candidate.length\n })\n\n const base = (suffix === undefined ? name : name.slice(0, -suffix.length)).replace(/^\\$+/, '')\n\n return `${base.charAt(0).toUpperCase()}${base.slice(1)}${argsSuffix}`\n}\n\nexport const atomNaming: Rule.RuleModule = {\n meta: {\n type: 'suggestion',\n docs: {\n description:\n 'Require readable Jotai atoms to start with `$`, write-only atoms to end with `Fx` (async) or `Atom` (sync), and write-only atoms to take a single `*Args` object.',\n recommended: true,\n url: 'https://github.com/ArthurSaenz/infra-kit/tree/main/apps/infra-kit/eslint-plugin#atom-naming',\n },\n schema: [\n {\n type: 'object',\n properties: {\n asyncSuffix: {\n type: 'string',\n minLength: 1,\n description: \"Suffix of an async write-only atom (default 'Fx').\",\n },\n syncSuffix: {\n type: 'string',\n minLength: 1,\n description: \"Suffix of a sync write-only atom (default 'Atom').\",\n },\n argsSuffix: {\n type: 'string',\n minLength: 1,\n description: \"Suffix of the type naming a write-only atom's argument (default 'Args').\",\n },\n readablePrefix: {\n type: 'string',\n minLength: 1,\n description: \"Prefix of a readable atom (default '$').\",\n },\n paths: {\n type: 'array',\n items: { type: 'string' },\n description:\n 'Optional glob patterns. When provided, the rule only runs for files whose path matches one of them.',\n },\n ignore: {\n type: 'array',\n items: { type: 'string' },\n description:\n 'Optional glob patterns. The rule is skipped for files whose path matches one of them, even if it also matches `paths`.',\n },\n },\n additionalProperties: false,\n },\n ],\n messages: {\n readablePrefix: 'Readable atom \"{{name}}\" must start with \"{{prefix}}\" (e.g. \"{{expected}}\").',\n writeOnlyPrefix: 'Write-only atom \"{{name}}\" must not start with \"{{prefix}}\": that prefix marks readable atoms.',\n writeOnlySuffix: 'Write-only atom \"{{name}}\" must end with {{expected}}.',\n argsNotNamed:\n 'Write-only atom \"{{name}}\" must take a single argument typed with a named `*{{suffix}}` type (e.g. `args: {{example}}`).',\n },\n },\n\n create(context) {\n const options = (context.options[0] ?? {}) as Options\n const paths = options.paths ?? []\n const ignore = options.ignore ?? []\n\n if (ignore.length > 0 && matchesAnyGlob(context.filename, ignore)) {\n return {}\n }\n\n if (paths.length > 0 && !matchesAnyGlob(context.filename, paths)) {\n return {}\n }\n\n const asyncSuffix = options.asyncSuffix ?? 'Fx'\n const syncSuffix = options.syncSuffix ?? 'Atom'\n const argsSuffix = options.argsSuffix ?? 'Args'\n const prefix = options.readablePrefix ?? '$'\n\n const checkWriteOnly = (id: ESTree.Identifier, call: ESTree.CallExpression): void => {\n const { name } = id\n const write = asFunction(call.arguments[1])\n\n if (name.startsWith(prefix)) {\n context.report({ node: id, messageId: 'writeOnlyPrefix', data: { name, prefix } })\n }\n\n // A write function passed by reference cannot be seen to be async, so either suffix passes.\n const asyncForm = { suffix: asyncSuffix, kind: 'async' }\n const syncForm = { suffix: syncSuffix, kind: 'sync' }\n let accepted = [asyncForm, syncForm]\n\n if (write !== null) {\n accepted = [write.async ? asyncForm : syncForm]\n }\n\n const hasSuffix = accepted.some((form) => {\n return name.endsWith(form.suffix)\n })\n\n if (!hasSuffix) {\n const expected = accepted\n .map((form) => {\n return `\"${form.suffix}\" (${form.kind})`\n })\n .join(' or ')\n\n context.report({ node: id, messageId: 'writeOnlySuffix', data: { name, expected } })\n }\n\n // Jotai's write signature is `(get, set, ...args)`: everything past `set` is the caller's input.\n const inputs = write?.params.slice(2) ?? []\n\n if (inputs.length === 0) {\n return\n }\n\n if (inputs.length > 1 || !isNamedArgsType(inputs[0]!, argsSuffix)) {\n context.report({\n node: inputs[0]!,\n messageId: 'argsNotNamed',\n data: { name, suffix: argsSuffix, example: exampleArgsType(name, [asyncSuffix, syncSuffix], argsSuffix) },\n })\n }\n }\n\n const check = (node: ESTree.VariableDeclarator): void => {\n const { id, init } = node\n\n if (\n id.type !== 'Identifier' ||\n init?.type !== 'CallExpression' ||\n init.callee.type !== 'Identifier' ||\n !ATOM_FACTORIES.has(init.callee.name)\n ) {\n return\n }\n\n if (isWriteOnly(init)) {\n checkWriteOnly(id, init)\n\n return\n }\n\n // Everything else is readable: primitive, derived, read-write, and `atomFamily(...)`, whose\n // members are read through the family even when they are write-only themselves.\n if (!id.name.startsWith(prefix)) {\n context.report({\n node: id,\n messageId: 'readablePrefix',\n data: { name: id.name, prefix, expected: `${prefix}${id.name}` },\n })\n }\n }\n\n return {\n 'Program > VariableDeclaration > VariableDeclarator': check,\n 'Program > ExportNamedDeclaration > VariableDeclaration > VariableDeclarator': check,\n }\n },\n}\n", "import type * as ESTree from 'estree'\n\nexport type ComponentFunction = ESTree.ArrowFunctionExpression | ESTree.FunctionDeclaration | ESTree.FunctionExpression\n\n// Minimal structural view over the `parent` back-reference ESLint adds to every node.\ninterface WithParent {\n parent?: ESTree.Node\n}\n\n// Calls that wrap a component while preserving its identity (memo, forwardRef, observer, ...).\nconst COMPONENT_WRAPPER_CALLEES = new Set(['memo', 'forwardRef', 'observer', 'React.memo', 'React.forwardRef'])\n\n// Node types that introduce a new function scope \u2014 their returns are not the outer component's.\nconst NESTED_SCOPES = new Set(['FunctionDeclaration', 'FunctionExpression', 'ArrowFunctionExpression'])\n\nconst isPascalCase = (name: string): boolean => {\n return /^[A-Z]/.test(name)\n}\n\nexport const isJsxNode = (node: ESTree.Node | null | undefined): boolean => {\n if (!node) {\n return false\n }\n\n const type = node.type as string\n\n return type === 'JSXElement' || type === 'JSXFragment'\n}\n\nconst getParent = (node: ESTree.Node | undefined): ESTree.Node | undefined => {\n return (node as (WithParent & ESTree.Node) | undefined)?.parent\n}\n\n/** Best-effort name of a call's callee: `memo` for `memo(...)`, `React.memo` for `React.memo(...)`. */\nconst getCalleeName = (callee: ESTree.CallExpression['callee']): string | null => {\n if (callee.type === 'Identifier') {\n return callee.name\n }\n\n if (\n callee.type === 'MemberExpression' &&\n callee.object.type === 'Identifier' &&\n callee.property.type === 'Identifier'\n ) {\n return `${callee.object.name}.${callee.property.name}`\n }\n\n return null\n}\n\n/**\n * Resolve the declared name of a function, looking through component wrappers\n * such as `memo`/`forwardRef` so that `const Comp = memo(({ a }) => ...)` is\n * still recognised by its PascalCase variable name.\n */\nexport const getComponentName = (node: ComponentFunction): string | null => {\n if (node.type === 'FunctionDeclaration') {\n return node.id?.name ?? null\n }\n\n let current = getParent(node)\n\n // Walk through wrapping call expressions (memo, forwardRef, React.memo, ...).\n while (current?.type === 'CallExpression') {\n const calleeName = getCalleeName(current.callee)\n\n if (!calleeName || !COMPONENT_WRAPPER_CALLEES.has(calleeName)) {\n break\n }\n\n current = getParent(current)\n }\n\n if (current?.type === 'VariableDeclarator' && current.id.type === 'Identifier') {\n return current.id.name\n }\n\n return null\n}\n\n/**\n * Collect every *own* return argument of a function \u2014 the expression of each\n * `return <expr>` reachable without entering a nested function scope, plus the\n * implicit-return body of an expression-bodied arrow.\n *\n * Bare `return;` (a null argument) contributes nothing, so callers never receive\n * a null and can safely walk each result. This is the multi-return counterpart\n * to the boolean `returnsJsx`, which is defined in terms of it; the deliberate\n * \"skip nested scopes\" behaviour answers *which* returns belong to this function\n * (a `return` inside an inline `.map`/IIFE callback is that callback's return,\n * not this one's).\n */\nexport const collectOwnReturnArguments = (node: ComponentFunction): ESTree.Expression[] => {\n if (node.body.type !== 'BlockStatement') {\n return [node.body]\n }\n\n const args: ESTree.Expression[] = []\n\n const visit = (current: ESTree.Node | null | undefined): void => {\n if (!current || NESTED_SCOPES.has(current.type)) {\n return\n }\n\n if (current.type === 'ReturnStatement') {\n if (current.argument) {\n args.push(current.argument)\n }\n\n return\n }\n\n if (current.type === 'IfStatement') {\n visit(current.consequent)\n visit(current.alternate)\n\n return\n }\n\n if (current.type === 'BlockStatement') {\n for (const statement of current.body) {\n visit(statement)\n }\n\n return\n }\n\n if (current.type === 'SwitchStatement') {\n const statements = current.cases.flatMap((switchCase) => {\n return switchCase.consequent\n })\n\n for (const statement of statements) {\n visit(statement)\n }\n\n return\n }\n\n if (current.type === 'TryStatement') {\n visit(current.block)\n visit(current.handler?.body)\n visit(current.finalizer)\n\n return\n }\n\n if (\n current.type === 'ForStatement' ||\n current.type === 'ForInStatement' ||\n current.type === 'ForOfStatement' ||\n current.type === 'WhileStatement' ||\n current.type === 'DoWhileStatement'\n ) {\n visit(current.body)\n }\n }\n\n for (const statement of node.body.body) {\n visit(statement)\n }\n\n return args\n}\n\n/** Whether a function returns JSX, scanning its own body without descending into nested functions. */\nconst returnsJsx = (node: ComponentFunction): boolean => {\n return collectOwnReturnArguments(node).some(isJsxNode)\n}\n\n/** A function is treated as a React component when it is PascalCase-named or returns JSX. */\nexport const isComponent = (node: ComponentFunction): boolean => {\n const name = getComponentName(node)\n\n if (name && isPascalCase(name)) {\n return true\n }\n\n return returnsJsx(node)\n}\n\nconst isComponentFunctionNode = (node: ESTree.Node): node is ComponentFunction => {\n return (\n node.type === 'ArrowFunctionExpression' || node.type === 'FunctionExpression' || node.type === 'FunctionDeclaration'\n )\n}\n\n/**\n * Extract the component function from an expression, unwrapping a single layer of\n * component wrappers (`memo(fn)`, `forwardRef(fn)`, `React.memo(fn)`, ...). Returns\n * null when no function is found.\n */\nexport const getComponentFunction = (node: ESTree.Node | null | undefined): ComponentFunction | null => {\n if (!node) {\n return null\n }\n\n if (isComponentFunctionNode(node)) {\n return node\n }\n\n if (node.type === 'CallExpression') {\n for (const argument of node.arguments) {\n if (argument.type === 'SpreadElement') {\n continue\n }\n\n const found = getComponentFunction(argument)\n\n if (found) {\n return found\n }\n }\n }\n\n return null\n}\n\n// TS-only nodes are not modelled by estree. A parameter's `typeAnnotation` wraps the type node;\n// for a named type that inner node is a `TSTypeReference` whose `typeName` is the referenced\n// identifier (`Props`, `ButtonProps`, ...). Inline object types, qualified names (`NS.Props`) and\n// generics surface a different `typeName` shape and are intentionally left unresolved.\ninterface TypeReferenceNode {\n type?: string\n typeName?: { type?: string; name?: string }\n}\n\ninterface AnnotatedParam {\n typeAnnotation?: {\n typeAnnotation?: TypeReferenceNode\n }\n}\n\n/**\n * The parameter that actually carries the props type annotation. A default value wraps the\n * parameter in an `AssignmentPattern` (`(props: Props = {})`), moving the annotation onto its\n * `.left`; unwrap one layer so the annotation is found either way.\n */\nexport const getAnnotatedParam = (param: ESTree.Pattern): ESTree.Pattern => {\n return param.type === 'AssignmentPattern' ? param.left : param\n}\n\n/** The named type referenced by a component function's first parameter (`Props`), or null. */\nexport const getPropsTypeNameFromFunction = (node: ComponentFunction): string | null => {\n const firstParam = node.params[0]\n\n if (!firstParam) {\n return null\n }\n\n const inner = (getAnnotatedParam(firstParam) as AnnotatedParam).typeAnnotation?.typeAnnotation\n\n if (inner?.type !== 'TSTypeReference' || inner.typeName?.type !== 'Identifier') {\n return null\n }\n\n return inner.typeName.name ?? null\n}\n\n/**\n * Resolve the props type name a component *uses* \u2014 the named type on its first parameter \u2014\n * looking through component wrappers (`memo`/`forwardRef`). Returns null when the component is\n * anonymous of props (no parameter) or its props type is not a simple named reference (inline\n * object, qualified name, generic). Mirrors `getDeclaredComponentName`'s node dispatch so a\n * `const`-declared arrow component resolves through its `init`, not the `VariableDeclaration`.\n */\nexport const getComponentPropsTypeName = (node: ESTree.Node | null): string | null => {\n if (!node) {\n return null\n }\n\n if (node.type === 'FunctionDeclaration') {\n return isComponent(node) ? getPropsTypeNameFromFunction(node) : null\n }\n\n if (node.type === 'VariableDeclaration') {\n for (const declaration of node.declarations) {\n const fn = getComponentFunction(declaration.init)\n\n if (fn && isComponent(fn)) {\n return getPropsTypeNameFromFunction(fn)\n }\n }\n\n return null\n }\n\n const fn = getComponentFunction(node)\n\n return fn && isComponent(fn) ? getPropsTypeNameFromFunction(fn) : null\n}\n\n/** Unwrap an `export ...` statement to the declaration it wraps (or the statement itself). */\nexport const unwrapExport = (statement: ESTree.Statement | ESTree.ModuleDeclaration): ESTree.Node | null => {\n if (statement.type === 'ExportNamedDeclaration' || statement.type === 'ExportDefaultDeclaration') {\n return (statement.declaration as ESTree.Node | null) ?? null\n }\n\n return statement\n}\n\n/** Whether a single top-level declaration declares a React component. */\nexport const declaresComponent = (node: ESTree.Node | null): boolean => {\n if (!node) {\n return false\n }\n\n if (node.type === 'FunctionDeclaration') {\n return isComponent(node)\n }\n\n if (node.type === 'VariableDeclaration') {\n return node.declarations.some((declaration) => {\n const fn = getComponentFunction(declaration.init)\n\n return fn ? isComponent(fn) : false\n })\n }\n\n const fn = getComponentFunction(node)\n\n return fn ? isComponent(fn) : false\n}\n\n/**\n * Resolve the name of the React component declared by a single top-level declaration,\n * or null when the declaration is not a component or the component is anonymous\n * (e.g. `export default () => <div />`). Mirrors `declaresComponent`'s node dispatch and\n * resolves the name through component wrappers (`memo`/`forwardRef`).\n */\nexport const getDeclaredComponentName = (node: ESTree.Node | null): string | null => {\n if (!node) {\n return null\n }\n\n if (node.type === 'FunctionDeclaration') {\n return isComponent(node) ? getComponentName(node) : null\n }\n\n if (node.type === 'VariableDeclaration') {\n for (const declaration of node.declarations) {\n const fn = getComponentFunction(declaration.init)\n\n if (fn && isComponent(fn)) {\n return getComponentName(fn)\n }\n }\n\n return null\n }\n\n const fn = getComponentFunction(node)\n\n return fn && isComponent(fn) ? getComponentName(fn) : null\n}\n\n/** Whether any top-level statement in a program body declares a React component. */\nexport const bodyDeclaresComponent = (body: Array<ESTree.Statement | ESTree.ModuleDeclaration>): boolean => {\n return body.some((statement) => {\n return declaresComponent(unwrapExport(statement))\n })\n}\n", "import type { Rule } from 'eslint'\nimport type * as ESTree from 'estree'\n\nimport { getComponentFunction, getComponentName, isComponent, unwrapExport } from '../../utils/component'\nimport type { ComponentFunction } from '../../utils/component'\nimport { matchesAnyGlob } from '../../utils/path-match'\n\ninterface Options {\n paths?: string[]\n ignore?: string[]\n}\n\n// Fallback used when a component is anonymous (e.g. `export default memo(function () { ... })`),\n// since `getComponentName` returns null rather than a placeholder in that case.\nconst ANONYMOUS_NAME = 'component'\n\ntype MessageId = 'functionDeclaration' | 'functionExpression'\n\ninterface Violation {\n node: ESTree.Node\n messageId: MessageId\n name: string\n}\n\nconst reportName = (fn: ComponentFunction): string => {\n return getComponentName(fn) ?? ANONYMOUS_NAME\n}\n\n/**\n * Violation for a single non-`VariableDeclaration` top-level declaration:\n * - a `function Foo() {}` component declaration (incl. exported/default/anonymous), or\n * - an expression that resolves to a function-expression component\n * (e.g. `export default memo(function () { ... })`).\n */\nconst nonVariableViolation = (declaration: ESTree.Node): Violation | null => {\n if (declaration.type === 'FunctionDeclaration') {\n return isComponent(declaration)\n ? { node: declaration, messageId: 'functionDeclaration', name: reportName(declaration) }\n : null\n }\n\n const fn = getComponentFunction(declaration)\n\n return fn?.type === 'FunctionExpression' && isComponent(fn)\n ? { node: fn, messageId: 'functionExpression', name: reportName(fn) }\n : null\n}\n\n/** Function-expression component violations across every declarator in a `const`/`let`/`var`. */\nconst variableViolations = (declaration: ESTree.VariableDeclaration): Violation[] => {\n const violations: Violation[] = []\n\n for (const declarator of declaration.declarations) {\n const fn = getComponentFunction(declarator.init)\n\n if (fn?.type === 'FunctionExpression' && isComponent(fn)) {\n violations.push({ node: declarator, messageId: 'functionExpression', name: reportName(fn) })\n }\n }\n\n return violations\n}\n\n/** Every non-arrow component declared at the top level of the program body. */\nconst collectViolations = (body: Array<ESTree.Statement | ESTree.ModuleDeclaration>): Violation[] => {\n const violations: Violation[] = []\n\n for (const statement of body) {\n const declaration = unwrapExport(statement)\n\n if (!declaration) {\n continue\n }\n\n if (declaration.type === 'VariableDeclaration') {\n violations.push(...variableViolations(declaration))\n\n continue\n }\n\n const violation = nonVariableViolation(declaration)\n\n if (violation) {\n violations.push(violation)\n }\n }\n\n return violations\n}\n\nexport const componentArrowFunction: Rule.RuleModule = {\n meta: {\n type: 'suggestion',\n docs: {\n description:\n 'Enforce that React components are declared as arrow functions, not `function` declarations or function expressions.',\n recommended: true,\n url: 'https://github.com/ArthurSaenz/infra-kit/tree/main/apps/infra-kit/eslint-plugin#component-arrow-function',\n },\n schema: [\n {\n type: 'object',\n properties: {\n paths: {\n type: 'array',\n items: { type: 'string' },\n description:\n 'Optional glob patterns. When provided, the rule only runs for files whose path matches one of them.',\n },\n ignore: {\n type: 'array',\n items: { type: 'string' },\n description:\n 'Optional glob patterns. The rule is skipped for files whose path matches one of them, even if it also matches `paths`. Use this to exclude pages and routes (e.g. `**/pages/**`, `**/routes/**`).',\n },\n },\n additionalProperties: false,\n },\n ],\n messages: {\n functionDeclaration:\n 'React components must be arrow functions; convert the `function {{name}}` declaration to `const {{name}} = () => { \u2026 }`.',\n functionExpression:\n 'React components must be arrow functions; replace the `function` expression for `{{name}}` with an arrow function.',\n },\n },\n\n create(context) {\n const options = (context.options[0] ?? {}) as Options\n const paths = options.paths ?? []\n const ignore = options.ignore ?? []\n\n // `ignore` takes precedence: skip excluded files even when they also match `paths`.\n if (ignore.length > 0 && matchesAnyGlob(context.filename, ignore)) {\n return {}\n }\n\n if (paths.length > 0 && !matchesAnyGlob(context.filename, paths)) {\n return {}\n }\n\n return {\n Program(program) {\n for (const { node, messageId, name } of collectViolations(program.body)) {\n context.report({ node, messageId, data: { name } })\n }\n },\n }\n },\n}\n", "import fs from 'node:fs'\nimport path from 'node:path'\n\nexport const CONFIG_FILENAME = 'infra-kit.config.ts'\nconst PACKAGE_MARKERS = [CONFIG_FILENAME, 'package.json']\nconst REPO_MARKERS = ['pnpm-workspace.yaml']\n\nconst hasAnyMarker = (dir: string, markers: readonly string[]): boolean => {\n return markers.some((marker) => {\n return fs.existsSync(path.posix.join(dir, marker))\n })\n}\n\n// The steady-state cost of the rule is one `statSync` per linted file (see package-type-reader), so\n// the directory walk must not add a stat per ancestor per file: every dirname seen resolves to its\n// package root once per lint process.\nconst rootCache = new Map<string, string | null>()\n\n/** Nearest ancestor of `startDir` (inclusive) that holds one of `markers`, or null at the fs root. */\nconst findUp = (startDir: string, markers: readonly string[]): string | null => {\n let current = startDir\n\n while (!hasAnyMarker(current, markers)) {\n const parent = path.posix.dirname(current)\n\n if (parent === current) {\n return null\n }\n\n current = parent\n }\n\n return current\n}\n\n/**\n * The package directory a linted file belongs to: the nearest ancestor holding `infra-kit.config.ts`\n * or `package.json`. Null for virtual / relative filenames, which have no place on disk to walk from.\n */\nexport const findPackageRoot = (filename: string): string | null => {\n // ESLint hands rules `<input>` / `<text>` for virtual sources; there is nothing to walk up from.\n if (!path.posix.isAbsolute(filename)) {\n return null\n }\n\n const dir = path.posix.dirname(filename)\n const cached = rootCache.get(dir)\n\n if (cached !== undefined) {\n return cached\n }\n\n const root = findUp(dir, PACKAGE_MARKERS)\n\n rootCache.set(dir, root)\n\n return root\n}\n\n/**\n * The directory names between `<packageRoot>/src/` and `filename`, outermost first \u2014 `[]` for a\n * file directly in `src/`, null when the file is not under `src/` at all (so `dist/src/x/...`,\n * built output a consumer ships, is null too).\n */\nexport const dirsUnderSrc = (packageRoot: string, filename: string): string[] | null => {\n const srcPrefix = `${packageRoot}/src/`\n\n if (!filename.startsWith(srcPrefix)) {\n return null\n }\n\n return filename.slice(srcPrefix.length).split('/').slice(0, -1)\n}\n\n/** Nearest ancestor of `packageRoot` (inclusive) that is a pnpm workspace root, or null outside one. */\nexport const findRepoRoot = (packageRoot: string): string | null => {\n return findUp(packageRoot, REPO_MARKERS)\n}\n\n/** Drops the dirname \u2192 root memo; only tests that build and tear down fixture trees need this. */\nexport const resetPackageRootCache = (): void => {\n rootCache.clear()\n}\n", "import path from 'node:path'\n\n/**\n * The kind of workspace package a guidance block is written for. The repo root\n * has its own body and is deliberately not a `PackageType`.\n */\nexport type PackageType = 'frontend' | 'backend' | 'lib' | 'e2e' | 'mobile'\n\n/** Every package type, in registry order. Useful for exhaustive table-driven tests. */\nexport const PACKAGE_TYPES: readonly PackageType[] = ['frontend', 'backend', 'lib', 'e2e', 'mobile']\n\n/** The `package.json` fields package-type detection reads. */\nexport interface PackageTypeManifest {\n scripts?: Record<string, string>\n dependencies?: Record<string, string>\n devDependencies?: Record<string, string>\n peerDependencies?: Record<string, string>\n}\n\nexport interface DetectPackageTypeArgs {\n /** Absolute path to the package directory. */\n packageDir: string\n /** Absolute path to the repo root the directory convention is measured against. */\n repoRoot: string\n /** The package's parsed `package.json` (an empty object when it is missing or unreadable). */\n pkgJson: PackageTypeManifest\n /** `type` declared in the package's `infra-kit.config.ts`. Wins over every detected signal. */\n declaredType?: PackageType\n}\n\n/** Directory names under `apps/<app>/` that carry declared semantics inside infra-kit. */\nconst APP_DIRECTORY_TYPES: Readonly<Record<string, PackageType>> = {\n ui: 'frontend',\n api: 'backend',\n tests: 'e2e',\n}\n\n/** A directory with this basename is a Capacitor shell wherever it sits in the tree. */\nconst MOBILE_BASENAME = 'mobile-app'\n\n/**\n * Dependency signals, first match wins. `react` alone is deliberately absent:\n * component libraries carry it too, so `vite` + `react` + a `dev` script is what\n * separates an app from a library (handled separately below).\n */\nconst DEPENDENCY_SIGNALS: ReadonlyArray<{ type: PackageType; packages: readonly string[] }> = [\n { type: 'e2e', packages: ['@playwright/test'] },\n { type: 'mobile', packages: ['@capacitor/core', '@capacitor/cli'] },\n // `aws-lambda` / `@types/aws-lambda` are deliberately NOT signals: every consumer backend already\n // lives at `apps/<app>/api` (row 2), while the only packages those two deps would catch are\n // libraries (`packages/lib-core` in both consumers, the infra-kit CLI itself) \u2014 a lambda types\n // dependency alone never means backend, exactly as `react` alone never means frontend.\n { type: 'backend', packages: ['serverless'] },\n]\n\n/**\n * Type implied by where the package sits, or `null` when the path carries no\n * declared semantics. `apps/<app>/{ui,api,tests}` is already load-bearing inside\n * infra-kit (`infra-kit dev --target` keys must be `<app>/api` or `<app>/ui`), so this\n * is the repo's own convention rather than a heuristic \u2014 which is why it beats\n * the dependency signals.\n *\n * @example\n * fromDirectory('/repo/apps/client/ui', '/repo') // => 'frontend'\n * fromDirectory('/repo/packages/mobile-app', '/repo') // => 'mobile'\n */\nconst fromDirectory = (packageDir: string, repoRoot: string): PackageType | null => {\n const segments = path\n .relative(repoRoot, packageDir)\n .split(path.sep)\n .filter((segment) => {\n return segment !== '' && segment !== '.'\n })\n\n const [first, , third] = segments\n\n if (segments.length === 3 && first === 'apps' && third !== undefined) {\n const appType = APP_DIRECTORY_TYPES[third]\n\n if (appType) return appType\n }\n\n return segments.at(-1) === MOBILE_BASENAME ? 'mobile' : null\n}\n\n/**\n * Type implied by the merged `dependencies` / `devDependencies` / `peerDependencies`\n * plus the `dev` script, or `null` when nothing matches.\n *\n * @example\n * fromDependencies({ dependencies: { '@playwright/test': '^1' } }) // => 'e2e'\n * fromDependencies({ dependencies: { react: '^19' } }) // => null (react alone is not a frontend)\n */\nconst fromDependencies = (pkgJson: PackageTypeManifest): PackageType | null => {\n const deps = new Set([\n ...Object.keys(pkgJson.dependencies ?? {}),\n ...Object.keys(pkgJson.devDependencies ?? {}),\n ...Object.keys(pkgJson.peerDependencies ?? {}),\n ])\n\n for (const signal of DEPENDENCY_SIGNALS) {\n if (\n signal.packages.some((name) => {\n return deps.has(name)\n })\n )\n return signal.type\n }\n\n const isViteReactApp = deps.has('vite') && deps.has('react') && Boolean(pkgJson.scripts?.dev)\n\n return isViteReactApp ? 'frontend' : null\n}\n\n/**\n * Resolve a package's type by the \u00A73.2 precedence: an explicit `type` in\n * `infra-kit.config.ts` beats the directory convention, which beats the\n * dependency signals, which fall back to `lib`. There is no `unknown` \u2014 the\n * fallback is the least opinionated body, so an unrecognised package still gets\n * a usable block rather than a failing check.\n *\n * @example\n * detectPackageType({\n * packageDir: '/repo/apps/client/ui',\n * repoRoot: '/repo',\n * pkgJson: { dependencies: { '@playwright/test': '^1' } },\n * })\n * // => 'frontend' (the directory convention beats the dependency signal)\n */\nexport const detectPackageType = ({\n packageDir,\n repoRoot,\n pkgJson,\n declaredType,\n}: DetectPackageTypeArgs): PackageType => {\n return declaredType ?? fromDirectory(packageDir, repoRoot) ?? fromDependencies(pkgJson) ?? 'lib'\n}\n", "import type { PackageType, PackageTypeManifest } from '@slip-stream-kit/config/package-type'\nimport { PACKAGE_TYPES, detectPackageType } from '@slip-stream-kit/config/package-type'\nimport fs from 'node:fs'\nimport path from 'node:path'\n\nimport { CONFIG_FILENAME, findRepoRoot } from './package-root'\n\nconst BLOCK_COMMENT = /\\/\\*[\\s\\S]*?\\*\\//g\n// Full-line `//` comments only: a trailing `//` after code is left alone so the `https://` inside\n// every consumer's `templates.cloud` string value survives the strip. Indentation is `[ \\t]`, not\n// `\\s`, because under the `m` flag `\\s*` spans line breaks and backtracks super-linearly.\nconst FULL_LINE_COMMENT = /^[ \\t]*\\/\\/.*$/gm\n// Built from PACKAGE_TYPES so a sixth type added to the config package cannot escape the reader.\nconst DECLARED_TYPE = new RegExp(`(?:^|[\\\\s{,])type:\\\\s*['\"](${PACKAGE_TYPES.join('|')})['\"]`, 'm')\n\n/**\n * The literal `type` declared in an `infra-kit.config.ts` source text, or undefined when it is\n * absent, computed, or not one of the known types.\n *\n * The config is read as text rather than imported: `require(esm)` is cached by the ESM loader, so a\n * rewritten config would keep returning its old value, and importing it would execute consumer code\n * (and its zod import) inside the ESLint process. Comments are stripped first so a commented-out\n * `// type: 'backend'` above the live literal cannot win; the first live match does.\n */\nexport const readDeclaredType = (text: string): PackageType | undefined => {\n const stripped = text.replace(BLOCK_COMMENT, '').replace(FULL_LINE_COMMENT, '')\n const literal = DECLARED_TYPE.exec(stripped)?.[1]\n\n return PACKAGE_TYPES.find((candidate) => {\n return candidate === literal\n })\n}\n\ninterface CachedType {\n /** `-1` when the config file is absent, so its later creation is a cache miss like any edit. */\n mtimeMs: number\n type: PackageType\n}\n\nconst typeCache = new Map<string, CachedType>()\n\nconst configMtimeMs = (configPath: string): number => {\n try {\n return fs.statSync(configPath).mtimeMs\n } catch {\n return -1\n }\n}\n\nconst readManifest = (manifestPath: string): PackageTypeManifest => {\n try {\n return JSON.parse(fs.readFileSync(manifestPath, 'utf8')) as PackageTypeManifest\n } catch {\n return {}\n }\n}\n\n/**\n * The package's type: the literal declared in its `infra-kit.config.ts` when there is one, else the\n * CLI's inference from directory and dependency signals.\n *\n * One `statSync` on the config per call is the steady-state cost; the text is re-read only when the\n * mtime moved, so a config edit is seen by the next lint of any file in the package \u2014 in a CLI run\n * or a long-lived IDE server alike. `package.json` is read once per root and never revalidated: it\n * only feeds the dependency fallback, and a dependency change is a `pnpm install` event, not an\n * edit-lint loop.\n */\nexport const resolvePackageType = (packageRoot: string): PackageType => {\n const configPath = path.posix.join(packageRoot, CONFIG_FILENAME)\n const mtimeMs = configMtimeMs(configPath)\n const hit = typeCache.get(packageRoot)\n\n if (hit !== undefined && hit.mtimeMs === mtimeMs) {\n return hit.type\n }\n\n const declaredType = mtimeMs >= 0 ? readDeclaredType(fs.readFileSync(configPath, 'utf8')) : undefined\n\n const type = detectPackageType({\n packageDir: packageRoot,\n repoRoot: findRepoRoot(packageRoot) ?? packageRoot,\n pkgJson: readManifest(path.posix.join(packageRoot, 'package.json')),\n declaredType,\n })\n\n typeCache.set(packageRoot, { mtimeMs, type })\n\n return type\n}\n\n/** Drops the root \u2192 type memo; only tests that build and tear down fixture trees need this. */\nexport const resetPackageTypeCache = (): void => {\n typeCache.clear()\n}\n", "import { findPackageRoot } from './package-root'\nimport { resolvePackageType } from './package-type-reader'\nimport { matchesAnyGlob } from './path-match'\n\n/** Where a feature's dumb components live \u2014 the default scope of the dumb-component rules. */\nexport const DUMB_COMPONENT_PATHS = ['**/features/*/components/**/*.tsx', '**/*-component.tsx']\n\n// Backends and Playwright suites render no React, so a `.tsx` there is never a UI component.\nconst NON_UI_TYPES = new Set(['backend', 'e2e'])\n\nconst STORY_OR_TEST_DIR = /(?:^|\\/)(?:__tests__|__stories__)\\//\nconst STORY_OR_TEST_EXT = /\\.(?:stories|test|spec)\\.[cm]?[jt]sx?$/\n\n/** Whether `filename` is a story or test file, which renders components without being one. */\nexport const isStoryOrTestFile = (filename: string): boolean => {\n return STORY_OR_TEST_DIR.test(filename) || STORY_OR_TEST_EXT.test(filename)\n}\n\n/** Whether `filename` sits in a package that can hold UI components (virtual filenames count). */\nexport const isUiPackageFile = (filename: string): boolean => {\n const packageRoot = findPackageRoot(filename)\n\n return packageRoot === null || !NON_UI_TYPES.has(resolvePackageType(packageRoot))\n}\n\n/** The shared `paths`/`ignore` gate: ignore wins, an empty `paths` matches everything. */\nexport const isInScope = (filename: string, paths: readonly string[], ignore: readonly string[]): boolean => {\n if (ignore.length > 0 && matchesAnyGlob(filename, ignore)) {\n return false\n }\n\n return paths.length === 0 || matchesAnyGlob(filename, paths)\n}\n", "import type * as ESTree from 'estree'\n\nimport type { ComponentFunction } from './component'\nimport { getComponentFunction, isComponent } from './component'\n\nexport interface ExportedComponent {\n /** Local (declared) name, or null for an anonymous default export. */\n name: string | null\n /** The identifier that declares the name, or null for an anonymous default export. */\n id: ESTree.Identifier | null\n /** The node a variable lookup resolves the declaration from (`getDeclaredVariables`). */\n declaration: ESTree.FunctionDeclaration | ESTree.VariableDeclarator | null\n fn: ComponentFunction\n}\n\ntype TopLevelStatement = ESTree.Statement | ESTree.ModuleDeclaration\n\nconst fromFunctionDeclaration = (node: ESTree.FunctionDeclaration): ExportedComponent | null => {\n if (!isComponent(node)) {\n return null\n }\n\n return { name: node.id?.name ?? null, id: node.id ?? null, declaration: node.id ? node : null, fn: node }\n}\n\nconst fromVariableDeclaration = (node: ESTree.VariableDeclaration): ExportedComponent[] => {\n return node.declarations.flatMap((declarator) => {\n const fn = getComponentFunction(declarator.init)\n\n if (!fn || declarator.id.type !== 'Identifier' || !isComponent(fn)) {\n return []\n }\n\n return [{ name: declarator.id.name, id: declarator.id, declaration: declarator, fn }]\n })\n}\n\nconst fromDeclaration = (node: ESTree.Node | null | undefined): ExportedComponent[] => {\n if (node?.type === 'FunctionDeclaration') {\n const component = fromFunctionDeclaration(node)\n\n return component ? [component] : []\n }\n\n if (node?.type === 'VariableDeclaration') {\n return fromVariableDeclaration(node)\n }\n\n return []\n}\n\n/** Top-level, non-exported component declarations by name, for resolving `export { X }`. */\nconst collectLocalComponents = (body: TopLevelStatement[]): Map<string, ExportedComponent> => {\n const local = new Map<string, ExportedComponent>()\n\n for (const statement of body) {\n for (const component of fromDeclaration(statement)) {\n if (component.name !== null) {\n local.set(component.name, component)\n }\n }\n }\n\n return local\n}\n\nconst fromDefaultExport = (\n declaration: ESTree.ExportDefaultDeclaration['declaration'],\n local: Map<string, ExportedComponent>,\n): ExportedComponent[] => {\n if (declaration.type === 'Identifier') {\n const component = local.get(declaration.name)\n\n return component ? [component] : []\n }\n\n const node = declaration as ESTree.Node\n\n if (node.type === 'FunctionDeclaration' && node.id) {\n return fromDeclaration(node)\n }\n\n const fn = getComponentFunction(node)\n\n return fn && isComponent(fn) ? [{ name: null, id: null, declaration: null, fn }] : []\n}\n\nconst fromStatement = (statement: TopLevelStatement, local: Map<string, ExportedComponent>): ExportedComponent[] => {\n if (statement.type === 'ExportDefaultDeclaration') {\n return fromDefaultExport(statement.declaration, local)\n }\n\n if (statement.type !== 'ExportNamedDeclaration') {\n return []\n }\n\n if (statement.declaration) {\n return fromDeclaration(statement.declaration)\n }\n\n // `export { X } from './x'` is declared in another module.\n if (statement.source) {\n return []\n }\n\n return statement.specifiers.flatMap((specifier) => {\n const component = specifier.local.type === 'Identifier' ? local.get(specifier.local.name) : undefined\n\n return component ? [component] : []\n })\n}\n\n/**\n * The React components a module exports: `export const X = ...`, `export function X`,\n * `export default function X`, and `export { X }` / `export default X` of a local component.\n */\nexport const collectExportedComponents = (program: ESTree.Program): ExportedComponent[] => {\n const local = collectLocalComponents(program.body)\n\n const found = program.body.flatMap((statement) => {\n return fromStatement(statement, local)\n })\n\n return [...new Set(found)]\n}\n", "import type { Rule, SourceCode } from 'eslint'\nimport type * as ESTree from 'estree'\n\nimport type { ComponentFunction } from '../../utils/component'\nimport { collectOwnReturnArguments, getAnnotatedParam } from '../../utils/component'\nimport { DUMB_COMPONENT_PATHS, isInScope, isStoryOrTestFile, isUiPackageFile } from '../../utils/component-file-scope'\nimport type { ExportedComponent } from '../../utils/exported-components'\nimport { collectExportedComponents } from '../../utils/exported-components'\n\ninterface Options {\n paths?: string[]\n ignore?: string[]\n}\n\n// TS and JSX nodes are not modelled by estree; these are the minimal structural views the rule reads.\ninterface TsMember {\n type: string\n computed?: boolean\n key?: { type: string; name?: string; value?: unknown }\n range: [number, number]\n loc: ESTree.SourceLocation\n}\n\ninterface TsType {\n type: string\n members?: TsMember[]\n types?: TsType[]\n typeName?: { type: string; name?: string }\n typeArguments?: unknown\n range: [number, number]\n loc: ESTree.SourceLocation\n}\n\ninterface TsDeclaration {\n type: string\n id?: { name?: string }\n body?: { body: TsMember[]; range: [number, number]; loc: ESTree.SourceLocation }\n extends?: unknown[]\n typeAnnotation?: TsType\n}\n\ninterface JsxNode {\n type: string\n name?: JsxNode & { name?: string | JsxNode }\n property?: JsxNode & { name?: string }\n openingElement?: JsxNode\n attributes?: JsxNode[]\n value?: { type: string; expression?: ESTree.Node } | null\n}\n\n/** Where `className?: string` can be appended: the member list and the braces around it. */\ninterface MemberContainer {\n members: TsMember[]\n body: { range: [number, number]; loc: ESTree.SourceLocation }\n}\n\n/** What is known about a props type: null when it cannot be resolved in this file. */\ntype PropsShape = { hasClassName: boolean; container: MemberContainer | null } | null\n\n/** How the root element can reach the prop: the `className` binding or `<object>.className`. */\ntype ClassNameBinding = { kind: 'identifier'; name: string } | { kind: 'member'; object: string }\n\nconst MAX_ALIAS_DEPTH = 5\n\nconst isClassNameMember = (member: TsMember): boolean => {\n if (member.type !== 'TSPropertySignature' || member.computed) {\n return false\n }\n\n return member.key?.name === 'className' || member.key?.value === 'className'\n}\n\nconst findTypeDeclaration = (program: ESTree.Program, name: string): TsDeclaration | null => {\n for (const statement of program.body) {\n const node = (\n statement.type === 'ExportNamedDeclaration' ? statement.declaration : statement\n ) as TsDeclaration | null\n\n if (\n (node?.type === 'TSInterfaceDeclaration' || node?.type === 'TSTypeAliasDeclaration') &&\n node.id?.name === name\n ) {\n return node\n }\n }\n\n return null\n}\n\nconst fromMembers = (members: TsMember[], body: MemberContainer['body']): PropsShape => {\n return { hasClassName: members.some(isClassNameMember), container: { members, body } }\n}\n\nconst fromIntersection = (shapes: PropsShape[]): PropsShape => {\n if (\n shapes.some((shape) => {\n return shape?.hasClassName\n })\n ) {\n return { hasClassName: true, container: null }\n }\n\n // An unresolved part (an imported base type) may well declare `className`.\n if (shapes.includes(null)) {\n return null\n }\n\n return {\n hasClassName: false,\n container:\n shapes.findLast((shape) => {\n return shape?.container\n })?.container ?? null,\n }\n}\n\nconst resolveShape = (program: ESTree.Program, type: TsType | undefined, depth: number): PropsShape => {\n if (!type || depth > MAX_ALIAS_DEPTH) {\n return null\n }\n\n if (type.type === 'TSTypeLiteral') {\n return fromMembers(type.members ?? [], type)\n }\n\n if (type.type === 'TSIntersectionType') {\n return fromIntersection(\n (type.types ?? []).map((part) => {\n return resolveShape(program, part, depth + 1)\n }),\n )\n }\n\n if (type.type !== 'TSTypeReference' || type.typeName?.type !== 'Identifier' || type.typeArguments) {\n return null\n }\n\n const declaration = findTypeDeclaration(program, type.typeName.name!)\n\n if (declaration?.type === 'TSTypeAliasDeclaration') {\n return resolveShape(program, declaration.typeAnnotation, depth + 1)\n }\n\n if (!declaration?.body) {\n return null\n }\n\n const shape = fromMembers(declaration.body.body, declaration.body)\n\n // An inherited `className` is invisible here; only an interface with no `extends` is conclusive.\n return shape?.hasClassName || !declaration.extends?.length ? shape : null\n}\n\nconst bindingFromObjectPattern = (pattern: ESTree.ObjectPattern): ClassNameBinding | null => {\n const destructured = pattern.properties.find((property) => {\n return (\n property.type === 'Property' &&\n !property.computed &&\n property.key.type === 'Identifier' &&\n property.key.name === 'className'\n )\n }) as ESTree.AssignmentProperty | undefined\n\n if (destructured) {\n const value = destructured.value.type === 'AssignmentPattern' ? destructured.value.left : destructured.value\n\n return value.type === 'Identifier' ? { kind: 'identifier', name: value.name } : null\n }\n\n const rest = pattern.properties.find((property) => {\n return property.type === 'RestElement'\n })\n\n return rest?.argument.type === 'Identifier' ? { kind: 'member', object: rest.argument.name } : null\n}\n\n/** `const { className } = props` statements at the top of the component body. */\nconst bindingsFromBody = (fn: ComponentFunction, propsName: string): ClassNameBinding[] => {\n const statements = fn.body.type === 'BlockStatement' ? fn.body.body : []\n\n return statements.flatMap((statement) => {\n if (statement.type !== 'VariableDeclaration') {\n return []\n }\n\n return statement.declarations.flatMap((declarator) => {\n const isPropsDestructure =\n declarator.id.type === 'ObjectPattern' &&\n declarator.init?.type === 'Identifier' &&\n declarator.init.name === propsName\n\n const binding = isPropsDestructure ? bindingFromObjectPattern(declarator.id as ESTree.ObjectPattern) : null\n\n return binding ? [binding] : []\n })\n })\n}\n\nconst getClassNameBindings = (fn: ComponentFunction): ClassNameBinding[] => {\n const param = fn.params[0]\n const pattern = param ? getAnnotatedParam(param) : null\n\n if (pattern?.type === 'Identifier') {\n return [{ kind: 'member', object: pattern.name }, ...bindingsFromBody(fn, pattern.name)]\n }\n\n const binding = pattern?.type === 'ObjectPattern' ? bindingFromObjectPattern(pattern) : null\n\n return binding ? [binding] : []\n}\n\nconst matchesBinding = (node: ESTree.Node, binding: ClassNameBinding): boolean => {\n if (binding.kind === 'identifier') {\n return node.type === 'Identifier' && node.name === binding.name\n }\n\n return (\n node.type === 'MemberExpression' &&\n !node.computed &&\n node.object.type === 'Identifier' &&\n node.object.name === binding.object &&\n node.property.type === 'Identifier' &&\n node.property.name === 'className'\n )\n}\n\nconst referencesBinding = (\n node: ESTree.Node,\n binding: ClassNameBinding,\n visitorKeys: SourceCode.VisitorKeys,\n): boolean => {\n if (matchesBinding(node, binding)) {\n return true\n }\n\n // A non-computed property name (`styles.className`, `{ className: x }`) is a label, not the binding.\n const label = node.type === 'MemberExpression' ? 'property' : 'key'\n\n const keys = (visitorKeys[node.type] ?? []).filter((key) => {\n return !(key === label && 'computed' in node && !node.computed)\n })\n\n return keys.some((key) => {\n const child = (node as unknown as Record<string, unknown>)[key]\n const children = (Array.isArray(child) ? child : [child]) as Array<ESTree.Node | null>\n\n return children.some((item) => {\n return item !== null && typeof item?.type === 'string' && referencesBinding(item, binding, visitorKeys)\n })\n })\n}\n\nconst isFragment = (element: JsxNode): boolean => {\n const name = element.openingElement?.name\n\n if (name?.type === 'JSXIdentifier') {\n return name.name === 'Fragment'\n }\n\n return name?.type === 'JSXMemberExpression' && name.property?.name === 'Fragment'\n}\n\n/** The single JSX element a component returns, or null when the root is not one plain element. */\nconst getRootElement = (fn: ComponentFunction): JsxNode | null => {\n const returns = collectOwnReturnArguments(fn)\n const root = returns.length === 1 ? (returns[0] as unknown as JsxNode) : null\n\n return root?.type === 'JSXElement' && !isFragment(root) ? root : null\n}\n\nconst buildMemberFix = (sourceCode: SourceCode, container: MemberContainer): Rule.ReportFixer => {\n return (fixer) => {\n const last = container.members.at(-1)\n\n if (!last) {\n return fixer.replaceTextRange(container.body.range, '{ className?: string }')\n }\n\n const separator = /[;,]$/.exec(sourceCode.text.slice(...last.range))?.[0] ?? ''\n\n if (container.body.loc.start.line === container.body.loc.end.line) {\n return fixer.insertTextAfterRange(\n last.range,\n separator ? ` className?: string${separator}` : '; className?: string',\n )\n }\n\n const indent = /^\\s*/.exec(sourceCode.lines[last.loc.start.line - 1]!)![0]\n\n return fixer.insertTextAfterRange(last.range, `\\n${indent}className?: string${separator}`)\n }\n}\n\nexport const componentClassname: Rule.RuleModule = {\n meta: {\n type: 'suggestion',\n fixable: 'code',\n docs: {\n description:\n 'Require a dumb component to declare a `className` prop and merge it into its root element (`className={cn(..., className)}`).',\n recommended: true,\n url: 'https://github.com/ArthurSaenz/infra-kit/tree/main/apps/infra-kit/eslint-plugin#component-classname',\n },\n schema: [\n {\n type: 'object',\n properties: {\n paths: {\n type: 'array',\n items: { type: 'string' },\n description: `Glob patterns of the files to check. Replaces the default (${DUMB_COMPONENT_PATHS.join(', ')}).`,\n },\n ignore: {\n type: 'array',\n items: { type: 'string' },\n description:\n 'Glob patterns of files to skip (e.g. svg sprites, icons), even if they also match `paths`. Stories and tests are always skipped.',\n },\n },\n additionalProperties: false,\n },\n ],\n messages: {\n missingClassNameProp:\n '`{{name}}` must accept a `className` prop: declare `className?: string` on its props type so callers can position it.',\n rootMissingClassName:\n \"The root element of `{{name}}` must merge the `className` prop, e.g. `className={cn('\u2026', className)}`.\",\n },\n },\n\n create(context) {\n const options = (context.options[0] ?? {}) as Options\n const filename = context.filename.split('\\\\').join('/')\n\n if (\n isStoryOrTestFile(filename) ||\n !isInScope(filename, options.paths ?? DUMB_COMPONENT_PATHS, options.ignore ?? []) ||\n !isUiPackageFile(filename)\n ) {\n return {}\n }\n\n const { sourceCode } = context\n\n const checkProps = (program: ESTree.Program, component: ExportedComponent, name: string): void => {\n const param = component.fn.params[0]\n\n if (!param) {\n context.report({ node: component.id ?? component.fn, messageId: 'missingClassNameProp', data: { name } })\n\n return\n }\n\n const annotation = (getAnnotatedParam(param) as { typeAnnotation?: { typeAnnotation?: TsType } }).typeAnnotation\n ?.typeAnnotation\n\n const shape = annotation ? resolveShape(program, annotation, 0) : null\n\n if (shape && !shape.hasClassName) {\n context.report({\n node: param,\n messageId: 'missingClassNameProp',\n data: { name },\n fix: shape.container ? buildMemberFix(sourceCode, shape.container) : null,\n })\n }\n }\n\n const checkRoot = (component: ExportedComponent, name: string): void => {\n const root = getRootElement(component.fn)\n const attributes = root?.openingElement?.attributes ?? []\n\n // A spread (`{...rest}`) may carry `className` through; it cannot be told apart statically.\n if (\n !root ||\n attributes.some((attribute) => {\n return attribute.type === 'JSXSpreadAttribute'\n })\n ) {\n return\n }\n\n const attribute = attributes.find((candidate) => {\n return candidate.type === 'JSXAttribute' && candidate.name?.name === 'className'\n })\n\n const bindings = getClassNameBindings(component.fn)\n\n const expression =\n attribute?.value?.type === 'JSXExpressionContainer' ? (attribute.value.expression ?? null) : null\n\n const merged =\n expression !== null &&\n bindings.some((binding) => {\n return referencesBinding(expression, binding, sourceCode.visitorKeys)\n })\n\n if (!merged) {\n context.report({\n node: (attribute ?? root.openingElement!.name!) as unknown as ESTree.Node,\n messageId: 'rootMissingClassName',\n data: { name },\n })\n }\n }\n\n return {\n Program(program) {\n for (const component of collectExportedComponents(program)) {\n const name = component.name ?? 'this component'\n\n checkProps(program, component, name)\n checkRoot(component, name)\n }\n },\n }\n },\n}\n", "import type { Rule } from 'eslint'\nimport type * as ESTree from 'estree'\n\nimport {\n declaresComponent,\n getComponentPropsTypeName,\n getDeclaredComponentName,\n unwrapExport,\n} from '../../utils/component'\nimport { matchesAnyGlob } from '../../utils/path-match'\n\ninterface Options {\n paths?: string[]\n ignore?: string[]\n}\n\n// TS-only nodes are not modelled by estree; access their identifier structurally.\ninterface NamedDeclaration {\n type: string\n id?: { name?: string } | null\n}\n\nconst PROPS_SUFFIX = 'Props'\n\n/**\n * Count the directive prologue \u2014 the leading run of string-literal expression statements\n * (`'use client'`, `'use server'`, `'use strict'`) at the top of the file. They are\n * legitimate file-leading content (like imports) and must not count as \"stray\" before the\n * props interface. Per the ECMAScript spec a directive is only one that *precedes* any other\n * statement, so we stop at the first non-string-literal statement rather than matching any\n * bare string anywhere in the body.\n */\nconst getDirectivePrologueCount = (body: Array<ESTree.Statement | ESTree.ModuleDeclaration>): number => {\n let count = 0\n\n for (const statement of body) {\n const isStringExpression =\n statement.type === 'ExpressionStatement' &&\n statement.expression.type === 'Literal' &&\n typeof statement.expression.value === 'string'\n\n if (!isStringExpression) {\n break\n }\n\n count += 1\n }\n\n return count\n}\n\n/**\n * The name of a top-level interface or type-alias declaration, or null when it is neither.\n * Unlike the props lookup, this is name-agnostic: any local type declaration is indexed so a\n * component can be matched against the type it actually references, whatever that type is called.\n */\nconst getTypeDeclName = (node: ESTree.Node | null): string | null => {\n if (!node) {\n return null\n }\n\n const named = node as NamedDeclaration\n\n if (named.type !== 'TSInterfaceDeclaration' && named.type !== 'TSTypeAliasDeclaration') {\n return null\n }\n\n return named.id?.name ?? null\n}\n\ninterface ComponentRef {\n index: number\n name: string | null\n // The type name the component uses for its props \u2014 resolved from its parameter annotation, or\n // the `<Name>Props` convention when the parameter carries no resolvable named type. Null when\n // neither is available (e.g. an anonymous component with no typed props parameter).\n propsName: string | null\n}\n\ninterface TopLevel {\n importIndices: number[]\n components: ComponentRef[]\n // First index of each top-level type declaration, keyed by its name.\n declIndexByName: Map<string, number>\n // Local binding names introduced by imports \u2014 used to detect a props type that is\n // imported (e.g. `import type { CompProps }`) rather than declared in the file.\n importedNames: Set<string>\n}\n\n/** Classify each top-level statement into imports, components, local type declarations, and import bindings. */\nconst collectTopLevel = (body: Array<ESTree.Statement | ESTree.ModuleDeclaration>): TopLevel => {\n const importIndices: number[] = []\n const components: ComponentRef[] = []\n const declIndexByName = new Map<string, number>()\n const importedNames = new Set<string>()\n\n for (const [index, statement] of body.entries()) {\n if (statement.type === 'ImportDeclaration') {\n importIndices.push(index)\n\n for (const specifier of statement.specifiers) {\n importedNames.add(specifier.local.name)\n }\n\n continue\n }\n\n const declaration = unwrapExport(statement)\n\n const declName = getTypeDeclName(declaration)\n\n if (declName !== null && !declIndexByName.has(declName)) {\n declIndexByName.set(declName, index)\n }\n\n if (declaresComponent(declaration)) {\n const name = getDeclaredComponentName(declaration)\n // Prefer the type the component's parameter actually references; fall back to the\n // `<Name>Props` convention only when no named parameter type is resolvable.\n const propsName = getComponentPropsTypeName(declaration) ?? (name === null ? null : `${name}${PROPS_SUFFIX}`)\n\n components.push({ index, name, propsName })\n }\n }\n\n return { importIndices, components, declIndexByName, importedNames }\n}\n\n/**\n * Whether any top-level statement in the half-open range `[directiveCount, boundary)` is a stray \u2014\n * i.e. not an import and not part of the leading directive prologue. `skipIndex` excludes a single\n * known-good statement (the component itself, when scanning the gap before its props interface).\n */\nconst hasStrayBefore = (\n body: Array<ESTree.Statement | ESTree.ModuleDeclaration>,\n boundary: number,\n directiveCount: number,\n skipIndex?: number,\n): boolean => {\n return body.some((statement, index) => {\n return index < boundary && index >= directiveCount && index !== skipIndex && statement.type !== 'ImportDeclaration'\n })\n}\n\ntype MessageId =\n | 'importsFirst'\n | 'interfaceImmediatelyBeforeComponent'\n | 'interfaceImmediatelyAfterImports'\n | 'componentImmediatelyAfterImports'\n\n// A pending report, expressed as a body index plus the message to raise against it. `data`\n// carries the identifier names interpolated into the message so an AI fix loop reads the\n// concrete interface/component to move \u2014 omitted for `importsFirst`, which stays generic.\ninterface Violation {\n index: number\n messageId: MessageId\n data?: Record<string, string>\n}\n\n// Fallback when a component is anonymous (e.g. `export default (props: Props) => \u2026`), matching\n// the `ANONYMOUS_NAME` convention the sibling rules use for a name-less component.\nconst ANONYMOUS_COMPONENT = 'component'\n\n/** Imports that sit after the first component (or its props interface) must move up. */\nconst findImportOrderViolations = (importIndices: number[], importBoundary: number): Violation[] => {\n return importIndices\n .filter((importIndex) => {\n return importIndex > importBoundary\n })\n .map((importIndex) => {\n return { index: importIndex, messageId: 'importsFirst' }\n })\n}\n\n/**\n * Each component's props type, when declared locally, must sit immediately before the component.\n * The type is matched by the name the component's parameter actually references, so an interface\n * named anything (`Props`, `UserCardProps`, ...) is judged \u2014 not just the `<Name>Props` convention.\n * A type referenced by more than one component is skipped: a single declaration cannot sit\n * immediately before two components, so adjacency is unenforceable and would misfire.\n */\nconst findAdjacencyViolations = (components: ComponentRef[], declIndexByName: Map<string, number>): Violation[] => {\n const violations: Violation[] = []\n\n const referenceCount = new Map<string, number>()\n\n for (const component of components) {\n if (component.propsName !== null) {\n referenceCount.set(component.propsName, (referenceCount.get(component.propsName) ?? 0) + 1)\n }\n }\n\n for (const component of components) {\n const propsName = component.propsName\n\n if (propsName === null || (referenceCount.get(propsName) ?? 0) > 1) {\n continue\n }\n\n const propsIndex = declIndexByName.get(propsName)\n\n if (propsIndex !== undefined && propsIndex !== component.index - 1) {\n violations.push({\n index: propsIndex,\n messageId: 'interfaceImmediatelyBeforeComponent',\n data: { interface: propsName, component: component.name ?? ANONYMOUS_COMPONENT },\n })\n }\n }\n\n return violations\n}\n\n/**\n * The first component is anchored to the import block: no stray top-level definition may wedge\n * between the imports and the props interface \u2014 or, when the props type is *imported* rather than\n * declared in the file, between the imports and the component itself. Only the first component is\n * anchored; later interfaces are governed solely by the adjacency check. Each `every` guard skips\n * when an import sits after its anchor, since that misorder is already reported by `importsFirst`.\n */\nconst findAnchorViolations = (\n body: Array<ESTree.Statement | ESTree.ModuleDeclaration>,\n directiveCount: number,\n importIndices: number[],\n first: ComponentRef,\n firstPropsName: string | null,\n firstPropsIndex: number | undefined,\n importedNames: Set<string>,\n): Violation[] => {\n const violations: Violation[] = []\n\n const importsBeforeInterface =\n firstPropsIndex !== undefined &&\n importIndices.every((importIndex) => {\n return importIndex < firstPropsIndex\n })\n\n if (importsBeforeInterface && hasStrayBefore(body, firstPropsIndex!, directiveCount, first.index)) {\n violations.push({\n index: firstPropsIndex!,\n messageId: 'interfaceImmediatelyAfterImports',\n // `firstPropsIndex !== undefined` implies `firstPropsName !== null` (it is derived from it).\n data: { interface: firstPropsName!, component: first.name ?? ANONYMOUS_COMPONENT },\n })\n }\n\n const firstPropsImported =\n firstPropsIndex === undefined && firstPropsName !== null && importedNames.has(firstPropsName)\n\n const importsBeforeComponent = importIndices.every((importIndex) => {\n return importIndex < first.index\n })\n\n if (firstPropsImported && importsBeforeComponent && hasStrayBefore(body, first.index, directiveCount)) {\n violations.push({\n index: first.index,\n messageId: 'componentImmediatelyAfterImports',\n // `firstPropsImported` requires `firstPropsName !== null`.\n data: { interface: firstPropsName!, component: first.name ?? ANONYMOUS_COMPONENT },\n })\n }\n\n return violations\n}\n\nexport const componentFileOrder: Rule.RuleModule = {\n meta: {\n type: 'suggestion',\n docs: {\n description:\n 'Enforce a strict top-level order in React component files: imports first, then \u2014 for each component \u2014 its props interface/type declared immediately before the component.',\n recommended: true,\n url: 'https://github.com/ArthurSaenz/infra-kit/tree/main/apps/infra-kit/eslint-plugin#component-file-order',\n },\n schema: [\n {\n type: 'object',\n properties: {\n paths: {\n type: 'array',\n items: { type: 'string' },\n description:\n 'Optional glob patterns. When provided, the rule only runs for files whose path matches one of them.',\n },\n ignore: {\n type: 'array',\n items: { type: 'string' },\n description:\n 'Optional glob patterns. The rule is skipped for files whose path matches one of them, even if it also matches `paths`.',\n },\n },\n additionalProperties: false,\n },\n ],\n messages: {\n // Generic on purpose: fires on a misplaced import, and the constraint is \"before *every*\n // component\", so naming a single component would mislead in a multi-component file.\n importsFirst: 'Imports must come before the component interface and declaration.',\n // \"props type\" (not \"interface\"): the rule matches both `interface` and `type` alias props\n // declarations, so the neutral term reads correctly for either.\n interfaceImmediatelyBeforeComponent:\n 'Declare the props type `{{interface}}` immediately before component `{{component}}` (no declarations between them).',\n interfaceImmediatelyAfterImports:\n 'Declare the props type `{{interface}}` (for component `{{component}}`) immediately after the imports, with no other declarations in between.',\n componentImmediatelyAfterImports:\n 'Props type `{{interface}}` is imported, so declare component `{{component}}` immediately after the imports, with no other declarations in between.',\n },\n },\n\n create(context) {\n const options = (context.options[0] ?? {}) as Options\n const paths = options.paths ?? []\n const ignore = options.ignore ?? []\n\n // `ignore` takes precedence: skip excluded files even when they also match `paths`.\n if (ignore.length > 0 && matchesAnyGlob(context.filename, ignore)) {\n return {}\n }\n\n if (paths.length > 0 && !matchesAnyGlob(context.filename, paths)) {\n return {}\n }\n\n return {\n Program(program) {\n const body = program.body\n\n // Leading directive prologue (`'use client'`, ...) \u2014 excluded from the stray checks.\n const directiveCount = getDirectivePrologueCount(body)\n\n const { importIndices, components, declIndexByName, importedNames } = collectTopLevel(body)\n\n // The rule only governs files that actually contain a component.\n if (components.length === 0) {\n return\n }\n\n const first = components[0]!\n const firstPropsName = first.propsName\n const firstPropsIndex = firstPropsName === null ? undefined : declIndexByName.get(firstPropsName)\n // `importBoundary` is intentionally directive-insensitive: a leading directive prologue\n // shifts every subsequent index up uniformly, so it never crosses this boundary. The\n // prologue is excluded only from the stray checks, where the raw index matters.\n const importBoundary = Math.min(first.index, firstPropsIndex ?? first.index)\n\n const violations = [\n ...findImportOrderViolations(importIndices, importBoundary),\n ...findAdjacencyViolations(components, declIndexByName),\n ...findAnchorViolations(\n body,\n directiveCount,\n importIndices,\n first,\n firstPropsName,\n firstPropsIndex,\n importedNames,\n ),\n ]\n\n for (const violation of violations) {\n context.report({ node: body[violation.index]!, messageId: violation.messageId, data: violation.data })\n }\n },\n }\n },\n}\n", "import type { Rule, Scope } from 'eslint'\nimport type * as ESTree from 'estree'\nimport path from 'node:path'\n\nimport { isInScope, isStoryOrTestFile, isUiPackageFile } from '../../utils/component-file-scope'\nimport type { ExportedComponent } from '../../utils/exported-components'\nimport { collectExportedComponents } from '../../utils/exported-components'\n\ninterface Options {\n paths?: string[]\n ignore?: string[]\n}\n\n// Route/page entry files and design-system primitives follow their framework's naming, not the\n// feature `*-component` / `*-container` convention.\n// Shared libraries (ui-kit, `lib/`) name files by concept, not by component; the convention binds\n// feature code and any file that already opts in with the suffix.\nexport const DEFAULT_PATHS = ['**/features/**', '**/*-component.tsx', '**/*-container.tsx']\n\nexport const DEFAULT_IGNORE = ['**/pages/**', '**/routes/**', '**/renderer/**', '**/primitives/**']\n\nconst SUFFIX_BY_DIR: Record<string, string> = {\n components: '-component',\n containers: '-container',\n}\n\nconst toPascalCase = (basename: string): string => {\n return basename\n .split(/[-_.]/)\n .filter(Boolean)\n .map((part) => {\n return part[0]!.toUpperCase() + part.slice(1)\n })\n .join('')\n}\n\n/**\n * The suffix the nearest `components/` or `containers/` folder inside a feature requires, or null elsewhere. Shared\n * `src/components/<name>/<name>.tsx` libraries follow their own folder-per-component layout.\n */\nconst requiredSuffix = (dirs: readonly string[]): { dir: string; suffix: string } | null => {\n const featureRoot = dirs.indexOf('features') + 2\n\n const index = dirs.findLastIndex((name, position) => {\n return name in SUFFIX_BY_DIR && featureRoot > 1 && position >= featureRoot\n })\n\n if (index === -1) {\n return null\n }\n\n const dir = dirs[index]!\n\n return { dir, suffix: SUFFIX_BY_DIR[dir]! }\n}\n\nconst findVariable = (sourceCode: Rule.RuleContext['sourceCode'], component: ExportedComponent) => {\n return sourceCode.getDeclaredVariables(component.declaration!).find((variable) => {\n return variable.name === component.name\n })\n}\n\nconst renameFix = (variable: Scope.Variable, expected: string): Rule.ReportFixer => {\n return (fixer) => {\n const nodes = [\n ...variable.identifiers,\n ...variable.references.map((reference) => {\n return reference.identifier\n }),\n ]\n\n // `export { X }` parses local and exported as two nodes over one range; one edit covers both.\n const ranges = new Map(\n nodes.map((node) => {\n return [node.range!.join(':'), node.range!] as const\n }),\n )\n\n return [...ranges.values()].map((range) => {\n return fixer.replaceTextRange(range, expected)\n })\n }\n}\n\nexport const componentNameMatchesFile: Rule.RuleModule = {\n meta: {\n type: 'suggestion',\n hasSuggestions: true,\n docs: {\n description:\n \"Require a `.tsx` file's exported component to be named after the file (`abroad-slider-component.tsx` \u2192 `AbroadSliderComponent`), and files under `components/` / `containers/` to end with `-component` / `-container`.\",\n recommended: true,\n url: 'https://github.com/ArthurSaenz/infra-kit/tree/main/apps/infra-kit/eslint-plugin#component-name-matches-file',\n },\n schema: [\n {\n type: 'object',\n properties: {\n paths: {\n type: 'array',\n items: { type: 'string' },\n description: `Glob patterns of files to check. Replaces the default (${DEFAULT_PATHS.join(', ')}).`,\n },\n ignore: {\n type: 'array',\n items: { type: 'string' },\n description: `Glob patterns of files to skip, even if they also match \\`paths\\`. Replaces the default (${DEFAULT_IGNORE.join(', ')}).`,\n },\n },\n additionalProperties: false,\n },\n ],\n messages: {\n nameMismatch: 'The exported component in `{{file}}` must be named `{{expected}}`, but it is named `{{actual}}`.',\n wrongSuffix: 'A file under `{{dir}}/` must be named `*{{suffix}}.tsx`, but it is `{{file}}`.',\n renameComponent: 'Rename `{{actual}}` to `{{expected}}`.',\n },\n },\n\n create(context) {\n const options = (context.options[0] ?? {}) as Options\n const filename = context.filename.split('\\\\').join('/')\n const file = path.posix.basename(filename)\n\n if (\n !file.endsWith('.tsx') ||\n file === 'index.tsx' ||\n isStoryOrTestFile(filename) ||\n !isInScope(filename, options.paths ?? DEFAULT_PATHS, options.ignore ?? DEFAULT_IGNORE) ||\n !isUiPackageFile(filename)\n ) {\n return {}\n }\n\n const basename = file.slice(0, -'.tsx'.length)\n const expected = toPascalCase(basename)\n\n return {\n Program(program) {\n const suffixRule = requiredSuffix(path.posix.dirname(filename).split('/'))\n\n if (suffixRule && !basename.endsWith(suffixRule.suffix)) {\n context.report({\n node: program,\n loc: { line: 1, column: 0 },\n messageId: 'wrongSuffix',\n data: { ...suffixRule, file },\n })\n }\n\n const named = collectExportedComponents(program).filter((component) => {\n return component.name !== null\n })\n\n // With several exports the intended one is ambiguous; `max-components-per-file` owns that case.\n if (named.length !== 1 || named[0]!.name === expected) {\n return\n }\n\n const component = named[0]!\n const actual = component.name!\n const variable = findVariable(context.sourceCode, component)\n const moduleScope = context.sourceCode.getScope(program).childScopes[0] ?? context.sourceCode.getScope(program)\n const nameTaken = moduleScope.set.has(expected)\n\n context.report({\n node: component.id as ESTree.Node,\n messageId: 'nameMismatch',\n data: { file, expected, actual },\n suggest:\n variable && !nameTaken\n ? [{ messageId: 'renameComponent', data: { actual, expected }, fix: renameFix(variable, expected) }]\n : [],\n })\n },\n }\n },\n}\n", "import type { Rule } from 'eslint'\nimport type * as ESTree from 'estree'\n\nimport { DUMB_COMPONENT_PATHS, isInScope, isStoryOrTestFile, isUiPackageFile } from '../../utils/component-file-scope'\n\ninterface Options {\n paths?: string[]\n ignore?: string[]\n allowHooks?: string[]\n}\n\n// React's local-state and DOM hooks: everything a dumb component needs without knowing about data.\nexport const DEFAULT_ALLOWED_HOOKS = [\n 'useState',\n 'useRef',\n 'useMemo',\n 'useCallback',\n 'useId',\n 'useEffect',\n 'useLayoutEffect',\n 'useImperativeHandle',\n]\n\nconst EFFECT_HOOKS = new Set(['useEffect', 'useLayoutEffect'])\nconst HOOK_NAME = /^use[A-Z]/\nconst ANALYTICS = /analytics/i\n\n/** `useX` for `useX(...)` and `React.useX(...)`, else null. */\nconst getHookName = (callee: ESTree.CallExpression['callee']): string | null => {\n if (callee.type === 'Identifier') {\n return HOOK_NAME.test(callee.name) ? callee.name : null\n }\n\n if (\n callee.type === 'MemberExpression' &&\n callee.object.type === 'Identifier' &&\n callee.object.name === 'React' &&\n callee.property.type === 'Identifier' &&\n HOOK_NAME.test(callee.property.name)\n ) {\n return callee.property.name\n }\n\n return null\n}\n\n/** Every identifier name along a callee chain: `window.analytics.track` \u2192 window, analytics, track. */\nconst calleeNames = (node: ESTree.Node): string[] => {\n if (node.type === 'Identifier') {\n return [node.name]\n }\n\n if (node.type === 'MemberExpression') {\n const property = !node.computed && node.property.type === 'Identifier' ? [node.property.name] : []\n\n return [...calleeNames(node.object), ...property]\n }\n\n return []\n}\n\nconst rootObjectName = (node: ESTree.Node): string | null => {\n if (node.type === 'Identifier') {\n return node.name\n }\n\n return node.type === 'MemberExpression' ? rootObjectName(node.object) : null\n}\n\nconst isSideEffectCall = (callee: ESTree.CallExpression['callee']): boolean => {\n if (callee.type === 'Identifier' && callee.name === 'fetch') {\n return true\n }\n\n if (callee.type === 'MemberExpression' && rootObjectName(callee) === 'httpClient') {\n return true\n }\n\n return calleeNames(callee).some((name) => {\n return ANALYTICS.test(name)\n })\n}\n\nexport const dumbComponentPurity: Rule.RuleModule = {\n meta: {\n type: 'problem',\n docs: {\n description:\n \"Keep dumb components pure: only React's local-state hooks are allowed, and effects may not fetch, call `httpClient` or send analytics.\",\n recommended: true,\n url: 'https://github.com/ArthurSaenz/infra-kit/tree/main/apps/infra-kit/eslint-plugin#dumb-component-purity',\n },\n schema: [\n {\n type: 'object',\n properties: {\n paths: {\n type: 'array',\n items: { type: 'string' },\n description: `Glob patterns of the files to check. Replaces the default (${DUMB_COMPONENT_PATHS.join(', ')}).`,\n },\n ignore: {\n type: 'array',\n items: { type: 'string' },\n description:\n 'Glob patterns of files to skip, even if they also match `paths`. Stories and tests are always skipped.',\n },\n allowHooks: {\n type: 'array',\n items: { type: 'string' },\n description: `Hooks allowed on top of the defaults (${DEFAULT_ALLOWED_HOOKS.join(', ')}), e.g. UI-library hooks like \\`useMediaQuery\\`.`,\n },\n },\n additionalProperties: false,\n },\n ],\n messages: {\n forbiddenHook:\n '\"{{hook}}\" is not in the allowed hook list for dumb components. Call it in the container and pass the value as a prop.',\n sideEffectInEffect:\n '`{{call}}` is a side effect a dumb component must not run. Move it to the container and pass a callback or the result as a prop.',\n },\n },\n\n create(context) {\n const options = (context.options[0] ?? {}) as Options\n const filename = context.filename.split('\\\\').join('/')\n\n if (\n isStoryOrTestFile(filename) ||\n !isInScope(filename, options.paths ?? DUMB_COMPONENT_PATHS, options.ignore ?? []) ||\n !isUiPackageFile(filename)\n ) {\n return {}\n }\n\n const allowed = new Set([...DEFAULT_ALLOWED_HOOKS, ...(options.allowHooks ?? [])])\n const effectCallbacks = new Set<ESTree.Node>()\n\n return {\n CallExpression(node) {\n const hook = getHookName(node.callee)\n\n if (hook !== null && !allowed.has(hook)) {\n context.report({ node: node.callee, messageId: 'forbiddenHook', data: { hook } })\n }\n\n if (hook !== null && EFFECT_HOOKS.has(hook) && node.arguments[0]) {\n effectCallbacks.add(node.arguments[0])\n }\n\n if (!isSideEffectCall(node.callee)) {\n return\n }\n\n // Effects are entered before their body is visited, so an enclosing callback is already registered.\n const inEffect = context.sourceCode.getAncestors(node).some((ancestor) => {\n return effectCallbacks.has(ancestor)\n })\n\n if (inEffect) {\n context.report({\n node: node.callee,\n messageId: 'sideEffectInEffect',\n data: { call: context.sourceCode.getText(node.callee) },\n })\n }\n },\n }\n },\n}\n", "import type { Rule } from 'eslint'\nimport type { CallExpression, Expression, Node, ObjectExpression, SpreadElement } from 'estree'\n\nimport { findPackageRoot } from './package-root'\nimport { resolvePackageType } from './package-type-reader'\n\nexport type PlaywrightCallKind = 'test' | 'describe'\n\n// Modifiers that keep a call a test / describe declaration; `step`, `use`, `beforeEach` and the\n// rest are not declarations and carry no title or tags of their own.\nconst TEST_MODIFIERS = new Set(['only', 'skip', 'fixme', 'fail'])\nconst DESCRIBE_MODIFIERS = new Set(['only', 'skip', 'fixme', 'serial', 'parallel'])\n\n/** `test.describe.serial` \u2192 `['test', 'describe', 'serial']`; null for anything but a plain name chain. */\nexport const calleeNames = (callee: Expression | Node): string[] | null => {\n if (callee.type === 'Identifier') {\n return [callee.name]\n }\n\n if (callee.type !== 'MemberExpression' || callee.computed || callee.property.type !== 'Identifier') {\n return null\n }\n\n const head = calleeNames(callee.object)\n\n return head === null ? null : [...head, callee.property.name]\n}\n\n/**\n * Whether `node` declares a Playwright test or describe block, read from its callee alone.\n *\n * @example\n * playwrightCallKind(parse(\"test.describe.serial('Checkout', () => {})\")) // => 'describe'\n */\nexport const playwrightCallKind = (node: CallExpression): PlaywrightCallKind | null => {\n const names = calleeNames(node.callee)\n\n if (names === null || names[0] !== 'test') {\n return null\n }\n\n const [, second, ...rest] = names\n\n if (second === undefined) {\n return 'test'\n }\n\n if (second === 'describe') {\n const isDescribe = rest.every((name) => {\n return DESCRIBE_MODIFIERS.has(name)\n })\n\n return isDescribe ? 'describe' : null\n }\n\n return rest.length === 0 && TEST_MODIFIERS.has(second) ? 'test' : null\n}\n\n/** The `{ tag, annotation }` details object, present only in the three-argument form. */\nexport const detailsArgument = (node: CallExpression): ObjectExpression | null => {\n const details: Expression | SpreadElement | undefined = node.arguments[1]\n\n return node.arguments.length >= 3 && details?.type === 'ObjectExpression' ? details : null\n}\n\n/** A title that is a plain string: a literal, or a template without expressions. */\nexport const staticTitle = (node: CallExpression): string | null => {\n const title = node.arguments[0]\n\n if (title?.type === 'Literal' && typeof title.value === 'string') {\n return title.value\n }\n\n if (title?.type === 'TemplateLiteral' && title.expressions.length === 0) {\n return title.quasis[0]?.value.cooked ?? null\n }\n\n return null\n}\n\n/** True when the linted file belongs to a package whose type resolves to `e2e`. */\n/** The callee chain of a top-level `test.*(\u2026)` statement, e.g. `['test', 'describe', 'configure']`. */\nexport const testStatementNames = (statement: Node): string[] | null => {\n if (statement.type !== 'ExpressionStatement' || statement.expression.type !== 'CallExpression') {\n return null\n }\n\n const names = calleeNames(statement.expression.callee)\n\n return names?.[0] === 'test' ? names : null\n}\n\nexport const isInE2ePackage = (context: Rule.RuleContext): boolean => {\n const packageRoot = findPackageRoot(context.filename.split('\\\\').join('/'))\n\n return packageRoot !== null && resolvePackageType(packageRoot) === 'e2e'\n}\n", "import type { Rule } from 'eslint'\nimport type * as ESTree from 'estree'\n\nimport { matchesAnyGlob } from '../../utils/path-match'\nimport { isInE2ePackage, playwrightCallKind, staticTitle, testStatementNames } from '../../utils/playwright-call'\n\nexport interface Options {\n /** Globs; the rule is skipped for matching files. */\n ignore?: string[]\n}\n\nconst SPEC_FILE = /\\.spec\\.[cm]?[jt]sx?$/\n\nconst SETUP_RANK = 0\nconst BODY_RANK = 5\nconst HOOK_RANK: Record<string, number> = { beforeAll: 1, beforeEach: 2, afterEach: 3, afterAll: 4 }\nconst SETUP_CALLS = new Set(['use', 'configure', 'setTimeout', 'slow'])\n// Without a test callback these annotate the block (`test.skip(isMobile, '\u2026')`) instead of declaring a test.\nconst ANNOTATION_CALLS = new Set(['skip', 'fixme', 'fail'])\n\nconst RANK_NAMES = ['setup', 'beforeAll hook', 'beforeEach hook', 'afterEach hook', 'afterAll hook', 'test']\n\ninterface Ranked {\n rank: number\n label: string\n}\n\nconst isFunction = (node: ESTree.Node | undefined): boolean => {\n return node?.type === 'ArrowFunctionExpression' || node?.type === 'FunctionExpression'\n}\n\nconst rankFor = (method: string, call: ESTree.CallExpression): number => {\n if (method in HOOK_RANK) {\n return HOOK_RANK[method]!\n }\n\n const declaresTest = call.arguments.slice(1).some(isFunction)\n\n return SETUP_CALLS.has(method) || (ANNOTATION_CALLS.has(method) && !declaresTest) ? SETUP_RANK : BODY_RANK\n}\n\n/** A statement's slot in a describe body, or null when it is not a `test.*` call. */\nconst rankOf = (statement: ESTree.Statement): Ranked | null => {\n const names = testStatementNames(statement)\n\n if (names === null) {\n return null\n }\n\n const call = (statement as ESTree.ExpressionStatement).expression as ESTree.CallExpression\n const rank = rankFor(names.at(-1)!, call)\n const title = rank === BODY_RANK ? staticTitle(call) : null\n const label = title === null ? `\\`${names.join('.')}\\`` : `\\`${names.join('.')}('${title}')\\``\n\n return { rank, label: `${label} (${RANK_NAMES[rank]})` }\n}\n\nconst describeBody = (call: ESTree.CallExpression): ESTree.Statement[] | null => {\n const callback = call.arguments.at(-1)\n\n if (callback?.type !== 'ArrowFunctionExpression' && callback?.type !== 'FunctionExpression') {\n return null\n }\n\n return callback.body.type === 'BlockStatement' ? callback.body.body : null\n}\n\nexport const e2eDescribeOrder: Rule.RuleModule = {\n meta: {\n type: 'suggestion',\n docs: {\n description:\n 'Order an e2e `test.describe` body: `test.use` / `configure` / annotations, then hooks beforeAll \u2192 beforeEach \u2192 afterEach \u2192 afterAll, then tests and nested describes.',\n recommended: true,\n url: 'https://github.com/ArthurSaenz/infra-kit/tree/main/apps/infra-kit/eslint-plugin#e2e-describe-order',\n },\n schema: [\n {\n type: 'object',\n properties: {\n ignore: {\n type: 'array',\n items: { type: 'string' },\n description: 'Optional globs; the rule is skipped for matching files.',\n },\n },\n additionalProperties: false,\n },\n ],\n messages: {\n outOfOrder:\n '{{label}} comes after {{afterLabel}} in describe {{describe}}. Order a describe body: `test.use` / `test.describe.configure` / annotations, then hooks beforeAll \u2192 beforeEach \u2192 afterEach \u2192 afterAll, then tests and nested describes.',\n },\n },\n\n create(context) {\n const options = (context.options[0] ?? {}) as Options\n const filename = context.filename.split('\\\\').join('/')\n\n if (!SPEC_FILE.test(filename) || (options.ignore?.length && matchesAnyGlob(filename, options.ignore))) {\n return {}\n }\n\n if (!isInE2ePackage(context)) {\n return {}\n }\n\n return {\n CallExpression(node) {\n const body = playwrightCallKind(node) === 'describe' ? describeBody(node) : null\n\n if (body === null) {\n return\n }\n\n const title = staticTitle(node)\n const describe = title === null ? 'block' : `'${title}'`\n let latest: Ranked | null = null\n\n for (const statement of body) {\n const ranked = rankOf(statement)\n\n if (ranked === null) {\n continue\n }\n\n if (latest !== null && ranked.rank < latest.rank) {\n context.report({\n node: statement,\n messageId: 'outOfOrder',\n data: {\n label: ranked.label,\n afterLabel: latest.label,\n describe,\n },\n })\n } else {\n latest = ranked\n }\n }\n },\n }\n },\n}\n", "import type { Rule } from 'eslint'\n\nimport { dirsUnderSrc, findPackageRoot } from '../../utils/package-root'\nimport { resolvePackageType } from '../../utils/package-type-reader'\nimport { matchesAnyGlob } from '../../utils/path-match'\n\nexport interface Options {\n /** Globs; the rule is skipped for matching files. */\n ignore?: string[]\n}\n\nconst TEST_FILE = /\\.(?:test|spec)\\.[cm]?[jt]sx?$/\nconst LEGACY_TEST_SUFFIX = /\\.test(\\.[cm]?[jt]sx?)$/\nconst SPEC_LAYERS = new Set(['tests', 'visual'])\n\n/** Support-file suffix \u2192 the domain subfolder it belongs in; anything unmatched is a domain helper. */\nconst SUBFOLDER_BY_SUFFIX: readonly (readonly [RegExp, string])[] = [\n [/\\.(?:page|component)\\.[cm]?[jt]sx?$/, 'pages'],\n [/\\.fixture\\.[cm]?[jt]sx?$/, 'fixtures'],\n [/\\.mock\\.[cm]?[jt]sx?$/, 'mocks'],\n [/\\.data\\.[cm]?[jt]sx?$/, 'data'],\n]\n\ntype MessageId = 'legacyTestSuffix' | 'specOutsideDomain' | 'nestedSpec' | 'supportInDomainRoot'\n\ninterface Violation {\n messageId: MessageId\n data: Record<string, string>\n}\n\nconst subfolderFor = (basename: string): string => {\n const match = SUBFOLDER_BY_SUFFIX.find(([pattern]) => {\n return pattern.test(basename)\n })\n\n return match ? match[1] : 'lib'\n}\n\nconst specViolation = (dirs: readonly string[], basename: string): Violation | null => {\n if (LEGACY_TEST_SUFFIX.test(basename)) {\n return {\n messageId: 'legacyTestSuffix',\n data: { basename, target: basename.replace(LEGACY_TEST_SUFFIX, '.spec$1') },\n }\n }\n\n const [layer, domain] = dirs\n\n if (layer === undefined || !SPEC_LAYERS.has(layer) || domain === undefined) {\n return { messageId: 'specOutsideDomain', data: { basename, path: ['src', ...dirs, basename].join('/') } }\n }\n\n if (dirs.length > 2) {\n return {\n messageId: 'nestedSpec',\n data: { basename, path: ['src', ...dirs, basename].join('/'), target: `src/${layer}/${domain}/${basename}` },\n }\n }\n\n return null\n}\n\nconst supportViolation = (dirs: readonly string[], basename: string): Violation | null => {\n const [layer, domain] = dirs\n\n if (dirs.length !== 2 || layer === undefined || !SPEC_LAYERS.has(layer) || domain === undefined) {\n return null\n }\n\n const subfolder = subfolderFor(basename)\n\n return {\n messageId: 'supportInDomainRoot',\n data: { basename, domain, subfolder, target: `src/${layer}/${domain}/${subfolder}/${basename}` },\n }\n}\n\n/** The layout problem with `filename`, or null when it is fine or not an e2e source file. */\nconst findViolation = (filename: string, ignore: readonly string[]): Violation | null => {\n if (ignore.length > 0 && matchesAnyGlob(filename, ignore)) {\n return null\n }\n\n const packageRoot = findPackageRoot(filename)\n\n if (packageRoot === null || resolvePackageType(packageRoot) !== 'e2e') {\n return null\n }\n\n const dirs = dirsUnderSrc(packageRoot, filename)\n\n if (dirs === null) {\n return null\n }\n\n const basename = filename.slice(filename.lastIndexOf('/') + 1)\n\n return TEST_FILE.test(basename) ? specViolation(dirs, basename) : supportViolation(dirs, basename)\n}\n\nexport const e2eFileLayout: Rule.RuleModule = {\n meta: {\n type: 'problem',\n docs: {\n description:\n 'Require e2e packages to keep `*.spec.ts` files at the root of `src/tests/<domain>/` and every other file in a domain subfolder.',\n recommended: true,\n url: 'https://github.com/ArthurSaenz/infra-kit/tree/main/apps/infra-kit/eslint-plugin#e2e-file-layout',\n },\n schema: [\n {\n type: 'object',\n properties: {\n ignore: {\n type: 'array',\n items: { type: 'string' },\n description: 'Optional globs; the rule is skipped for matching files.',\n },\n },\n additionalProperties: false,\n },\n ],\n messages: {\n legacyTestSuffix:\n '`{{basename}}` uses `.test`. Rename it to `{{target}}` \u2014 every Playwright spec in an e2e package is `*.spec.ts`.',\n specOutsideDomain:\n '`{{path}}` is a spec outside a domain folder. Move it into `src/tests/<domain>/`, where `<domain>` is the business domain it covers.',\n nestedSpec:\n '`{{path}}` nests a spec below its domain folder. Move it to `{{target}}`, or split the domain into two sibling domains if it holds too many specs.',\n supportInDomainRoot:\n '`{{basename}}` sits in the root of domain `{{domain}}`, which holds only `*.spec.ts`. Move it to `{{target}}`.',\n },\n },\n\n create(context) {\n const options = (context.options[0] ?? {}) as Options\n const violation = findViolation(context.filename.split('\\\\').join('/'), options.ignore ?? [])\n\n if (violation === null) {\n return {}\n }\n\n return {\n // Reported on Program: the violation is the file's location, not any node inside it.\n Program(program) {\n context.report({ node: program, messageId: violation.messageId, data: violation.data })\n },\n }\n },\n}\n", "import type { SourceCode } from 'eslint'\nimport type * as ESTree from 'estree'\n\n/**\n * Where `node` starts once its attached leading comments are included: the unbroken run of comments\n * directly above it, each on the line after the previous one ends. A comment separated by a blank\n * line (a file overview, a section banner) stays behind when the node moves.\n *\n * @example\n * attachedStart(sourceCode, node) // => range start of the JSDoc right above `node`, else of `node`\n */\nexport const attachedStart = (sourceCode: SourceCode, node: ESTree.Node): number => {\n const previousEndLine = sourceCode.getTokenBefore(node)?.loc.end.line ?? 0\n let start = node.range![0]\n let startLine = node.loc!.start.line\n\n for (const comment of sourceCode.getCommentsBefore(node).toReversed()) {\n if (comment.loc!.end.line < startLine - 1 || comment.loc!.start.line <= previousEndLine) {\n break\n }\n\n start = comment.range![0]\n startLine = comment.loc!.start.line\n }\n\n return start\n}\n", "import type { Rule, Scope, SourceCode } from 'eslint'\nimport type * as ESTree from 'estree'\n\nimport { attachedStart } from '../../utils/attached-comments'\nimport { matchesAnyGlob } from '../../utils/path-match'\nimport { isInE2ePackage, playwrightCallKind } from '../../utils/playwright-call'\n\nexport interface Options {\n /** Globs; the rule is skipped for matching files. */\n ignore?: string[]\n}\n\ntype Statement = ESTree.Statement | ESTree.ModuleDeclaration\ntype FileKind = 'pageObject' | 'fixture' | 'spec' | 'mock' | 'lib'\ntype AnchorKind = Exclude<FileKind, 'lib'>\n\n// TS-only nodes are not modelled by estree; read them structurally.\ninterface TsNode {\n type: string\n id?: { name?: string } | null\n static?: boolean\n value?: unknown\n typeArguments?: { params: TsNode[] }\n typeName?: { type: string; name?: string }\n types?: TsNode[]\n}\n\ninterface Anchor {\n index: number\n label: string\n /** Type names the anchor is declared with (a fixture's `extend<\u2026>` argument); they may precede it. */\n headerTypes: Set<string>\n}\n\nconst FILE_KIND: readonly (readonly [RegExp, FileKind])[] = [\n [/\\.(?:page|component)\\.[cm]?[jt]sx?$/, 'pageObject'],\n [/\\.fixture\\.[cm]?[jt]sx?$/, 'fixture'],\n [/\\.spec\\.[cm]?[jt]sx?$/, 'spec'],\n [/\\.mock\\.[cm]?[jt]sx?$/, 'mock'],\n]\n\nconst LIB_DIR = /\\/lib\\//\n// Fixed-content files with no single main declaration to lead with.\nconst UNORDERED_FILE = /\\.data\\.[cm]?[jt]sx?$/\n\nconst KIND_OPENING: Record<FileKind, string> = {\n pageObject: 'a page object file opens with its imports, then the class',\n fixture: 'a fixture file opens with its imports, then the fixtures type and the `extend` call',\n spec: 'a spec file opens with its imports, then its `test.*` calls',\n mock: 'a mock file opens with its imports, then the exported mock function',\n lib: 'a lib file opens with its imports, then its exports',\n}\n\nconst fileKindOf = (filename: string): FileKind | null => {\n const match = FILE_KIND.find(([pattern]) => {\n return pattern.test(filename)\n })\n\n if (match) {\n return match[1]\n }\n\n return LIB_DIR.test(filename) && !UNORDERED_FILE.test(filename) ? 'lib' : null\n}\n\nconst unwrapExport = (statement: Statement): ESTree.Node => {\n const isExport = statement.type === 'ExportNamedDeclaration' || statement.type === 'ExportDefaultDeclaration'\n\n return isExport && statement.declaration ? (statement.declaration as ESTree.Node) : statement\n}\n\n/** The root identifier of a call chain: `test` for `test.describe.configure(\u2026)`. */\nconst calleeRoot = (callee: ESTree.Node): string | null => {\n if (callee.type === 'Identifier') {\n return callee.name\n }\n\n if (callee.type === 'MemberExpression') {\n return calleeRoot(callee.object)\n }\n\n return callee.type === 'CallExpression' ? calleeRoot(callee.callee) : null\n}\n\nconst typeNamesOf = (node: TsNode | undefined): string[] => {\n if (node === undefined) {\n return []\n }\n\n if (node.type === 'TSTypeReference' && node.typeName?.type === 'Identifier') {\n return [node.typeName.name!]\n }\n\n return (node.types ?? []).flatMap(typeNamesOf)\n}\n\nconst pageObjectAnchor = (declaration: ESTree.Node, index: number): Anchor | null => {\n if (declaration.type !== 'ClassDeclaration') {\n return null\n }\n\n return { index, label: `class \\`${declaration.id?.name ?? 'default'}\\``, headerTypes: new Set() }\n}\n\nconst fixtureAnchor = (declaration: ESTree.Node, index: number): Anchor | null => {\n if (declaration.type !== 'VariableDeclaration') {\n return null\n }\n\n const [declarator] = declaration.declarations\n const init = declarator?.init\n\n if (init?.type !== 'CallExpression' || init.callee.type !== 'MemberExpression') {\n return null\n }\n\n const property = init.callee.property\n\n if (property.type !== 'Identifier' || property.name !== 'extend') {\n return null\n }\n\n const name = declarator!.id.type === 'Identifier' ? declarator!.id.name : 'test'\n const typeArguments = (init as unknown as TsNode).typeArguments?.params ?? []\n\n return { index, label: `fixture \\`${name}\\``, headerTypes: new Set(typeArguments.flatMap(typeNamesOf)) }\n}\n\nconst specAnchor = (statement: Statement, index: number): Anchor | null => {\n if (statement.type !== 'ExpressionStatement' || statement.expression.type !== 'CallExpression') {\n return null\n }\n\n if (calleeRoot(statement.expression.callee) !== 'test') {\n return null\n }\n\n return { index, label: 'the first `test.*` call', headerTypes: new Set() }\n}\n\nconst isFunctionValue = (node: ESTree.Node | null | undefined): boolean => {\n return node?.type === 'ArrowFunctionExpression' || node?.type === 'FunctionExpression'\n}\n\nconst mockAnchor = (statement: Statement, index: number): Anchor | null => {\n if (statement.type !== 'ExportNamedDeclaration' && statement.type !== 'ExportDefaultDeclaration') {\n return null\n }\n\n const declaration = unwrapExport(statement)\n\n if (declaration.type === 'FunctionDeclaration') {\n return { index, label: `mock \\`${declaration.id?.name ?? 'default'}\\``, headerTypes: new Set() }\n }\n\n const declarator = declaration.type === 'VariableDeclaration' ? declaration.declarations[0] : undefined\n\n if (declarator?.id.type !== 'Identifier' || !isFunctionValue(declarator.init)) {\n return null\n }\n\n return { index, label: `mock \\`${declarator.id.name}\\``, headerTypes: new Set() }\n}\n\nconst ANCHOR_FINDERS: Record<AnchorKind, (statement: Statement, index: number) => Anchor | null> = {\n pageObject: (statement, index) => {\n return pageObjectAnchor(unwrapExport(statement), index)\n },\n fixture: (statement, index) => {\n return fixtureAnchor(unwrapExport(statement), index)\n },\n spec: specAnchor,\n mock: mockAnchor,\n}\n\nconst findAnchor = (body: Statement[], kind: AnchorKind): Anchor | null => {\n for (const [index, statement] of body.entries()) {\n const anchor = ANCHOR_FINDERS[kind](statement, index)\n\n if (anchor !== null) {\n return anchor\n }\n }\n\n return null\n}\n\nconst isDirective = (statement: Statement): boolean => {\n return (\n statement.type === 'ExpressionStatement' &&\n statement.expression.type === 'Literal' &&\n typeof statement.expression.value === 'string'\n )\n}\n\ninterface Misplaced {\n candidates: number[]\n /** What the misplaced statements must follow, as the report names it. */\n target: string\n}\n\nconst anchoredCandidates = (body: Statement[], kind: AnchorKind): Misplaced | null => {\n const anchor = findAnchor(body, kind)\n\n if (anchor === null) {\n return null\n }\n\n const candidates = body.slice(0, anchor.index).flatMap((statement, index) => {\n const declaration = unwrapExport(statement) as TsNode\n\n const isHeader =\n statement.type === 'ImportDeclaration' ||\n isDirective(statement) ||\n (declaration.id?.name !== undefined && anchor.headerTypes.has(declaration.id.name))\n\n return isHeader ? [] : [index]\n })\n\n return { candidates, target: anchor.label }\n}\n\n/** Names a local `export { a, b as c }` list exports, so `const a` below counts as an export. */\nconst locallyExportedNames = (body: Statement[]): Set<string> => {\n const names = body.flatMap((statement) => {\n if (statement.type !== 'ExportNamedDeclaration' || statement.source) {\n return []\n }\n\n return statement.specifiers.flatMap((specifier) => {\n return specifier.local.type === 'Identifier' ? [specifier.local.name] : []\n })\n })\n\n return new Set(names)\n}\n\nconst declaredNames = (statement: Statement): string[] => {\n const declaration = unwrapExport(statement) as TsNode & ESTree.Node\n\n if (declaration.type === 'VariableDeclaration') {\n return declaration.declarations.flatMap((declarator) => {\n return declarator.id.type === 'Identifier' ? [declarator.id.name] : []\n })\n }\n\n return declaration.id?.name ? [declaration.id.name] : []\n}\n\n/** A lib file's private statements that sit above one of its exports. */\nconst libCandidates = (body: Statement[]): Misplaced | null => {\n const exportedNames = locallyExportedNames(body)\n\n const isExported = (statement: Statement): boolean => {\n return (\n statement.type.startsWith('Export') ||\n declaredNames(statement).some((name) => {\n return exportedNames.has(name)\n })\n )\n }\n\n const lastExport = body.findLastIndex(isExported)\n\n if (lastExport === -1) {\n return null\n }\n\n const candidates = body.slice(0, lastExport).flatMap((statement, index) => {\n return statement.type === 'ImportDeclaration' || isDirective(statement) || isExported(statement) ? [] : [index]\n })\n\n return { candidates, target: 'the exports' }\n}\n\nconst misplacedStatements = (body: Statement[], kind: FileKind): Misplaced | null => {\n return kind === 'lib' ? libCandidates(body) : anchoredCandidates(body, kind)\n}\n\n/**\n * Whether a function passed to \u2014 or invoked as \u2014 `call` runs as part of it. Playwright runs every\n * `test.*` callback later, except a `describe` body; any other callback (`forEach`, `map`, an IIFE)\n * is assumed to run on the spot.\n */\nconst runsWithCall = (fn: ESTree.Node, call: ESTree.CallExpression): boolean => {\n if (call.callee === fn || playwrightCallKind(call) === 'describe') {\n return true\n }\n\n return calleeRoot(call.callee) !== 'test'\n}\n\nconst isFunctionNode = (node: ESTree.Node): boolean => {\n return (\n node.type === 'ArrowFunctionExpression' || node.type === 'FunctionExpression' || node.type === 'FunctionDeclaration'\n )\n}\n\n/** Whether `node` is evaluated while the module loads, rather than later from a function or instance. */\nconst runsAtLoad = (node: ESTree.Node): boolean => {\n let child: ESTree.Node = node\n let parent = (node as Rule.Node).parent as ESTree.Node | null | undefined\n\n while (parent) {\n if (isFunctionNode(child)) {\n if (parent.type !== 'CallExpression' || !runsWithCall(child, parent)) {\n return false\n }\n }\n\n const tsParent = parent as unknown as TsNode\n\n if (tsParent.type === 'PropertyDefinition' && tsParent.value === child && !tsParent.static) {\n return false\n }\n\n child = parent\n parent = (parent as Rule.Node).parent as ESTree.Node | null | undefined\n }\n\n return true\n}\n\nconst topLevelIndex = (node: ESTree.Node, body: Statement[]): number => {\n let current = node as Rule.Node\n\n while (current.parent && current.parent.type !== 'Program') {\n current = current.parent\n }\n\n return body.indexOf(current as Statement)\n}\n\nconst valueReferences = (sourceCode: SourceCode, statement: Statement): Scope.Reference[] => {\n return sourceCode.getDeclaredVariables(unwrapExport(statement)).flatMap((variable) => {\n return variable.references.filter((reference) => {\n const tsReference = reference as Scope.Reference & { isValueReference?: boolean }\n\n return tsReference.isValueReference !== false && reference.identifier !== variable.identifiers[0]\n })\n })\n}\n\n/**\n * Narrows the stray candidates to the ones that can move to the end of the file. A binding stays\n * put when it is read while the module loads \u2014 a `describe` title, `test.use({\u2026})`, a loop inside\n * `describe`, a `static` field, an `extend` option \u2014 since a `const` below that point is in its TDZ.\n * Any read from a statement that stays counts, so a kept helper keeps what it closes over.\n */\nconst movableStrays = (sourceCode: SourceCode, body: Statement[], candidates: number[]): Set<number> => {\n const movable = new Set(candidates)\n let changed = true\n\n while (changed) {\n changed = false\n\n for (const index of movable) {\n const pinned = valueReferences(sourceCode, body[index]!).some((reference) => {\n const from = topLevelIndex(reference.identifier as ESTree.Node, body)\n\n return !movable.has(from) && (candidates.includes(from) || runsAtLoad(reference.identifier as ESTree.Node))\n })\n\n if (pinned) {\n movable.delete(index)\n changed = true\n }\n }\n }\n\n return movable\n}\n\nconst describeStatement = (statement: Statement): string => {\n const names = declaredNames(statement)\n\n if (names.length > 0) {\n return names\n .map((name) => {\n return `\\`${name}\\``\n })\n .join(', ')\n }\n\n return `a ${unwrapExport(statement).type} statement`\n}\n\n/** The statement's source range, widened over its attached comments and a same-line trailing one. */\nconst statementSpan = (sourceCode: SourceCode, statement: Statement): [number, number] => {\n const trailing = sourceCode.getCommentsAfter(statement).filter((comment) => {\n return comment.loc!.start.line === statement.loc!.end.line\n })\n\n return [attachedStart(sourceCode, statement), (trailing.at(-1) ?? statement).range![1]]\n}\n\nconst buildFix = (sourceCode: SourceCode, body: Statement[], movable: number[]): Rule.ReportFixer => {\n return (fixer) => {\n const spans = movable.map((index) => {\n return statementSpan(sourceCode, body[index]!)\n })\n\n const moved = spans.map(([start, end]) => {\n return sourceCode.text.slice(start, end)\n })\n\n const end = sourceCode.text.length\n const separator = sourceCode.text.endsWith('\\n') ? '\\n' : '\\n\\n'\n\n return [\n ...spans.map(([start, stop]) => {\n const next = sourceCode.text.slice(stop).search(/\\S/)\n\n return fixer.removeRange([start, next === -1 ? end : stop + next])\n }),\n fixer.insertTextAfterRange([end, end], `${separator}${moved.join('\\n\\n')}\\n`),\n ]\n }\n}\n\nexport const e2eFileOrder: Rule.RuleModule = {\n meta: {\n type: 'suggestion',\n fixable: 'code',\n docs: {\n description:\n 'Require e2e page objects, fixtures, specs, mocks and lib files to open with their imports followed by the class, the `extend` call, the `test.*` calls, the mock function or the exports \u2014 helpers and constants go below.',\n recommended: true,\n url: 'https://github.com/ArthurSaenz/infra-kit/tree/main/apps/infra-kit/eslint-plugin#e2e-file-order',\n },\n schema: [\n {\n type: 'object',\n properties: {\n ignore: {\n type: 'array',\n items: { type: 'string' },\n description: 'Optional globs; the rule is skipped for matching files.',\n },\n },\n additionalProperties: false,\n },\n ],\n messages: {\n strayBeforeAnchor:\n '{{name}} sits between the imports and {{anchor}}. Move it below {{anchor}}: {{opening}}. The autofix moves it to the end of the file.',\n },\n },\n\n create(context) {\n const options = (context.options[0] ?? {}) as Options\n const filename = context.filename.split('\\\\').join('/')\n const kind = fileKindOf(filename)\n\n if (kind === null || (options.ignore?.length && matchesAnyGlob(filename, options.ignore))) {\n return {}\n }\n\n if (!isInE2ePackage(context)) {\n return {}\n }\n\n return {\n Program(program) {\n const body = program.body as Statement[]\n const misplaced = misplacedStatements(body, kind)\n\n if (misplaced === null) {\n return\n }\n\n const movable = [...movableStrays(context.sourceCode, body, misplaced.candidates)].toSorted((a, b) => {\n return a - b\n })\n\n if (movable.length === 0) {\n return\n }\n\n const fix = buildFix(context.sourceCode, body, movable)\n\n for (const index of movable) {\n context.report({\n node: body[index]!,\n messageId: 'strayBeforeAnchor',\n data: { name: describeStatement(body[index]!), anchor: misplaced.target, opening: KIND_OPENING[kind] },\n fix,\n })\n }\n },\n }\n },\n}\n", "import type { Rule, SourceCode } from 'eslint'\nimport type * as ESTree from 'estree'\n\nimport { attachedStart } from '../../utils/attached-comments'\nimport { matchesAnyGlob } from '../../utils/path-match'\nimport { isInE2ePackage } from '../../utils/playwright-call'\n\nexport interface Options {\n /** Globs; the rule is skipped for matching files. */\n ignore?: string[]\n}\n\ntype Member = ESTree.MethodDefinition | ESTree.PropertyDefinition | ESTree.StaticBlock\n\n// TS-only member fields are not modelled by estree; read them structurally.\ninterface TsMember {\n type: string\n kind?: string\n accessibility?: 'public' | 'protected' | 'private'\n key?: ESTree.Node\n}\n\nconst PAGE_OBJECT_FILE = /\\.(?:page|component)\\.[cm]?[jt]sx?$/\n\nconst GROUPS = ['field', 'constructor', 'getter', 'public method', 'private method'] as const\n\ntype Group = (typeof GROUPS)[number]\n\nconst isPrivate = (member: TsMember): boolean => {\n return (\n member.accessibility === 'private' ||\n member.accessibility === 'protected' ||\n member.key?.type === 'PrivateIdentifier'\n )\n}\n\n/**\n * A member's group. A property is a field even when it holds an arrow function: properties initialize\n * in source order, so moving one past another could break an initializer that reads it.\n */\nconst groupOf = (member: TsMember): Group => {\n if (member.kind === 'constructor') {\n return 'constructor'\n }\n\n if (member.type !== 'MethodDefinition') {\n return 'field'\n }\n\n if (isPrivate(member)) {\n return 'private method'\n }\n\n return member.kind === 'get' || member.kind === 'set' ? 'getter' : 'public method'\n}\n\nconst memberName = (member: TsMember): string => {\n if (member.kind === 'constructor') {\n return 'the constructor'\n }\n\n const key = member.key\n\n if (key?.type === 'Identifier') {\n return `\\`${key.name}\\``\n }\n\n return key?.type === 'PrivateIdentifier' ? `\\`#${key.name}\\`` : 'a computed member'\n}\n\n/**\n * Reorders the members into the group order. Each member keeps its own comments; the text between\n * members (blank lines, indentation) stays where it was. Sorting is stable, so fields keep their\n * relative order and field initializers see the same `this` they did before.\n */\nconst buildFix = (sourceCode: SourceCode, members: Member[]): Rule.ReportFixer => {\n return (fixer) => {\n const spans = members.map((_, index) => {\n return [attachedStart(sourceCode, members[index]!), members[index]!.range![1]] as [number, number]\n })\n\n const texts = spans.map(([start, end]) => {\n return sourceCode.text.slice(start, end)\n })\n\n const order = members\n .map((member, index) => {\n return { index, rank: GROUPS.indexOf(groupOf(member as TsMember)) }\n })\n .toSorted((a, b) => {\n return a.rank - b.rank || a.index - b.index\n })\n\n return spans.map((span, slot) => {\n return fixer.replaceTextRange(span, texts[order[slot]!.index]!)\n })\n }\n}\n\ninterface Violation {\n member: Member\n group: Group\n after: Member\n afterGroup: Group\n}\n\nconst findViolations = (members: Member[]): Violation[] => {\n const violations: Violation[] = []\n let latest: { member: Member; group: Group } | null = null\n\n for (const member of members) {\n const group = groupOf(member as TsMember)\n\n if (latest !== null && GROUPS.indexOf(group) < GROUPS.indexOf(latest.group)) {\n violations.push({ member, group, after: latest.member, afterGroup: latest.group })\n } else {\n latest = { member, group }\n }\n }\n\n return violations\n}\n\nexport const e2ePageObjectMemberOrder: Rule.RuleModule = {\n meta: {\n type: 'suggestion',\n fixable: 'code',\n docs: {\n description:\n 'Order the members of an e2e page object: fields, the constructor, getters, public methods, then private methods.',\n recommended: true,\n url: 'https://github.com/ArthurSaenz/infra-kit/tree/main/apps/infra-kit/eslint-plugin#e2e-page-object-member-order',\n },\n schema: [\n {\n type: 'object',\n properties: {\n ignore: {\n type: 'array',\n items: { type: 'string' },\n description: 'Optional globs; the rule is skipped for matching files.',\n },\n },\n additionalProperties: false,\n },\n ],\n messages: {\n outOfOrder:\n 'The {{group}} {{name}} comes after the {{afterGroup}} {{afterName}} in class `{{className}}`. Order a page object: fields, constructor, getters, public methods, private methods.',\n },\n },\n\n create(context) {\n const options = (context.options[0] ?? {}) as Options\n const filename = context.filename.split('\\\\').join('/')\n\n if (!PAGE_OBJECT_FILE.test(filename) || (options.ignore?.length && matchesAnyGlob(filename, options.ignore))) {\n return {}\n }\n\n if (!isInE2ePackage(context)) {\n return {}\n }\n\n const check = (node: ESTree.ClassDeclaration | ESTree.ClassExpression): void => {\n const members = node.body.body as Member[]\n const violations = findViolations(members)\n\n if (violations.length === 0) {\n return\n }\n\n const fix = buildFix(context.sourceCode, members)\n\n for (const violation of violations) {\n context.report({\n node: violation.member,\n messageId: 'outOfOrder',\n data: {\n group: violation.group,\n name: memberName(violation.member as TsMember),\n afterGroup: violation.afterGroup,\n afterName: memberName(violation.after as TsMember),\n className: node.id?.name ?? 'anonymous',\n },\n fix,\n })\n }\n }\n\n return {\n ClassDeclaration: check,\n ClassExpression: check,\n }\n },\n}\n", "import type { Rule } from 'eslint'\nimport type { Expression, Node, ObjectExpression, SpreadElement } from 'estree'\n\nimport { detailsArgument, isInE2ePackage, playwrightCallKind } from '../../utils/playwright-call'\n\nexport interface Options {\n /** The only tags a test or describe may carry. */\n allowed?: string[]\n}\n\nexport const DEFAULT_ALLOWED_TAGS = ['@smoke', '@readonly', '@mocked', '@slow']\n\n/** The `tag` property's value node, or null when the details object has none. */\nconst tagValue = (details: ObjectExpression): Expression | null => {\n for (const property of details.properties) {\n if (\n property.type === 'Property' &&\n !property.computed &&\n property.key.type === 'Identifier' &&\n property.key.name === 'tag'\n ) {\n return property.value as Expression\n }\n }\n\n return null\n}\n\n/** String-literal tags with their nodes; non-literal entries (a shared constant) are not judged. */\nconst literalTags = (value: Expression): { tag: string; node: Node }[] => {\n const entries: (Expression | SpreadElement | null)[] = value.type === 'ArrayExpression' ? value.elements : [value]\n\n return entries.flatMap((entry) => {\n return entry?.type === 'Literal' && typeof entry.value === 'string' ? [{ tag: entry.value, node: entry }] : []\n })\n}\n\nexport const e2eTestTags: Rule.RuleModule = {\n meta: {\n type: 'problem',\n docs: {\n description: 'Restrict Playwright test and describe tags in e2e packages to an allowed set.',\n recommended: true,\n url: 'https://github.com/ArthurSaenz/infra-kit/tree/main/apps/infra-kit/eslint-plugin#e2e-test-tags',\n },\n schema: [\n {\n type: 'object',\n properties: {\n allowed: {\n type: 'array',\n items: { type: 'string', pattern: '^@' },\n uniqueItems: true,\n description: 'The only tags allowed; defaults to @smoke, @readonly, @mocked, @slow.',\n },\n },\n additionalProperties: false,\n },\n ],\n messages: {\n unknownTag:\n 'Tag `{{tag}}` is not an allowed e2e tag. Use one of {{allowed}}; browsers, devices and environments are Playwright projects, not tags.',\n },\n },\n\n create(context) {\n if (!isInE2ePackage(context)) {\n return {}\n }\n\n const options = (context.options[0] ?? {}) as Options\n const allowed = new Set(options.allowed ?? DEFAULT_ALLOWED_TAGS)\n\n const allowedList = [...allowed]\n .map((tag) => {\n return `\\`${tag}\\``\n })\n .join(', ')\n\n return {\n CallExpression(node) {\n const details = playwrightCallKind(node) === null ? null : detailsArgument(node)\n const value = details === null ? null : tagValue(details)\n\n if (value === null) {\n return\n }\n\n for (const { tag, node: tagNode } of literalTags(value)) {\n if (!allowed.has(tag)) {\n context.report({ node: tagNode, messageId: 'unknownTag', data: { tag, allowed: allowedList } })\n }\n }\n },\n }\n },\n}\n", "import type { Rule } from 'eslint'\n\nimport { isInE2ePackage, playwrightCallKind, staticTitle } from '../../utils/playwright-call'\n\nconst SHOULD_PREFIX = /^should\\s+/i\n\nexport const e2eTestTitle: Rule.RuleModule = {\n meta: {\n type: 'suggestion',\n docs: {\n description: 'Require e2e test titles to state the behaviour directly, without a leading `should`.',\n recommended: true,\n url: 'https://github.com/ArthurSaenz/infra-kit/tree/main/apps/infra-kit/eslint-plugin#e2e-test-title',\n },\n schema: [],\n messages: {\n shouldPrefix:\n 'Test title \"{{title}}\" starts with `should`. State the behaviour and its observable outcome directly: \"{{suggested}}\".',\n },\n },\n\n create(context) {\n if (!isInE2ePackage(context)) {\n return {}\n }\n\n return {\n CallExpression(node) {\n const title = playwrightCallKind(node) === 'test' ? staticTitle(node) : null\n\n if (title === null || !SHOULD_PREFIX.test(title)) {\n return\n }\n\n context.report({\n node: node.arguments[0] ?? node,\n messageId: 'shouldPrefix',\n data: { title, suggested: title.replace(SHOULD_PREFIX, '') },\n })\n },\n }\n },\n}\n", "import type { Rule, SourceCode } from 'eslint'\nimport type * as ESTree from 'estree'\n\nimport { attachedStart } from '../../utils/attached-comments'\nimport { matchesAnyGlob } from '../../utils/path-match'\nimport { isInE2ePackage, playwrightCallKind, staticTitle, testStatementNames } from '../../utils/playwright-call'\n\nexport interface Options {\n /** Globs; the rule is skipped for matching files. */\n ignore?: string[]\n /** Top-level `test.describe` blocks a spec may hold. */\n max?: number\n}\n\nconst SPEC_FILE = /\\.spec\\.[cm]?[jt]sx?$/\nconst DEFAULT_MAX = 1\n\ntype Statement = ESTree.Statement | ESTree.ModuleDeclaration\n\ninterface TopLevelCall {\n statement: ESTree.ExpressionStatement\n call: ESTree.CallExpression\n names: string[]\n}\n\nconst topLevelCalls = (body: Statement[]): TopLevelCall[] => {\n return body.flatMap((statement) => {\n const names = testStatementNames(statement)\n\n if (names === null) {\n return []\n }\n\n const expressionStatement = statement as ESTree.ExpressionStatement\n\n return [{ statement: expressionStatement, call: expressionStatement.expression as ESTree.CallExpression, names }]\n })\n}\n\nconst describeLabel = (call: ESTree.CallExpression): string => {\n const title = staticTitle(call)\n\n return title === null ? 'the `test.describe` block' : `\\`test.describe('${title}')\\``\n}\n\nconst callbackBlock = (call: ESTree.CallExpression): ESTree.BlockStatement | null => {\n const callback = call.arguments.at(-1)\n\n if (callback?.type !== 'ArrowFunctionExpression' && callback?.type !== 'FunctionExpression') {\n return null\n }\n\n return callback.body.type === 'BlockStatement' ? callback.body : null\n}\n\n/** The statement's range, widened over its attached comments and the whitespace that follows it. */\nconst removalRange = (sourceCode: SourceCode, statement: Statement): [number, number] => {\n const end = statement.range![1]\n const next = sourceCode.text.slice(end).search(/\\S/)\n\n return [attachedStart(sourceCode, statement), next === -1 ? sourceCode.text.length : end + next]\n}\n\n/**\n * Moves every top-level `test.use` / `configure` / hook / annotation into the one describe, at the\n * start of its body and in source order. Equivalent while the spec has a single describe: each of\n * them then applies to exactly the tests it applied to before.\n */\nconst buildFix = (sourceCode: SourceCode, moved: TopLevelCall[], block: ESTree.BlockStatement): Rule.ReportFixer => {\n return (fixer) => {\n // The describe is top-level, so an empty body indents one level from column 0.\n const indent = ' '.repeat(block.body[0]?.loc?.start.column ?? 2)\n\n const texts = moved.map(({ statement }) => {\n const [start] = removalRange(sourceCode, statement)\n\n return sourceCode.text\n .slice(start, statement.range![1])\n .split('\\n')\n .map((line) => {\n return line === '' ? line : `${indent}${line}`\n })\n .join('\\n')\n })\n\n return [\n ...moved.map(({ statement }) => {\n return fixer.removeRange(removalRange(sourceCode, statement))\n }),\n fixer.insertTextAfterRange([block.range![0], block.range![0] + 1], `\\n${texts.join('\\n\\n')}\\n`),\n ]\n }\n}\n\nexport const e2eTopLevelDescribe: Rule.RuleModule = {\n meta: {\n type: 'suggestion',\n fixable: 'code',\n docs: {\n description:\n 'Require an e2e spec to hold one top-level `test.describe`, with its `test.use`, `configure`, hooks and tests inside it.',\n recommended: true,\n url: 'https://github.com/ArthurSaenz/infra-kit/tree/main/apps/infra-kit/eslint-plugin#e2e-top-level-describe',\n },\n schema: [\n {\n type: 'object',\n properties: {\n ignore: {\n type: 'array',\n items: { type: 'string' },\n description: 'Optional globs; the rule is skipped for matching files.',\n },\n max: {\n type: 'integer',\n minimum: 1,\n description: 'Top-level `test.describe` blocks a spec may hold.',\n },\n },\n additionalProperties: false,\n },\n ],\n messages: {\n extraDescribe:\n '{{describe}} is top-level describe number {{count}} in this spec; the limit is {{max}}. Move it to its own spec file, or nest it inside {{first}}.',\n outsideDescribe:\n '`{{call}}` sits at the top level of the spec. Move it inside {{describe}}: a spec holds one top-level describe, and its setup, hooks and tests live inside it.',\n testOutsideDescribe:\n 'Test {{test}} sits at the top level of the spec. Wrap the spec\u2019s tests in a `test.describe` named after the feature they cover.',\n },\n },\n\n create(context) {\n const options = (context.options[0] ?? {}) as Options\n const filename = context.filename.split('\\\\').join('/')\n\n if (!SPEC_FILE.test(filename) || (options.ignore?.length && matchesAnyGlob(filename, options.ignore))) {\n return {}\n }\n\n if (!isInE2ePackage(context)) {\n return {}\n }\n\n const max = options.max ?? DEFAULT_MAX\n\n return {\n Program(program) {\n const calls = topLevelCalls(program.body as Statement[])\n\n const describes = calls.filter(({ call }) => {\n return playwrightCallKind(call) === 'describe'\n })\n\n const tests = calls.filter(({ call }) => {\n return (\n playwrightCallKind(call) === 'test' &&\n call.arguments.slice(1).some((argument) => {\n return argument.type === 'ArrowFunctionExpression' || argument.type === 'FunctionExpression'\n })\n )\n })\n\n const setup = calls.filter((entry) => {\n return !describes.includes(entry) && !tests.includes(entry)\n })\n\n for (const [index, extra] of describes.slice(max).entries()) {\n context.report({\n node: extra.statement,\n messageId: 'extraDescribe',\n data: {\n describe: describeLabel(extra.call),\n count: String(max + index + 1),\n max: String(max),\n first: describeLabel(describes[0]!.call),\n },\n })\n }\n\n for (const test of tests) {\n const title = staticTitle(test.call)\n\n context.report({\n node: test.statement,\n messageId: 'testOutsideDescribe',\n data: { test: title === null ? `\\`${test.names.join('.')}\\`` : `'${title}'` },\n })\n }\n\n const [only] = describes\n const block = describes.length === 1 && only ? callbackBlock(only.call) : null\n const fix = block === null ? undefined : buildFix(context.sourceCode, setup, block)\n\n for (const entry of setup) {\n context.report({\n node: entry.statement,\n messageId: 'outsideDescribe',\n data: {\n call: entry.names.join('.'),\n describe: only ? describeLabel(only.call) : 'a `test.describe` block',\n },\n fix,\n })\n }\n },\n }\n },\n}\n", "import type { Rule } from 'eslint'\nimport fs from 'node:fs'\nimport path from 'node:path'\n\nimport { isUiPackageFile } from '../../utils/component-file-scope'\nimport { fileDirsUnderSrc, srcDirOf } from '../../utils/import-target'\nimport { matchesAnyGlob } from '../../utils/path-match'\n\ninterface Options {\n /** File names (without extension) allowed directly in a feature root, on top of the defaults. */\n extraRootFiles?: string[]\n /** File names (without extension) allowed directly in a feature's `services/`, on top of the defaults. */\n extraServiceFiles?: string[]\n paths?: string[]\n ignore?: string[]\n}\n\nexport const ROOT_FILES = ['index', 'types', 'services', 'analytics', 'constants', 'translates']\nexport const SERVICE_FILES = ['main', 'api', 'libs', 'index', 'types', 'constants']\n\nconst SERVICES = 'services'\nconst TEST_OR_STORY_DIR = /\\/__(?:tests|stories)__\\//\nconst EXEMPT_FILE = /\\.(?:(?:test|spec|stories)\\.[cm]?[jt]sx?|d\\.[cm]?ts)$/\n\nconst stemOf = (basename: string): string => {\n return basename.slice(0, basename.length - path.posix.extname(basename).length)\n}\n\nconst describeAllowed = (stems: readonly string[]): string => {\n return stems\n .map((stem) => {\n return `${stem}.ts`\n })\n .join(', ')\n}\n\ninterface Violation {\n messageId: 'unknownRootFile' | 'unknownServiceFile' | 'servicesFileAndFolder'\n data: Record<string, string>\n}\n\n/** `features/<feature>/services.*` or anything under `features/<feature>/services/`. */\nconst isServiceFile = (filename: string, dirs: readonly string[]): boolean => {\n return dirs[2] === SERVICES || (dirs.length === 2 && stemOf(path.posix.basename(filename)) === SERVICES)\n}\n\n/** `dirs` are the file's directories under `src/`, starting `['features', <feature>]`. */\nconst findNameViolation = (filename: string, dirs: readonly string[], options: Options): Violation | null => {\n const basename = path.posix.basename(filename)\n const stem = stemOf(basename)\n\n if (dirs.length === 2) {\n const allowed = [...ROOT_FILES, ...(options.extraRootFiles ?? [])]\n\n if (!allowed.includes(stem)) {\n return { messageId: 'unknownRootFile', data: { file: basename, allowed: describeAllowed(allowed) } }\n }\n\n // A rule sees one file at a time, so the sibling folder is only visible on disk.\n if (stem === SERVICES && fs.existsSync(path.posix.join(path.posix.dirname(filename), SERVICES))) {\n return { messageId: 'servicesFileAndFolder', data: { feature: dirs[1]! } }\n }\n\n return null\n }\n\n // Deeper folders under `services/` are not judged; other segments are package-structure's concern.\n if (dirs.length === 3 && dirs[2] === SERVICES) {\n const allowed = [...SERVICE_FILES, ...(options.extraServiceFiles ?? [])]\n\n if (!allowed.includes(stem)) {\n return { messageId: 'unknownServiceFile', data: { file: basename, allowed: describeAllowed(allowed) } }\n }\n }\n\n return null\n}\n\nexport const featureFiles: Rule.RuleModule = {\n meta: {\n type: 'problem',\n docs: {\n description:\n 'Allow only the conventional files in a feature root and its `services/`, one of `services.ts` or `services/`, and no JSX in services.',\n recommended: true,\n url: 'https://github.com/ArthurSaenz/infra-kit/tree/main/apps/infra-kit/eslint-plugin#feature-files',\n },\n schema: [\n {\n type: 'object',\n properties: {\n extraRootFiles: {\n type: 'array',\n items: { type: 'string', minLength: 1 },\n uniqueItems: true,\n description: `File names without extension allowed in a feature root besides ${ROOT_FILES.join(', ')}.`,\n },\n extraServiceFiles: {\n type: 'array',\n items: { type: 'string', minLength: 1 },\n uniqueItems: true,\n description: `File names without extension allowed in \\`services/\\` besides ${SERVICE_FILES.join(', ')}.`,\n },\n paths: {\n type: 'array',\n items: { type: 'string' },\n description:\n 'Optional glob patterns. When provided, the rule only runs for files whose path matches one of them.',\n },\n ignore: {\n type: 'array',\n items: { type: 'string' },\n description:\n 'Optional glob patterns. The rule is skipped for files whose path matches one of them, even if it also matches `paths`.',\n },\n },\n additionalProperties: false,\n },\n ],\n messages: {\n unknownRootFile: '\"{{file}}\" is not an allowed feature-root file. Allowed: {{allowed}}.',\n unknownServiceFile: '\"{{file}}\" is not an allowed file in `services/`. Allowed: {{allowed}}.',\n servicesFileAndFolder:\n 'Feature \"{{feature}}\" has both `services.ts` and a `services/` folder. Keep one: move this file into `services/main.ts`, or fold the folder into this file.',\n jsxInService: 'Services hold atoms and pure functions; JSX belongs in a component or container.',\n },\n },\n\n create(context) {\n const options = (context.options[0] ?? {}) as Options\n const filename = context.filename.split('\\\\').join('/')\n const paths = options.paths ?? []\n const ignore = options.ignore ?? []\n\n if (ignore.length > 0 && matchesAnyGlob(filename, ignore)) {\n return {}\n }\n\n if (paths.length > 0 && !matchesAnyGlob(filename, paths)) {\n return {}\n }\n\n if (TEST_OR_STORY_DIR.test(filename) || EXEMPT_FILE.test(filename)) {\n return {}\n }\n\n const srcDir = srcDirOf(filename)\n\n if (srcDir === null) {\n return {}\n }\n\n const dirs = fileDirsUnderSrc(filename, srcDir)\n\n if (dirs[0] !== 'features' || dirs.length < 2 || !isUiPackageFile(filename)) {\n return {}\n }\n\n const violation = findNameViolation(filename, dirs, options)\n const listeners: Rule.RuleListener = {}\n\n if (violation !== null) {\n // Reported on Program, like package-structure: the file's name is the problem, not a line in it.\n listeners.Program = (program) => {\n context.report({ ...violation, node: program })\n }\n }\n\n if (isServiceFile(filename, dirs)) {\n let reported = false\n\n const reportJsx = (node: Rule.Node): void => {\n if (!reported) {\n reported = true\n context.report({ node, messageId: 'jsxInService' })\n }\n }\n\n Object.assign(listeners, { JSXElement: reportJsx, JSXFragment: reportJsx })\n }\n\n return listeners\n },\n}\n", "import type { Rule } from 'eslint'\nimport path from 'node:path'\n\nimport { findPackageRoot } from './package-root'\nimport { resolvePackageType } from './package-type-reader'\nimport { matchesAnyGlob } from './path-match'\n\nexport const DEFAULT_ROOT_ALIAS = '#root'\n\nconst INDEX_FILE = /^index(?:\\.[cm]?[jt]sx?)?$/\n\n/** An import-like node whose module path is a string literal, with the literal node to report on. */\nexport interface ImportSource {\n specifier: string\n node: Rule.Node\n typeOnly: boolean\n}\n\ninterface SourceLiteral {\n type: string\n value?: unknown\n literal?: { value?: unknown }\n}\n\nconst literalValue = (source: SourceLiteral | null | undefined): string | null => {\n if (source === null || source === undefined) {\n return null\n }\n\n // `typeof import('x')` wraps the literal in a TSLiteralType; every other carrier holds it directly.\n const value = source.type === 'TSLiteralType' ? source.literal?.value : source.value\n\n return typeof value === 'string' ? value : null\n}\n\ninterface SpecifierLike {\n importKind?: string\n exportKind?: string\n}\n\nconst allSpecifiersAreTypes = (specifiers: readonly SpecifierLike[] | undefined, key: keyof SpecifierLike): boolean => {\n return (\n specifiers !== undefined &&\n specifiers.length > 0 &&\n specifiers.every((specifier) => {\n return specifier[key] === 'type'\n })\n )\n}\n\ninterface ImportLikeNode {\n type: string\n source?: SourceLiteral | null\n argument?: SourceLiteral\n importKind?: string\n exportKind?: string\n specifiers?: SpecifierLike[]\n}\n\n/**\n * The module path an import-like node names, or null for a node without a static string path\n * (`import(name)`, a template literal, a local `export { a }`). `typeof import('x')` counts and is\n * type-only: hulyo reaches into feature internals that way, past every import-statement rule.\n */\nexport const readImportSource = (node: Rule.Node): ImportSource | null => {\n const candidate = node as unknown as ImportLikeNode\n // typescript-eslint 8 moved TSImportType's path from `argument` to `source`; read either.\n const sourceNode = candidate.type === 'TSImportType' ? (candidate.source ?? candidate.argument) : candidate.source\n const specifier = literalValue(sourceNode)\n\n if (specifier === null || sourceNode === null || sourceNode === undefined) {\n return null\n }\n\n const typeOnly =\n candidate.type === 'TSImportType' ||\n candidate.importKind === 'type' ||\n candidate.exportKind === 'type' ||\n allSpecifiersAreTypes(candidate.specifiers, candidate.type === 'ImportDeclaration' ? 'importKind' : 'exportKind')\n\n return { specifier, node: sourceNode as unknown as Rule.Node, typeOnly }\n}\n\n/** The `src` directory of the package `filename` lives in, or null when it is not under one. */\nexport const srcDirOf = (filename: string): string | null => {\n const packageRoot = findPackageRoot(filename)\n\n if (packageRoot !== null) {\n return filename.startsWith(`${packageRoot}/src/`) ? `${packageRoot}/src` : null\n }\n\n // Virtual filenames (RuleTester, `<input>`) have no package on disk: the innermost `src/` stands in.\n const index = filename.lastIndexOf('/src/')\n\n return index >= 0 ? filename.slice(0, index + '/src'.length) : null\n}\n\n/**\n * Where `specifier` points, as the path segments under `srcDir` \u2014 `['features', 'user']` for\n * `#root/features/user` or `../../features/user`. Null for a package import, another alias, or a\n * relative path that climbs out of `src/`: those have no layer.\n */\nexport const resolveUnderSrc = (\n filename: string,\n srcDir: string,\n specifier: string,\n rootAlias: string,\n): string[] | null => {\n let absolute: string\n\n if (specifier === rootAlias || specifier.startsWith(`${rootAlias}/`)) {\n absolute = path.posix.join(srcDir, specifier.slice(rootAlias.length))\n } else if (specifier.startsWith('.')) {\n absolute = path.posix.resolve(path.posix.dirname(filename), specifier)\n } else {\n return null\n }\n\n if (!absolute.startsWith(`${srcDir}/`)) {\n return null\n }\n\n return absolute.slice(srcDir.length + 1).split('/')\n}\n\n/** Path segments of `filename`'s directory under `srcDir`. */\nexport const fileDirsUnderSrc = (filename: string, srcDir: string): string[] => {\n return filename\n .slice(srcDir.length + 1)\n .split('/')\n .slice(0, -1)\n}\n\n/** `features/<name>` or `features/<name>/index.*` \u2014 the only paths that form a feature's public API. */\nexport const isFeaturePublicApi = (target: readonly string[]): boolean => {\n return target.length === 2 || (target.length === 3 && INDEX_FILE.test(target[2]!))\n}\n\n/** The feature name a src-relative path sits in (`features/<name>/\u2026`), or null outside `features/`. */\nexport const featureNameOf = (segments: readonly string[]): string | null => {\n return segments[0] === 'features' && segments.length >= 2 ? segments[1]! : null\n}\n\n/**\n * Every node kind that names a module: static imports, re-exports, dynamic `import('x')` and the\n * type-level `typeof import('x')`. A rule registers one handler for all of them.\n */\nexport const IMPORT_SELECTORS = [\n 'ImportDeclaration',\n 'ExportNamedDeclaration',\n 'ExportAllDeclaration',\n 'ImportExpression',\n 'TSImportType',\n] as const\n\n// Backends and Playwright suites have no UI layering; their `src/` folders mean something else.\nconst UNLAYERED_TYPES = new Set(['backend', 'e2e'])\n\n/** Whether the src-layout import rules apply to `filename`: not ignored, not in a backend or e2e package. */\nexport const isLayeredFile = (filename: string, ignore: readonly string[]): boolean => {\n if (ignore.length > 0 && matchesAnyGlob(filename, ignore)) {\n return false\n }\n\n const packageRoot = findPackageRoot(filename)\n\n return packageRoot === null || !UNLAYERED_TYPES.has(resolvePackageType(packageRoot))\n}\n", "import type { Rule } from 'eslint'\n\nimport {\n DEFAULT_ROOT_ALIAS,\n IMPORT_SELECTORS,\n featureNameOf,\n fileDirsUnderSrc,\n isFeaturePublicApi,\n isLayeredFile,\n readImportSource,\n resolveUnderSrc,\n srcDirOf,\n} from '../../utils/import-target'\n\nexport interface Options {\n /** The alias that maps to the package's `src/`. */\n rootAlias?: string\n /** Globs; the rule is skipped for matching files. */\n ignore?: string[]\n}\n\nexport const featurePublicApi: Rule.RuleModule = {\n meta: {\n type: 'problem',\n docs: {\n description:\n 'Require code outside a feature to import it only through its public API (`features/<name>` / its `index`), whatever the path form.',\n recommended: true,\n url: 'https://github.com/ArthurSaenz/infra-kit/tree/main/apps/infra-kit/eslint-plugin#feature-public-api',\n },\n schema: [\n {\n type: 'object',\n properties: {\n rootAlias: { type: 'string', description: 'The alias that maps to `src/` (default `#root`).' },\n ignore: {\n type: 'array',\n items: { type: 'string' },\n description: 'Optional globs; the rule is skipped for matching files.',\n },\n },\n additionalProperties: false,\n },\n ],\n messages: {\n deepImport:\n '`{{specifier}}` reaches into the internals of feature `{{feature}}`. Import from its public API `{{publicApi}}` instead, exporting what you need from `features/{{feature}}/index.ts`.',\n },\n },\n\n create(context) {\n const options = (context.options[0] ?? {}) as Options\n const filename = context.filename.split('\\\\').join('/')\n const srcDir = srcDirOf(filename)\n\n if (srcDir === null || !isLayeredFile(filename, options.ignore ?? [])) {\n return {}\n }\n\n const rootAlias = options.rootAlias ?? DEFAULT_ROOT_ALIAS\n const ownFeature = featureNameOf(fileDirsUnderSrc(filename, srcDir))\n\n const check = (node: Rule.Node): void => {\n const source = readImportSource(node)\n const target = source === null ? null : resolveUnderSrc(filename, srcDir, source.specifier, rootAlias)\n const feature = target === null ? null : featureNameOf(target)\n\n if (source === null || feature === null || feature === ownFeature || isFeaturePublicApi(target!)) {\n return\n }\n\n context.report({\n node: source.node,\n messageId: 'deepImport',\n data: { specifier: source.specifier, feature, publicApi: `${rootAlias}/features/${feature}` },\n })\n }\n\n return Object.fromEntries(\n IMPORT_SELECTORS.map((selector) => {\n return [selector, check]\n }),\n )\n },\n}\n", "import type { Rule } from 'eslint'\n\nimport {\n DEFAULT_ROOT_ALIAS,\n IMPORT_SELECTORS,\n fileDirsUnderSrc,\n isLayeredFile,\n readImportSource,\n resolveUnderSrc,\n srcDirOf,\n} from '../../utils/import-target'\n\nexport interface Options {\n /** Folders under `src/`, lowest level first; folders in one inner array share a level. */\n layers?: string[][]\n /** Type-only imports carry no runtime edge, so they may point at any level. */\n allowTypeImports?: boolean\n /** The alias that maps to the package's `src/`. */\n rootAlias?: string\n /** Globs; the rule is skipped for matching files. */\n ignore?: string[]\n /** Folders whose subfolders may not import each other (`commands/a` \u2192 `commands/b`). */\n isolate?: string[]\n}\n\n// `renderer` and `mobile` are entry points like `app`: they mount pages, nothing imports them.\n// A test assembles its own environment (global styles, app providers) the way an entry point does,\n// and it is not part of the runtime graph the layers protect.\nconst TEST_FILE = /\\.(?:test|spec)\\.[cm]?[jt]sx?$/\n\nconst isTestFile = (filename: string): boolean => {\n return filename.includes('/__tests__/') || TEST_FILE.test(filename)\n}\n\nexport const DEFAULT_LAYERS: string[][] = [\n ['lib', 'components', 'shared', 'assets', 'styles', 'data'],\n ['core', 'entities'],\n ['features'],\n ['pages', 'routes'],\n ['app', 'renderer', 'mobile'],\n]\n\nconst levelIndex = (layers: readonly string[][]): Map<string, number> => {\n return new Map(\n layers.flatMap((level, index) => {\n return level.map((layer): [string, number] => {\n return [layer, index]\n })\n }),\n )\n}\n\nconst describeOrder = (layers: readonly string[][]): string => {\n return layers\n .map((level) => {\n return level.join(', ')\n })\n .join(' \u2192 ')\n}\n\nexport const layerImports: Rule.RuleModule = {\n meta: {\n type: 'problem',\n docs: {\n description:\n 'Allow imports only to the same or a lower layer of `src/` (lib/components \u2192 entities \u2192 features \u2192 pages/routes \u2192 app).',\n recommended: true,\n url: 'https://github.com/ArthurSaenz/infra-kit/tree/main/apps/infra-kit/eslint-plugin#layer-imports',\n },\n schema: [\n {\n type: 'object',\n properties: {\n layers: {\n type: 'array',\n items: { type: 'array', items: { type: 'string' }, minItems: 1 },\n minItems: 1,\n description: 'Folders under `src/`, lowest level first; folders in one inner array share a level.',\n },\n allowTypeImports: {\n type: 'boolean',\n description: 'Whether type-only imports may point at a higher layer (default true).',\n },\n rootAlias: { type: 'string', description: 'The alias that maps to `src/` (default `#root`).' },\n ignore: {\n type: 'array',\n items: { type: 'string' },\n description: 'Optional globs; the rule is skipped for matching files.',\n },\n isolate: {\n type: 'array',\n items: { type: 'string' },\n description: 'Folders whose subfolders may not import each other (`commands/a` \u2192 `commands/b`).',\n },\n },\n additionalProperties: false,\n },\n ],\n messages: {\n upward:\n '`{{fromLayer}}` cannot import `{{specifier}}` from the higher layer `{{toLayer}}`. Layers import only their own level or below: {{order}}. Move the shared code down into a lower layer, or pass it in from above.',\n sibling:\n '`{{fromLayer}}/{{fromUnit}}` cannot import `{{specifier}}` from its sibling `{{fromLayer}}/{{toUnit}}`: folders under `{{fromLayer}}/` are isolated from each other. Move the shared code down into a lower layer, or pass it in from above.',\n },\n },\n\n create(context) {\n const options = (context.options[0] ?? {}) as Options\n const filename = context.filename.split('\\\\').join('/')\n const srcDir = srcDirOf(filename)\n\n if (srcDir === null || isTestFile(filename) || !isLayeredFile(filename, options.ignore ?? [])) {\n return {}\n }\n\n const layers = options.layers ?? DEFAULT_LAYERS\n const levels = levelIndex(layers)\n const [fromLayer, fromUnit] = fileDirsUnderSrc(filename, srcDir)\n const fromLevel = fromLayer === undefined ? undefined : levels.get(fromLayer)\n\n // A file directly in `src/` (main.tsx) or in an unlisted folder has no level to compare against.\n if (fromLayer === undefined || fromLevel === undefined) {\n return {}\n }\n\n const allowTypeImports = options.allowTypeImports ?? true\n const rootAlias = options.rootAlias ?? DEFAULT_ROOT_ALIAS\n const isolated = fromUnit !== undefined && (options.isolate ?? []).includes(fromLayer)\n\n const check = (node: Rule.Node): void => {\n const source = readImportSource(node)\n\n if (source === null || (allowTypeImports && source.typeOnly)) {\n return\n }\n\n const [toLayer, toUnit] = resolveUnderSrc(filename, srcDir, source.specifier, rootAlias) ?? []\n const toLevel = toLayer === undefined ? undefined : levels.get(toLayer)\n\n if (isolated && toLayer === fromLayer && toUnit !== undefined && toUnit !== fromUnit) {\n context.report({\n node: source.node,\n messageId: 'sibling',\n data: { fromLayer, fromUnit: fromUnit!, toUnit, specifier: source.specifier },\n })\n\n return\n }\n\n if (toLevel === undefined || toLevel <= fromLevel) {\n return\n }\n\n context.report({\n node: source.node,\n messageId: 'upward',\n data: { fromLayer, toLayer: toLayer!, specifier: source.specifier, order: describeOrder(layers) },\n })\n }\n\n return Object.fromEntries(\n IMPORT_SELECTORS.map((selector) => {\n return [selector, check]\n }),\n )\n },\n}\n", "import type { Rule } from 'eslint'\nimport type * as ESTree from 'estree'\n\nimport { getComponentFunction, getComponentName, isComponent, unwrapExport } from '../../utils/component'\nimport type { ComponentFunction } from '../../utils/component'\nimport { matchesAnyGlob } from '../../utils/path-match'\n\ninterface Options {\n maxComponents?: number\n paths?: string[]\n ignore?: string[]\n}\n\n// Default ceiling on component declarations in a single file. Tunable via the\n// `maxComponents` option; the value is a convention nudge (\"split this file\"),\n// not a hard truth.\nconst DEFAULT_MAX_COMPONENTS = 4\n\n// Fallback used when the offending component is anonymous (e.g.\n// `export default () => <div />`), since `getComponentName` returns null rather\n// than a placeholder in that case.\nconst ANONYMOUS_NAME = 'component'\n\n/** The component function(s) declared by a single top-level declaration. */\nconst componentFunctionsIn = (declaration: ESTree.Node): ComponentFunction[] => {\n if (declaration.type === 'FunctionDeclaration') {\n return isComponent(declaration) ? [declaration] : []\n }\n\n if (declaration.type === 'VariableDeclaration') {\n return declaration.declarations\n .map((declarator) => {\n return getComponentFunction(declarator.init)\n })\n .filter((fn): fn is ComponentFunction => {\n return fn !== null && isComponent(fn)\n })\n }\n\n // e.g. `export default memo(() => \u2026)`.\n const fn = getComponentFunction(declaration)\n\n return fn && isComponent(fn) ? [fn] : []\n}\n\n/**\n * Every component declared at the TOP LEVEL of the program body (mirrors\n * `max-jsx-return-size` and `component-arrow-function`). Multi-declarator\n * declarations (`const A = \u2026, B = \u2026`) count each component separately;\n * re-exports (`export { X } from './x'`) declare nothing and are not counted.\n * Nested/in-render components are deliberately out of scope \u2014 that is a\n * different concern (component identity/perf), not file organisation.\n *\n * Returns the component *functions* (not just a count) so a future export-aware\n * variant \u2014 count only non-exported helpers \u2014 is an additive change, not a\n * rewrite.\n */\nconst collectComponents = (body: Array<ESTree.Statement | ESTree.ModuleDeclaration>): ComponentFunction[] => {\n return body.flatMap((statement) => {\n const declaration = unwrapExport(statement)\n\n return declaration ? componentFunctionsIn(declaration) : []\n })\n}\n\nexport const maxComponentsPerFile: Rule.RuleModule = {\n meta: {\n type: 'suggestion',\n docs: {\n description:\n 'Limit the number of React components declared in a single file; move extra components into their own files.',\n recommended: true,\n url: 'https://github.com/ArthurSaenz/infra-kit/tree/main/apps/infra-kit/eslint-plugin#max-components-per-file',\n },\n schema: [\n {\n type: 'object',\n properties: {\n maxComponents: {\n type: 'integer',\n minimum: 1,\n description: 'Maximum number of component declarations a single file may contain before the rule reports.',\n },\n paths: {\n type: 'array',\n items: { type: 'string' },\n description:\n 'Optional glob patterns. When provided, the rule only runs for files whose path matches one of them.',\n },\n ignore: {\n type: 'array',\n items: { type: 'string' },\n description:\n 'Optional glob patterns. The rule is skipped for files whose path matches one of them, even if it also matches `paths`.',\n },\n },\n additionalProperties: false,\n },\n ],\n messages: {\n // File-scoped problem \u2192 reported once, anchored to the first component over\n // the limit so a human or AI fix loop has a concrete node to move out.\n tooManyComponents:\n 'This file declares {{count}} components (max {{max}}); move components such as {{name}} into separate files.',\n },\n },\n\n create(context) {\n const options = (context.options[0] ?? {}) as Options\n const max = options.maxComponents ?? DEFAULT_MAX_COMPONENTS\n const paths = options.paths ?? []\n const ignore = options.ignore ?? []\n\n // `ignore` takes precedence: skip excluded files even when they also match `paths`.\n if (ignore.length > 0 && matchesAnyGlob(context.filename, ignore)) {\n return {}\n }\n\n if (paths.length > 0 && !matchesAnyGlob(context.filename, paths)) {\n return {}\n }\n\n return {\n Program(program) {\n const components = collectComponents(program.body)\n\n if (components.length <= max) {\n return\n }\n\n // The first component beyond the limit: a real, moveable node, and the\n // single report keeps one file-scoped problem from emitting N squiggles\n // (there is no autofix to justify multiplicity). `length > max` guarantees\n // this index exists; the guard satisfies `noUncheckedIndexedAccess`.\n const offender = components[max]\n\n if (!offender) {\n return\n }\n\n const name = getComponentName(offender) ?? ANONYMOUS_NAME\n\n context.report({\n node: offender,\n messageId: 'tooManyComponents',\n data: { count: components.length, max, name },\n })\n },\n }\n },\n}\n", "import type { Rule } from 'eslint'\nimport type * as ESTree from 'estree'\n\ninterface Options {\n maxLines?: number\n maxExampleLines?: number\n exemptTags?: string[]\n}\n\n// Prose budget = total lines MINUS `@example` body lines. Simulated against the real rule\n// semantics over the linted corpus (6108 blocks across the source repo + its five sync\n// targets; evidence brief \u00A74c): 15 \u2192 125 reports / 113 unique / 2.12% of linted blocks \u2014\n// a normal lint-rule yield, roughly one sprint of cleanup. 20 \u2192 47 reports, too thin to\n// change behaviour; 12 \u2192 235, more than one sprint.\n// NOTE: the brief's \u00A72 figure (\"183 at cap 15\") measures raw BLOCK length, not this budget.\nconst DEFAULT_MAX_LINES = 15\n\n// `@example` body length across the 637 example-carrying blocks (brief \u00A74b):\n// p50=4, p90=9, p95=12, p99=23, max=35. 10 \u2248 p90 \u2192 48 reports / 28 unique (\u00A74c).\n// 20 would reach only 10 blocks corpus-wide \u2014 too loose to justify the rule's strongest half.\nconst DEFAULT_MAX_EXAMPLE_LINES = 10\n\n// Zero existing usages of any of these tags corpus-wide (\u00A74), so adopting them costs nothing.\n// This is the ONLY exemption mechanism: there is deliberately no positional fallback, because\n// position exempts by luck \u2014 the corpus's `stdin-ref.ts:3` is a 39-line file-level block whose\n// next statement is `let readers = 0`, so no \"precedes the first import\" spelling would reach it.\nconst DEFAULT_EXEMPT_TAGS = ['fileoverview', 'module', 'packageDocumentation']\n\n/** A JSDoc block: the house idiom, shared verbatim with `require-jsdoc-example`. */\nconst isJsdocBlock = (comment: ESTree.Comment): boolean => {\n return comment.type === 'Block' && comment.value.startsWith('*')\n}\n\n/**\n * The block's lines with the leading whitespace and `*` gutter removed, so tag\n * detection sees `@example` rather than ` * @example`. One entry per source line the\n * block occupies (`comment.value` keeps every newline between `/**` and the closer).\n */\nconst strippedLines = (comment: ESTree.Comment): string[] => {\n return comment.value.split('\\n').map((line) => {\n return line.replace(/^\\s*\\*+/, '').trim()\n })\n}\n\n/**\n * The JSDoc tag a stripped line opens (`@example \u2026` \u2192 `example`), or null for body/prose.\n *\n * Lower-cased on the way out: the match is case-insensitive, so every comparison against it\n * must be too. Without this, `@Example` parses as a tag but matches neither the example scan\n * nor `exemptTags` \u2014 the author gets a prose violation and a `@Fileoverview` escape hatch that\n * silently does not work.\n */\nconst tagNameOf = (line: string): string | null => {\n return line.match(/^@([A-Z][\\w-]*)/i)?.[1]?.toLowerCase() ?? null\n}\n\n// KNOWN PARSER HAZARD: any line opening with `@` ends the body, so a decorator (`@Injectable`)\n// written inside an `@example` truncates it early. The effect is worse than an under-count: the\n// truncated lines are recharged to PROSE, so the block reports `tooManyLines` and advises\n// `@fileoverview` \u2014 misleading advice for a block whose real problem is a long example. A scan of\n// all 637 example bodies in the corpus found ZERO lines starting with `@` that were not real tags,\n// so this is correct today \u2014 measured, not assumed, and not future-proof. A real JSDoc parser is\n// the fix if that ever stops holding.\n/**\n * Total lines occupied by the block's `@example` bodies.\n *\n * A scan enters example mode on an `@example` line (the tag line itself counts) and leaves\n * it at the next line opening any tag. An `@example` that is the block's last tag therefore\n * runs through the closing `*` + `/` line \u2014 which is how the corpus was measured, and what\n * makes `prose + example === total` exact. Bodies from multiple `@example` tags sum.\n */\nconst countExampleLines = (lines: string[]): number => {\n let inExample = false\n let count = 0\n\n for (const line of lines) {\n const tag = tagNameOf(line)\n\n if (tag) {\n inExample = tag === 'example'\n }\n\n if (inExample) {\n count += 1\n }\n }\n\n return count\n}\n\n/**\n * Whether the block declares any exempt tag \u2014 the rule's one and only escape hatch.\n *\n * `exemptTags` is normalised here rather than at the call site so a configured\n * `['FileOverview']` behaves the same as `['fileoverview']`; `tagNameOf` already lower-cases.\n */\nconst hasExemptTag = (lines: string[], exemptTags: string[]): boolean => {\n const normalized = exemptTags.map((tag) => {\n return tag.toLowerCase()\n })\n\n return lines.some((line) => {\n const tag = tagNameOf(line)\n\n return tag !== null && normalized.includes(tag)\n })\n}\n\nexport const maxJsdocLines: Rule.RuleModule = {\n meta: {\n type: 'suggestion',\n docs: {\n description:\n 'Cap the height of a JSDoc block, budgeting its prose and its `@example` bodies separately so a rule-mandated example never consumes the prose budget.',\n recommended: true,\n url: 'https://github.com/ArthurSaenz/infra-kit/tree/main/apps/infra-kit/eslint-plugin#max-jsdoc-lines',\n },\n // Deliberately NOT fixable. Any fixer would have to delete sentences, and the longest\n // blocks in the corpus are the most valuable documentation in it. The part of this\n // problem that IS mechanically fixable \u2014 blank-line padding and `{type}` annotations \u2014\n // is already handled upstream by `jsdoc/tag-lines` and `jsdoc/no-types`.\n schema: [\n {\n type: 'object',\n properties: {\n maxLines: {\n type: 'integer',\n minimum: 1,\n description:\n 'Maximum lines a JSDoc block may span, excluding its `@example` bodies, before the rule reports.',\n },\n maxExampleLines: {\n type: 'integer',\n minimum: 1,\n description:\n \"Maximum lines the block's `@example` bodies may span in total. Budgeted separately from `maxLines` so a rule-mandated example never consumes the prose budget.\",\n },\n exemptTags: {\n type: 'array',\n items: { type: 'string' },\n description:\n 'Tag names (without `@`) that exempt a block from every check. The only exemption mechanism; intended for module-level blocks whose length is the point.',\n },\n },\n additionalProperties: false,\n },\n ],\n messages: {\n // Names `@fileoverview` inline: with no positional exemption, this message is the only\n // thing standing between a long file-level rationale block and an author's delete key.\n tooManyLines:\n 'This JSDoc block spans {{lines}} lines of prose (max {{max}}; `@example` bodies are budgeted separately). Keep the contract \u2014 what it does and what a caller must know \u2014 and move rationale into a `//` note or the file-level block. If this IS module-level rationale, tag the block `@fileoverview` to exempt it.',\n exampleTooLong:\n 'The `@example` bodies in this JSDoc block span {{lines}} lines (max {{max}}). Show the smallest call that teaches usage; a full walkthrough belongs in a test or the readme.',\n },\n },\n\n create(context) {\n const options = (context.options[0] ?? {}) as Options\n const maxLines = options.maxLines ?? DEFAULT_MAX_LINES\n const maxExampleLines = options.maxExampleLines ?? DEFAULT_MAX_EXAMPLE_LINES\n const exemptTags = options.exemptTags ?? DEFAULT_EXEMPT_TAGS\n\n const { sourceCode } = context\n\n return {\n Program() {\n // EOF guard (NOT symbol attachment \u2014 this rule deliberately never resolves the symbol\n // a block documents): the start offset of the last token, so a trailing block with no\n // token after it can be skipped as degenerate input.\n const lastTokenStart = sourceCode.ast.tokens.at(-1)?.range[0] ?? -1\n\n // Comment-driven, not node-driven: every JSDoc-shaped block in the file is linted and\n // exemptions are explicit. A node-driven walk needs an anchor-type allowlist, which is\n // exactly how `jsdoc/match-description` ends up not covering `type`/`interface`. It also\n // avoids `SourceCode#getJSDocComment`, which ESLint 10 removed outright.\n for (const comment of sourceCode.getAllComments()) {\n if (!isJsdocBlock(comment) || !comment.loc || !comment.range) {\n continue\n }\n\n if (lastTokenStart <= comment.range[1]) {\n continue\n }\n\n const lines = strippedLines(comment)\n\n if (hasExemptTag(lines, exemptTags)) {\n continue\n }\n\n const totalLines = comment.loc.end.line - comment.loc.start.line + 1\n const exampleLines = countExampleLines(lines)\n const proseLines = totalLines - exampleLines\n\n // Two independent budgets: both can report on the same block.\n if (proseLines > maxLines) {\n context.report({\n loc: comment.loc,\n messageId: 'tooManyLines',\n data: { lines: proseLines, max: maxLines },\n })\n }\n\n if (exampleLines > maxExampleLines) {\n context.report({\n loc: comment.loc,\n messageId: 'exampleTooLong',\n data: { lines: exampleLines, max: maxExampleLines },\n })\n }\n }\n },\n }\n },\n}\n", "import type { Rule } from 'eslint'\nimport type * as ESTree from 'estree'\n\ninterface Options {\n maxSummaryLines?: number\n exemptTags?: string[]\n}\n\n// The user's stated requirement: a reader should grasp the essence of a comment in 3 to 5 lines.\n// 5 is the loose end of that range, so it is the default \u2014 the rule enforces the ceiling the user\n// named, not a tighter one invented here.\n//\n// Calibration: 51 of 2,171 JSDoc blocks in `apps/infra-kit/cli/src` exceed 5 summary lines (static\n// script, 2026-09-05, `docs/comment-review-skill-plan.md` \u00A79). That is 2.3% of linted blocks \u2014 the\n// same order as `max-jsdoc-lines`'s 2.12%, i.e. a normal lint-rule yield rather than a sweep.\nconst DEFAULT_MAX_SUMMARY_LINES = 5\n\n// COMPOSES WITH `max-jsdoc-lines`, does not overlap it: that rule caps the WHOLE block at 15 lines\n// (prose and `@example` bodies budgeted separately); this one caps only the FIRST PARAGRAPH at 5.\n// A block can satisfy either and fail the other \u2014 a 40-line block whose summary is two lines is a\n// well-shaped long block, and a 7-line block that is one unbroken paragraph is a badly-shaped short\n// one. Do not unify them: the second number is about whether a reader can skim, not about height.\n//\n// Same list as `max-jsdoc-lines` deliberately, so one `@fileoverview` tag exempts a module-level\n// block from both rules rather than requiring two different escape hatches.\nconst DEFAULT_EXEMPT_TAGS = ['fileoverview', 'module', 'packageDocumentation']\n\n/** A JSDoc block: the house idiom, shared verbatim with `max-jsdoc-lines`. */\nconst isJsdocBlock = (comment: ESTree.Comment): boolean => {\n return comment.type === 'Block' && comment.value.startsWith('*')\n}\n\n/**\n * The block's lines with the leading whitespace and `*` gutter removed, so a gutter-only line\n * reads as `''` and tag detection sees `@param` rather than ` * @param`. One entry per source\n * line the block occupies (`comment.value` keeps every newline between `/**` and the closer).\n */\nconst strippedLines = (comment: ESTree.Comment): string[] => {\n return comment.value.split('\\n').map((line) => {\n return line.replace(/^\\s*\\*+/, '').trim()\n })\n}\n\n/**\n * The JSDoc tag a stripped line opens (`@param \u2026` \u2192 `param`), or null for body/prose.\n *\n * Lower-cased on the way out so every comparison against it can be case-insensitive; without\n * this a `@Fileoverview` would parse as a tag but match neither the paragraph boundary check nor\n * `exemptTags`, giving the author an escape hatch that silently does not work.\n */\nconst tagNameOf = (line: string): string | null => {\n return line.match(/^@([A-Z][\\w-]*)/i)?.[1]?.toLowerCase() ?? null\n}\n\n/**\n * The height of the summary paragraph, in PROSE lines.\n *\n * The scan skips leading gutter-only lines (the `/**` opener strips to `''`, and so does a block\n * that opens with a blank gutter line), then counts prose until the first blank line or the first\n * line opening any tag, whichever comes first. A block with neither is one paragraph end to end,\n * so its whole prose body is the summary.\n *\n * Delimiter lines are NOT counted: the opener and the closing line carry no prose, and charging them\n * would make every block read two lines longer than what a reader actually reads. This is the one\n * place the count differs from `max-jsdoc-lines`, which measures visual height and so counts them.\n *\n * A block whose first non-empty line already opens a tag has a zero-line summary and can never\n * report \u2014 intentional, since `@param`-only blocks are a contract, not a description.\n */\nconst summaryLineCount = (lines: string[]): number => {\n let count = 0\n\n for (const line of lines) {\n const isBlank = line === ''\n\n if (tagNameOf(line) !== null || (isBlank && count > 0)) {\n break\n }\n\n if (!isBlank) {\n count += 1\n }\n }\n\n return count\n}\n\n/**\n * Whether the block declares any exempt tag \u2014 the rule's one and only escape hatch.\n *\n * `exemptTags` is normalised here rather than at the call site so a configured `['FileOverview']`\n * behaves the same as `['fileoverview']`; `tagNameOf` already lower-cases.\n */\nconst hasExemptTag = (lines: string[], exemptTags: string[]): boolean => {\n const normalized = exemptTags.map((tag) => {\n return tag.toLowerCase()\n })\n\n return lines.some((line) => {\n const tag = tagNameOf(line)\n\n return tag !== null && normalized.includes(tag)\n })\n}\n\nexport const maxJsdocSummaryLines: Rule.RuleModule = {\n meta: {\n type: 'suggestion',\n docs: {\n description:\n 'Cap the height of a JSDoc summary paragraph, so the first thing a reader sees is graspable at a glance and the detail sits below a blank line.',\n recommended: true,\n url: 'https://github.com/ArthurSaenz/infra-kit/tree/main/apps/infra-kit/eslint-plugin#max-jsdoc-summary-lines',\n },\n // Deliberately NOT fixable, for the same reason `max-jsdoc-lines` is not: the mechanical fix\n // (insert a blank line after line 5) splits a paragraph at an arbitrary point and produces a\n // summary that reads as truncated. Deciding what the first glance must contain is judgement.\n schema: [\n {\n type: 'object',\n properties: {\n maxSummaryLines: {\n type: 'integer',\n minimum: 1,\n description:\n 'Maximum prose lines the summary paragraph may span before the rule reports. The summary runs from the first prose line to the first blank line or first tag.',\n },\n exemptTags: {\n type: 'array',\n items: { type: 'string' },\n description:\n 'Tag names (without `@`) that exempt a block from the check. The only exemption mechanism; intended for module-level blocks whose length is the point.',\n },\n },\n additionalProperties: false,\n },\n ],\n messages: {\n // Names the offending count, the cap, and the escape hatch inline. No `suggest`: a suggestion\n // is host-UI-only and therefore invisible to the text-reading agents that are half this\n // rule's audience.\n summaryTooLong:\n 'This JSDoc summary paragraph runs {{lines}} lines (max {{max}}). Keep the first paragraph to what a reader needs in one glance, then a blank line, then the detail. If this IS module-level rationale, tag the block `@fileoverview` to exempt it.',\n },\n },\n\n create(context) {\n const options = (context.options[0] ?? {}) as Options\n const maxSummaryLines = options.maxSummaryLines ?? DEFAULT_MAX_SUMMARY_LINES\n const exemptTags = options.exemptTags ?? DEFAULT_EXEMPT_TAGS\n\n const { sourceCode } = context\n\n return {\n Program() {\n // EOF guard (NOT symbol attachment \u2014 this rule deliberately never resolves the symbol a\n // block documents): the start offset of the last token, so a trailing block with no token\n // after it is skipped as degenerate input. Mirrors `max-jsdoc-lines`.\n const lastTokenStart = sourceCode.ast.tokens.at(-1)?.range[0] ?? -1\n\n // Comment-driven, not node-driven: every JSDoc-shaped block in the file is linted and\n // exemptions are explicit. `//` line comments and plain `/* */` blocks are not JSDoc and\n // are never measured \u2014 `isJsdocBlock` is the whole filter.\n for (const comment of sourceCode.getAllComments()) {\n if (!isJsdocBlock(comment) || !comment.loc || !comment.range) {\n continue\n }\n\n if (lastTokenStart <= comment.range[1]) {\n continue\n }\n\n const lines = strippedLines(comment)\n\n if (hasExemptTag(lines, exemptTags)) {\n continue\n }\n\n const summaryLines = summaryLineCount(lines)\n\n if (summaryLines > maxSummaryLines) {\n context.report({\n loc: comment.loc,\n messageId: 'summaryTooLong',\n data: { lines: summaryLines, max: maxSummaryLines },\n })\n }\n }\n },\n }\n },\n}\n", "import type { Rule, SourceCode } from 'eslint'\nimport type * as ESTree from 'estree'\n\nimport {\n collectOwnReturnArguments,\n getComponentFunction,\n getComponentName,\n isComponent,\n unwrapExport,\n} from '../../utils/component'\nimport type { ComponentFunction } from '../../utils/component'\nimport { matchesAnyGlob } from '../../utils/path-match'\n\ninterface Options {\n maxElements?: number\n paths?: string[]\n ignore?: string[]\n}\n\n// Default ceiling on JSX elements rendered by a single return. Tunable via the\n// `maxElements` option; the value is a starting estimate, not a hard truth.\nconst DEFAULT_MAX_ELEMENTS = 20\n\n// Fallback used when a component is anonymous (e.g. `export default () => <div />`),\n// since `getComponentName` returns null rather than a placeholder in that case.\nconst ANONYMOUS_NAME = 'component'\n\ntype VisitorKeys = SourceCode.VisitorKeys\n\nconst isNode = (value: unknown): value is ESTree.Node => {\n return typeof value === 'object' && value !== null && typeof (value as { type?: unknown }).type === 'string'\n}\n\n// estree does not model JSX, so child traversal is driven by the parser-provided\n// `visitorKeys` (real child keys only \u2014 excludes `parent`/`loc`/`range`), falling\n// back to `Object.keys`; `parent` is skipped explicitly to guard recursion.\nconst childNodes = (node: ESTree.Node, visitorKeys: VisitorKeys): ESTree.Node[] => {\n const children: ESTree.Node[] = []\n const keys = visitorKeys[node.type as string] ?? Object.keys(node)\n\n for (const key of keys) {\n if (key === 'parent') {\n continue\n }\n\n const value = (node as unknown as Record<string, unknown>)[key]\n\n if (Array.isArray(value)) {\n children.push(...value.filter(isNode))\n } else if (isNode(value)) {\n children.push(value)\n }\n }\n\n return children\n}\n\n/**\n * Count the `JSXElement` nodes in an expression subtree. `JSXElement` counts 1;\n * `JSXFragment` counts 0 (a no-op wrapper) but still recurses. The walk descends\n * into nested function scopes, so inline-callback JSX (`.map(() => <li/>)`) is\n * counted once within its enclosing return \u2014 the counterpart to\n * `collectOwnReturnArguments`, which skips those scopes.\n */\nconst countJsxElements = (node: ESTree.Node, visitorKeys: VisitorKeys): number => {\n const self = (node.type as string) === 'JSXElement' ? 1 : 0\n\n return childNodes(node, visitorKeys).reduce((total, child) => {\n return total + countJsxElements(child, visitorKeys)\n }, self)\n}\n\n// Structural views over JSX nodes estree does not type. A JSX element's tag name\n// is on `openingElement.name`, which is an identifier (`name` is a string), a\n// member expression (`Foo.Bar`), or a namespaced name (`svg:rect`) \u2014 so the\n// child slots are read as `unknown` and narrowed per node type.\ninterface JsxNameNode {\n type?: string\n name?: unknown\n object?: unknown\n property?: unknown\n namespace?: unknown\n}\n\ninterface JsxElementNode {\n openingElement?: { name?: unknown }\n loc?: { start: { line: number } }\n}\n\nconst jsxNameToString = (node: unknown): string => {\n const name = node as JsxNameNode | null | undefined\n\n switch (name?.type) {\n case 'JSXIdentifier':\n return typeof name.name === 'string' ? name.name : 'element'\n case 'JSXMemberExpression':\n return `${jsxNameToString(name.object)}.${jsxNameToString(name.property)}`\n case 'JSXNamespacedName':\n return `${jsxNameToString(name.namespace)}:${jsxNameToString(name.name)}`\n default:\n return 'element'\n }\n}\n\n// The JSXElements directly under `root` (descending only through non-element\n// wrappers like fragments, expression containers, conditionals, and `.map`\n// callbacks). A parent always out-counts its children, so the largest of these\n// is the single biggest block a reader could lift out of the return.\nconst topLevelElements = (root: ESTree.Node, visitorKeys: VisitorKeys): ESTree.Node[] => {\n const elements: ESTree.Node[] = []\n\n const walk = (node: ESTree.Node, isRoot: boolean): void => {\n if (!isRoot && (node.type as string) === 'JSXElement') {\n elements.push(node)\n\n return\n }\n\n for (const child of childNodes(node, visitorKeys)) {\n walk(child, false)\n }\n }\n\n walk(root, true)\n\n return elements\n}\n\ninterface LargestBlock {\n name: string\n line: number\n count: number\n}\n\n/** The biggest extractable JSX block inside a return, for an actionable message. */\nconst largestBlock = (root: ESTree.Node, visitorKeys: VisitorKeys): LargestBlock | null => {\n let best: { node: ESTree.Node; count: number } | null = null\n\n for (const element of topLevelElements(root, visitorKeys)) {\n const count = countJsxElements(element, visitorKeys)\n\n if (!best || count > best.count) {\n best = { node: element, count }\n }\n }\n\n if (!best) {\n return null\n }\n\n const element = best.node as unknown as JsxElementNode\n\n return { name: jsxNameToString(element.openingElement?.name), line: element.loc?.start.line ?? 0, count: best.count }\n}\n\n/** The component function(s) declared by a single top-level declaration. */\nconst componentFunctionsIn = (declaration: ESTree.Node): ComponentFunction[] => {\n if (declaration.type === 'FunctionDeclaration') {\n return isComponent(declaration) ? [declaration] : []\n }\n\n if (declaration.type === 'VariableDeclaration') {\n return declaration.declarations\n .map((declarator) => {\n return getComponentFunction(declarator.init)\n })\n .filter((fn): fn is ComponentFunction => {\n return fn !== null && isComponent(fn)\n })\n }\n\n // e.g. `export default memo(() => \u2026)`.\n const fn = getComponentFunction(declaration)\n\n return fn && isComponent(fn) ? [fn] : []\n}\n\n/**\n * Every component declared at the TOP LEVEL of the program body (mirrors\n * `component-arrow-function`). Anonymous inline callbacks are never collected, so\n * a single oversized return can never be reported twice.\n */\nconst collectComponents = (body: Array<ESTree.Statement | ESTree.ModuleDeclaration>): ComponentFunction[] => {\n return body.flatMap((statement) => {\n const declaration = unwrapExport(statement)\n\n return declaration ? componentFunctionsIn(declaration) : []\n })\n}\n\nexport const maxJsxReturnSize: Rule.RuleModule = {\n meta: {\n type: 'suggestion',\n docs: {\n description:\n 'Warn when a component return renders too many JSX elements; extract parts into variables or sub-components.',\n recommended: true,\n url: 'https://github.com/ArthurSaenz/infra-kit/tree/main/apps/infra-kit/eslint-plugin#max-jsx-return-size',\n },\n schema: [\n {\n type: 'object',\n properties: {\n maxElements: {\n type: 'integer',\n minimum: 1,\n description: 'Maximum number of JSX elements a single return may render before the rule reports.',\n },\n paths: {\n type: 'array',\n items: { type: 'string' },\n description:\n 'Optional glob patterns. When provided, the rule only runs for files whose path matches one of them.',\n },\n ignore: {\n type: 'array',\n items: { type: 'string' },\n description:\n 'Optional glob patterns. The rule is skipped for files whose path matches one of them, even if it also matches `paths`.',\n },\n },\n additionalProperties: false,\n },\n ],\n messages: {\n // Points at the single biggest block so a human or AI fix loop knows\n // exactly what to lift out.\n tooManyElements:\n '{{name}} renders {{count}} JSX elements in one return (max {{max}}). Extract the largest block \u2014 <{{largest}}> at line {{line}} ({{largestCount}} elements) \u2014 into a variable or a sub-component.',\n // Fallback when no single block dominates (e.g. many flat siblings): there is\n // nothing meaningful to point at, so advise splitting.\n tooManyElementsFlat:\n '{{name}} renders {{count}} JSX elements in one return (max {{max}}). Split it into smaller sub-components or extract groups of elements into variables.',\n },\n },\n\n create(context) {\n const options = (context.options[0] ?? {}) as Options\n const max = options.maxElements ?? DEFAULT_MAX_ELEMENTS\n const paths = options.paths ?? []\n const ignore = options.ignore ?? []\n\n // `ignore` takes precedence: skip excluded files even when they also match `paths`.\n if (ignore.length > 0 && matchesAnyGlob(context.filename, ignore)) {\n return {}\n }\n\n if (paths.length > 0 && !matchesAnyGlob(context.filename, paths)) {\n return {}\n }\n\n const visitorKeys = context.sourceCode.visitorKeys\n\n // Measure one declared component: count each of its own return arguments\n // (nested scopes skipped by `collectOwnReturnArguments`; arrow implicit body\n // included) and report once per return that exceeds `max`.\n const checkComponent = (fn: ComponentFunction): void => {\n const name = getComponentName(fn) ?? ANONYMOUS_NAME\n\n for (const argument of collectOwnReturnArguments(fn)) {\n const count = countJsxElements(argument, visitorKeys)\n\n if (count <= max) {\n continue\n }\n\n const largest = largestBlock(argument, visitorKeys)\n\n if (largest && largest.count >= 2) {\n context.report({\n node: argument,\n messageId: 'tooManyElements',\n data: { count, max, name, largest: largest.name, line: largest.line, largestCount: largest.count },\n })\n } else {\n context.report({ node: argument, messageId: 'tooManyElementsFlat', data: { count, max, name } })\n }\n }\n }\n\n return {\n Program(program) {\n for (const component of collectComponents(program.body)) {\n checkComponent(component)\n }\n },\n }\n },\n}\n", "import type { Rule } from 'eslint'\n\nimport {\n DEFAULT_ROOT_ALIAS,\n IMPORT_SELECTORS,\n featureNameOf,\n fileDirsUnderSrc,\n isFeaturePublicApi,\n isLayeredFile,\n readImportSource,\n resolveUnderSrc,\n srcDirOf,\n} from '../../utils/import-target'\n\nexport interface Options {\n /** The alias that maps to the package's `src/`. */\n rootAlias?: string\n /** Globs; the rule is skipped for matching files. */\n ignore?: string[]\n}\n\n// Tests and stories exercise the feature from outside, so its public API is the right entry for them.\nconst CONSUMER_DIRS = new Set(['__tests__', '__stories__'])\n\nexport const noFeatureSelfImport: Rule.RuleModule = {\n meta: {\n type: 'problem',\n docs: {\n description:\n 'Forbid a feature from importing itself through its own public API, which closes an import cycle through `index.ts`.',\n recommended: true,\n url: 'https://github.com/ArthurSaenz/infra-kit/tree/main/apps/infra-kit/eslint-plugin#no-feature-self-import',\n },\n schema: [\n {\n type: 'object',\n properties: {\n rootAlias: { type: 'string', description: 'The alias that maps to `src/` (default `#root`).' },\n ignore: {\n type: 'array',\n items: { type: 'string' },\n description: 'Optional globs; the rule is skipped for matching files.',\n },\n },\n additionalProperties: false,\n },\n ],\n messages: {\n selfImport:\n '`{{specifier}}` imports feature `{{feature}}` through its own public API from inside it, which makes an import cycle via `index.ts`. Import the module that defines it with a relative path instead.',\n selfTypeImport:\n '`{{specifier}}` reads types of feature `{{feature}}` through its own public API from inside it. Import them from the module that defines them with a relative path; the public API is for code outside the feature.',\n },\n },\n\n create(context) {\n const options = (context.options[0] ?? {}) as Options\n const filename = context.filename.split('\\\\').join('/')\n const srcDir = srcDirOf(filename)\n\n if (srcDir === null || !isLayeredFile(filename, options.ignore ?? [])) {\n return {}\n }\n\n const dirs = fileDirsUnderSrc(filename, srcDir)\n const ownFeature = featureNameOf(dirs)\n\n const isConsumer = dirs.some((dir) => {\n return CONSUMER_DIRS.has(dir)\n })\n\n if (ownFeature === null || isConsumer) {\n return {}\n }\n\n const rootAlias = options.rootAlias ?? DEFAULT_ROOT_ALIAS\n\n const check = (node: Rule.Node): void => {\n const source = readImportSource(node)\n const target = source === null ? null : resolveUnderSrc(filename, srcDir, source.specifier, rootAlias)\n\n if (source === null || target === null || featureNameOf(target) !== ownFeature || !isFeaturePublicApi(target)) {\n return\n }\n\n context.report({\n node: source.node,\n // A type-only import is erased at build time, so it closes no runtime cycle.\n messageId: source.typeOnly ? 'selfTypeImport' : 'selfImport',\n data: { specifier: source.specifier, feature: ownFeature },\n })\n }\n\n return Object.fromEntries(\n IMPORT_SELECTORS.map((selector) => {\n return [selector, check]\n }),\n )\n },\n}\n", "import type { Rule } from 'eslint'\nimport type * as ESTree from 'estree'\n\nimport { isUiPackageFile } from '../../utils/component-file-scope'\nimport { matchesAnyGlob } from '../../utils/path-match'\n\ninterface Options {\n paths?: string[]\n ignore?: string[]\n}\n\n// A leading `/` rather than `**/`: path-match's `**/` also matches a bare suffix, so `**/services.ts`\n// would catch `lib/use-services.ts`, the very place a hook belongs.\nexport const DEFAULT_PATHS = [\n '/services/',\n '/services.ts',\n '/services.tsx',\n '/service.ts',\n '/service.tsx',\n '/entities/**/model.ts',\n '/entities/**/model.tsx',\n]\n\nconst HOOK_NAME = /^use[A-Z0-9]/\nconst TEST_OR_STORY_DIR = /\\/__(?:tests|stories)__\\//\nconst TEST_OR_STORY_FILE = /\\.(?:test|spec|stories)\\.[cm]?[jt]sx?$/\n\nexport const noHooksInServices: Rule.RuleModule = {\n meta: {\n type: 'problem',\n docs: {\n description:\n 'Disallow declaring React hooks in services and entity models: they hold atoms and pure functions, the hook belongs in a container or `lib/`.',\n recommended: true,\n url: 'https://github.com/ArthurSaenz/infra-kit/tree/main/apps/infra-kit/eslint-plugin#no-hooks-in-services',\n },\n schema: [\n {\n type: 'object',\n properties: {\n paths: {\n type: 'array',\n items: { type: 'string' },\n description: `Glob patterns of service files; replaces the default (${DEFAULT_PATHS.join(', ')}).`,\n },\n ignore: {\n type: 'array',\n items: { type: 'string' },\n description:\n 'Optional glob patterns. The rule is skipped for files whose path matches one of them, even if it also matches `paths`.',\n },\n },\n additionalProperties: false,\n },\n ],\n messages: {\n hookInService:\n '\"{{name}}\" is a hook, and services hold only atoms and pure functions. Move it to a container or to `lib/`.',\n },\n },\n\n create(context) {\n const options = (context.options[0] ?? {}) as Options\n const filename = context.filename.split('\\\\').join('/')\n const ignore = options.ignore ?? []\n\n if (ignore.length > 0 && matchesAnyGlob(filename, ignore)) {\n return {}\n }\n\n if (\n !matchesAnyGlob(filename, options.paths ?? DEFAULT_PATHS) ||\n TEST_OR_STORY_DIR.test(filename) ||\n TEST_OR_STORY_FILE.test(filename) ||\n // Backend packages have `src/services/` too, where `use*` means something else.\n !isUiPackageFile(filename)\n ) {\n return {}\n }\n\n const report = (id: ESTree.Identifier): void => {\n if (HOOK_NAME.test(id.name)) {\n context.report({ node: id, messageId: 'hookInService', data: { name: id.name } })\n }\n }\n\n return {\n FunctionDeclaration(node) {\n if (node.id) {\n report(node.id)\n }\n },\n VariableDeclarator(node) {\n if (\n node.id.type === 'Identifier' &&\n (node.init?.type === 'ArrowFunctionExpression' || node.init?.type === 'FunctionExpression')\n ) {\n report(node.id)\n }\n },\n }\n },\n}\n", "import type { Rule } from 'eslint'\n\nimport { dirsUnderSrc, findPackageRoot } from '../../utils/package-root'\nimport { resolvePackageType } from '../../utils/package-type-reader'\nimport { matchesAnyGlob } from '../../utils/path-match'\n\n// Declared locally rather than imported: this type reaches the plugin's public `dist/index.d.ts`,\n// and a `@slip-stream-kit/config` specifier there would make every consumer's tsc resolve a package\n// the plugin does not ship. A unit test binds the members to the config package's PACKAGE_TYPES.\nexport const PACKAGE_TYPE_VALUES = ['frontend', 'backend', 'lib', 'e2e', 'mobile'] as const\n\nexport type PackageType = (typeof PACKAGE_TYPE_VALUES)[number]\n\nexport interface LayerEntry {\n /** First-level directories allowed under `src/`. */\n layers: string[]\n /**\n * Allowed directories one level further down, keyed by where they sit: `features/*` means \"inside\n * every folder of `features/`\" (each folder is a unit of any name), `services` means \"directly\n * inside `services/`\". A layer without a key is not inspected below its first level.\n */\n segments?: Record<string, string[]>\n /** Skill or doc that owns this layout, appended to the message. `''` or absent \u2192 no \"See \u2026\" sentence. */\n skill?: string\n}\n\nexport interface Options extends Partial<Record<PackageType, LayerEntry>> {\n /** Globs; the rule is skipped for matching files. */\n ignore?: string[]\n}\n\n/**\n * Built-in entries per package type. A present option key replaces the whole entry (layers,\n * segments AND skill) \u2014 the same absent\u2192default / set\u2192replace semantics as every other option in\n * the plugin. `mobile` and `lib` have no entry until their layouts settle, so they are silent.\n */\nexport const DEFAULT_ENTRIES: Partial<Record<PackageType, LayerEntry>> = {\n frontend: {\n // `__tests__` holds the tests of files that sit directly in `src/` (see `test-location`).\n layers: ['app', 'features', 'lib', 'components', 'pages', 'routes', '__tests__'],\n segments: {\n 'features/*': ['containers', 'components', 'services', '__stories__', '__tests__'],\n },\n skill: '/infra-kit:fe-architect',\n },\n backend: {\n layers: ['controllers', 'services', 'lib', 'config', '__tests__'],\n segments: {\n 'services/*': ['__tests__'],\n },\n // The skill does not exist yet; the user adds `plugins/infra-kit/skills/be-architect/SKILL.md`\n // and accepted the dangling pointer until then.\n skill: '/infra-kit:be-architect',\n },\n e2e: {\n layers: ['tests', 'visual', 'setup', 'pages', 'config', 'lib', 'components', 'mocks', 'fixtures'],\n // A domain folder's root holds only specs; its support files always sit in one of these.\n segments: {\n 'tests/*': ['pages', 'fixtures', 'mocks', 'data', 'lib'],\n 'visual/*': ['pages', 'fixtures', 'mocks', 'data', 'lib'],\n },\n skill: '/infra-kit:e2e-architect',\n },\n}\n\nexport const resolveEntry = (type: PackageType, options: Options): LayerEntry | undefined => {\n return options[type] ?? DEFAULT_ENTRIES[type]\n}\n\nconst UNIT_KEY_SUFFIX = '/*'\n\n/**\n * A `segments` key that names a layer outside `layers` can never match a file, so it is a typo in\n * the consumer's config rather than a policy \u2014 surfaced as a config error, not silently ignored.\n */\nconst assertSegmentKeysNameLayers = (type: PackageType, entry: LayerEntry): void => {\n for (const key of Object.keys(entry.segments ?? {})) {\n const layer = key.endsWith(UNIT_KEY_SUFFIX) ? key.slice(0, -UNIT_KEY_SUFFIX.length) : key\n\n if (!entry.layers.includes(layer)) {\n throw new Error(\n `@wl/package-structure: \\`${type}.segments\\` key \"${key}\" names a layer that is not in \\`${type}.layers\\` (${entry.layers.join(', ')}).`,\n )\n }\n }\n}\n\nconst LAYER_ENTRY_SCHEMA = {\n type: 'object',\n properties: {\n layers: {\n type: 'array',\n items: { type: 'string', minLength: 1 },\n uniqueItems: true,\n description: 'First-level directories allowed under `src/`.',\n },\n segments: {\n type: 'object',\n propertyNames: { pattern: '^[^/]+(/\\\\*)?$' },\n additionalProperties: {\n type: 'array',\n items: { type: 'string', minLength: 1 },\n uniqueItems: true,\n },\n description:\n 'Allowed directories one level down, keyed by `<layer>` (directly inside it) or `<layer>/*` (inside each of its folders).',\n },\n skill: {\n type: 'string',\n description: 'Skill or doc that owns this layout, appended to the message; `\"\"` drops the sentence.',\n },\n },\n required: ['layers'],\n additionalProperties: false,\n} as const\n\ninterface Violation {\n messageId: 'unknownLayer' | 'unknownSegment'\n /** The offending directory name. */\n name: string\n /** Where it sits, as the message names it: the layer, or `features/<unit>`. */\n scope: string\n allowed: string[]\n}\n\n/**\n * The directory `dirs[1]` or `dirs[2]` that `entry.segments` forbids, or null. Files directly inside\n * a layer or a unit (`features/<unit>/index.ts`) are not a segment and are never reported.\n */\nconst findSegmentViolation = (dirs: string[], entry: LayerEntry): Violation | null => {\n const [layer, second, third] = dirs\n const segments = entry.segments ?? {}\n const perUnit = segments[`${layer}${UNIT_KEY_SUFFIX}`]\n\n if (perUnit !== undefined) {\n return second !== undefined && third !== undefined && !perUnit.includes(third)\n ? { messageId: 'unknownSegment', name: third, scope: `${layer}/${second}`, allowed: perUnit }\n : null\n }\n\n const direct = segments[layer!]\n\n if (direct !== undefined && second !== undefined && !direct.includes(second)) {\n return { messageId: 'unknownSegment', name: second, scope: layer!, allowed: direct }\n }\n\n return null\n}\n\nconst findViolation = (dirs: string[], entry: LayerEntry): Violation | null => {\n const layer = dirs[0]!\n\n if (!entry.layers.includes(layer)) {\n return { messageId: 'unknownLayer', name: layer, scope: 'src', allowed: entry.layers }\n }\n\n return findSegmentViolation(dirs, entry)\n}\n\n/** The violation `filename` commits under its package's entry, or null when exempt or allowed. */\nconst inspect = (\n filename: string,\n options: Options,\n): { violation: Violation; type: PackageType; entry: LayerEntry } | null => {\n const packageRoot = findPackageRoot(filename)\n\n if (packageRoot === null) {\n return null\n }\n\n const dirs = dirsUnderSrc(packageRoot, filename)\n\n if (dirs === null || dirs.length === 0) {\n return null\n }\n\n const type = resolvePackageType(packageRoot)\n const entry = resolveEntry(type, options)\n\n if (entry === undefined) {\n return null\n }\n\n assertSegmentKeysNameLayers(type, entry)\n\n const violation = findViolation(dirs, entry)\n\n return violation === null ? null : { violation, type, entry }\n}\n\nexport const packageStructure: Rule.RuleModule = {\n meta: {\n type: 'problem',\n docs: {\n description: 'Allow only the `src/` layers, and the segments inside them, that belong to the package type.',\n recommended: true,\n url: 'https://github.com/ArthurSaenz/infra-kit/tree/main/apps/infra-kit/eslint-plugin#package-structure',\n },\n schema: [\n {\n type: 'object',\n properties: {\n frontend: LAYER_ENTRY_SCHEMA,\n backend: LAYER_ENTRY_SCHEMA,\n lib: LAYER_ENTRY_SCHEMA,\n e2e: LAYER_ENTRY_SCHEMA,\n mobile: LAYER_ENTRY_SCHEMA,\n ignore: {\n type: 'array',\n items: { type: 'string' },\n description: 'Optional globs; the rule is skipped for matching files.',\n },\n },\n additionalProperties: false,\n },\n ],\n messages: {\n unknownLayer:\n '`{{name}}` is not an allowed `src/` layer for package type `{{type}}` (allowed: {{allowed}}).{{seeSkill}}',\n unknownSegment:\n '`{{name}}` is not an allowed segment of `{{scope}}` for package type `{{type}}` (allowed: {{allowed}}).{{seeSkill}}',\n },\n },\n\n create(context) {\n const options = (context.options[0] ?? {}) as Options\n const ignore = options.ignore ?? []\n\n if (ignore.length > 0 && matchesAnyGlob(context.filename, ignore)) {\n return {}\n }\n\n const found = inspect(context.filename, options)\n\n if (found === null) {\n return {}\n }\n\n const { violation, type, entry } = found\n\n return {\n // Reported on Program so the IDE marks the file from line 1: every file under the offending\n // directory carries the same message, which is how a \"red folder\" surfaces in the explorer.\n Program(program) {\n context.report({\n node: program,\n messageId: violation.messageId,\n data: {\n name: violation.name,\n scope: violation.scope,\n type,\n allowed: violation.allowed.join(', '),\n // Message templates have no conditionals, so the optional sentence is assembled here.\n seeSkill: entry.skill ? ` See ${entry.skill} for the ${type} layout.` : '',\n },\n })\n },\n }\n },\n}\n", "import type { Rule } from 'eslint'\nimport type * as ESTree from 'estree'\n\nimport type { ComponentFunction } from '../../utils/component'\nimport { isComponent } from '../../utils/component'\n\n/** Whether a statement is `const { ... } = props` (destructuring the `props` identifier). */\nconst isPropsDestructuring = (statement: ESTree.Statement): boolean => {\n if (statement.type !== 'VariableDeclaration') {\n return false\n }\n\n return statement.declarations.some((declaration) => {\n return (\n declaration.id.type === 'ObjectPattern' &&\n declaration.init?.type === 'Identifier' &&\n declaration.init.name === 'props'\n )\n })\n}\n\nexport const propsDestructuringBlankLine: Rule.RuleModule = {\n meta: {\n type: 'suggestion',\n docs: {\n description:\n 'Require a blank line after the `const { ... } = props` destructuring statement at the top of a React component body.',\n recommended: true,\n url: 'https://github.com/ArthurSaenz/infra-kit/tree/main/apps/infra-kit/eslint-plugin#props-destructuring-blank-line',\n },\n fixable: 'whitespace',\n schema: [],\n messages: {\n blankLineAfterProps: 'Add a blank line after destructuring props.',\n },\n },\n\n create(context) {\n const sourceCode = context.sourceCode\n\n const check = (node: ComponentFunction): void => {\n if (node.body.type !== 'BlockStatement') {\n return\n }\n\n if (!isComponent(node)) {\n return\n }\n\n const statements = node.body.body\n const index = statements.findIndex(isPropsDestructuring)\n\n if (index === -1) {\n return\n }\n\n const propsStatement = statements[index]\n const nextStatement = statements[index + 1]\n\n // `propsStatement` is defined because `index !== -1`; the guard also narrows the type.\n // Nothing follows the destructuring \u2014 no separation needed.\n if (!propsStatement || !nextStatement) {\n return\n }\n\n // The token/comment that follows the destructuring statement; a comment on the\n // next line still counts as \"no blank line\" until it is pushed down.\n const tokenAfter = sourceCode.getTokenAfter(propsStatement, { includeComments: true })\n const referenceLine = (tokenAfter ?? nextStatement).loc!.start.line\n\n if (referenceLine - propsStatement.loc!.end.line >= 2) {\n return\n }\n\n context.report({\n node: propsStatement,\n messageId: 'blankLineAfterProps',\n fix(fixer) {\n return fixer.insertTextAfter(propsStatement, '\\n')\n },\n })\n }\n\n return {\n ArrowFunctionExpression: check,\n FunctionDeclaration: check,\n FunctionExpression: check,\n }\n },\n}\n", "import type { Rule } from 'eslint'\nimport type * as ESTree from 'estree'\n\nimport type { ComponentFunction } from '../../utils/component'\nimport { isComponent } from '../../utils/component'\n\n// Minimal structural views over nodes that estree's types do not fully model:\n// the optional TS type annotation and `range` that the parser attaches to params.\ninterface WithRange {\n range?: [number, number]\n}\ntype AnnotatedPattern = ESTree.ObjectPattern & { typeAnnotation?: ESTree.Node & WithRange } & WithRange\n\n// Recursively collect every identifier a destructuring pattern binds, so we can detect\n// whether it already introduces a `props` binding (e.g. a `...props` rest).\nconst collectBoundNames = (node: ESTree.Node | null, names: Set<string>): void => {\n if (!node) {\n return\n }\n\n switch (node.type) {\n case 'Identifier':\n names.add(node.name)\n break\n case 'ObjectPattern':\n for (const property of node.properties) collectBoundNames(property, names)\n break\n case 'ArrayPattern':\n for (const element of node.elements) collectBoundNames(element, names)\n break\n case 'Property':\n collectBoundNames(node.value, names)\n break\n case 'RestElement':\n collectBoundNames(node.argument, names)\n break\n case 'AssignmentPattern':\n collectBoundNames(node.left, names)\n break\n default:\n break\n }\n}\n\nexport const propsDestructuringNewline: Rule.RuleModule = {\n meta: {\n type: 'suggestion',\n docs: {\n description:\n 'Require React components to accept a single props parameter and destructure it on its own line in the body, rather than destructuring inline in the parameter list.',\n recommended: true,\n url: 'https://github.com/ArthurSaenz/infra-kit/tree/main/apps/infra-kit/eslint-plugin#props-destructuring-newline',\n },\n fixable: 'code',\n schema: [],\n messages: {\n destructureOnNewLine:\n 'Accept a single `props` parameter and destructure it on its own line in the component body instead of destructuring in the parameter list.',\n },\n },\n\n create(context) {\n const sourceCode = context.sourceCode\n\n const check = (node: ComponentFunction): void => {\n const firstParam = node.params[0]\n\n if (!firstParam || firstParam.type !== 'ObjectPattern') {\n return\n }\n\n if (!isComponent(node)) {\n return\n }\n\n // The fix renames the parameter to `props` and re-destructures it in the body\n // (`const <pattern> = props`). If the pattern already binds `props` (e.g. a\n // `...props` rest, a `{ props }` shorthand, or a `{ data: props }` rename), that\n // body binding collides with the new parameter and yields an invalid \"Duplicate\n // declaration props\". No safe rename keeps the `props` name the rule mandates \u2014\n // and an ESLint fixer cannot scope-rename the downstream `props.*` usages a rename\n // would require \u2014 so these patterns are still reported (the inline destructuring is\n // a violation regardless) but WITHOUT an autofix; the developer resolves them by hand.\n const boundNames = new Set<string>()\n\n collectBoundNames(firstParam, boundNames)\n\n const bindsProps = boundNames.has('props')\n\n const objectPattern = firstParam as AnnotatedPattern\n\n context.report({\n node: firstParam,\n messageId: 'destructureOnNewLine',\n fix: bindsProps\n ? undefined\n : (fixer) => {\n const text = sourceCode.getText()\n const annotation = objectPattern.typeAnnotation\n\n const patternStart = objectPattern.range![0]\n const patternEnd = annotation ? annotation.range![0] : objectPattern.range![1]\n const fullEnd = annotation ? annotation.range![1] : objectPattern.range![1]\n\n const patternText = text.slice(patternStart, patternEnd).trim()\n const annotationText = annotation ? sourceCode.getText(annotation) : ''\n\n const fixes = [fixer.replaceTextRange([patternStart, fullEnd], `props${annotationText}`)]\n\n const destructureStatement = `const ${patternText} = props`\n\n // Indentation of the line the component is declared on, used as the base for inserted code.\n const lines = sourceCode.getLines()\n const declarationLine = lines[node.loc!.start.line - 1] ?? ''\n const baseIndent = declarationLine.slice(0, declarationLine.length - declarationLine.trimStart().length)\n const innerIndent = `${baseIndent} `\n\n if (node.body.type === 'BlockStatement') {\n const [firstStatement] = node.body.body\n\n if (firstStatement) {\n const indent = ' '.repeat(firstStatement.loc!.start.column)\n\n fixes.push(fixer.insertTextBefore(firstStatement, `${destructureStatement}\\n\\n${indent}`))\n } else {\n const openBrace = sourceCode.getFirstToken(node.body)!\n\n fixes.push(fixer.insertTextAfter(openBrace, `\\n${innerIndent}${destructureStatement}\\n${baseIndent}`))\n }\n\n return fixes\n }\n\n // Expression-bodied arrow (implicit return) \u2014 wrap it in a block.\n const bodyText = sourceCode.getText(node.body)\n\n fixes.push(\n fixer.replaceText(\n node.body,\n `{\\n${innerIndent}${destructureStatement}\\n\\n${innerIndent}return ${bodyText}\\n${baseIndent}}`,\n ),\n )\n\n return fixes\n },\n })\n }\n\n return {\n ArrowFunctionExpression: check,\n FunctionDeclaration: check,\n FunctionExpression: check,\n }\n },\n}\n", "import type { Rule } from 'eslint'\n\nimport type { ComponentFunction } from '../../utils/component'\nimport { getAnnotatedParam, getComponentName, getPropsTypeNameFromFunction, isComponent } from '../../utils/component'\nimport { matchesAnyGlob } from '../../utils/path-match'\n\ninterface Options {\n paths?: string[]\n ignore?: string[]\n}\n\nconst PROPS_SUFFIX = 'Props'\n\nexport const propsTypeName: Rule.RuleModule = {\n meta: {\n type: 'suggestion',\n docs: {\n description:\n \"Require a React component's props type to be named `<ComponentName>Props` (e.g. `ButtonProps` for `Button`).\",\n recommended: true,\n url: 'https://github.com/ArthurSaenz/infra-kit/tree/main/apps/infra-kit/eslint-plugin#props-type-name',\n },\n schema: [\n {\n type: 'object',\n properties: {\n paths: {\n type: 'array',\n items: { type: 'string' },\n description:\n 'Optional glob patterns. When provided, the rule only runs for files whose path matches one of them.',\n },\n ignore: {\n type: 'array',\n items: { type: 'string' },\n description:\n 'Optional glob patterns. The rule is skipped for files whose path matches one of them, even if it also matches `paths`.',\n },\n },\n additionalProperties: false,\n },\n ],\n messages: {\n propsTypeNameMismatch: \"A component's props type must be named `{{expected}}`, but it is named `{{actual}}`.\",\n },\n },\n\n create(context) {\n const options = (context.options[0] ?? {}) as Options\n const paths = options.paths ?? []\n const ignore = options.ignore ?? []\n\n // `ignore` takes precedence: skip excluded files even when they also match `paths`.\n if (ignore.length > 0 && matchesAnyGlob(context.filename, ignore)) {\n return {}\n }\n\n if (paths.length > 0 && !matchesAnyGlob(context.filename, paths)) {\n return {}\n }\n\n const check = (node: ComponentFunction): void => {\n if (!isComponent(node)) {\n return\n }\n\n // An anonymous component (e.g. `export default () => ...`) has no name to derive the\n // expected props type name from, so the convention cannot be checked.\n const componentName = getComponentName(node)\n\n if (componentName === null) {\n return\n }\n\n // Only a simple named type reference is checked. An inline object type is the\n // `props-type-reference` rule's concern; qualified names and generics are out of scope and\n // resolve to null. A component with no typed props parameter is likewise not constrained.\n const actual = getPropsTypeNameFromFunction(node)\n\n if (actual === null) {\n return\n }\n\n const expected = `${componentName}${PROPS_SUFFIX}`\n\n if (actual === expected) {\n return\n }\n\n // `getPropsTypeNameFromFunction` only returns non-null when the first parameter carries a\n // named type reference, so an annotated parameter is guaranteed to exist here.\n context.report({\n node: getAnnotatedParam(node.params[0]!),\n messageId: 'propsTypeNameMismatch',\n data: { expected, actual },\n })\n }\n\n return {\n ArrowFunctionExpression: check,\n FunctionDeclaration: check,\n FunctionExpression: check,\n }\n },\n}\n", "import type { Rule } from 'eslint'\n\nimport type { ComponentFunction } from '../../utils/component'\nimport { getAnnotatedParam, getComponentName, isComponent } from '../../utils/component'\nimport { matchesAnyGlob } from '../../utils/path-match'\n\ninterface Options {\n paths?: string[]\n ignore?: string[]\n}\n\n// TS-only nodes are not modelled by estree, so we view them through a minimal two-level\n// structural interface: the `TSTypeAnnotation` wrapper a parser attaches to a parameter, and\n// its inner type node. An inline object type is `TSTypeLiteral`; a named type is `TSTypeReference`.\ninterface AnnotatedNode {\n typeAnnotation?: {\n typeAnnotation?: { type?: string }\n }\n}\n\nconst INLINE_OBJECT_TYPE = 'TSTypeLiteral'\n\nexport const propsTypeReference: Rule.RuleModule = {\n meta: {\n type: 'suggestion',\n docs: {\n description:\n \"Require a React component's props parameter to use a named type (e.g. `ButtonProps`) instead of an inline object type literal.\",\n recommended: true,\n url: 'https://github.com/ArthurSaenz/infra-kit/tree/main/apps/infra-kit/eslint-plugin#props-type-reference',\n },\n schema: [\n {\n type: 'object',\n properties: {\n paths: {\n type: 'array',\n items: { type: 'string' },\n description:\n 'Optional glob patterns. When provided, the rule only runs for files whose path matches one of them.',\n },\n ignore: {\n type: 'array',\n items: { type: 'string' },\n description:\n 'Optional glob patterns. The rule is skipped for files whose path matches one of them, even if it also matches `paths`.',\n },\n },\n additionalProperties: false,\n },\n ],\n messages: {\n useNamedPropsType:\n \"Use a named props type (e.g. `{{name}}Props`) instead of an inline object type for this component's props.\",\n useNamedPropsTypeAnonymous: \"Use a named props type instead of an inline object type for this component's props.\",\n },\n },\n\n create(context) {\n const options = (context.options[0] ?? {}) as Options\n const paths = options.paths ?? []\n const ignore = options.ignore ?? []\n\n // `ignore` takes precedence: skip excluded files even when they also match `paths`.\n if (ignore.length > 0 && matchesAnyGlob(context.filename, ignore)) {\n return {}\n }\n\n if (paths.length > 0 && !matchesAnyGlob(context.filename, paths)) {\n return {}\n }\n\n const check = (node: ComponentFunction): void => {\n const firstParam = node.params[0]\n\n if (!firstParam || !isComponent(node)) {\n return\n }\n\n const annotatedParam = getAnnotatedParam(firstParam)\n const innerType = (annotatedParam as AnnotatedNode).typeAnnotation?.typeAnnotation?.type\n\n if (innerType !== INLINE_OBJECT_TYPE) {\n return\n }\n\n const name = getComponentName(node)\n\n context.report(\n name === null\n ? { node: annotatedParam, messageId: 'useNamedPropsTypeAnonymous' }\n : { node: annotatedParam, messageId: 'useNamedPropsType', data: { name } },\n )\n }\n\n return {\n ArrowFunctionExpression: check,\n FunctionDeclaration: check,\n FunctionExpression: check,\n }\n },\n}\n", "import type { Rule } from 'eslint'\nimport { existsSync } from 'node:fs'\nimport path from 'node:path'\n\nimport { bodyDeclaresComponent } from '../../utils/component'\nimport { matchesAnyGlob } from '../../utils/path-match'\nimport type { ExtraTarget, StoryPathOptions } from '../../utils/story-path'\nimport { DEFAULT_STORY_PATH_OPTIONS, classifyComponent, deriveExpectedStoryPaths } from '../../utils/story-path'\n\ninterface Options {\n paths?: string[]\n ignore?: string[]\n storiesDir?: string\n storySuffix?: string\n storyExtensions?: string[]\n componentSuffix?: string\n requireComponentAst?: boolean\n extraTargets?: ExtraTarget[]\n}\n\n/** Pick the story-path knobs out of the rule options, leaving defaults to the helper. */\nconst toStoryPathOptions = (options: Options): Partial<StoryPathOptions> => {\n const picked: Partial<StoryPathOptions> = {}\n\n if (options.storiesDir !== undefined) {\n picked.storiesDir = options.storiesDir\n }\n\n if (options.storySuffix !== undefined) {\n picked.storySuffix = options.storySuffix\n }\n\n if (options.storyExtensions !== undefined) {\n picked.storyExtensions = options.storyExtensions\n }\n\n if (options.componentSuffix !== undefined) {\n picked.componentSuffix = options.componentSuffix\n }\n\n if (options.extraTargets !== undefined) {\n picked.extraTargets = options.extraTargets\n }\n\n return picked\n}\n\nexport const requireComponentStories: Rule.RuleModule = {\n meta: {\n type: 'problem',\n docs: {\n description: 'Require a co-located Storybook story for every dumb component.',\n recommended: true,\n url: 'https://github.com/ArthurSaenz/infra-kit/tree/main/apps/infra-kit/eslint-plugin#require-component-stories',\n },\n schema: [\n {\n type: 'object',\n properties: {\n paths: {\n type: 'array',\n items: { type: 'string' },\n description: 'Optional globs; when provided the rule only runs for files whose path matches one.',\n },\n ignore: {\n type: 'array',\n items: { type: 'string' },\n description: 'Optional globs; the rule is skipped for matching files, even if they also match `paths`.',\n },\n storiesDir: {\n type: 'string',\n description: `Story directory name (default '${DEFAULT_STORY_PATH_OPTIONS.storiesDir}').`,\n },\n storySuffix: {\n type: 'string',\n description: `Suffix inserted before the extension (default '${DEFAULT_STORY_PATH_OPTIONS.storySuffix}').`,\n },\n storyExtensions: {\n type: 'array',\n items: { type: 'string' },\n description: 'Extensions a satisfying story file may have, in priority order.',\n },\n componentSuffix: {\n type: 'string',\n description: `Basename suffix a component file must end with (default '${DEFAULT_STORY_PATH_OPTIONS.componentSuffix}'; '' disables).`,\n },\n requireComponentAst: {\n type: 'boolean',\n description: 'When true (default), only require a story for files that actually declare a component.',\n },\n extraTargets: {\n type: 'array',\n items: {\n type: 'object',\n properties: {\n componentsDir: { type: 'string' },\n anchorParentDir: { type: 'string' },\n storyMode: { enum: ['feature-root', 'sibling'] },\n },\n required: ['componentsDir', 'storyMode'],\n additionalProperties: false,\n },\n description: 'Extra structured component layouts (componentsDir + optional anchorParentDir + storyMode).',\n },\n },\n additionalProperties: false,\n },\n ],\n messages: {\n missingStory: \"Dumb component '{{component}}' is missing a Storybook story (expected at '{{expected}}').\",\n },\n },\n\n create(context) {\n const options = (context.options[0] ?? {}) as Options\n const paths = options.paths ?? []\n const ignore = options.ignore ?? []\n const requireComponentAst = options.requireComponentAst ?? true\n const storyPathOptions = toStoryPathOptions(options)\n\n // `ignore` takes precedence: skip excluded files even when they also match `paths`.\n if (ignore.length > 0 && matchesAnyGlob(context.filename, ignore)) {\n return {}\n }\n\n if (paths.length > 0 && !matchesAnyGlob(context.filename, paths)) {\n return {}\n }\n\n return {\n Program(program) {\n // Is this file a dumb component that requires a story, and where would the story live?\n if (!classifyComponent(context.filename, storyPathOptions)) {\n return\n }\n\n // Only enforce on files that actually declare a component (avoids flagging stray\n // non-component files placed under a components/ directory).\n if (requireComponentAst && !bodyDeclaresComponent(program.body)) {\n return\n }\n\n const candidates = deriveExpectedStoryPaths(context.filename, storyPathOptions)\n\n // The story is satisfied if ANY candidate (by extension) exists on disk.\n const hasStory = candidates.some((candidate) => {\n return existsSync(candidate)\n })\n\n if (hasStory) {\n return\n }\n\n context.report({\n node: program,\n messageId: 'missingStory',\n data: {\n component: path.posix.basename(context.filename.split('\\\\').join('/')),\n expected: candidates[0] ?? '',\n },\n })\n },\n }\n },\n}\n", "import path from 'node:path'\n\n/** Where a story file lives relative to its component. */\nexport type StoryMode = 'feature-root' | 'sibling'\n\n/** A consumer-defined extra component layout (structured \u2014 never a glob). */\nexport interface ExtraTarget {\n /** Immediate parent directory name a component file must sit directly inside. */\n componentsDir: string\n /** Optional grandparent directory name gate (e.g. `features`). */\n anchorParentDir?: string\n /** Where the story is expected for files matched by this target. */\n storyMode: StoryMode\n}\n\nexport interface StoryPathOptions {\n /** Story directory name (default `__stories__`). */\n storiesDir: string\n /** Suffix inserted before the extension (default `.stories`). */\n storySuffix: string\n /** Extensions a satisfying story file may have, in priority order. */\n storyExtensions: string[]\n /** Extensions a file must have to be considered a component. */\n componentExtensions: string[]\n /** Basename suffix a component file must end with (default `-component`; `''` disables). */\n componentSuffix: string\n /** Additional structured component layouts beyond the two built-ins. */\n extraTargets: ExtraTarget[]\n}\n\nexport const DEFAULT_STORY_PATH_OPTIONS: StoryPathOptions = {\n storiesDir: '__stories__',\n storySuffix: '.stories',\n storyExtensions: ['.tsx', '.jsx', '.ts', '.js'],\n componentExtensions: ['.tsx', '.jsx'],\n componentSuffix: '-component',\n extraTargets: [],\n}\n\nconst resolveOptions = (opts?: Partial<StoryPathOptions>): StoryPathOptions => {\n return { ...DEFAULT_STORY_PATH_OPTIONS, ...opts }\n}\n\n/** Normalize OS-native separators to posix so all downstream path logic is deterministic. */\nconst toPosix = (filePath: string): string => {\n return filePath.split('\\\\').join('/')\n}\n\ninterface ParsedComponent {\n /** Posix directory of the file. */\n dir: string\n /** Basename without its extension. */\n base: string\n /** Original extension (e.g. `.tsx`). */\n ext: string\n /** Immediate parent directory name. */\n parent: string\n /** Grandparent directory name. */\n grandparent: string\n /** Great-grandparent directory name. */\n greatGrandparent: string\n}\n\n/** Parse a file path into the segment view the gate and derivation both need. */\nconst parse = (filePath: string): ParsedComponent => {\n const normalized = toPosix(filePath)\n const segments = normalized.split('/')\n const basename = segments[segments.length - 1] ?? ''\n const ext = path.posix.extname(basename)\n const base = ext ? basename.slice(0, -ext.length) : basename\n\n return {\n dir: path.posix.dirname(normalized),\n base,\n ext,\n parent: segments[segments.length - 2] ?? '',\n grandparent: segments[segments.length - 3] ?? '',\n greatGrandparent: segments[segments.length - 4] ?? '',\n }\n}\n\n/** Whether the file passes the component preconditions (extension + name suffix). */\nconst passesComponentPreconditions = (parsed: ParsedComponent, options: StoryPathOptions): boolean => {\n if (!options.componentExtensions.includes(parsed.ext)) {\n return false\n }\n\n return options.componentSuffix === '' || parsed.base.endsWith(options.componentSuffix)\n}\n\n/**\n * Classify a file as a dumb component requiring a story, resolving WHERE its story should live.\n * Returns null when the file is not a component-requiring-a-story under any branch.\n *\n * Exactly one admit-condition may hold:\n * - feature-root: direct child of `components/` whose chain is `features/<f>/components`.\n * - sibling: a `components/default/<name>-component` file (parent `default`, grandparent `components`).\n * - extraTargets: a structured consumer-defined layout.\n */\nexport const classifyComponent = (filePath: string, opts?: Partial<StoryPathOptions>): { mode: StoryMode } | null => {\n const options = resolveOptions(opts)\n const parsed = parse(filePath)\n\n if (!passesComponentPreconditions(parsed, options)) {\n return null\n }\n\n // (a) feature-root \u2014 immediate parent is `components` AND the chain is `features/<feature>/components`.\n if (parsed.parent === 'components' && parsed.greatGrandparent === 'features') {\n return { mode: 'feature-root' }\n }\n\n // (b) sibling \u2014 `components/default/<name>-component.*` (NOT a direct child of `components/`).\n if (parsed.parent === 'default' && parsed.grandparent === 'components') {\n return { mode: 'sibling' }\n }\n\n // (c) extraTargets \u2014 structured layouts (componentsDir + optional anchorParentDir).\n for (const target of options.extraTargets) {\n const parentMatches = parsed.parent === target.componentsDir\n const anchorMatches = target.anchorParentDir == null || parsed.grandparent === target.anchorParentDir\n\n if (parentMatches && anchorMatches) {\n return { mode: target.storyMode }\n }\n }\n\n return null\n}\n\n/**\n * Ordered candidate story paths for a component file. Empty when the file is not a\n * component-requiring-a-story (see {@link classifyComponent}). The story is considered present\n * when ANY candidate exists on disk.\n */\nexport const deriveExpectedStoryPaths = (filePath: string, opts?: Partial<StoryPathOptions>): string[] => {\n const options = resolveOptions(opts)\n const classification = classifyComponent(filePath, options)\n\n if (!classification) {\n return []\n }\n\n const parsed = parse(filePath)\n\n // feature-root: dirname(file) is `.../components`, so its parent is the feature root.\n // sibling: the story dir sits next to the component file itself.\n const storyBaseDir = classification.mode === 'feature-root' ? path.posix.dirname(parsed.dir) : parsed.dir\n const storyDir = path.posix.join(storyBaseDir, options.storiesDir)\n\n return options.storyExtensions.map((extension) => {\n return path.posix.join(storyDir, `${parsed.base}${options.storySuffix}${extension}`)\n })\n}\n", "import type * as ESTree from 'estree'\n\nexport type FunctionNode = ESTree.ArrowFunctionExpression | ESTree.FunctionDeclaration | ESTree.FunctionExpression\n\n// Keys that are never child AST nodes (back-reference + source positions + the discriminant).\nconst NON_CHILD_KEYS = new Set(['parent', 'loc', 'range', 'type'])\n\nconst LOOP_TYPES = new Set(['ForStatement', 'ForInStatement', 'ForOfStatement', 'WhileStatement', 'DoWhileStatement'])\nconst NESTED_FUNCTION_TYPES = new Set(['FunctionDeclaration', 'FunctionExpression', 'ArrowFunctionExpression'])\n\n// Mutable walk context: the running score plus the enclosing function's name (for recursion).\ninterface Ctx {\n score: number\n name: string | null\n}\n\nconst isNode = (value: unknown): value is ESTree.Node => {\n return typeof value === 'object' && value !== null && typeof (value as { type?: unknown }).type === 'string'\n}\n\n/**\n * The direct child AST nodes of `node`, read generically from its own enumerable\n * properties (skipping `parent`/`loc`/`range`). estree does not model JSX, but JSX\n * nodes still carry a string `type`, so embedded `&&`/ternaries are reached too.\n */\nconst childrenOf = (node: ESTree.Node): ESTree.Node[] => {\n const children: ESTree.Node[] = []\n\n for (const key of Object.keys(node)) {\n if (NON_CHILD_KEYS.has(key)) {\n continue\n }\n\n const value = (node as unknown as Record<string, unknown>)[key]\n\n if (Array.isArray(value)) {\n children.push(...value.filter(isNode))\n } else if (isNode(value)) {\n children.push(value)\n }\n }\n\n return children\n}\n\n// Flatten a logical chain into its operand leaves while collecting operators in order.\nconst flattenLogicalOperators = (node: ESTree.Node, operators: string[]): ESTree.Node[] => {\n if (node.type !== 'LogicalExpression') {\n return [node]\n }\n\n const left = flattenLogicalOperators(node.left, operators)\n\n operators.push(node.operator)\n\n const right = flattenLogicalOperators(node.right, operators)\n\n return [...left, ...right]\n}\n\n// Score = number of contiguous runs of the SAME operator (`a && b && c` \u2192 1, `a && b || c` \u2192 2).\nconst countOperatorRuns = (operators: string[]): number => {\n let runs = 0\n let previous: string | null = null\n\n for (const operator of operators) {\n if (operator !== previous) {\n runs += 1\n previous = operator\n }\n }\n\n return runs\n}\n\nconst recurseChildren = (ctx: Ctx, node: ESTree.Node, nesting: number): void => {\n for (const child of childrenOf(node)) {\n walk(ctx, child, nesting)\n }\n}\n\nconst handleLogical = (ctx: Ctx, node: ESTree.LogicalExpression, nesting: number): void => {\n const operators: string[] = []\n const operands = flattenLogicalOperators(node, operators)\n\n ctx.score += countOperatorRuns(operators)\n\n for (const operand of operands) {\n walk(ctx, operand, nesting)\n }\n}\n\nconst handleAlternate = (ctx: Ctx, alternate: ESTree.Statement | null | undefined, nesting: number): void => {\n if (!alternate) {\n return\n }\n\n // `else if` (the alternate IS another `if`): +1 with no nesting bump, processed\n // inline so the chained `if` does not also take its own structural increment.\n if (alternate.type === 'IfStatement') {\n ctx.score += 1\n walk(ctx, alternate.test, nesting)\n walk(ctx, alternate.consequent, nesting + 1)\n handleAlternate(ctx, alternate.alternate, nesting)\n\n return\n }\n\n // plain `else`: +1, body nested one level.\n ctx.score += 1\n walk(ctx, alternate, nesting + 1)\n}\n\nconst handleIf = (ctx: Ctx, node: ESTree.IfStatement, nesting: number): void => {\n ctx.score += 1 + nesting\n walk(ctx, node.test, nesting)\n walk(ctx, node.consequent, nesting + 1)\n handleAlternate(ctx, node.alternate, nesting)\n}\n\nconst handleTernary = (ctx: Ctx, node: ESTree.ConditionalExpression, nesting: number): void => {\n ctx.score += 1 + nesting\n walk(ctx, node.test, nesting)\n walk(ctx, node.consequent, nesting + 1)\n walk(ctx, node.alternate, nesting + 1)\n}\n\nconst handleSwitch = (ctx: Ctx, node: ESTree.SwitchStatement, nesting: number): void => {\n ctx.score += 1 + nesting\n walk(ctx, node.discriminant, nesting)\n\n for (const switchCase of node.cases) {\n if (switchCase.test) {\n walk(ctx, switchCase.test, nesting)\n }\n\n for (const statement of switchCase.consequent) {\n walk(ctx, statement, nesting + 1)\n }\n }\n}\n\nconst handleLoop = (ctx: Ctx, node: ESTree.Node, nesting: number): void => {\n ctx.score += 1 + nesting\n\n const body = (node as { body?: ESTree.Node }).body\n\n for (const child of childrenOf(node)) {\n // The loop body nests one level; conditions/headers stay at this level.\n walk(ctx, child, child === body ? nesting + 1 : nesting)\n }\n}\n\nconst handleTry = (ctx: Ctx, node: ESTree.TryStatement, nesting: number): void => {\n walk(ctx, node.block, nesting)\n\n if (node.handler) {\n ctx.score += 1 + nesting\n walk(ctx, node.handler.body, nesting + 1)\n }\n\n if (node.finalizer) {\n walk(ctx, node.finalizer, nesting)\n }\n}\n\nconst handleCall = (ctx: Ctx, node: ESTree.CallExpression, nesting: number): void => {\n if (ctx.name && node.callee.type === 'Identifier' && node.callee.name === ctx.name) {\n ctx.score += 1\n }\n\n recurseChildren(ctx, node, nesting)\n}\n\nfunction walk(ctx: Ctx, node: ESTree.Node, nesting: number): void {\n const type = node.type as string\n\n if (type === 'LogicalExpression') {\n handleLogical(ctx, node as ESTree.LogicalExpression, nesting)\n } else if (type === 'IfStatement') {\n handleIf(ctx, node as ESTree.IfStatement, nesting)\n } else if (type === 'ConditionalExpression') {\n handleTernary(ctx, node as ESTree.ConditionalExpression, nesting)\n } else if (type === 'SwitchStatement') {\n handleSwitch(ctx, node as ESTree.SwitchStatement, nesting)\n } else if (LOOP_TYPES.has(type)) {\n handleLoop(ctx, node, nesting)\n } else if (type === 'TryStatement') {\n handleTry(ctx, node as ESTree.TryStatement, nesting)\n } else if (NESTED_FUNCTION_TYPES.has(type)) {\n // Nested functions take no structural increment, but their bodies nest one level.\n walk(ctx, (node as FunctionNode).body, nesting + 1)\n } else if (type === 'CallExpression') {\n handleCall(ctx, node as ESTree.CallExpression, nesting)\n } else {\n recurseChildren(ctx, node, nesting)\n }\n}\n\n/**\n * Cognitive complexity of a function per the SonarSource white-paper model.\n *\n * Each `if`/ternary/switch/loop/`catch` adds 1 plus the current nesting level;\n * `else`/`else if` adds 1 with no nesting bump; each run of a logical operator\n * adds 1; recursion (a direct call to the enclosing function by name) adds 1.\n * Nesting deepens inside every branch, loop, switch, `catch`, and nested function.\n *\n * @example\n * cognitiveComplexity(node) // 0 for a flat function, 1 for a single `if`\n */\nexport const cognitiveComplexity = (fn: FunctionNode, enclosingName?: string | null): number => {\n const fallbackName = fn.type === 'FunctionDeclaration' ? (fn.id?.name ?? null) : null\n const ctx: Ctx = { score: 0, name: enclosingName ?? fallbackName }\n\n walk(ctx, fn.body, 0)\n\n return ctx.score\n}\n", "import type { Rule, SourceCode } from 'eslint'\nimport type * as ESTree from 'estree'\n\nimport { cognitiveComplexity } from '../../utils/cognitive-complexity'\nimport type { FunctionNode } from '../../utils/cognitive-complexity'\nimport { matchesAnyGlob } from '../../utils/path-match'\n\ninterface Options {\n minComplexity?: number\n exampleComplexity?: number\n paths?: string[]\n ignore?: string[]\n}\n\n// Defaults chosen so only genuinely \"substantial\" functions are flagged, and only the\n// most complex of those are pushed to also carry a worked `@example`.\nconst DEFAULT_MIN_COMPLEXITY = 8\nconst DEFAULT_EXAMPLE_COMPLEXITY = 12\n\ntype MessageId = 'missingExample' | 'missingJsdoc'\n\ninterface Settings {\n minComplexity: number\n exampleComplexity: number\n}\n\ninterface Target {\n fn: FunctionNode\n name: string\n // Nodes whose leading comments may carry the qualifying JSDoc (declaration + any `export` wrapper).\n anchors: ESTree.Node[]\n}\n\ninterface Violation {\n messageId: MessageId\n data: Record<string, number | string>\n}\n\nconst isTargetFn = (node: ESTree.Node | null | undefined): node is FunctionNode => {\n return node?.type === 'ArrowFunctionExpression' || node?.type === 'FunctionExpression'\n}\n\n/** Split a top-level statement into its inner declaration and any `export` wrapper. */\nconst getExportInfo = (\n statement: ESTree.Statement | ESTree.ModuleDeclaration,\n): { exportStmt: ESTree.Node | null; declaration: ESTree.Node | null } => {\n if (statement.type === 'ExportNamedDeclaration' || statement.type === 'ExportDefaultDeclaration') {\n return { exportStmt: statement, declaration: (statement.declaration as ESTree.Node | null) ?? null }\n }\n\n return { exportStmt: null, declaration: statement }\n}\n\n/** The named, definable functions declared by a single top-level declaration. */\nconst targetsFromDeclaration = (declaration: ESTree.Node, anchors: ESTree.Node[]): Target[] => {\n if (declaration.type === 'FunctionDeclaration') {\n return declaration.id ? [{ fn: declaration, name: declaration.id.name, anchors }] : []\n }\n\n if (declaration.type === 'VariableDeclaration') {\n return declaration.declarations.flatMap((declarator) => {\n return declarator.id.type === 'Identifier' && isTargetFn(declarator.init)\n ? [{ fn: declarator.init, name: declarator.id.name, anchors }]\n : []\n })\n }\n\n return []\n}\n\n/** Every named top-level function definition (bare or `export`/`export default` wrapped). */\nconst collectTargets = (body: Array<ESTree.Statement | ESTree.ModuleDeclaration>): Target[] => {\n return body.flatMap((statement) => {\n const { exportStmt, declaration } = getExportInfo(statement)\n\n if (!declaration) {\n return []\n }\n\n const anchors = exportStmt ? [exportStmt, declaration] : [declaration]\n\n return targetsFromDeclaration(declaration, anchors)\n })\n}\n\n/** Whether a `/** \u2026 *\\/` JSDoc block immediately precedes any anchor. */\nconst hasJsdocBlock = (sourceCode: SourceCode, anchors: ESTree.Node[]): boolean => {\n return anchors.some((anchor) => {\n return sourceCode.getCommentsBefore(anchor).some((comment) => {\n return comment.type === 'Block' && comment.value.startsWith('*')\n })\n })\n}\n\n/** Whether such a leading JSDoc block ALSO carries an `@example` tag. */\nconst hasJsdocExample = (sourceCode: SourceCode, anchors: ESTree.Node[]): boolean => {\n return anchors.some((anchor) => {\n return sourceCode.getCommentsBefore(anchor).some((comment) => {\n return comment.type === 'Block' && comment.value.startsWith('*') && comment.value.includes('@example')\n })\n })\n}\n\n/** Decide whether a target violates the rule and, if so, which message fits. */\nconst decideViolation = (target: Target, settings: Settings, sourceCode: SourceCode): Violation | null => {\n const complexity = cognitiveComplexity(target.fn, target.name)\n const { minComplexity, exampleComplexity } = settings\n\n // Below the floor: no documentation requirement at all.\n if (complexity < minComplexity) {\n return null\n }\n\n const { name } = target\n\n // A missing block always takes precedence over a missing `@example`.\n if (!hasJsdocBlock(sourceCode, target.anchors)) {\n return { messageId: 'missingJsdoc', data: { name, complexity, minComplexity } }\n }\n\n if (complexity >= exampleComplexity && !hasJsdocExample(sourceCode, target.anchors)) {\n return { messageId: 'missingExample', data: { name, complexity, exampleComplexity } }\n }\n\n return null\n}\n\nexport const requireJsdocExample: Rule.RuleModule = {\n meta: {\n type: 'suggestion',\n docs: {\n description:\n 'Graduated JSDoc requirement by cognitive complexity: at or above `minComplexity` a function must carry a leading JSDoc block, and at or above `exampleComplexity` that block must also include an `@example` tag.',\n recommended: true,\n url: 'https://github.com/ArthurSaenz/infra-kit/tree/main/apps/infra-kit/eslint-plugin#require-jsdoc-example',\n },\n schema: [\n {\n type: 'object',\n properties: {\n minComplexity: {\n type: 'integer',\n minimum: 1,\n description: 'Cognitive complexity at or above which a function must carry a leading JSDoc block.',\n },\n exampleComplexity: {\n type: 'integer',\n minimum: 1,\n description: 'Cognitive complexity at or above which the JSDoc block must also include an `@example` tag.',\n },\n paths: {\n type: 'array',\n items: { type: 'string' },\n description:\n 'Optional glob patterns. When provided, the rule only runs for files whose path matches one of them.',\n },\n ignore: {\n type: 'array',\n items: { type: 'string' },\n description:\n 'Optional glob patterns. The rule is skipped for files whose path matches one of them, even if it also matches `paths`.',\n },\n },\n additionalProperties: false,\n },\n ],\n messages: {\n missingJsdoc:\n 'function \"{{name}}\" has cognitive complexity {{complexity}} (>= {{minComplexity}}); add a JSDoc block documenting it.',\n missingExample:\n 'function \"{{name}}\" has cognitive complexity {{complexity}} (>= {{exampleComplexity}}); its JSDoc block needs an `@example` documenting usage.',\n },\n },\n\n create(context) {\n const options = (context.options[0] ?? {}) as Options\n const paths = options.paths ?? []\n const ignore = options.ignore ?? []\n\n // `ignore` takes precedence: skip excluded files even when they also match `paths`.\n if (ignore.length > 0 && matchesAnyGlob(context.filename, ignore)) {\n return {}\n }\n\n if (paths.length > 0 && !matchesAnyGlob(context.filename, paths)) {\n return {}\n }\n\n const settings: Settings = {\n minComplexity: options.minComplexity ?? DEFAULT_MIN_COMPLEXITY,\n exampleComplexity: options.exampleComplexity ?? DEFAULT_EXAMPLE_COMPLEXITY,\n }\n\n const { sourceCode } = context\n\n return {\n Program(program) {\n for (const target of collectTargets(program.body)) {\n const violation = decideViolation(target, settings, sourceCode)\n\n if (violation) {\n context.report({ node: target.fn, messageId: violation.messageId, data: violation.data })\n }\n }\n },\n }\n },\n}\n", "import type { Rule, Scope, SourceCode } from 'eslint'\nimport type { Node as EsNode, ImportDeclaration, ImportNamespaceSpecifier, Program } from 'estree'\n\nimport { isInScope, isUiPackageFile } from '../../utils/component-file-scope'\n\ninterface Options {\n /** The namespace binding every services import must use. */\n name?: string\n paths?: string[]\n ignore?: string[]\n}\n\nconst DEFAULT_NAME = 'service'\n\n// A barrel re-exports the services under a public, module-specific name (`export * as fooService`).\nconst BARREL_FILE = /\\/index\\.[cm]?[jt]sx?$/\n\n/** A relative path to a `services.ts` file or a `services/` folder barrel. */\nconst SERVICES_SPECIFIER = /^\\.{1,2}\\/(?:.*\\/)?services(?:\\/index)?(?:\\.[cm]?[jt]sx?)?$/\n\ntype Specifier = ImportDeclaration['specifiers'][number]\n\ninterface Replacement {\n range: [number, number]\n text: string\n}\n\ninterface GroupContext {\n context: Rule.RuleContext\n sourceCode: SourceCode\n source: string\n group: ImportDeclaration[]\n name: string\n /** False when any fix for this group could clash with another binding. */\n canFix: boolean\n}\n\nconst isTypeOnly = (node: ImportDeclaration | Specifier): boolean => {\n return (node as { importKind?: string }).importKind === 'type'\n}\n\nconst isValueBinding = (specifier: Specifier): boolean => {\n return specifier.type !== 'ImportNamespaceSpecifier' && !isTypeOnly(specifier)\n}\n\nconst importedName = (specifier: Specifier): string => {\n if (specifier.type === 'ImportDefaultSpecifier') {\n return 'default'\n }\n\n if (specifier.type === 'ImportSpecifier') {\n return specifier.imported.type === 'Identifier' ? specifier.imported.name : String(specifier.imported.value)\n }\n\n return specifier.local.name\n}\n\n/** Whether a scope between `reference` and the module scope declares its own `name`. */\nconst isShadowedAt = (reference: Scope.Reference, name: string): boolean => {\n let scope: Scope.Scope | null = reference.from\n\n while (scope !== null && scope.type !== 'module' && scope.type !== 'global') {\n if (scope.set.has(name)) {\n return true\n }\n\n scope = scope.upper\n }\n\n return false\n}\n\n/** JSX tag names and local re-exports cannot take a `namespace.member` form, so they block the fix. */\nconst isRewritable = (reference: Scope.Reference, name: string): boolean => {\n const identifier = reference.identifier as EsNode & { parent?: EsNode }\n\n return (\n (identifier.type as string) !== 'JSXIdentifier' &&\n identifier.parent?.type !== 'ExportSpecifier' &&\n !isShadowedAt(reference, name)\n )\n}\n\nconst referenceEdit = (reference: Scope.Reference, local: string, member: string): Replacement => {\n const identifier = reference.identifier as EsNode & { parent?: EsNode }\n const parent = identifier.parent\n\n // `{ foo }` must keep its key once the value becomes `service.foo`.\n if (parent?.type === 'Property' && parent.shorthand && parent.value === identifier) {\n return { range: parent.range!, text: `${local}: ${member}` }\n }\n\n return { range: identifier.range!, text: member }\n}\n\n/** Edits that point every reference of each binding at `${name}.<member>`; null when one cannot be rewritten. */\nconst rewriteBindings = (\n bindings: readonly { variable: Scope.Variable; member: string }[],\n name: string,\n): Replacement[] | null => {\n const references = bindings.flatMap(({ variable, member }) => {\n return variable.references.map((reference) => {\n return { reference, local: variable.name, member }\n })\n })\n\n const allRewritable = references.every(({ reference }) => {\n return isRewritable(reference, name)\n })\n\n if (!allRewritable) {\n return null\n }\n\n return references.map(({ reference, local, member }) => {\n return referenceEdit(reference, local, member === '' ? name : `${name}.${member}`)\n })\n}\n\nconst typeImportLine = (declaration: ImportDeclaration, sourceCode: SourceCode): string | null => {\n const names = declaration.specifiers.filter(isTypeOnly).map((specifier) => {\n return sourceCode.getText(specifier).replace(/^type\\s+/, '')\n })\n\n return names.length === 0\n ? null\n : `import type { ${names.join(', ')} } from ${sourceCode.getText(declaration.source)}`\n}\n\n/** Removes a whole import line, its trailing newline included. */\nconst lineRange = (declaration: ImportDeclaration, sourceCode: SourceCode): [number, number] => {\n const [start, end] = declaration.range!\n\n return [start, sourceCode.text[end] === '\\n' ? end + 1 : end]\n}\n\n/** Whether `name` is bound at module level by anything other than `except`. */\nconst isNameTaken = (sourceCode: SourceCode, program: Program, name: string, except?: EsNode): boolean => {\n const moduleScope = sourceCode.getScope(program).childScopes.find((scope) => {\n return scope.type === 'module'\n })\n\n const variable = moduleScope?.set.get(name)\n\n return (\n variable !== undefined &&\n variable.defs.some((def) => {\n return def.node !== except\n })\n )\n}\n\nconst namespacesOf = (group: readonly ImportDeclaration[]): ImportNamespaceSpecifier[] => {\n return group.flatMap((declaration) => {\n return declaration.specifiers.filter((specifier): specifier is ImportNamespaceSpecifier => {\n return specifier.type === 'ImportNamespaceSpecifier'\n })\n })\n}\n\nconst reportWrongNamespaces = (ctx: GroupContext, wrong: readonly ImportNamespaceSpecifier[]): void => {\n const { context, sourceCode, source, name } = ctx\n\n for (const specifier of wrong) {\n const variable = sourceCode.getDeclaredVariables(specifier)[0]\n\n // Only a lone wrongly named namespace can be renamed; two of them would collapse into one binding.\n const edits =\n ctx.canFix && wrong.length === 1 && variable ? rewriteBindings([{ variable, member: '' }], name) : null\n\n context.report({\n node: specifier,\n messageId: 'namespaceName',\n data: { source, name, actual: specifier.local.name },\n fix:\n edits === null\n ? null\n : (fixer) => {\n return [\n fixer.replaceText(specifier.local, name),\n ...edits.map((edit) => {\n return fixer.replaceTextRange(edit.range, edit.text)\n }),\n ]\n },\n })\n }\n}\n\nconst reportNamedImports = (\n ctx: GroupContext,\n offending: readonly ImportDeclaration[],\n hasNamespace: boolean,\n): void => {\n const { context, sourceCode, source, name } = ctx\n\n const bindings = offending.flatMap((declaration) => {\n return declaration.specifiers.filter(isValueBinding).map((specifier) => {\n return { variable: sourceCode.getDeclaredVariables(specifier)[0]!, member: importedName(specifier) }\n })\n })\n\n const edits = ctx.canFix ? rewriteBindings(bindings, name) : null\n // The first offending line becomes the namespace import unless one already exists; the others go away.\n const host = hasNamespace ? undefined : offending[0]\n\n const declarationFix = (fixer: Rule.RuleFixer, declaration: ImportDeclaration): Rule.Fix => {\n const lines = [\n declaration === host ? `import * as ${name} from ${sourceCode.getText(declaration.source)}` : null,\n typeImportLine(declaration, sourceCode),\n ].filter((line) => {\n return line !== null\n })\n\n return lines.length === 0\n ? fixer.removeRange(lineRange(declaration, sourceCode))\n : fixer.replaceText(declaration, lines.join('\\n'))\n }\n\n for (const declaration of offending) {\n // ESLint merges a report's fixes into one span, so separate reports would overlap and drop each\n // other's edits: the first report carries the whole group's rewrite.\n context.report({\n node: declaration,\n messageId: 'namedImport',\n data: { source, name },\n fix:\n edits === null || declaration !== offending[0]\n ? null\n : (fixer) => {\n return [\n ...offending.map((each) => {\n return declarationFix(fixer, each)\n }),\n ...edits.map((edit) => {\n return fixer.replaceTextRange(edit.range, edit.text)\n }),\n ]\n },\n })\n }\n}\n\nconst checkGroup = (ctx: GroupContext, program: Program): void => {\n const namespaces = namespacesOf(ctx.group)\n\n const correct = namespaces.find((specifier) => {\n return specifier.local.name === ctx.name\n })\n\n const wrong = namespaces.filter((specifier) => {\n return specifier !== correct\n })\n\n const nameTaken = isNameTaken(ctx.sourceCode, program, ctx.name, correct)\n\n reportWrongNamespaces({ ...ctx, canFix: ctx.canFix && correct === undefined && !nameTaken }, wrong)\n\n const offending = ctx.group.filter((declaration) => {\n return declaration.specifiers.some(isValueBinding)\n })\n\n if (offending.length > 0) {\n // A wrongly named namespace fixes first; the named imports fix on the next pass.\n reportNamedImports({ ...ctx, canFix: ctx.canFix && wrong.length === 0 && !nameTaken }, offending, !!correct)\n }\n}\n\nexport const servicesNamespaceImport: Rule.RuleModule = {\n meta: {\n type: 'suggestion',\n fixable: 'code',\n docs: {\n description:\n \"Import a feature's `services` module only as a namespace (`import * as service from '../services'`).\",\n recommended: true,\n url: 'https://github.com/ArthurSaenz/infra-kit/tree/main/apps/infra-kit/eslint-plugin#services-namespace-import',\n },\n schema: [\n {\n type: 'object',\n properties: {\n name: {\n type: 'string',\n minLength: 1,\n description: `The namespace binding (default '${DEFAULT_NAME}').`,\n },\n paths: {\n type: 'array',\n items: { type: 'string' },\n description:\n 'Optional glob patterns. When provided, the rule only runs for files whose path matches one of them.',\n },\n ignore: {\n type: 'array',\n items: { type: 'string' },\n description:\n 'Optional glob patterns. The rule is skipped for files whose path matches one of them, even if it also matches `paths`.',\n },\n },\n additionalProperties: false,\n },\n ],\n messages: {\n namedImport:\n \"Import `{{source}}` as a namespace \u2014 `import * as {{name}} from '{{source}}'` \u2014 and read members as `{{name}}.<member>`.\",\n namespaceName: 'Name the `{{source}}` namespace `{{name}}`, not `{{actual}}`.',\n },\n },\n\n create(context) {\n const options = (context.options[0] ?? {}) as Options\n const filename = context.filename.split('\\\\').join('/')\n\n if (\n BARREL_FILE.test(filename) ||\n !isInScope(filename, options.paths ?? [], options.ignore ?? []) ||\n !isUiPackageFile(filename)\n ) {\n return {}\n }\n\n const declarations: ImportDeclaration[] = []\n\n return {\n ImportDeclaration(node) {\n if (!isTypeOnly(node) && typeof node.source.value === 'string' && SERVICES_SPECIFIER.test(node.source.value)) {\n declarations.push(node)\n }\n },\n\n 'Program:exit': function (program: Program) {\n const bySource = Map.groupBy(declarations, (declaration) => {\n return String(declaration.source.value)\n })\n\n for (const [source, group] of bySource) {\n checkGroup(\n {\n context,\n sourceCode: context.sourceCode,\n source,\n group,\n name: options.name ?? DEFAULT_NAME,\n // Two different services modules cannot share one namespace name.\n canFix: bySource.size === 1,\n },\n program,\n )\n }\n },\n }\n },\n}\n", "import type { Rule } from 'eslint'\n\nimport { findPackageRoot } from '../../utils/package-root'\nimport { resolvePackageType } from '../../utils/package-type-reader'\nimport { matchesAnyGlob } from '../../utils/path-match'\n\nexport interface Options {\n /** Globs; the rule is skipped for matching files. */\n ignore?: string[]\n}\n\nconst TEST_FILE = /\\.(?:test|spec)\\.[cm]?[jt]sx?$/\nconst SPEC_SUFFIX = /\\.spec(\\.[cm]?[jt]sx?)$/\nconst TESTS_DIR = '__tests__'\nconst FEATURES_DIR = 'features'\n\ntype MessageId = 'outsideTestsDir' | 'outsideFeatureTestsDir' | 'specSuffix'\n\ninterface Violation {\n messageId: MessageId\n data: Record<string, string>\n}\n\n/** Relative from `src/` keeps the message short and still unambiguous inside a package. */\nconst fromSrc = (dirs: readonly string[]): string[] => {\n const srcIndex = dirs.lastIndexOf('src')\n\n return srcIndex >= 0 ? dirs.slice(srcIndex) : dirs.slice(-1)\n}\n\n/**\n * The directory of the feature `dirs` sits in (`\u2026/src/\u2026/features/<name>`), or null outside a\n * feature. Only a `features/` below `src/` counts, so a checkout path that happens to contain one\n * cannot turn every test into a feature test; the innermost wins so a nested feature owns its tests.\n */\nconst featureRoot = (dirs: readonly string[]): string[] | null => {\n const srcIndex = dirs.lastIndexOf('src')\n const featuresIndex = dirs.lastIndexOf(FEATURES_DIR)\n\n return srcIndex >= 0 && featuresIndex > srcIndex && featuresIndex + 1 < dirs.length\n ? dirs.slice(0, featuresIndex + 2)\n : null\n}\n\nconst locationViolation = (dirs: readonly string[], basename: string): Violation | null => {\n const feature = featureRoot(dirs)\n\n // A feature keeps every test in its root `__tests__/` (the `/infra-kit:fe-architect` layout), so a\n // `services/__tests__/` inside it is as misplaced as a test next to its source.\n if (feature !== null) {\n if (dirs[feature.length] === TESTS_DIR) {\n return null\n }\n\n return {\n messageId: 'outsideFeatureTestsDir',\n data: { basename, target: [...fromSrc(feature), TESTS_DIR, basename].join('/') },\n }\n }\n\n if (dirs.includes(TESTS_DIR)) {\n return null\n }\n\n return {\n messageId: 'outsideTestsDir',\n data: { basename, target: [...fromSrc(dirs), TESTS_DIR, basename].join('/') },\n }\n}\n\nconst findViolations = (filename: string, ignore: readonly string[]): Violation[] => {\n if (!TEST_FILE.test(filename) || (ignore.length > 0 && matchesAnyGlob(filename, ignore))) {\n return []\n }\n\n // e2e packages keep specs under `tests/*` by their own layout (see `e2e-file-layout`).\n const packageRoot = findPackageRoot(filename)\n\n if (packageRoot !== null && resolvePackageType(packageRoot) === 'e2e') {\n return []\n }\n\n const dirs = filename.split('/')\n const basename = dirs.pop()!\n const location = locationViolation(dirs, basename)\n\n const suffix: Violation | null = SPEC_SUFFIX.test(basename)\n ? { messageId: 'specSuffix', data: { basename, target: basename.replace(SPEC_SUFFIX, '.test$1') } }\n : null\n\n return [location, suffix].filter((violation): violation is Violation => {\n return violation !== null\n })\n}\n\nexport const testLocation: Rule.RuleModule = {\n meta: {\n type: 'problem',\n docs: {\n description:\n 'Require unit tests to be `*.test.*` files in a `__tests__/` folder beside the code they test \u2014 the feature root\u2019s inside a frontend feature.',\n recommended: true,\n url: 'https://github.com/ArthurSaenz/infra-kit/tree/main/apps/infra-kit/eslint-plugin#test-location',\n },\n schema: [\n {\n type: 'object',\n properties: {\n ignore: {\n type: 'array',\n items: { type: 'string' },\n description: 'Optional globs; the rule is skipped for matching files.',\n },\n },\n additionalProperties: false,\n },\n ],\n messages: {\n outsideTestsDir:\n '`{{basename}}` sits next to its source. Move it to `{{target}}` \u2014 tests live in a `__tests__/` folder beside the code they test.',\n outsideFeatureTestsDir:\n '`{{basename}}` is a feature test outside the feature root. Move it to `{{target}}` \u2014 a feature keeps all its tests in one `__tests__/` at its root.',\n specSuffix:\n '`{{basename}}` uses `.spec`. Rename it to `{{target}}` \u2014 unit tests are `*.test.*`; `.spec` belongs to Playwright specs in an e2e package.',\n },\n },\n\n create(context) {\n const options = (context.options[0] ?? {}) as Options\n const violations = findViolations(context.filename.split('\\\\').join('/'), options.ignore ?? [])\n\n if (violations.length === 0) {\n return {}\n }\n\n return {\n // Reported on Program: the violation is the file's location, not any node inside it.\n Program(program) {\n for (const violation of violations) {\n context.report({ node: program, messageId: violation.messageId, data: violation.data })\n }\n },\n }\n },\n}\n", "import type { Rule } from 'eslint'\n\n// Each './<rule>' resolves to './<rule>/index.ts' (the rule's folder barrel) under\n// `moduleResolution: bundler`; a future switch to node16/nodenext would require explicit paths.\nimport { atomNaming } from './atom-naming'\nimport { componentArrowFunction } from './component-arrow-function'\nimport { componentClassname } from './component-classname'\nimport { componentFileOrder } from './component-file-order'\nimport { componentNameMatchesFile } from './component-name-matches-file'\nimport { dumbComponentPurity } from './dumb-component-purity'\nimport { e2eDescribeOrder } from './e2e-describe-order'\nimport { e2eFileLayout } from './e2e-file-layout'\nimport { e2eFileOrder } from './e2e-file-order'\nimport { e2ePageObjectMemberOrder } from './e2e-page-object-member-order'\nimport { e2eTestTags } from './e2e-test-tags'\nimport { e2eTestTitle } from './e2e-test-title'\nimport { e2eTopLevelDescribe } from './e2e-top-level-describe'\nimport { featureFiles } from './feature-files'\nimport { featurePublicApi } from './feature-public-api'\nimport { layerImports } from './layer-imports'\nimport { maxComponentsPerFile } from './max-components-per-file'\nimport { maxJsdocLines } from './max-jsdoc-lines'\nimport { maxJsdocSummaryLines } from './max-jsdoc-summary-lines'\nimport { maxJsxReturnSize } from './max-jsx-return-size'\nimport { noFeatureSelfImport } from './no-feature-self-import'\nimport { noHooksInServices } from './no-hooks-in-services'\nimport { packageStructure } from './package-structure'\nimport { propsDestructuringBlankLine } from './props-destructuring-blank-line'\nimport { propsDestructuringNewline } from './props-destructuring-newline'\nimport { propsTypeName } from './props-type-name'\nimport { propsTypeReference } from './props-type-reference'\nimport { requireComponentStories } from './require-component-stories'\nimport { requireJsdocExample } from './require-jsdoc-example'\nimport { servicesNamespaceImport } from './services-namespace-import'\nimport { testLocation } from './test-location'\n\nexport const rules: Record<string, Rule.RuleModule> = {\n 'props-destructuring-newline': propsDestructuringNewline,\n 'props-destructuring-blank-line': propsDestructuringBlankLine,\n 'props-type-reference': propsTypeReference,\n 'props-type-name': propsTypeName,\n 'component-file-order': componentFileOrder,\n 'component-arrow-function': componentArrowFunction,\n 'max-components-per-file': maxComponentsPerFile,\n 'max-jsx-return-size': maxJsxReturnSize,\n 'max-jsdoc-lines': maxJsdocLines,\n 'max-jsdoc-summary-lines': maxJsdocSummaryLines,\n 'require-component-stories': requireComponentStories,\n 'require-jsdoc-example': requireJsdocExample,\n 'package-structure': packageStructure,\n 'test-location': testLocation,\n 'layer-imports': layerImports,\n 'feature-public-api': featurePublicApi,\n 'no-feature-self-import': noFeatureSelfImport,\n 'e2e-file-layout': e2eFileLayout,\n 'e2e-file-order': e2eFileOrder,\n 'e2e-page-object-member-order': e2ePageObjectMemberOrder,\n 'e2e-describe-order': e2eDescribeOrder,\n 'e2e-top-level-describe': e2eTopLevelDescribe,\n 'e2e-test-tags': e2eTestTags,\n 'e2e-test-title': e2eTestTitle,\n 'atom-naming': atomNaming,\n 'no-hooks-in-services': noHooksInServices,\n 'feature-files': featureFiles,\n 'services-namespace-import': servicesNamespaceImport,\n 'component-name-matches-file': componentNameMatchesFile,\n 'component-classname': componentClassname,\n 'dumb-component-purity': dumbComponentPurity,\n}\n", "import type { ESLint, Linter } from 'eslint'\n\nimport { rules } from './rules'\n\nconst PLUGIN_NAME = '@wl'\n\nconst plugin: ESLint.Plugin & { configs: Record<string, Linter.Config | Linter.Config[]> } = {\n meta: {\n name: '@wl/eslint-plugin',\n version: '0.45.0',\n },\n rules,\n configs: {},\n}\n\n/**\n * Flat-config preset that registers the plugin and turns every rule on, scoped to\n * the files each rule is meant for. It is an array of config blocks, so spread it:\n *\n * @example\n * import wl from '@wl/eslint-plugin'\n *\n * export default [...wl.configs.recommended]\n */\nplugin.configs.recommended = [\n {\n files: ['**/*.tsx'],\n plugins: {\n [PLUGIN_NAME]: plugin,\n },\n rules: {\n [`${PLUGIN_NAME}/props-destructuring-newline`]: 'error',\n [`${PLUGIN_NAME}/props-destructuring-blank-line`]: 'error',\n [`${PLUGIN_NAME}/props-type-reference`]: 'error',\n [`${PLUGIN_NAME}/props-type-name`]: 'error',\n [`${PLUGIN_NAME}/component-file-order`]: 'error',\n // Pages and routes are excluded: route/page modules commonly use `function`\n // declarations (and framework conventions like default-exported page functions).\n [`${PLUGIN_NAME}/component-arrow-function`]: ['error', { ignore: ['**/pages/**', '**/routes/**'] }],\n [`${PLUGIN_NAME}/require-component-stories`]: 'error',\n // Advisory: flags returns that render too many JSX elements; extract into a\n // variable or sub-component. Warn-class by nature (`type: 'suggestion'`);\n // severity confirmed against a repo-wide dry run at the default ceiling.\n [`${PLUGIN_NAME}/max-jsx-return-size`]: 'error',\n // Caps component declarations per file; extra components belong in their own\n // files. Pages and routes are excluded (framework conventions co-locate\n // route trees and default-exported page functions). Ceiling confirmed\n // against a repo-wide dry run at the default.\n [`${PLUGIN_NAME}/max-components-per-file`]: ['error', { ignore: ['**/pages/**', '**/routes/**'] }],\n },\n },\n // Storybook stories legitimately deviate from the component conventions: the\n // imports \u2192 *Props \u2192 component order (meta/args/decorators/render fns), and\n // named templates that reference the *component's* props type (e.g.\n // `const Template = (args: ButtonProps) => ...`) rather than their own\n // `<TemplateName>Props`. So both the ordering and the props-type-name rules\n // would only produce noise there. Every other rule stays enabled for stories.\n {\n files: ['**/*.stories.{ts,tsx}'],\n rules: {\n [`${PLUGIN_NAME}/component-file-order`]: 'off',\n [`${PLUGIN_NAME}/props-type-name`]: 'off',\n },\n },\n // Dumb presentational files (`*-component.tsx`) follow the one-component-per-file\n // convention the props/order/stories rules already assume, so they get a tighter\n // ceiling of 1. This MUST come AFTER the global `**/*.tsx` block: flat config\n // REPLACES rule options across matching blocks (it does not merge), and `ignore`\n // is re-declared here so pages/routes dumb-components keep their exemption.\n // A repo-wide dry run found zero `*-component.tsx` files declaring >1 component.\n {\n files: ['**/*-component.tsx'],\n rules: {\n [`${PLUGIN_NAME}/max-components-per-file`]: [\n 'error',\n { maxComponents: 1, ignore: ['**/pages/**', '**/routes/**'] },\n ],\n },\n },\n // `require-jsdoc-example` targets named functions, which overwhelmingly live in\n // plain `.ts` lib/util modules (not just `.tsx`), so it gets its OWN block scoped\n // to both extensions \u2014 the tsx-only blocks above would never reach where it\n // matters. Severity is `warn` (not `error`) so first adoption does not break\n // consumers' CI; the graduated defaults (minComplexity 8 \u2192 require a JSDoc block,\n // exampleComplexity 12 \u2192 also require `@example`) are left implicit. Flat config\n // REPLACES rule options across matching blocks, so this rule lives only here and\n // relies on no option merging.\n {\n files: ['**/*.ts', '**/*.tsx'],\n plugins: {\n [PLUGIN_NAME]: plugin,\n },\n rules: {\n [`${PLUGIN_NAME}/require-jsdoc-example`]: 'warn',\n },\n },\n // `package-structure` judges a file by its directory, not its contents, so it must reach every\n // source extension \u2014 the `**/*.tsx` block above would never see a `.ts` under `src/core/`. Its\n // own block (like `require-jsdoc-example`) with `plugins` re-declared keeps it self-contained.\n // `error` from day one: the per-type entries are overridable per package via `config({ rules })`.\n {\n files: ['**/*.{ts,tsx,js,jsx}'],\n plugins: {\n [PLUGIN_NAME]: plugin,\n },\n rules: {\n [`${PLUGIN_NAME}/package-structure`]: 'error',\n },\n },\n // Scoped by filename, so it never runs on non-test files. e2e packages are exempt inside the rule\n // (by package type); `*.e2e.test.*` covers e2e suites that sit in a package of another type.\n {\n files: ['**/*.{test,spec}.{ts,tsx,js,jsx,mts,cts,mjs,cjs}'],\n plugins: {\n [PLUGIN_NAME]: plugin,\n },\n rules: {\n [`${PLUGIN_NAME}/test-location`]: ['error', { ignore: ['**/*.e2e.test.*'] }],\n },\n },\n // Import-path rules read where a specifier lands under `src/`, so they reach every source extension.\n // They gate themselves on the package type (backend and e2e packages have no UI layering).\n {\n files: ['**/*.{ts,tsx,js,jsx,mts,cts,mjs,cjs}'],\n plugins: {\n [PLUGIN_NAME]: plugin,\n },\n rules: {\n [`${PLUGIN_NAME}/layer-imports`]: 'error',\n [`${PLUGIN_NAME}/feature-public-api`]: 'error',\n [`${PLUGIN_NAME}/no-feature-self-import`]: 'error',\n },\n },\n // fe-architect naming and purity rules. Each gates itself on path and package type (backend and e2e\n // packages are skipped), so one repo-wide block is enough.\n {\n files: ['**/*.{ts,tsx}'],\n plugins: {\n [PLUGIN_NAME]: plugin,\n },\n rules: {\n [`${PLUGIN_NAME}/atom-naming`]: 'error',\n [`${PLUGIN_NAME}/no-hooks-in-services`]: 'error',\n [`${PLUGIN_NAME}/feature-files`]: 'error',\n [`${PLUGIN_NAME}/services-namespace-import`]: 'error',\n [`${PLUGIN_NAME}/component-name-matches-file`]: 'error',\n [`${PLUGIN_NAME}/component-classname`]: 'error',\n [`${PLUGIN_NAME}/dumb-component-purity`]: 'error',\n },\n },\n // The e2e rules gate themselves on the package type, so a repo-wide glob costs one cached type\n // lookup per file elsewhere.\n {\n files: ['**/*.{ts,tsx,js,jsx,mts,cts,mjs,cjs}'],\n plugins: {\n [PLUGIN_NAME]: plugin,\n },\n rules: {\n [`${PLUGIN_NAME}/e2e-file-layout`]: 'error',\n [`${PLUGIN_NAME}/e2e-file-order`]: 'error',\n [`${PLUGIN_NAME}/e2e-page-object-member-order`]: 'error',\n [`${PLUGIN_NAME}/e2e-describe-order`]: 'error',\n [`${PLUGIN_NAME}/e2e-top-level-describe`]: 'error',\n [`${PLUGIN_NAME}/e2e-test-tags`]: 'error',\n [`${PLUGIN_NAME}/e2e-test-title`]: 'error',\n },\n },\n]\n\nexport const meta: ESLint.Plugin['meta'] = plugin.meta\nexport const configs: Record<string, Linter.Config | Linter.Config[]> = plugin.configs\nexport { rules }\n\nexport default plugin\n"],
5
+ "mappings": "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",
6
6
  "names": ["fn", "path", "fs", "path", "fs", "path", "attribute", "path", "featureRoot", "path", "component", "calleeNames", "unwrapExport", "end", "buildFix", "SPEC_FILE", "buildFix", "fs", "path", "path", "path", "path", "fs", "TEST_FILE", "ANONYMOUS_NAME", "fn", "DEFAULT_EXEMPT_TAGS", "isJsdocBlock", "strippedLines", "tagNameOf", "hasExemptTag", "ANONYMOUS_NAME", "walk", "element", "componentFunctionsIn", "fn", "collectComponents", "DEFAULT_PATHS", "HOOK_NAME", "TEST_OR_STORY_DIR", "findViolation", "PROPS_SUFFIX", "path", "path", "path", "isNode", "TEST_FILE", "findViolations"]
7
7
  }