@slip-stream-kit/eslint-plugin 0.4.0 → 0.5.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 +1 -1
- package/dist/index.js.map +2 -2
- package/package.json +5 -5
package/dist/index.js
CHANGED
package/dist/index.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/utils/component.ts", "../src/utils/path-match.ts", "../src/rules/component-arrow-function/component-arrow-function.ts", "../src/rules/component-file-order/component-file-order.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/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/index.ts", "../src/index.ts"],
|
|
4
|
-
"sourcesContent": ["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 current.body.forEach(visit)\n\n return\n }\n\n if (current.type === 'SwitchStatement') {\n for (const switchCase of current.cases) {\n switchCase.consequent.forEach(visit)\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 node.body.body.forEach(visit)\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", "// 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 { 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 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 body.forEach((statement, index) => {\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 return\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 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 } 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/**\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 *\n * KNOWN PARSER HAZARD: any line opening with `@` ends the body, so a decorator\n * (`@Injectable`) written inside an `@example` truncates it early. The effect is worse than an\n * under-count: the truncated lines are recharged to PROSE, so the block reports `tooManyLines`\n * and advises `@fileoverview` \u2014 misleading advice for a block whose real problem is a long\n * example. A scan of all 637 example bodies in the corpus found ZERO lines starting with `@`\n * that were not real tags, so this is correct today \u2014 measured, not assumed, and not\n * future-proof. A real JSDoc parser is the fix if that ever stops holding.\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 collectComponents(program.body).forEach(checkComponent)\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\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 { componentArrowFunction } from './component-arrow-function'\nimport { componentFileOrder } from './component-file-order'\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 { 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'\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}\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.4.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]\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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",
|
|
4
|
+
"sourcesContent": ["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 current.body.forEach(visit)\n\n return\n }\n\n if (current.type === 'SwitchStatement') {\n for (const switchCase of current.cases) {\n switchCase.consequent.forEach(visit)\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 node.body.body.forEach(visit)\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", "// 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 { 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 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 body.forEach((statement, index) => {\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 return\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 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 } 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 collectComponents(program.body).forEach(checkComponent)\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\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 { componentArrowFunction } from './component-arrow-function'\nimport { componentFileOrder } from './component-file-order'\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 { 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'\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}\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.5.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]\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", "ANONYMOUS_NAME", "fn", "DEFAULT_EXEMPT_TAGS", "isJsdocBlock", "strippedLines", "tagNameOf", "hasExemptTag", "ANONYMOUS_NAME", "walk", "element", "componentFunctionsIn", "fn", "collectComponents", "PROPS_SUFFIX", "path", "path", "isNode"]
|
|
7
7
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@slip-stream-kit/eslint-plugin",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.5.0",
|
|
5
5
|
"description": "Custom ESLint rules enforcing the white-label frontend architecture conventions",
|
|
6
6
|
"author": "Arthur Saenko <arthur.saenz7@gmail.com> (https://github.com/ArthurSaenz)",
|
|
7
7
|
"license": "MIT",
|
|
@@ -36,12 +36,12 @@
|
|
|
36
36
|
"eslint": ">=9"
|
|
37
37
|
},
|
|
38
38
|
"devDependencies": {
|
|
39
|
-
"@types/node": "^26.
|
|
40
|
-
"@typescript-eslint/parser": "^8.
|
|
39
|
+
"@types/node": "^26.5.0",
|
|
40
|
+
"@typescript-eslint/parser": "^8.70.0",
|
|
41
41
|
"esbuild": "^0.28.2",
|
|
42
|
-
"eslint": "^10.
|
|
42
|
+
"eslint": "^10.10.0",
|
|
43
43
|
"typescript": "^6.0.3",
|
|
44
|
-
"vitest": "^
|
|
44
|
+
"vitest": "^5.0.0",
|
|
45
45
|
"@wl/eslint-config": "0.1.0"
|
|
46
46
|
},
|
|
47
47
|
"scripts": {
|