eslint-plugin-functype 1.2.0 → 2.0.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.
Files changed (47) hide show
  1. package/README.md +86 -44
  2. package/dist/chunk-BlXvk904.js +1 -0
  3. package/dist/cli/list-rules.d.ts +1 -1
  4. package/dist/cli/list-rules.js +15 -239
  5. package/dist/cli/list-rules.js.map +1 -1
  6. package/dist/index.d.ts +19 -16
  7. package/dist/index.js +1 -1075
  8. package/dist/index.js.map +1 -1
  9. package/dist/rules/index.d.ts +24 -29
  10. package/dist/rules/index.js +1 -1071
  11. package/dist/rules/index.js.map +1 -1
  12. package/dist/rules/no-get-unsafe.d.ts +7 -0
  13. package/dist/rules/no-get-unsafe.js +2 -0
  14. package/dist/rules/no-get-unsafe.js.map +1 -0
  15. package/dist/rules/no-imperative-loops.d.ts +7 -0
  16. package/dist/rules/no-imperative-loops.js +2 -0
  17. package/dist/rules/no-imperative-loops.js.map +1 -0
  18. package/dist/rules/prefer-do-notation.d.ts +7 -0
  19. package/dist/rules/prefer-do-notation.js +5 -0
  20. package/dist/rules/prefer-do-notation.js.map +1 -0
  21. package/dist/rules/prefer-either.d.ts +7 -0
  22. package/dist/rules/prefer-either.js +2 -0
  23. package/dist/rules/prefer-either.js.map +1 -0
  24. package/dist/rules/prefer-flatmap.d.ts +7 -0
  25. package/dist/rules/prefer-flatmap.js +2 -0
  26. package/dist/rules/prefer-flatmap.js.map +1 -0
  27. package/dist/rules/prefer-fold.d.ts +7 -0
  28. package/dist/rules/prefer-fold.js +2 -0
  29. package/dist/rules/prefer-fold.js.map +1 -0
  30. package/dist/rules/prefer-list.d.ts +7 -0
  31. package/dist/rules/prefer-list.js +2 -0
  32. package/dist/rules/prefer-list.js.map +1 -0
  33. package/dist/rules/prefer-map.d.ts +7 -0
  34. package/dist/rules/prefer-map.js +2 -0
  35. package/dist/rules/prefer-map.js.map +1 -0
  36. package/dist/rules/prefer-option.d.ts +7 -0
  37. package/dist/rules/prefer-option.js +2 -0
  38. package/dist/rules/prefer-option.js.map +1 -0
  39. package/dist/types/ast.d.ts +12 -0
  40. package/dist/types/ast.js +1 -0
  41. package/dist/utils/dependency-validator.d.ts +13 -11
  42. package/dist/utils/dependency-validator.js +3 -108
  43. package/dist/utils/dependency-validator.js.map +1 -1
  44. package/dist/utils/functype-detection.d.ts +69 -0
  45. package/dist/utils/functype-detection.js +2 -0
  46. package/dist/utils/functype-detection.js.map +1 -0
  47. package/package.json +37 -34
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/utils/functype-detection.ts","../../src/rules/prefer-option.ts","../../src/rules/prefer-either.ts","../../src/rules/prefer-list.ts","../../src/rules/no-get-unsafe.ts","../../src/rules/prefer-fold.ts","../../src/rules/prefer-map.ts","../../src/rules/prefer-flatmap.ts","../../src/rules/no-imperative-loops.ts","../../src/rules/index.ts"],"names":["preferOption","preferEither","preferList","noGetUnsafe","preferFold","preferMap","preferFlatmap","noImperativeLoops"],"mappings":"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","file":"index.js","sourcesContent":["import type { Rule } from \"eslint\"\nimport type { ASTNode } from \"../types/ast\"\n\n/**\n * Utility functions for detecting functype library usage in ESLint rules\n */\n\n/**\n * Check if functype library is imported in the current file\n */\nexport function hasFunctypeImport(context: Rule.RuleContext): boolean {\n const sourceCode = context.sourceCode\n const program = sourceCode.ast\n \n // Look for import statements that import from 'functype'\n for (const node of program.body) {\n if (node.type === \"ImportDeclaration\" && \n node.source.type === \"Literal\" && \n node.source.value === \"functype\") {\n return true\n }\n }\n \n return false\n}\n\n/**\n * Get imported functype symbols from the current file\n */\nexport function getFunctypeImports(context: Rule.RuleContext): Set<string> {\n const imports = new Set<string>()\n const sourceCode = context.sourceCode\n const program = sourceCode.ast\n \n for (const node of program.body) {\n if (node.type === \"ImportDeclaration\" && \n node.source.type === \"Literal\" && \n node.source.value === \"functype\") {\n \n // Handle named imports: import { Option, Either } from 'functype'\n if (node.specifiers) {\n for (const spec of node.specifiers) {\n if (spec.type === \"ImportSpecifier\" && spec.imported.type === \"Identifier\") {\n imports.add(spec.imported.name)\n } else if (spec.type === \"ImportDefaultSpecifier\") {\n imports.add(\"default\")\n } else if (spec.type === \"ImportNamespaceSpecifier\") {\n imports.add(\"*\")\n }\n }\n }\n }\n }\n \n return imports\n}\n\n/**\n * Check if a type reference is using functype types\n */\nexport function isFunctypeType(node: ASTNode, functypeImports: Set<string>): boolean {\n if (!node) return false\n \n // Check direct type names\n if (node.type === \"TSTypeReference\" && node.typeName?.type === \"Identifier\") {\n const typeName = node.typeName.name\n return functypeImports.has(typeName) || \n [\"Option\", \"Either\", \"List\", \"LazyList\", \"Task\"].includes(typeName)\n }\n \n return false\n}\n\n/**\n * Check if a call expression is using functype methods\n */\nexport function isFunctypeCall(node: ASTNode, functypeImports: Set<string>): boolean {\n if (!node || node.type !== \"CallExpression\") return false\n \n const callee = node.callee\n \n // Check for static method calls like Option.some(), Either.left(), List.of()\n if (callee.type === \"MemberExpression\" && \n callee.object.type === \"Identifier\") {\n const objectName = callee.object.name\n const methodName = callee.property?.name\n \n // Check if calling methods on imported functype types\n if (functypeImports.has(objectName)) return true\n \n // Check for common functype patterns\n if ((objectName === \"Option\" && [\"some\", \"none\", \"of\"].includes(methodName)) ||\n (objectName === \"Either\" && [\"left\", \"right\", \"of\"].includes(methodName)) ||\n (objectName === \"List\" && [\"of\", \"from\", \"empty\"].includes(methodName))) {\n return true\n }\n }\n \n // Check for method calls on functype instances like someOption.map()\n if (callee.type === \"MemberExpression\") {\n const methodName = callee.property?.name\n \n // Common functype methods\n if ([\"map\", \"flatMap\", \"filter\", \"fold\", \"foldLeft\", \"foldRight\", \n \"getOrElse\", \"orElse\", \"isEmpty\", \"nonEmpty\", \"isDefined\",\n \"isSome\", \"isNone\", \"isLeft\", \"isRight\", \"toArray\"].includes(methodName)) {\n return true\n }\n }\n \n return false\n}\n\n/**\n * Check if current context is already using functype patterns appropriately\n */\nexport function isAlreadyUsingFunctype(node: ASTNode, functypeImports: Set<string>): boolean {\n let parent = node.parent\n \n // Walk up the AST to find functype usage\n while (parent) {\n if (isFunctypeCall(parent as ASTNode, functypeImports) || \n isFunctypeType(parent as ASTNode, functypeImports)) {\n return true\n }\n parent = parent.parent\n }\n \n return false\n}\n\n/**\n * Check if a variable or parameter is typed with functype types\n */\nexport function hasFunctypeTypeAnnotation(node: ASTNode, functypeImports: Set<string>): boolean {\n // Check for type annotation\n if (node.typeAnnotation?.typeAnnotation) {\n return isFunctypeType(node.typeAnnotation.typeAnnotation, functypeImports)\n }\n \n return false\n}","import type { Rule } from \"eslint\"\nimport type { ASTNode } from \"../types/ast\"\nimport { getFunctypeImports, isFunctypeType, isAlreadyUsingFunctype } from \"../utils/functype-detection\"\n\nconst rule: Rule.RuleModule = {\n meta: {\n type: \"suggestion\",\n docs: {\n description: \"Prefer Option<T> over nullable types (T | null | undefined)\",\n category: \"Stylistic Issues\",\n recommended: true,\n },\n fixable: \"code\",\n schema: [\n {\n type: \"object\",\n properties: {\n allowNullableIntersections: {\n type: \"boolean\",\n default: false,\n },\n },\n additionalProperties: false,\n },\n ],\n messages: {\n preferOption: \"Prefer Option<{{type}}> over nullable type '{{nullable}}'\",\n preferOptionReturn: \"Prefer Option<{{type}}> as return type over nullable '{{nullable}}'\",\n },\n },\n\n create(context) {\n // const options = context.options[0] || {}\n // Remove unused variable\n // const _allowNullableIntersections = options.allowNullableIntersections || false\n\n // Get functype imports if available (but still apply rule even without explicit import)\n const functypeImports = getFunctypeImports(context)\n\n return {\n TSUnionType(node: ASTNode) {\n if (!node.types || node.types.length < 2) return\n\n const hasNull = node.types.some((type: ASTNode) => \n type.type === \"TSNullKeyword\" || type.type === \"TSUndefinedKeyword\"\n )\n \n if (!hasNull) return\n\n const nonNullTypes = node.types.filter((type: ASTNode) => \n type.type !== \"TSNullKeyword\" && type.type !== \"TSUndefinedKeyword\"\n )\n\n if (nonNullTypes.length === 1) {\n const nonNullType = nonNullTypes[0]\n \n // Skip if it's already an Option type or other functype type\n if (isFunctypeType(nonNullType, functypeImports)) return\n \n // Skip if we're already in a functype context\n if (isAlreadyUsingFunctype(node, functypeImports)) return\n \n const sourceCode = context.sourceCode\n const nonNullTypeText = sourceCode.getText(nonNullType)\n const fullType = sourceCode.getText(node)\n \n // Skip if it's already an Option type (fallback check)\n if (nonNullTypeText.startsWith(\"Option<\")) return\n \n context.report({\n node,\n messageId: \"preferOption\",\n data: {\n type: nonNullTypeText,\n nullable: fullType,\n },\n fix(fixer) {\n return fixer.replaceText(node, `Option<${nonNullTypeText}>`)\n },\n })\n }\n },\n }\n },\n}\n\nexport = rule","import type { Rule } from \"eslint\"\nimport type { ASTNode } from \"../types/ast\"\n\nconst rule: Rule.RuleModule = {\n meta: {\n type: \"suggestion\",\n docs: {\n description: \"Prefer Either<E, T> over try/catch blocks and throw statements\",\n category: \"Best Practices\",\n recommended: true,\n },\n schema: [\n {\n type: \"object\",\n properties: {\n allowThrowInTests: {\n type: \"boolean\",\n default: true,\n },\n },\n additionalProperties: false,\n },\n ],\n messages: {\n preferEitherOverTryCatch: \"Prefer Either<Error, T> over try/catch block\",\n preferEitherOverThrow: \"Prefer Either.left(error) over throw statement\",\n preferEitherReturn: \"Consider returning Either<Error, {{type}}> instead of throwing\",\n },\n },\n\n create(context) {\n const options = context.options[0] || {}\n const allowThrowInTests = options.allowThrowInTests !== false\n\n function isInTestFile() {\n const filename = context.getFilename()\n return /\\.(test|spec)\\.(ts|js|tsx|jsx)$/.test(filename) ||\n filename.includes(\"__tests__\") ||\n filename.includes(\"/test/\") ||\n filename.includes(\"/tests/\")\n }\n\n\n function hasThrowStatementsOutsideCatch(node: ASTNode): boolean {\n if (!node) return false\n \n if (node.type === \"ThrowStatement\") {\n // Check if this throw is inside a catch block\n let parent = node.parent\n while (parent) {\n if (parent.type === \"CatchClause\") return false\n parent = parent.parent\n }\n return true\n }\n \n // Skip catch blocks when recursing\n if (node.type === \"CatchClause\") return false\n \n // Recursively check child nodes\n for (const key in node) {\n if (key === \"parent\") continue // Avoid circular references\n const child = node[key]\n if (Array.isArray(child)) {\n for (const item of child) {\n if (item && typeof item === \"object\" && hasThrowStatementsOutsideCatch(item)) {\n return true\n }\n }\n } else if (child && typeof child === \"object\" && hasThrowStatementsOutsideCatch(child)) {\n return true\n }\n }\n \n return false\n }\n\n return {\n TryStatement(node: ASTNode) {\n // Allow try/catch in test files\n if (allowThrowInTests && isInTestFile()) return\n \n // Allow try/catch that re-throws in the catch block (even with logging)\n if (node.handler && node.handler.body) {\n const catchBody = node.handler.body.body\n const hasRethrow = catchBody.some((stmt: ASTNode) => stmt.type === \"ThrowStatement\")\n if (hasRethrow) return\n }\n \n context.report({\n node,\n messageId: \"preferEitherOverTryCatch\",\n })\n },\n\n ThrowStatement(node: ASTNode) {\n // Allow throws in test files if configured\n if (allowThrowInTests && isInTestFile()) return\n\n // Allow re-throwing in catch blocks (common pattern)\n let parent = node.parent\n while (parent) {\n if (parent.type === \"CatchClause\") return\n parent = parent.parent\n }\n\n context.report({\n node,\n messageId: \"preferEitherOverThrow\",\n })\n },\n\n FunctionDeclaration(node: ASTNode) {\n // Allow functions in test files\n if (allowThrowInTests && isInTestFile()) return\n \n if (!node.body) return\n\n // Only report function-level errors if there are throws NOT in catch blocks\n // (throws in catch blocks are handled by ThrowStatement rule)\n const hasThrowsNotInCatch = hasThrowStatementsOutsideCatch(node.body)\n if (hasThrowsNotInCatch) {\n const returnType = node.returnType?.typeAnnotation\n if (returnType) {\n const sourceCode = context.sourceCode\n const returnTypeText = sourceCode.getText(returnType)\n \n // Don't report if already using Either\n if (!returnTypeText.includes(\"Either\")) {\n context.report({\n node: node.id || node,\n messageId: \"preferEitherReturn\",\n data: { type: returnTypeText },\n })\n }\n }\n }\n },\n\n }\n },\n}\n\nexport = rule","import type { Rule } from \"eslint\"\nimport type { ASTNode } from \"../types/ast\"\nimport { getFunctypeImports, isFunctypeCall } from \"../utils/functype-detection\"\n\nconst rule: Rule.RuleModule = {\n meta: {\n type: \"suggestion\",\n docs: {\n description: \"Prefer List<T> over native arrays for immutable collections\",\n category: \"Stylistic Issues\",\n recommended: true,\n },\n fixable: \"code\",\n schema: [\n {\n type: \"object\",\n properties: {\n allowArraysInTests: {\n type: \"boolean\",\n default: true,\n },\n allowReadonlyArrays: {\n type: \"boolean\", \n default: true,\n },\n },\n additionalProperties: false,\n },\n ],\n messages: {\n preferList: \"Prefer List<{{type}}> over array type {{arrayType}}\",\n preferListLiteral: \"Prefer List.of(...) or List.from([...]) over array literal\",\n },\n },\n\n create(context) {\n const options = context.options[0] || {}\n const allowArraysInTests = options.allowArraysInTests !== false\n const allowReadonlyArrays = options.allowReadonlyArrays !== false\n\n // Get functype imports if available (but still apply rule even without explicit import)\n const functypeImports = getFunctypeImports(context)\n\n function isInTestFile() {\n const filename = context.getFilename()\n return /\\.(test|spec)\\.(ts|js|tsx|jsx)$/.test(filename) ||\n filename.includes(\"__tests__\") ||\n filename.includes(\"/test/\") ||\n filename.includes(\"/tests/\")\n }\n\n function findTypeParameter(node: ASTNode, sourceCode: typeof context.sourceCode): string | null {\n // Look for TSTypeParameterInstantiation child\n function findInNode(n: ASTNode): string | null {\n if (n.type === \"TSTypeParameterInstantiation\" && n.params && n.params[0]) {\n return sourceCode.getText(n.params[0])\n }\n \n // Recursively search child nodes\n for (const key in n) {\n if (key === \"parent\") continue\n const child = n[key]\n if (Array.isArray(child)) {\n for (const item of child) {\n if (item && typeof item === \"object\" && item.type) {\n const result = findInNode(item)\n if (result) return result\n }\n }\n } else if (child && typeof child === \"object\" && child.type) {\n const result = findInNode(child)\n if (result) return result\n }\n }\n \n return null\n }\n \n return findInNode(node)\n }\n\n return {\n TSArrayType(node: ASTNode) {\n if (allowArraysInTests && isInTestFile()) return\n\n const sourceCode = context.sourceCode\n const elementType = sourceCode.getText(node.elementType)\n const fullType = sourceCode.getText(node)\n\n context.report({\n node,\n messageId: \"preferList\",\n data: {\n type: elementType,\n arrayType: fullType,\n },\n fix(fixer) {\n return fixer.replaceText(node, `List<${elementType}>`)\n },\n })\n },\n\n TSTypeReference(node: ASTNode) {\n if (allowArraysInTests && isInTestFile()) return\n\n const sourceCode = context.sourceCode\n \n // Get type name - handle both simple identifiers and member expressions\n let typeName = \"\"\n if (node.typeName && node.typeName.type === \"Identifier\") {\n typeName = node.typeName.name\n } else if (node.typeName) {\n typeName = sourceCode.getText(node.typeName)\n } else {\n return // No type name found\n }\n\n // Handle Array<T> syntax\n if (typeName === \"Array\") {\n // Look for type parameters in child nodes\n const typeParam = findTypeParameter(node, sourceCode)\n const fullType = sourceCode.getText(node)\n\n // Skip if already readonly\n if (allowReadonlyArrays && fullType.startsWith(\"readonly\")) return\n\n context.report({\n node,\n messageId: \"preferList\",\n data: {\n type: typeParam || \"T\",\n arrayType: fullType,\n },\n fix(fixer) {\n return fixer.replaceText(node, `List<${typeParam || \"T\"}>`)\n },\n })\n }\n\n // Handle ReadonlyArray<T> - suggest List even if allowing readonly arrays\n if (typeName === \"ReadonlyArray\") {\n const typeParam = findTypeParameter(node, sourceCode)\n const fullType = sourceCode.getText(node)\n\n context.report({\n node,\n messageId: \"preferList\",\n data: {\n type: typeParam || \"T\",\n arrayType: fullType,\n },\n fix(fixer) {\n return fixer.replaceText(node, `List<${typeParam || \"T\"}>`)\n },\n })\n }\n },\n\n ArrayExpression(node: ASTNode) {\n if (allowArraysInTests && isInTestFile()) return\n\n // Only flag non-empty arrays to avoid noise\n if (node.elements.length === 0) return\n\n // Don't flag arrays that are already arguments to List.from() or other functype calls\n let parent = node.parent\n if (parent && isFunctypeCall(parent, functypeImports)) {\n return\n }\n \n // Additional specific check for List.from/List.of patterns\n if (parent && parent.type === \"CallExpression\" && \n parent.callee.type === \"MemberExpression\" &&\n parent.callee.object.type === \"Identifier\" &&\n parent.callee.object.name === \"List\" &&\n [\"from\", \"of\"].includes(parent.callee.property.name)) {\n return\n }\n\n // Don't flag nested array literals - only flag the outermost one\n // Check if this array is inside another array literal\n parent = node.parent\n while (parent) {\n if (parent.type === \"ArrayExpression\") {\n return // Skip nested arrays, let the outer one handle it\n }\n parent = parent.parent\n }\n\n // Don't flag array literals that are already part of a type annotation context\n // (those should be handled by the type checking rules)\n let hasTypeAnnotation = false\n parent = node.parent\n while (parent) {\n if (parent.type === \"VariableDeclarator\" && parent.id?.typeAnnotation) {\n // Skip array literal if there's already a type annotation that would be flagged\n hasTypeAnnotation = true\n break\n }\n if (parent.type === \"TSTypeAnnotation\") {\n hasTypeAnnotation = true\n break\n }\n parent = parent.parent\n }\n \n if (hasTypeAnnotation) return\n\n context.report({\n node,\n messageId: \"preferListLiteral\",\n fix(fixer) {\n const sourceCode = context.sourceCode\n const elements = sourceCode.getText(node)\n return fixer.replaceText(node, `List.from(${elements})`)\n },\n })\n },\n }\n },\n}\n\nexport = rule","import type { Rule } from \"eslint\"\nimport type { ASTNode } from \"../types/ast\"\n\nconst rule: Rule.RuleModule = {\n meta: {\n type: \"problem\",\n docs: {\n description: \"Avoid unsafe .get() calls on Option, Either, and other monadic types\",\n category: \"Possible Errors\",\n recommended: true,\n },\n schema: [\n {\n type: \"object\",\n properties: {\n allowInTests: {\n type: \"boolean\",\n default: true,\n },\n unsafeMethods: {\n type: \"array\",\n items: { type: \"string\" },\n default: [\"get\", \"getOrThrow\", \"unwrap\", \"expect\"],\n },\n },\n additionalProperties: false,\n },\n ],\n messages: {\n noUnsafeGet: \"Avoid unsafe .{{method}}() call. Use .fold(), .map(), or .getOrElse() instead\",\n noUnsafeGetSuggestion: \"Consider using .getOrElse(defaultValue) or .fold() for safe access\",\n },\n },\n\n create(context) {\n const options = context.options[0] || {}\n const allowInTests = options.allowInTests !== false\n const unsafeMethods = options.unsafeMethods || [\"get\", \"getOrThrow\", \"unwrap\", \"expect\"]\n\n function isInTestFile() {\n const filename = context.getFilename()\n return /\\.(test|spec)\\.(ts|js|tsx|jsx)$/.test(filename) ||\n filename.includes(\"__tests__\") ||\n filename.includes(\"/test/\") ||\n filename.includes(\"/tests/\")\n }\n\n function isMonadicType(node: ASTNode): boolean {\n // This is a simplified check - in a real implementation, you'd want\n // more sophisticated type checking using TypeScript's type checker\n if (!node) return false\n \n const sourceCode = context.sourceCode\n \n // Check for common patterns that indicate monadic types\n const text = sourceCode.getText(node)\n \n // Direct type checks - constructors or type names\n if (/\\b(Option|Either|Maybe|Result|Some|None|Left|Right)\\b/.test(text)) {\n return true\n }\n \n // Method chains that suggest monadic operations\n if (/\\.(map|flatMap|filter|fold)\\s*\\(/.test(text)) {\n return true\n }\n \n // Variable names that suggest monadic types (case insensitive)\n if (/\\b(option|either|maybe|result|some|none|left|right)\\w*\\b/i.test(text)) {\n return true\n }\n \n // Check the specific node type and name\n if (node.type === \"Identifier\") {\n const varName = node.name.toLowerCase()\n if (/(option|either|maybe|result|some|none|left|right|opt)/.test(varName)) {\n return true\n }\n }\n \n // Check for CallExpression pattern like Some(\"test\").map()\n if (node.type === \"CallExpression\" && \n node.callee.type === \"MemberExpression\" &&\n node.callee.object) {\n return isMonadicType(node.callee.object)\n }\n \n return false\n }\n\n return {\n CallExpression(node: ASTNode) {\n if (allowInTests && isInTestFile()) return\n\n if (node.callee.type !== \"MemberExpression\") return\n\n const property = node.callee.property\n if (!property || property.type !== \"Identifier\") return\n\n const methodName = property.name\n if (!unsafeMethods.includes(methodName)) return\n\n // Check if this looks like it's being called on a monadic type\n if (isMonadicType(node.callee.object)) {\n context.report({\n node,\n messageId: \"noUnsafeGet\",\n data: { method: methodName },\n })\n }\n },\n }\n },\n}\n\nexport = rule","import type { Rule } from \"eslint\"\nimport type { ASTNode } from \"../types/ast\"\n\nconst rule: Rule.RuleModule = {\n meta: {\n type: \"suggestion\",\n docs: {\n description: \"Prefer .fold() over if/else chains when working with monadic types\",\n category: \"Best Practices\", \n recommended: true,\n },\n schema: [\n {\n type: \"object\",\n properties: {\n minComplexity: {\n type: \"integer\",\n minimum: 1,\n default: 2,\n },\n },\n additionalProperties: false,\n },\n ],\n messages: {\n preferFold: \"Prefer .fold() over if/else when working with {{type}} types\",\n preferFoldTernary: \"Consider using .fold() instead of ternary operator for {{type}}\",\n },\n },\n\n create(context) {\n const options = context.options[0] || {}\n const minComplexity = options.minComplexity || 2\n\n function isMonadicCheck(node: ASTNode): { isMonadic: boolean; type: string } {\n const sourceCode = context.sourceCode\n const text = sourceCode.getText(node)\n\n // Check for common monadic type checks\n if (/\\.(isSome|isNone|isEmpty|isDefined)\\s*\\(\\s*\\)/.test(text)) {\n return { isMonadic: true, type: \"Option\" }\n }\n \n if (/\\.(isLeft|isRight)\\s*\\(\\s*\\)/.test(text)) {\n return { isMonadic: true, type: \"Either\" }\n }\n\n if (/\\.(isSuccess|isFailure)\\s*\\(\\s*\\)/.test(text)) {\n return { isMonadic: true, type: \"Result\" }\n }\n\n // Check for null/undefined checks on variables that might be Options\n if (node.type === \"BinaryExpression\") {\n if ((node.operator === \"===\" || node.operator === \"!==\") &&\n ((node.left.type === \"Literal\" && (node.left.value === null || node.left.value === undefined)) ||\n (node.right.type === \"Literal\" && (node.right.value === null || node.right.value === undefined)))) {\n // This might be checking an Option that hasn't been properly typed\n return { isMonadic: true, type: \"Option\" }\n }\n \n // Check for == or != with undefined\n if ((node.operator === \"==\" || node.operator === \"!=\" || node.operator === \"===\" || node.operator === \"!==\")) {\n const leftIsUndefined = (node.left.type === \"Identifier\" && node.left.name === \"undefined\") ||\n (node.left.type === \"Literal\" && node.left.value === undefined)\n const rightIsUndefined = (node.right.type === \"Identifier\" && node.right.name === \"undefined\") ||\n (node.right.type === \"Literal\" && node.right.value === undefined)\n \n if (leftIsUndefined || rightIsUndefined) {\n return { isMonadic: true, type: \"Option\" }\n }\n }\n }\n\n return { isMonadic: false, type: \"\" }\n }\n\n function analyzeIfStatement(node: ASTNode) {\n const test = node.test\n const monadicInfo = isMonadicCheck(test)\n \n if (!monadicInfo.isMonadic) return\n\n // Don't analyze if this is part of a larger if/else chain\n // (only analyze the outermost if statement)\n if (node.parent && node.parent.type === \"IfStatement\") return\n\n // Count the complexity (if/else if/else chain)\n let complexity = 1\n let current = node\n while (current.alternate) {\n complexity++\n if (current.alternate.type === \"IfStatement\") {\n current = current.alternate\n } else {\n break\n }\n }\n\n if (complexity >= minComplexity) {\n context.report({\n node,\n messageId: \"preferFold\",\n data: { type: monadicInfo.type },\n })\n }\n }\n\n return {\n IfStatement(node: ASTNode) {\n analyzeIfStatement(node)\n },\n\n ConditionalExpression(node: ASTNode) {\n const monadicInfo = isMonadicCheck(node.test)\n if (monadicInfo.isMonadic) {\n context.report({\n node,\n messageId: \"preferFoldTernary\", \n data: { type: monadicInfo.type },\n })\n }\n },\n }\n },\n}\n\nexport = rule","import type { Rule } from \"eslint\"\nimport type { ASTNode } from \"../types/ast\"\n\nconst rule: Rule.RuleModule = {\n meta: {\n type: \"suggestion\",\n docs: {\n description: \"Prefer .map() over manual transformations and imperative patterns\",\n category: \"Best Practices\",\n recommended: true,\n },\n schema: [\n {\n type: \"object\",\n properties: {\n checkArrayMethods: {\n type: \"boolean\",\n default: true,\n },\n checkForLoops: {\n type: \"boolean\", \n default: true,\n },\n },\n additionalProperties: false,\n },\n ],\n messages: {\n preferMapOverLoop: \"Prefer .map() over for loop for transforming {{collection}}\",\n preferMapOverPush: \"Prefer .map() over manual .push() in loop\",\n preferMapChain: \"Consider using .map() for transformation instead of manual property access\",\n },\n },\n\n create(context) {\n const options = context.options[0] || {}\n const checkArrayMethods = options.checkArrayMethods !== false\n const checkForLoops = options.checkForLoops !== false\n\n function isTransformationLoop(node: ASTNode): boolean {\n if (!node.body || node.body.type !== \"BlockStatement\") return false\n \n const statements = node.body.body\n if (statements.length === 0) return false\n\n // Look for patterns like: newArray.push(transform(item))\n return statements.some((stmt: ASTNode) => {\n if (stmt.type === \"ExpressionStatement\" && \n stmt.expression.type === \"CallExpression\") {\n const call = stmt.expression\n return call.callee.type === \"MemberExpression\" &&\n call.callee.property.name === \"push\"\n }\n return false\n })\n }\n\n function isSimplePropertyAccess(node: ASTNode): boolean {\n // Check for patterns like: items.forEach(item => console.log(item.name))\n // These could often be: items.map(item => item.name)\n if (node.type === \"CallExpression\" &&\n node.callee.type === \"MemberExpression\" &&\n node.callee.property.name === \"forEach\") {\n \n const callback = node.arguments[0]\n if (callback && (callback.type === \"ArrowFunctionExpression\" || \n callback.type === \"FunctionExpression\")) {\n const body = callback.body\n // Simple property access in arrow function\n if (body.type === \"MemberExpression\") {\n return true\n }\n }\n }\n return false\n }\n\n return {\n ForStatement(node: ASTNode) {\n if (!checkForLoops) return\n\n if (isTransformationLoop(node)) {\n context.report({\n node,\n messageId: \"preferMapOverLoop\", \n data: { collection: \"array\" },\n })\n }\n },\n\n ForInStatement(node: ASTNode) {\n if (!checkForLoops) return\n\n if (isTransformationLoop(node)) {\n context.report({\n node,\n messageId: \"preferMapOverLoop\",\n data: { collection: \"object\" },\n })\n }\n },\n\n ForOfStatement(node: ASTNode) {\n if (!checkForLoops) return\n\n if (isTransformationLoop(node)) {\n context.report({\n node,\n messageId: \"preferMapOverLoop\",\n data: { collection: \"iterable\" },\n })\n }\n },\n\n CallExpression(node: ASTNode) {\n if (!checkArrayMethods) return\n\n // Check for forEach that could be map\n if (node.callee.type === \"MemberExpression\" &&\n node.callee.property.name === \"forEach\") {\n \n if (isSimplePropertyAccess(node)) {\n context.report({\n node,\n messageId: \"preferMapChain\",\n })\n }\n }\n\n // Check for manual push patterns in callbacks\n if (node.callee.type === \"MemberExpression\" &&\n node.callee.property.name === \"push\") {\n \n // Check if we're inside a forEach or similar iteration\n let parent = node.parent\n while (parent) {\n if (parent.type === \"CallExpression\" &&\n parent.callee.type === \"MemberExpression\" &&\n (parent.callee.property.name === \"forEach\" ||\n parent.callee.property.name === \"for\")) {\n \n context.report({\n node,\n messageId: \"preferMapOverPush\",\n })\n break\n }\n parent = parent.parent\n }\n }\n },\n }\n },\n}\n\nexport = rule","import type { Rule } from \"eslint\"\nimport type { ASTNode } from \"../types/ast\"\n\nconst rule: Rule.RuleModule = {\n meta: {\n type: \"suggestion\",\n docs: {\n description: \"Prefer .flatMap() over .map().flat() and nested transformations\",\n category: \"Best Practices\",\n recommended: true,\n },\n fixable: \"code\",\n schema: [\n {\n type: \"object\",\n properties: {\n checkNestedMaps: {\n type: \"boolean\",\n default: true,\n },\n },\n additionalProperties: false,\n },\n ],\n messages: {\n preferFlatMapOverMapFlat: \"Use .flatMap() instead of .map().flat()\",\n preferFlatMapNested: \"Consider .flatMap() for nested transformations that return arrays\",\n preferFlatMapChain: \"Use .flatMap() instead of chained .map() operations that flatten results\",\n },\n },\n\n create(context) {\n const options = context.options[0] || {}\n const checkNestedMaps = options.checkNestedMaps !== false\n\n function isMapFollowedByFlat(node: ASTNode): boolean {\n if (node.type !== \"CallExpression\") return false\n \n const callee = node.callee\n if (callee.type !== \"MemberExpression\") return false\n \n // Check if this is .flat()\n if (callee.property.name === \"flat\") {\n const object = callee.object\n \n // Check if the object is a .map() call\n if (object.type === \"CallExpression\" &&\n object.callee.type === \"MemberExpression\" &&\n object.callee.property.name === \"map\") {\n return true\n }\n }\n \n return false\n }\n\n function returnsArray(functionNode: ASTNode): boolean {\n if (!functionNode || !functionNode.body) return false\n\n // Arrow function with expression body\n if (functionNode.body.type === \"ArrayExpression\") {\n return true\n }\n\n // Arrow function with call expression body\n if (functionNode.body.type === \"CallExpression\") {\n const call = functionNode.body\n if (call.callee.type === \"MemberExpression\") {\n const methodName = call.callee.property.name\n // Common methods that return arrays\n if ([\"map\", \"filter\", \"slice\", \"concat\", \"split\"].includes(methodName)) {\n return true\n }\n }\n }\n\n // Function with block body\n if (functionNode.body.type === \"BlockStatement\") {\n const statements = functionNode.body.body\n \n // Look for return statements that return arrays\n for (const stmt of statements) {\n if (stmt.type === \"ReturnStatement\" && stmt.argument) {\n if (stmt.argument.type === \"ArrayExpression\") {\n return true\n }\n \n // Check for method calls that return arrays\n if (stmt.argument.type === \"CallExpression\") {\n const call = stmt.argument\n if (call.callee.type === \"MemberExpression\") {\n const methodName = call.callee.property.name\n // Common methods that return arrays\n if ([\"map\", \"filter\", \"slice\", \"concat\", \"split\"].includes(methodName)) {\n return true\n }\n }\n }\n }\n }\n }\n\n return false\n }\n\n function isNestedMapReturningArrays(node: ASTNode): boolean {\n if (node.type !== \"CallExpression\") return false\n \n const callee = node.callee\n if (callee.type !== \"MemberExpression\") return false\n \n // Check if this is .map()\n if (callee.property.name === \"map\") {\n const callback = node.arguments[0]\n if (callback && (callback.type === \"ArrowFunctionExpression\" ||\n callback.type === \"FunctionExpression\")) {\n return returnsArray(callback)\n }\n }\n \n return false\n }\n\n return {\n CallExpression(node: ASTNode) {\n // Check for .map().flat() pattern first (highest priority)\n if (isMapFollowedByFlat(node)) {\n const sourceCode = context.sourceCode\n \n context.report({\n node,\n messageId: \"preferFlatMapOverMapFlat\",\n fix(fixer) {\n // Get the .map() call\n const mapCall = (node.callee as ASTNode).object\n const mapCallText = sourceCode.getText(mapCall)\n \n // Replace .map() with .flatMap() and remove .flat()\n const flatMapText = mapCallText.replace(/\\.map\\s*\\(/, \".flatMap(\")\n \n return fixer.replaceText(node, flatMapText)\n },\n })\n return // Don't check other patterns if we found .map().flat()\n }\n\n // Check for chained maps where intermediate results are arrays (highest priority after map().flat())\n if (node.callee.type === \"MemberExpression\" &&\n node.callee.property.name === \"map\") {\n \n const object = node.callee.object\n if (object.type === \"CallExpression\" &&\n object.callee.type === \"MemberExpression\" &&\n object.callee.property.name === \"map\") {\n \n // Check if the first map returns arrays\n const firstMapCallback = object.arguments[0]\n if (firstMapCallback && returnsArray(firstMapCallback)) {\n context.report({\n node: object, // Report on the first map call\n messageId: \"preferFlatMapChain\",\n })\n return // Don't check other patterns for this chain\n }\n }\n }\n\n // Check for nested maps that return arrays (but not if they're part of map().flat() or chains)\n if (checkNestedMaps && isNestedMapReturningArrays(node)) {\n // Don't flag if this map is immediately followed by flat()\n if (node.parent && \n node.parent.type === \"MemberExpression\" &&\n node.parent.parent &&\n node.parent.parent.type === \"CallExpression\" &&\n node.parent.property.name === \"flat\") {\n return // Skip - this will be handled by the map().flat() rule\n }\n\n // Don't flag if this map is part of a chain (either as first or second map)\n const object = node.callee?.object\n if (object?.type === \"CallExpression\" &&\n object.callee?.type === \"MemberExpression\" &&\n object.callee?.property?.name === \"map\") {\n return // Skip - this is part of a chain\n }\n \n // Check if this map feeds into another map\n if (node.parent?.type === \"MemberExpression\" &&\n node.parent.parent?.type === \"CallExpression\" &&\n node.parent.parent.callee?.property?.name === \"map\") {\n return // Skip - this feeds into a chain\n }\n \n context.report({\n node,\n messageId: \"preferFlatMapNested\",\n })\n }\n },\n }\n },\n}\n\nexport = rule","import type { Rule } from \"eslint\"\nimport type { ASTNode } from \"../types/ast\"\n\nconst rule: Rule.RuleModule = {\n meta: {\n type: \"suggestion\",\n docs: {\n description: \"Prefer functional iteration methods over imperative for loops\",\n category: \"Best Practices\",\n recommended: true,\n },\n schema: [\n {\n type: \"object\",\n properties: {\n allowForIndexAccess: {\n type: \"boolean\",\n default: false,\n },\n allowWhileLoops: {\n type: \"boolean\", \n default: false,\n },\n allowInTests: {\n type: \"boolean\",\n default: true,\n },\n },\n additionalProperties: false,\n },\n ],\n messages: {\n noForLoop: \"Prefer functional methods (.map, .filter, .forEach, .reduce) over for loops\",\n noForInLoop: \"Prefer Object.keys().forEach() or functional methods over for..in loops\",\n noForOfLoop: \"Prefer .forEach() or .map() over for..of loops\", \n noWhileLoop: \"Prefer functional iteration or recursion over while loops\",\n noDoWhileLoop: \"Prefer functional iteration or recursion over do..while loops\",\n suggestFunctional: \"Consider: {{suggestion}}\",\n },\n },\n\n create(context) {\n const options = context.options[0] || {}\n const allowForIndexAccess = options.allowForIndexAccess || false\n const allowWhileLoops = options.allowWhileLoops || false\n const allowInTests = options.allowInTests !== false\n\n function isInTestFile() {\n const filename = context.getFilename()\n return /\\.(test|spec)\\.(ts|js|tsx|jsx)$/.test(filename) ||\n filename.includes(\"__tests__\") ||\n filename.includes(\"/test/\") ||\n filename.includes(\"/tests/\")\n }\n\n function needsIndexAccess(node: ASTNode): boolean {\n if (!node.body || node.body.type !== \"BlockStatement\") return false\n \n const sourceCode = context.sourceCode\n const bodyText = sourceCode.getText(node.body)\n \n // Look for array index access patterns like arr[i]\n return /\\[\\s*\\w+\\s*\\]/.test(bodyText) && node.init && \n node.init.type === \"VariableDeclaration\"\n }\n\n function getSuggestionForForLoop(node: ASTNode): string {\n if (!node.body) return \"functional iteration method\"\n \n const sourceCode = context.sourceCode\n const bodyText = sourceCode.getText(node.body)\n \n // Simple heuristics for suggestions\n if (bodyText.includes(\"if\") && bodyText.includes(\"push\")) {\n return \"array.filter().map() for conditional transformation\"\n } else if (bodyText.includes(\"push\")) {\n return \"array.map() to transform elements\"\n } else if (bodyText.includes(\"console.log\") || bodyText.includes(\"print\")) {\n return \"array.forEach() for side effects\"\n } else if (bodyText.includes(\"+=\") || bodyText.includes(\"sum\")) {\n return \"array.reduce() for accumulation\"\n }\n \n return \"functional iteration method (.map, .filter, .forEach, .reduce)\"\n }\n\n // Remove unused function to fix lint error\n // getSuggestionForForLoop could be used for better error messages in the future\n // Mark as used to avoid lint error:\n void getSuggestionForForLoop\n \n return {\n ForStatement(node: ASTNode) {\n if (allowInTests && isInTestFile()) return\n \n // Allow traditional for loops if they need index access and option is set\n if (allowForIndexAccess && needsIndexAccess(node)) return\n\n // Remove unused suggestion variable\n // const _suggestion = getSuggestionForForLoop(node)\n context.report({\n node,\n messageId: \"noForLoop\",\n })\n },\n\n ForInStatement(node: ASTNode) {\n if (allowInTests && isInTestFile()) return\n\n context.report({\n node,\n messageId: \"noForInLoop\",\n })\n },\n\n ForOfStatement(node: ASTNode) {\n if (allowInTests && isInTestFile()) return\n\n context.report({\n node,\n messageId: \"noForOfLoop\",\n })\n },\n\n WhileStatement(node: ASTNode) {\n if (allowWhileLoops) return\n if (allowInTests && isInTestFile()) return\n\n context.report({\n node,\n messageId: \"noWhileLoop\",\n })\n },\n\n DoWhileStatement(node: ASTNode) {\n if (allowWhileLoops) return\n if (allowInTests && isInTestFile()) return\n\n context.report({\n node,\n messageId: \"noDoWhileLoop\",\n })\n },\n }\n },\n}\n\nexport = rule","import preferOption from \"./prefer-option\"\nimport preferEither from \"./prefer-either\"\nimport preferList from \"./prefer-list\"\nimport noGetUnsafe from \"./no-get-unsafe\"\nimport preferFold from \"./prefer-fold\"\nimport preferMap from \"./prefer-map\"\nimport preferFlatmap from \"./prefer-flatmap\"\nimport noImperativeLoops from \"./no-imperative-loops\"\n\nexport {\n preferOption,\n preferEither,\n preferList,\n noGetUnsafe,\n preferFold,\n preferMap,\n preferFlatmap,\n noImperativeLoops,\n}\n\nexport default {\n \"prefer-option\": preferOption,\n \"prefer-either\": preferEither,\n \"prefer-list\": preferList,\n \"no-get-unsafe\": noGetUnsafe,\n \"prefer-fold\": preferFold,\n \"prefer-map\": preferMap,\n \"prefer-flatmap\": preferFlatmap,\n \"no-imperative-loops\": noImperativeLoops,\n}"]}
1
+ {"version":3,"file":"index.js","names":["preferOption","preferEither","preferList","noGetUnsafe","preferFold","preferMap","preferFlatmap","noImperativeLoops","preferDoNotation"],"sources":["../../src/rules/index.ts"],"sourcesContent":["import noGetUnsafe from \"./no-get-unsafe\"\nimport noImperativeLoops from \"./no-imperative-loops\"\nimport preferDoNotation from \"./prefer-do-notation\"\nimport preferEither from \"./prefer-either\"\nimport preferFlatmap from \"./prefer-flatmap\"\nimport preferFold from \"./prefer-fold\"\nimport preferList from \"./prefer-list\"\nimport preferMap from \"./prefer-map\"\nimport preferOption from \"./prefer-option\"\n\nexport {\n noGetUnsafe,\n noImperativeLoops,\n preferDoNotation,\n preferEither,\n preferFlatmap,\n preferFold,\n preferList,\n preferMap,\n preferOption,\n}\n\nexport default {\n \"prefer-option\": preferOption,\n \"prefer-either\": preferEither,\n \"prefer-list\": preferList,\n \"no-get-unsafe\": noGetUnsafe,\n \"prefer-fold\": preferFold,\n \"prefer-map\": preferMap,\n \"prefer-flatmap\": preferFlatmap,\n \"no-imperative-loops\": noImperativeLoops,\n \"prefer-do-notation\": preferDoNotation,\n}\n"],"mappings":"uTAsBA,IAAA,EAAe,CACb,gBAAiBA,EACjB,gBAAiBC,EACjB,cAAeC,EACf,gBAAiBC,EACjB,cAAeC,EACf,aAAcC,EACd,iBAAkBC,EAClB,sBAAuBC,EACvB,qBAAsBC,EACvB"}
@@ -0,0 +1,7 @@
1
+ import { Rule } from "eslint";
2
+
3
+ //#region src/rules/no-get-unsafe.d.ts
4
+ declare const rule: Rule.RuleModule;
5
+ //#endregion
6
+ export { rule as default };
7
+ //# sourceMappingURL=no-get-unsafe.d.ts.map
@@ -0,0 +1,2 @@
1
+ const e={meta:{type:`problem`,docs:{description:`Avoid unsafe .get() calls on Option, Either, and other monadic types`,recommended:!0},fixable:`code`,schema:[{type:`object`,properties:{allowInTests:{type:`boolean`,default:!0},unsafeMethods:{type:`array`,items:{type:`string`},default:[`get`,`getOrThrow`,`unwrap`,`expect`]}},additionalProperties:!1}],messages:{noUnsafeGet:`Avoid unsafe .{{method}}() call. Use .fold(), .map(), or .getOrElse() instead`,noUnsafeGetSuggestion:`Consider using .getOrElse(defaultValue) or .fold() for safe access`}},create(e){let t=e.options[0]||{},n=t.allowInTests!==!1,r=t.unsafeMethods||[`get`,`getOrThrow`,`unwrap`,`expect`];function i(){let t=e.filename;return/\.(test|spec)\.(ts|js|tsx|jsx)$/.test(t)||t.includes(`__tests__`)||t.includes(`/test/`)||t.includes(`/tests/`)}function a(t){if(!t)return!1;let n=e.sourceCode.getText(t);if(/\b(Option|Either|Maybe|Result|Some|None|Left|Right)\b/.test(n)||/\.(map|flatMap|filter|fold)\s*\(/.test(n)||/\b(option|either|maybe|result|some|none|left|right)\w*\b/i.test(n))return!0;if(t.type===`Identifier`){let e=t.name.toLowerCase();if(/(option|either|maybe|result|some|none|left|right|opt)/.test(e))return!0}return t.type===`CallExpression`&&t.callee.type===`MemberExpression`&&t.callee.object?a(t.callee.object):!1}return{CallExpression(t){if(n&&i()||t.callee.type!==`MemberExpression`)return;let o=t.callee.property;if(!o||o.type!==`Identifier`)return;let s=o.name;r.includes(s)&&a(t.callee.object)&&e.report({node:t,messageId:`noUnsafeGet`,data:{method:s},fix(n){let r=e.sourceCode.getText(t.callee.object),i;return i=`${r}.getOrElse(/* TODO: provide default value */)`,n.replaceText(t,i)}})}}}};export{e as default};
2
+ //# sourceMappingURL=no-get-unsafe.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"no-get-unsafe.js","names":[],"sources":["../../src/rules/no-get-unsafe.ts"],"sourcesContent":["import type { Rule } from \"eslint\"\n\nimport type { ASTNode } from \"../types/ast\"\n\nconst rule: Rule.RuleModule = {\n meta: {\n type: \"problem\",\n docs: {\n description: \"Avoid unsafe .get() calls on Option, Either, and other monadic types\",\n recommended: true,\n },\n fixable: \"code\",\n schema: [\n {\n type: \"object\",\n properties: {\n allowInTests: {\n type: \"boolean\",\n default: true,\n },\n unsafeMethods: {\n type: \"array\",\n items: { type: \"string\" },\n default: [\"get\", \"getOrThrow\", \"unwrap\", \"expect\"],\n },\n },\n additionalProperties: false,\n },\n ],\n messages: {\n noUnsafeGet: \"Avoid unsafe .{{method}}() call. Use .fold(), .map(), or .getOrElse() instead\",\n noUnsafeGetSuggestion: \"Consider using .getOrElse(defaultValue) or .fold() for safe access\",\n },\n },\n\n create(context) {\n const options = context.options[0] || {}\n const allowInTests = options.allowInTests !== false\n const unsafeMethods = options.unsafeMethods || [\"get\", \"getOrThrow\", \"unwrap\", \"expect\"]\n\n function isInTestFile() {\n const filename = context.filename\n return (\n /\\.(test|spec)\\.(ts|js|tsx|jsx)$/.test(filename) ||\n filename.includes(\"__tests__\") ||\n filename.includes(\"/test/\") ||\n filename.includes(\"/tests/\")\n )\n }\n\n function isMonadicType(node: ASTNode): boolean {\n // This is a simplified check - in a real implementation, you'd want\n // more sophisticated type checking using TypeScript's type checker\n if (!node) return false\n\n const sourceCode = context.sourceCode\n\n // Check for common patterns that indicate monadic types\n const text = sourceCode.getText(node)\n\n // Direct type checks - constructors or type names\n if (/\\b(Option|Either|Maybe|Result|Some|None|Left|Right)\\b/.test(text)) {\n return true\n }\n\n // Method chains that suggest monadic operations\n if (/\\.(map|flatMap|filter|fold)\\s*\\(/.test(text)) {\n return true\n }\n\n // Variable names that suggest monadic types (case insensitive)\n if (/\\b(option|either|maybe|result|some|none|left|right)\\w*\\b/i.test(text)) {\n return true\n }\n\n // Check the specific node type and name\n if (node.type === \"Identifier\") {\n const varName = node.name.toLowerCase()\n if (/(option|either|maybe|result|some|none|left|right|opt)/.test(varName)) {\n return true\n }\n }\n\n // Check for CallExpression pattern like Some(\"test\").map()\n if (node.type === \"CallExpression\" && node.callee.type === \"MemberExpression\" && node.callee.object) {\n return isMonadicType(node.callee.object)\n }\n\n return false\n }\n\n return {\n CallExpression(node: ASTNode) {\n if (allowInTests && isInTestFile()) return\n\n if (node.callee.type !== \"MemberExpression\") return\n\n const property = node.callee.property\n if (!property || property.type !== \"Identifier\") return\n\n const methodName = property.name\n if (!unsafeMethods.includes(methodName)) return\n\n // Check if this looks like it's being called on a monadic type\n if (isMonadicType(node.callee.object)) {\n context.report({\n node,\n messageId: \"noUnsafeGet\",\n data: { method: methodName },\n fix(fixer) {\n const sourceCode = context.sourceCode\n const objectText = sourceCode.getText(node.callee.object)\n\n // Choose safer alternative based on method name\n let replacement: string\n if (methodName === \"get\") {\n // Replace .get() with .getOrElse(/* provide default */)\n replacement = `${objectText}.getOrElse(/* TODO: provide default value */)`\n } else if (methodName === \"getOrThrow\") {\n // Replace .getOrThrow() with .getOrElse()\n replacement = `${objectText}.getOrElse(/* TODO: provide default value */)`\n } else if (methodName === \"unwrap\") {\n // Replace .unwrap() with .getOrElse()\n replacement = `${objectText}.getOrElse(/* TODO: provide default value */)`\n } else if (methodName === \"expect\") {\n // Replace .expect(msg) with .getOrElse()\n replacement = `${objectText}.getOrElse(/* TODO: provide default value */)`\n } else {\n // Generic fallback\n replacement = `${objectText}.getOrElse(/* TODO: provide default value */)`\n }\n\n return fixer.replaceText(node, replacement)\n },\n })\n }\n },\n }\n },\n}\n\nexport default rule\n"],"mappings":"AAIA,MAAM,EAAwB,CAC5B,KAAM,CACJ,KAAM,UACN,KAAM,CACJ,YAAa,uEACb,YAAa,GACd,CACD,QAAS,OACT,OAAQ,CACN,CACE,KAAM,SACN,WAAY,CACV,aAAc,CACZ,KAAM,UACN,QAAS,GACV,CACD,cAAe,CACb,KAAM,QACN,MAAO,CAAE,KAAM,SAAU,CACzB,QAAS,CAAC,MAAO,aAAc,SAAU,SAAS,CACnD,CACF,CACD,qBAAsB,GACvB,CACF,CACD,SAAU,CACR,YAAa,gFACb,sBAAuB,qEACxB,CACF,CAED,OAAO,EAAS,CACd,IAAM,EAAU,EAAQ,QAAQ,IAAM,EAAE,CAClC,EAAe,EAAQ,eAAiB,GACxC,EAAgB,EAAQ,eAAiB,CAAC,MAAO,aAAc,SAAU,SAAS,CAExF,SAAS,GAAe,CACtB,IAAM,EAAW,EAAQ,SACzB,MACE,kCAAkC,KAAK,EAAS,EAChD,EAAS,SAAS,YAAY,EAC9B,EAAS,SAAS,SAAS,EAC3B,EAAS,SAAS,UAAU,CAIhC,SAAS,EAAc,EAAwB,CAG7C,GAAI,CAAC,EAAM,MAAO,GAKlB,IAAM,EAHa,EAAQ,WAGH,QAAQ,EAAK,CAarC,GAVI,wDAAwD,KAAK,EAAK,EAKlE,mCAAmC,KAAK,EAAK,EAK7C,4DAA4D,KAAK,EAAK,CACxE,MAAO,GAIT,GAAI,EAAK,OAAS,aAAc,CAC9B,IAAM,EAAU,EAAK,KAAK,aAAa,CACvC,GAAI,wDAAwD,KAAK,EAAQ,CACvE,MAAO,GASX,OAJI,EAAK,OAAS,kBAAoB,EAAK,OAAO,OAAS,oBAAsB,EAAK,OAAO,OACpF,EAAc,EAAK,OAAO,OAAO,CAGnC,GAGT,MAAO,CACL,eAAe,EAAe,CAG5B,GAFI,GAAgB,GAAc,EAE9B,EAAK,OAAO,OAAS,mBAAoB,OAE7C,IAAM,EAAW,EAAK,OAAO,SAC7B,GAAI,CAAC,GAAY,EAAS,OAAS,aAAc,OAEjD,IAAM,EAAa,EAAS,KACvB,EAAc,SAAS,EAAW,EAGnC,EAAc,EAAK,OAAO,OAAO,EACnC,EAAQ,OAAO,CACb,OACA,UAAW,cACX,KAAM,CAAE,OAAQ,EAAY,CAC5B,IAAI,EAAO,CAET,IAAM,EADa,EAAQ,WACG,QAAQ,EAAK,OAAO,OAAO,CAGrD,EAkBJ,MAjBA,CAcE,EAZc,GAAG,EAAW,+CAevB,EAAM,YAAY,EAAM,EAAY,EAE9C,CAAC,EAGP,EAEJ"}
@@ -0,0 +1,7 @@
1
+ import { Rule } from "eslint";
2
+
3
+ //#region src/rules/no-imperative-loops.d.ts
4
+ declare const rule: Rule.RuleModule;
5
+ //#endregion
6
+ export { rule as default };
7
+ //# sourceMappingURL=no-imperative-loops.d.ts.map
@@ -0,0 +1,2 @@
1
+ const e={meta:{type:`suggestion`,docs:{description:`Prefer functional iteration methods over imperative for loops`,recommended:!0},schema:[{type:`object`,properties:{allowForIndexAccess:{type:`boolean`,default:!1},allowWhileLoops:{type:`boolean`,default:!1},allowInTests:{type:`boolean`,default:!0}},additionalProperties:!1}],messages:{noForLoop:`Prefer functional methods (.map, .filter, .forEach, .reduce) over for loops`,noForInLoop:`Prefer Object.keys().forEach() or functional methods over for..in loops`,noForOfLoop:`Prefer .forEach() or .map() over for..of loops`,noWhileLoop:`Prefer functional iteration or recursion over while loops`,noDoWhileLoop:`Prefer functional iteration or recursion over do..while loops`,suggestFunctional:`Consider: {{suggestion}}`}},create(e){let t=e.options[0]||{},n=t.allowForIndexAccess||!1,r=t.allowWhileLoops||!1,i=t.allowInTests!==!1;function a(){let t=e.filename;return/\.(test|spec)\.(ts|js|tsx|jsx)$/.test(t)||t.includes(`__tests__`)||t.includes(`/test/`)||t.includes(`/tests/`)}function o(t){if(!t.body||t.body.type!==`BlockStatement`)return!1;let n=e.sourceCode.getText(t.body);return/\[\s*\w+\s*\]/.test(n)&&t.init&&t.init.type===`VariableDeclaration`}return{ForStatement(t){i&&a()||n&&o(t)||e.report({node:t,messageId:`noForLoop`})},ForInStatement(t){i&&a()||e.report({node:t,messageId:`noForInLoop`})},ForOfStatement(t){i&&a()||e.report({node:t,messageId:`noForOfLoop`})},WhileStatement(t){r||i&&a()||e.report({node:t,messageId:`noWhileLoop`})},DoWhileStatement(t){r||i&&a()||e.report({node:t,messageId:`noDoWhileLoop`})}}}};export{e as default};
2
+ //# sourceMappingURL=no-imperative-loops.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"no-imperative-loops.js","names":[],"sources":["../../src/rules/no-imperative-loops.ts"],"sourcesContent":["import type { Rule } from \"eslint\"\n\nimport type { ASTNode } from \"../types/ast\"\n\nconst rule: Rule.RuleModule = {\n meta: {\n type: \"suggestion\",\n docs: {\n description: \"Prefer functional iteration methods over imperative for loops\",\n recommended: true,\n },\n schema: [\n {\n type: \"object\",\n properties: {\n allowForIndexAccess: {\n type: \"boolean\",\n default: false,\n },\n allowWhileLoops: {\n type: \"boolean\",\n default: false,\n },\n allowInTests: {\n type: \"boolean\",\n default: true,\n },\n },\n additionalProperties: false,\n },\n ],\n messages: {\n noForLoop: \"Prefer functional methods (.map, .filter, .forEach, .reduce) over for loops\",\n noForInLoop: \"Prefer Object.keys().forEach() or functional methods over for..in loops\",\n noForOfLoop: \"Prefer .forEach() or .map() over for..of loops\",\n noWhileLoop: \"Prefer functional iteration or recursion over while loops\",\n noDoWhileLoop: \"Prefer functional iteration or recursion over do..while loops\",\n suggestFunctional: \"Consider: {{suggestion}}\",\n },\n },\n\n create(context) {\n const options = context.options[0] || {}\n const allowForIndexAccess = options.allowForIndexAccess || false\n const allowWhileLoops = options.allowWhileLoops || false\n const allowInTests = options.allowInTests !== false\n\n function isInTestFile() {\n const filename = context.filename\n return (\n /\\.(test|spec)\\.(ts|js|tsx|jsx)$/.test(filename) ||\n filename.includes(\"__tests__\") ||\n filename.includes(\"/test/\") ||\n filename.includes(\"/tests/\")\n )\n }\n\n function needsIndexAccess(node: ASTNode): boolean {\n if (!node.body || node.body.type !== \"BlockStatement\") return false\n\n const sourceCode = context.sourceCode\n const bodyText = sourceCode.getText(node.body)\n\n // Look for array index access patterns like arr[i]\n return /\\[\\s*\\w+\\s*\\]/.test(bodyText) && node.init && node.init.type === \"VariableDeclaration\"\n }\n\n function getSuggestionForForLoop(node: ASTNode): string {\n if (!node.body) return \"functional iteration method\"\n\n const sourceCode = context.sourceCode\n const bodyText = sourceCode.getText(node.body)\n\n // Simple heuristics for suggestions\n if (bodyText.includes(\"if\") && bodyText.includes(\"push\")) {\n return \"array.filter().map() for conditional transformation\"\n } else if (bodyText.includes(\"push\")) {\n return \"array.map() to transform elements\"\n } else if (bodyText.includes(\"console.log\") || bodyText.includes(\"print\")) {\n return \"array.forEach() for side effects\"\n } else if (bodyText.includes(\"+=\") || bodyText.includes(\"sum\")) {\n return \"array.reduce() for accumulation\"\n }\n\n return \"functional iteration method (.map, .filter, .forEach, .reduce)\"\n }\n\n // Remove unused function to fix lint error\n // getSuggestionForForLoop could be used for better error messages in the future\n // Mark as used to avoid lint error:\n void getSuggestionForForLoop\n\n return {\n ForStatement(node: ASTNode) {\n if (allowInTests && isInTestFile()) return\n\n // Allow traditional for loops if they need index access and option is set\n if (allowForIndexAccess && needsIndexAccess(node)) return\n\n // Remove unused suggestion variable\n // const _suggestion = getSuggestionForForLoop(node)\n context.report({\n node,\n messageId: \"noForLoop\",\n })\n },\n\n ForInStatement(node: ASTNode) {\n if (allowInTests && isInTestFile()) return\n\n context.report({\n node,\n messageId: \"noForInLoop\",\n })\n },\n\n ForOfStatement(node: ASTNode) {\n if (allowInTests && isInTestFile()) return\n\n context.report({\n node,\n messageId: \"noForOfLoop\",\n })\n },\n\n WhileStatement(node: ASTNode) {\n if (allowWhileLoops) return\n if (allowInTests && isInTestFile()) return\n\n context.report({\n node,\n messageId: \"noWhileLoop\",\n })\n },\n\n DoWhileStatement(node: ASTNode) {\n if (allowWhileLoops) return\n if (allowInTests && isInTestFile()) return\n\n context.report({\n node,\n messageId: \"noDoWhileLoop\",\n })\n },\n }\n },\n}\n\nexport default rule\n"],"mappings":"AAIA,MAAM,EAAwB,CAC5B,KAAM,CACJ,KAAM,aACN,KAAM,CACJ,YAAa,gEACb,YAAa,GACd,CACD,OAAQ,CACN,CACE,KAAM,SACN,WAAY,CACV,oBAAqB,CACnB,KAAM,UACN,QAAS,GACV,CACD,gBAAiB,CACf,KAAM,UACN,QAAS,GACV,CACD,aAAc,CACZ,KAAM,UACN,QAAS,GACV,CACF,CACD,qBAAsB,GACvB,CACF,CACD,SAAU,CACR,UAAW,8EACX,YAAa,0EACb,YAAa,iDACb,YAAa,4DACb,cAAe,gEACf,kBAAmB,2BACpB,CACF,CAED,OAAO,EAAS,CACd,IAAM,EAAU,EAAQ,QAAQ,IAAM,EAAE,CAClC,EAAsB,EAAQ,qBAAuB,GACrD,EAAkB,EAAQ,iBAAmB,GAC7C,EAAe,EAAQ,eAAiB,GAE9C,SAAS,GAAe,CACtB,IAAM,EAAW,EAAQ,SACzB,MACE,kCAAkC,KAAK,EAAS,EAChD,EAAS,SAAS,YAAY,EAC9B,EAAS,SAAS,SAAS,EAC3B,EAAS,SAAS,UAAU,CAIhC,SAAS,EAAiB,EAAwB,CAChD,GAAI,CAAC,EAAK,MAAQ,EAAK,KAAK,OAAS,iBAAkB,MAAO,GAG9D,IAAM,EADa,EAAQ,WACC,QAAQ,EAAK,KAAK,CAG9C,MAAO,gBAAgB,KAAK,EAAS,EAAI,EAAK,MAAQ,EAAK,KAAK,OAAS,sBA4B3E,MAAO,CACL,aAAa,EAAe,CACtB,GAAgB,GAAc,EAG9B,GAAuB,EAAiB,EAAK,EAIjD,EAAQ,OAAO,CACb,OACA,UAAW,YACZ,CAAC,EAGJ,eAAe,EAAe,CACxB,GAAgB,GAAc,EAElC,EAAQ,OAAO,CACb,OACA,UAAW,cACZ,CAAC,EAGJ,eAAe,EAAe,CACxB,GAAgB,GAAc,EAElC,EAAQ,OAAO,CACb,OACA,UAAW,cACZ,CAAC,EAGJ,eAAe,EAAe,CACxB,GACA,GAAgB,GAAc,EAElC,EAAQ,OAAO,CACb,OACA,UAAW,cACZ,CAAC,EAGJ,iBAAiB,EAAe,CAC1B,GACA,GAAgB,GAAc,EAElC,EAAQ,OAAO,CACb,OACA,UAAW,gBACZ,CAAC,EAEL,EAEJ"}
@@ -0,0 +1,7 @@
1
+ import { Rule } from "eslint";
2
+
3
+ //#region src/rules/prefer-do-notation.d.ts
4
+ declare const rule: Rule.RuleModule;
5
+ //#endregion
6
+ export { rule as default };
7
+ //# sourceMappingURL=prefer-do-notation.d.ts.map
@@ -0,0 +1,5 @@
1
+ import{getFunctypeImports as e,isChainedMethodCall as t}from"../utils/functype-detection.js";const n={meta:{type:`suggestion`,docs:{description:`Prefer Do notation for complex monadic compositions and nested operations`,recommended:!0},fixable:`code`,messages:{preferDoForNestedChecks:`Prefer Do notation for nested null/undefined checks instead of logical AND chains`,preferDoForChainedMethods:`Prefer Do notation for complex flatMap chains ({{count}} levels deep)`,preferDoForMixedMonads:`Consider Do notation when mixing Option, Either, and Try operations`,preferDoAsyncForChainedTasks:`Prefer DoAsync notation for chained async operations`},schema:[{type:`object`,properties:{minChainDepth:{type:`integer`,minimum:2,default:3},detectMixedMonads:{type:`boolean`,default:!0}},additionalProperties:!1}]},create(n){let r=n.options[0]||{},i=r.minChainDepth||3,a=r.detectMixedMonads!==!1,o=e(n),s=o.functions.has(`Do`)||o.functions.has(`DoAsync`);function c(e){if(e.operator!==`&&`)return;let t=0,r=e;for(;r.type===`LogicalExpression`&&r.operator===`&&`;)(r.right.type===`MemberExpression`||r.right.type===`LogicalExpression`&&r.right.operator===`&&`)&&t++,r=r.left;t>=2&&l(e)&&n.report({node:e,messageId:`preferDoForNestedChecks`,fix:s?t=>f(t,e):void 0})}function l(e){let t=n.sourceCode.getText(e).match(/\w+(\.\w+){2,}/g);return t!==null&&t.length>0}function u(e){if(!t(e,`flatMap`))return;let r=d(e);r>=i&&n.report({node:e,messageId:`preferDoForChainedMethods`,data:{count:r.toString()},fix:s?t=>p(t,e):void 0})}function d(e){let t=1,n=e;for(;n.callee.type===`MemberExpression`&&n.callee.object.type===`CallExpression`;){let e=n.callee.property;e.type===`Identifier`&&[`flatMap`,`map`,`filter`,`fold`].includes(e.name)&&t++,n=n.callee.object}return t}function f(e,t){let r=n.sourceCode.getText(t),i=r.match(/(\w+)(\.\w+)+/);if(i){let n=i[1],r=`Do(function* () {
2
+ const obj = yield* $(Option(${n}))
3
+ return yield* $(Option(obj${i[0].substring(n.length)}))
4
+ })`;return e.replaceText(t,r)}return e.replaceText(t,`/* TODO: Convert to Do notation */ ${r}`)}function p(e,t){let r=n.sourceCode.getText(t);return e.replaceText(t,`/* TODO: Consider Do notation for complex chains */ ${r}`)}function m(e){if(!a)return;let t=n.sourceCode.getText(e);[`Option`,`Either`,`Try`,`Task`].filter(e=>t.includes(e)).length>=2&&n.report({node:e,messageId:`preferDoForMixedMonads`})}return{LogicalExpression(e){c(e)},CallExpression(e){u(e),m(e)}}}};export{n as default};
5
+ //# sourceMappingURL=prefer-do-notation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prefer-do-notation.js","names":[],"sources":["../../src/rules/prefer-do-notation.ts"],"sourcesContent":["import type { Rule } from \"eslint\"\n\nimport type { ASTNode } from \"../types/ast\"\nimport { getFunctypeImports, isChainedMethodCall } from \"../utils/functype-detection\"\n\nconst rule: Rule.RuleModule = {\n meta: {\n type: \"suggestion\",\n docs: {\n description: \"Prefer Do notation for complex monadic compositions and nested operations\",\n recommended: true,\n },\n fixable: \"code\",\n messages: {\n preferDoForNestedChecks: \"Prefer Do notation for nested null/undefined checks instead of logical AND chains\",\n preferDoForChainedMethods: \"Prefer Do notation for complex flatMap chains ({{count}} levels deep)\",\n preferDoForMixedMonads: \"Consider Do notation when mixing Option, Either, and Try operations\",\n preferDoAsyncForChainedTasks: \"Prefer DoAsync notation for chained async operations\",\n },\n schema: [\n {\n type: \"object\",\n properties: {\n minChainDepth: {\n type: \"integer\",\n minimum: 2,\n default: 3,\n },\n detectMixedMonads: {\n type: \"boolean\",\n default: true,\n },\n },\n additionalProperties: false,\n },\n ],\n },\n create(context) {\n const options = context.options[0] || {}\n const minChainDepth = options.minChainDepth || 3\n const detectMixedMonads = options.detectMixedMonads !== false\n\n const functypeImports = getFunctypeImports(context)\n\n // Track if Do notation is already imported\n const hasDoImport = functypeImports.functions.has(\"Do\") || functypeImports.functions.has(\"DoAsync\")\n\n /**\n * Detect nested null/undefined checks like: a && a.b && a.b.c\n */\n function checkNestedNullChecks(node: ASTNode): void {\n if (node.operator !== \"&&\") return\n\n let depth = 0\n let current: ASTNode = node\n\n // Count the depth of && chains with property access\n while (current.type === \"LogicalExpression\" && current.operator === \"&&\") {\n if (\n current.right.type === \"MemberExpression\" ||\n (current.right.type === \"LogicalExpression\" && current.right.operator === \"&&\")\n ) {\n depth++\n }\n current = current.left\n }\n\n // Check if this looks like nested property access guarding\n if (depth >= 2 && hasNestedPropertyAccess(node)) {\n context.report({\n node,\n messageId: \"preferDoForNestedChecks\",\n fix: hasDoImport ? (fixer) => fixNestedChecks(fixer, node) : undefined,\n })\n }\n }\n\n /**\n * Check if logical expression contains nested property access patterns\n */\n function hasNestedPropertyAccess(node: ASTNode): boolean {\n const text = context.sourceCode.getText(node)\n\n // Look for patterns like: obj && obj.prop && obj.prop.nested\n const nestedPattern = /\\w+(\\.\\w+){2,}/g\n const matches = text.match(nestedPattern)\n\n return matches !== null && matches.length > 0\n }\n\n /**\n * Detect long flatMap chains\n */\n function checkChainedMethods(node: ASTNode): void {\n if (!isChainedMethodCall(node, \"flatMap\")) return\n\n const chainDepth = getChainDepth(node)\n\n if (chainDepth >= minChainDepth) {\n context.report({\n node,\n messageId: \"preferDoForChainedMethods\",\n data: { count: chainDepth.toString() },\n fix: hasDoImport ? (fixer) => fixChainedMethods(fixer, node) : undefined,\n })\n }\n }\n\n /**\n * Calculate chain depth for method calls\n */\n function getChainDepth(node: ASTNode): number {\n let depth = 1\n let current = node\n\n while (current.callee.type === \"MemberExpression\" && current.callee.object.type === \"CallExpression\") {\n const method = current.callee.property\n if (method.type === \"Identifier\" && [\"flatMap\", \"map\", \"filter\", \"fold\"].includes(method.name)) {\n depth++\n }\n current = current.callee.object\n }\n\n return depth\n }\n\n /**\n * Auto-fix for nested null checks\n */\n function fixNestedChecks(fixer: Rule.RuleFixer, node: ASTNode): Rule.Fix {\n const text = context.sourceCode.getText(node)\n\n // Simple transformation for common patterns\n // a && a.b && a.b.c -> Do(function* () { const x = yield* $(Option(a)); const y = yield* $(Option(x.b)); return Option(y.c) })\n const match = text.match(/(\\w+)(\\.\\w+)+/)\n if (match) {\n const baseVar = match[1]\n const chain = match[0]\n\n const doNotation = `Do(function* () {\n const obj = yield* $(Option(${baseVar}))\n return yield* $(Option(obj${chain.substring(baseVar.length)}))\n})`\n\n return fixer.replaceText(node, doNotation)\n }\n\n return fixer.replaceText(node, `/* TODO: Convert to Do notation */ ${text}`)\n }\n\n /**\n * Auto-fix for chained methods (basic)\n */\n function fixChainedMethods(fixer: Rule.RuleFixer, node: ASTNode): Rule.Fix {\n const text = context.sourceCode.getText(node)\n\n // For now, just add a comment suggesting Do notation\n return fixer.replaceText(node, `/* TODO: Consider Do notation for complex chains */ ${text}`)\n }\n\n /**\n * Detect mixed monad usage\n */\n function checkMixedMonads(node: ASTNode): void {\n if (!detectMixedMonads) return\n\n const text = context.sourceCode.getText(node)\n const monadTypes = [\"Option\", \"Either\", \"Try\", \"Task\"]\n const foundMonads = monadTypes.filter((type) => text.includes(type))\n\n if (foundMonads.length >= 2) {\n context.report({\n node,\n messageId: \"preferDoForMixedMonads\",\n })\n }\n }\n\n return {\n LogicalExpression(node) {\n checkNestedNullChecks(node)\n },\n\n CallExpression(node) {\n checkChainedMethods(node)\n checkMixedMonads(node)\n },\n }\n },\n}\n\nexport default rule\n"],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ import { Rule } from "eslint";
2
+
3
+ //#region src/rules/prefer-either.d.ts
4
+ declare const rule: Rule.RuleModule;
5
+ //#endregion
6
+ export { rule as default };
7
+ //# sourceMappingURL=prefer-either.d.ts.map
@@ -0,0 +1,2 @@
1
+ const e={meta:{type:`suggestion`,docs:{description:`Prefer Either<E, T> over try/catch blocks and throw statements`,recommended:!0},schema:[{type:`object`,properties:{allowThrowInTests:{type:`boolean`,default:!0}},additionalProperties:!1}],messages:{preferEitherOverTryCatch:`Prefer Either<Error, T> over try/catch block`,preferEitherOverThrow:`Prefer Either.left(error) over throw statement`,preferEitherReturn:`Consider returning Either<Error, {{type}}> instead of throwing`}},create(e){let t=(e.options[0]||{}).allowThrowInTests!==!1;function n(){let t=e.filename;return/\.(test|spec)\.(ts|js|tsx|jsx)$/.test(t)||t.includes(`__tests__`)||t.includes(`/test/`)||t.includes(`/tests/`)}function r(e){if(!e)return!1;if(e.type===`ThrowStatement`){let t=e.parent;for(;t;){if(t.type===`CatchClause`)return!1;t=t.parent}return!0}if(e.type===`CatchClause`)return!1;for(let t in e){if(t===`parent`)continue;let n=e[t];if(Array.isArray(n)){for(let e of n)if(e&&typeof e==`object`&&r(e))return!0}else if(n&&typeof n==`object`&&r(n))return!0}return!1}return{TryStatement(r){t&&n()||r.handler&&r.handler.body&&r.handler.body.body.some(e=>e.type===`ThrowStatement`)||e.report({node:r,messageId:`preferEitherOverTryCatch`})},ThrowStatement(r){if(t&&n())return;let i=r.parent;for(;i;){if(i.type===`CatchClause`)return;i=i.parent}e.report({node:r,messageId:`preferEitherOverThrow`})},FunctionDeclaration(i){if(!(t&&n())&&i.body&&r(i.body)){let t=i.returnType?.typeAnnotation;if(t){let n=e.sourceCode.getText(t);n.includes(`Either`)||e.report({node:i.id||i,messageId:`preferEitherReturn`,data:{type:n}})}}}}}};export{e as default};
2
+ //# sourceMappingURL=prefer-either.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prefer-either.js","names":[],"sources":["../../src/rules/prefer-either.ts"],"sourcesContent":["import type { Rule } from \"eslint\"\n\nimport type { ASTNode } from \"../types/ast\"\n\nconst rule: Rule.RuleModule = {\n meta: {\n type: \"suggestion\",\n docs: {\n description: \"Prefer Either<E, T> over try/catch blocks and throw statements\",\n recommended: true,\n },\n schema: [\n {\n type: \"object\",\n properties: {\n allowThrowInTests: {\n type: \"boolean\",\n default: true,\n },\n },\n additionalProperties: false,\n },\n ],\n messages: {\n preferEitherOverTryCatch: \"Prefer Either<Error, T> over try/catch block\",\n preferEitherOverThrow: \"Prefer Either.left(error) over throw statement\",\n preferEitherReturn: \"Consider returning Either<Error, {{type}}> instead of throwing\",\n },\n },\n\n create(context) {\n const options = context.options[0] || {}\n const allowThrowInTests = options.allowThrowInTests !== false\n\n function isInTestFile() {\n const filename = context.filename\n return (\n /\\.(test|spec)\\.(ts|js|tsx|jsx)$/.test(filename) ||\n filename.includes(\"__tests__\") ||\n filename.includes(\"/test/\") ||\n filename.includes(\"/tests/\")\n )\n }\n\n function hasThrowStatementsOutsideCatch(node: ASTNode): boolean {\n if (!node) return false\n\n if (node.type === \"ThrowStatement\") {\n // Check if this throw is inside a catch block\n let parent = node.parent\n while (parent) {\n if (parent.type === \"CatchClause\") return false\n parent = parent.parent\n }\n return true\n }\n\n // Skip catch blocks when recursing\n if (node.type === \"CatchClause\") return false\n\n // Recursively check child nodes\n for (const key in node) {\n if (key === \"parent\") continue // Avoid circular references\n const child = node[key]\n if (Array.isArray(child)) {\n for (const item of child) {\n if (item && typeof item === \"object\" && hasThrowStatementsOutsideCatch(item)) {\n return true\n }\n }\n } else if (child && typeof child === \"object\" && hasThrowStatementsOutsideCatch(child)) {\n return true\n }\n }\n\n return false\n }\n\n return {\n TryStatement(node: ASTNode) {\n // Allow try/catch in test files\n if (allowThrowInTests && isInTestFile()) return\n\n // Allow try/catch that re-throws in the catch block (even with logging)\n if (node.handler && node.handler.body) {\n const catchBody = node.handler.body.body\n const hasRethrow = catchBody.some((stmt: ASTNode) => stmt.type === \"ThrowStatement\")\n if (hasRethrow) return\n }\n\n context.report({\n node,\n messageId: \"preferEitherOverTryCatch\",\n })\n },\n\n ThrowStatement(node: ASTNode) {\n // Allow throws in test files if configured\n if (allowThrowInTests && isInTestFile()) return\n\n // Allow re-throwing in catch blocks (common pattern)\n let parent = node.parent\n while (parent) {\n if (parent.type === \"CatchClause\") return\n parent = parent.parent\n }\n\n context.report({\n node,\n messageId: \"preferEitherOverThrow\",\n })\n },\n\n FunctionDeclaration(node: ASTNode) {\n // Allow functions in test files\n if (allowThrowInTests && isInTestFile()) return\n\n if (!node.body) return\n\n // Only report function-level errors if there are throws NOT in catch blocks\n // (throws in catch blocks are handled by ThrowStatement rule)\n const hasThrowsNotInCatch = hasThrowStatementsOutsideCatch(node.body)\n if (hasThrowsNotInCatch) {\n const returnType = node.returnType?.typeAnnotation\n if (returnType) {\n const sourceCode = context.sourceCode\n const returnTypeText = sourceCode.getText(returnType)\n\n // Don't report if already using Either\n if (!returnTypeText.includes(\"Either\")) {\n context.report({\n node: node.id || node,\n messageId: \"preferEitherReturn\",\n data: { type: returnTypeText },\n })\n }\n }\n }\n },\n }\n },\n}\n\nexport default rule\n"],"mappings":"AAIA,MAAM,EAAwB,CAC5B,KAAM,CACJ,KAAM,aACN,KAAM,CACJ,YAAa,iEACb,YAAa,GACd,CACD,OAAQ,CACN,CACE,KAAM,SACN,WAAY,CACV,kBAAmB,CACjB,KAAM,UACN,QAAS,GACV,CACF,CACD,qBAAsB,GACvB,CACF,CACD,SAAU,CACR,yBAA0B,+CAC1B,sBAAuB,iDACvB,mBAAoB,iEACrB,CACF,CAED,OAAO,EAAS,CAEd,IAAM,GADU,EAAQ,QAAQ,IAAM,EAAE,EACN,oBAAsB,GAExD,SAAS,GAAe,CACtB,IAAM,EAAW,EAAQ,SACzB,MACE,kCAAkC,KAAK,EAAS,EAChD,EAAS,SAAS,YAAY,EAC9B,EAAS,SAAS,SAAS,EAC3B,EAAS,SAAS,UAAU,CAIhC,SAAS,EAA+B,EAAwB,CAC9D,GAAI,CAAC,EAAM,MAAO,GAElB,GAAI,EAAK,OAAS,iBAAkB,CAElC,IAAI,EAAS,EAAK,OAClB,KAAO,GAAQ,CACb,GAAI,EAAO,OAAS,cAAe,MAAO,GAC1C,EAAS,EAAO,OAElB,MAAO,GAIT,GAAI,EAAK,OAAS,cAAe,MAAO,GAGxC,IAAK,IAAM,KAAO,EAAM,CACtB,GAAI,IAAQ,SAAU,SACtB,IAAM,EAAQ,EAAK,GACnB,GAAI,MAAM,QAAQ,EAAM,MACjB,IAAM,KAAQ,EACjB,GAAI,GAAQ,OAAO,GAAS,UAAY,EAA+B,EAAK,CAC1E,MAAO,WAGF,GAAS,OAAO,GAAU,UAAY,EAA+B,EAAM,CACpF,MAAO,GAIX,MAAO,GAGT,MAAO,CACL,aAAa,EAAe,CAEtB,GAAqB,GAAc,EAGnC,EAAK,SAAW,EAAK,QAAQ,MACb,EAAK,QAAQ,KAAK,KACP,KAAM,GAAkB,EAAK,OAAS,iBAAiB,EAItF,EAAQ,OAAO,CACb,OACA,UAAW,2BACZ,CAAC,EAGJ,eAAe,EAAe,CAE5B,GAAI,GAAqB,GAAc,CAAE,OAGzC,IAAI,EAAS,EAAK,OAClB,KAAO,GAAQ,CACb,GAAI,EAAO,OAAS,cAAe,OACnC,EAAS,EAAO,OAGlB,EAAQ,OAAO,CACb,OACA,UAAW,wBACZ,CAAC,EAGJ,oBAAoB,EAAe,CAE7B,QAAqB,GAAc,GAElC,EAAK,MAIkB,EAA+B,EAAK,KAAK,CAC5C,CACvB,IAAM,EAAa,EAAK,YAAY,eACpC,GAAI,EAAY,CAEd,IAAM,EADa,EAAQ,WACO,QAAQ,EAAW,CAGhD,EAAe,SAAS,SAAS,EACpC,EAAQ,OAAO,CACb,KAAM,EAAK,IAAM,EACjB,UAAW,qBACX,KAAM,CAAE,KAAM,EAAgB,CAC/B,CAAC,IAKX,EAEJ"}
@@ -0,0 +1,7 @@
1
+ import { Rule } from "eslint";
2
+
3
+ //#region src/rules/prefer-flatmap.d.ts
4
+ declare const rule: Rule.RuleModule;
5
+ //#endregion
6
+ export { rule as default };
7
+ //# sourceMappingURL=prefer-flatmap.d.ts.map
@@ -0,0 +1,2 @@
1
+ const e={meta:{type:`suggestion`,docs:{description:`Prefer .flatMap() over .map().flat() and nested transformations`,recommended:!0},fixable:`code`,schema:[{type:`object`,properties:{checkNestedMaps:{type:`boolean`,default:!0}},additionalProperties:!1}],messages:{preferFlatMapOverMapFlat:`Use .flatMap() instead of .map().flat()`,preferFlatMapNested:`Consider .flatMap() for nested transformations that return arrays`,preferFlatMapChain:`Use .flatMap() instead of chained .map() operations that flatten results`}},create(e){let t=(e.options[0]||{}).checkNestedMaps!==!1;function n(e){if(e.type!==`CallExpression`)return!1;let t=e.callee;if(t.type!==`MemberExpression`)return!1;if(t.property.name===`flat`){let e=t.object;if(e.type===`CallExpression`&&e.callee.type===`MemberExpression`&&e.callee.property.name===`map`)return!0}return!1}function r(e){if(!e||!e.body)return!1;if(e.body.type===`ArrayExpression`)return!0;if(e.body.type===`CallExpression`){let t=e.body;if(t.callee.type===`MemberExpression`){let e=t.callee.property.name;if([`map`,`filter`,`slice`,`concat`,`split`].includes(e))return!0}}if(e.body.type===`BlockStatement`){let t=e.body.body;for(let e of t)if(e.type===`ReturnStatement`&&e.argument){if(e.argument.type===`ArrayExpression`)return!0;if(e.argument.type===`CallExpression`){let t=e.argument;if(t.callee.type===`MemberExpression`){let e=t.callee.property.name;if([`map`,`filter`,`slice`,`concat`,`split`].includes(e))return!0}}}}return!1}function i(e){if(e.type!==`CallExpression`)return!1;let t=e.callee;if(t.type!==`MemberExpression`)return!1;if(t.property.name===`map`){let t=e.arguments[0];if(t&&(t.type===`ArrowFunctionExpression`||t.type===`FunctionExpression`))return r(t)}return!1}return{CallExpression(a){if(n(a)){let t=e.sourceCode;e.report({node:a,messageId:`preferFlatMapOverMapFlat`,fix(e){let n=a.callee.object,r=t.getText(n).replace(/\.map\s*\(/,`.flatMap(`);return e.replaceText(a,r)}});return}if(a.callee.type===`MemberExpression`&&a.callee.property.name===`map`){let t=a.callee.object;if(t.type===`CallExpression`&&t.callee.type===`MemberExpression`&&t.callee.property.name===`map`){let n=t.arguments[0];if(n&&r(n)){e.report({node:t,messageId:`preferFlatMapChain`});return}}}if(t&&i(a)){if(a.parent&&a.parent.type===`MemberExpression`&&a.parent.parent&&a.parent.parent.type===`CallExpression`&&a.parent.property.name===`flat`)return;let t=a.callee?.object;if(t?.type===`CallExpression`&&t.callee?.type===`MemberExpression`&&t.callee?.property?.name===`map`||a.parent?.type===`MemberExpression`&&a.parent.parent?.type===`CallExpression`&&a.parent.parent.callee?.property?.name===`map`)return;e.report({node:a,messageId:`preferFlatMapNested`})}}}}};export{e as default};
2
+ //# sourceMappingURL=prefer-flatmap.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prefer-flatmap.js","names":[],"sources":["../../src/rules/prefer-flatmap.ts"],"sourcesContent":["import type { Rule } from \"eslint\"\n\nimport type { ASTNode } from \"../types/ast\"\n\nconst rule: Rule.RuleModule = {\n meta: {\n type: \"suggestion\",\n docs: {\n description: \"Prefer .flatMap() over .map().flat() and nested transformations\",\n recommended: true,\n },\n fixable: \"code\",\n schema: [\n {\n type: \"object\",\n properties: {\n checkNestedMaps: {\n type: \"boolean\",\n default: true,\n },\n },\n additionalProperties: false,\n },\n ],\n messages: {\n preferFlatMapOverMapFlat: \"Use .flatMap() instead of .map().flat()\",\n preferFlatMapNested: \"Consider .flatMap() for nested transformations that return arrays\",\n preferFlatMapChain: \"Use .flatMap() instead of chained .map() operations that flatten results\",\n },\n },\n\n create(context) {\n const options = context.options[0] || {}\n const checkNestedMaps = options.checkNestedMaps !== false\n\n function isMapFollowedByFlat(node: ASTNode): boolean {\n if (node.type !== \"CallExpression\") return false\n\n const callee = node.callee\n if (callee.type !== \"MemberExpression\") return false\n\n // Check if this is .flat()\n if (callee.property.name === \"flat\") {\n const object = callee.object\n\n // Check if the object is a .map() call\n if (\n object.type === \"CallExpression\" &&\n object.callee.type === \"MemberExpression\" &&\n object.callee.property.name === \"map\"\n ) {\n return true\n }\n }\n\n return false\n }\n\n function returnsArray(functionNode: ASTNode): boolean {\n if (!functionNode || !functionNode.body) return false\n\n // Arrow function with expression body\n if (functionNode.body.type === \"ArrayExpression\") {\n return true\n }\n\n // Arrow function with call expression body\n if (functionNode.body.type === \"CallExpression\") {\n const call = functionNode.body\n if (call.callee.type === \"MemberExpression\") {\n const methodName = call.callee.property.name\n // Common methods that return arrays\n if ([\"map\", \"filter\", \"slice\", \"concat\", \"split\"].includes(methodName)) {\n return true\n }\n }\n }\n\n // Function with block body\n if (functionNode.body.type === \"BlockStatement\") {\n const statements = functionNode.body.body\n\n // Look for return statements that return arrays\n for (const stmt of statements) {\n if (stmt.type === \"ReturnStatement\" && stmt.argument) {\n if (stmt.argument.type === \"ArrayExpression\") {\n return true\n }\n\n // Check for method calls that return arrays\n if (stmt.argument.type === \"CallExpression\") {\n const call = stmt.argument\n if (call.callee.type === \"MemberExpression\") {\n const methodName = call.callee.property.name\n // Common methods that return arrays\n if ([\"map\", \"filter\", \"slice\", \"concat\", \"split\"].includes(methodName)) {\n return true\n }\n }\n }\n }\n }\n }\n\n return false\n }\n\n function isNestedMapReturningArrays(node: ASTNode): boolean {\n if (node.type !== \"CallExpression\") return false\n\n const callee = node.callee\n if (callee.type !== \"MemberExpression\") return false\n\n // Check if this is .map()\n if (callee.property.name === \"map\") {\n const callback = node.arguments[0]\n if (callback && (callback.type === \"ArrowFunctionExpression\" || callback.type === \"FunctionExpression\")) {\n return returnsArray(callback)\n }\n }\n\n return false\n }\n\n return {\n CallExpression(node: ASTNode) {\n // Check for .map().flat() pattern first (highest priority)\n if (isMapFollowedByFlat(node)) {\n const sourceCode = context.sourceCode\n\n context.report({\n node,\n messageId: \"preferFlatMapOverMapFlat\",\n fix(fixer) {\n // Get the .map() call\n const mapCall = (node.callee as ASTNode).object\n const mapCallText = sourceCode.getText(mapCall)\n\n // Replace .map() with .flatMap() and remove .flat()\n const flatMapText = mapCallText.replace(/\\.map\\s*\\(/, \".flatMap(\")\n\n return fixer.replaceText(node, flatMapText)\n },\n })\n return // Don't check other patterns if we found .map().flat()\n }\n\n // Check for chained maps where intermediate results are arrays (highest priority after map().flat())\n if (node.callee.type === \"MemberExpression\" && node.callee.property.name === \"map\") {\n const object = node.callee.object\n if (\n object.type === \"CallExpression\" &&\n object.callee.type === \"MemberExpression\" &&\n object.callee.property.name === \"map\"\n ) {\n // Check if the first map returns arrays\n const firstMapCallback = object.arguments[0]\n if (firstMapCallback && returnsArray(firstMapCallback)) {\n context.report({\n node: object, // Report on the first map call\n messageId: \"preferFlatMapChain\",\n })\n return // Don't check other patterns for this chain\n }\n }\n }\n\n // Check for nested maps that return arrays (but not if they're part of map().flat() or chains)\n if (checkNestedMaps && isNestedMapReturningArrays(node)) {\n // Don't flag if this map is immediately followed by flat()\n if (\n node.parent &&\n node.parent.type === \"MemberExpression\" &&\n node.parent.parent &&\n node.parent.parent.type === \"CallExpression\" &&\n node.parent.property.name === \"flat\"\n ) {\n return // Skip - this will be handled by the map().flat() rule\n }\n\n // Don't flag if this map is part of a chain (either as first or second map)\n const object = node.callee?.object\n if (\n object?.type === \"CallExpression\" &&\n object.callee?.type === \"MemberExpression\" &&\n object.callee?.property?.name === \"map\"\n ) {\n return // Skip - this is part of a chain\n }\n\n // Check if this map feeds into another map\n if (\n node.parent?.type === \"MemberExpression\" &&\n node.parent.parent?.type === \"CallExpression\" &&\n node.parent.parent.callee?.property?.name === \"map\"\n ) {\n return // Skip - this feeds into a chain\n }\n\n context.report({\n node,\n messageId: \"preferFlatMapNested\",\n })\n }\n },\n }\n },\n}\n\nexport default rule\n"],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ import { Rule } from "eslint";
2
+
3
+ //#region src/rules/prefer-fold.d.ts
4
+ declare const rule: Rule.RuleModule;
5
+ //#endregion
6
+ export { rule as default };
7
+ //# sourceMappingURL=prefer-fold.d.ts.map
@@ -0,0 +1,2 @@
1
+ const e={meta:{type:`suggestion`,docs:{description:`Prefer .fold() over if/else chains when working with monadic types`,recommended:!0},fixable:`code`,schema:[{type:`object`,properties:{minComplexity:{type:`integer`,minimum:1,default:2}},additionalProperties:!1}],messages:{preferFold:`Prefer .fold() over if/else when working with {{type}} types`,preferFoldTernary:`Consider using .fold() instead of ternary operator for {{type}}`}},create(e){let t=(e.options[0]||{}).minComplexity||2;function n(e,t){if(e.type===`BlockStatement`){let n=e.body;return n.length===1&&n[0].type===`ReturnStatement`?t.getText(n[0].argument):t.getText(e).slice(1,-1).trim()}else return t.getText(e)}function r(t){let r=e.sourceCode;if(t.type!==`IfStatement`)return null;let i=t.test,a=t.consequent,o=t.alternate;if(!a||!o)return null;let s=null,c=!1;if(i.type===`CallExpression`&&i.callee.type===`MemberExpression`){let e=i.callee.property.name;s=r.getText(i.callee.object),e===`isSome`||e===`isRight`||e===`isSuccess`?c=!1:(e===`isNone`||e===`isEmpty`||e===`isLeft`||e===`isFailure`)&&(c=!0)}if(!s||a.type===`BlockStatement`&&(a.body.length!==1||a.body[0].type!==`ReturnStatement`))return null;if(o.type===`BlockStatement`){if(o.body.length!==1||o.body[0].type!==`ReturnStatement`)return null}else if(o.type===`IfStatement`)return null;let l=n(a,r),u=n(o,r);return c?`${s}.fold(() => ${l}, () => ${u})`:`${s}.fold(() => ${u}, (value) => ${l})`}function i(t){let n=e.sourceCode;if(t.type!==`ConditionalExpression`)return null;let r=t.test,i=t.consequent,a=t.alternate,o=null,s=!1;if(r.type===`CallExpression`&&r.callee.type===`MemberExpression`){let e=r.callee.property.name;o=n.getText(r.callee.object),e===`isSome`||e===`isRight`||e===`isSuccess`?s=!1:(e===`isNone`||e===`isEmpty`||e===`isLeft`||e===`isFailure`)&&(s=!0)}if(!o)return null;let c=n.getText(i),l=n.getText(a);return s?`${o}.fold(() => ${c}, () => ${l})`:`${o}.fold(() => ${l}, (value) => ${c})`}function a(e){if(e.type===`CallExpression`&&e.callee.type===`MemberExpression`){let t=e.callee.property.name;return[`isSome`,`isNone`,`isEmpty`,`isRight`,`isLeft`,`isSuccess`,`isFailure`].includes(t)}return!1}function o(t){let n=e.sourceCode.getText(t);if(/\.(isSome|isNone|isEmpty|isDefined)\s*\(\s*\)/.test(n))return{isMonadic:!0,type:`Option`};if(/\.(isLeft|isRight)\s*\(\s*\)/.test(n))return{isMonadic:!0,type:`Either`};if(/\.(isSuccess|isFailure)\s*\(\s*\)/.test(n))return{isMonadic:!0,type:`Result`};if(t.type===`BinaryExpression`){if((t.operator===`===`||t.operator===`!==`)&&(t.left.type===`Literal`&&(t.left.value===null||t.left.value===void 0)||t.right.type===`Literal`&&(t.right.value===null||t.right.value===void 0)))return{isMonadic:!0,type:`Option`};if(t.operator===`==`||t.operator===`!=`||t.operator===`===`||t.operator===`!==`){let e=t.left.type===`Identifier`&&t.left.name===`undefined`||t.left.type===`Literal`&&t.left.value===void 0,n=t.right.type===`Identifier`&&t.right.name===`undefined`||t.right.type===`Literal`&&t.right.value===void 0;if(e||n)return{isMonadic:!0,type:`Option`}}}return{isMonadic:!1,type:``}}function s(n){let i=n.test,s=o(i);if(!s.isMonadic||n.parent&&n.parent.type===`IfStatement`)return;let c=1,l=n;for(;l.alternate&&(c++,l.alternate.type===`IfStatement`);)l=l.alternate;c>=t&&e.report({node:n,messageId:`preferFold`,data:{type:s.type},fix(e){if(!a(n.test))return null;let t=r(n);return t?e.replaceText(n,t):null}})}return{IfStatement(e){s(e)},ConditionalExpression(t){let n=o(t.test);n.isMonadic&&e.report({node:t,messageId:`preferFoldTernary`,data:{type:n.type},fix(e){if(!a(t.test))return null;let n=i(t);return n?e.replaceText(t,n):null}})}}}};export{e as default};
2
+ //# sourceMappingURL=prefer-fold.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prefer-fold.js","names":[],"sources":["../../src/rules/prefer-fold.ts"],"sourcesContent":["import type { Rule, SourceCode } from \"eslint\"\n\nimport type { ASTNode } from \"../types/ast\"\n\nconst rule: Rule.RuleModule = {\n meta: {\n type: \"suggestion\",\n docs: {\n description: \"Prefer .fold() over if/else chains when working with monadic types\",\n recommended: true,\n },\n fixable: \"code\",\n schema: [\n {\n type: \"object\",\n properties: {\n minComplexity: {\n type: \"integer\",\n minimum: 1,\n default: 2,\n },\n },\n additionalProperties: false,\n },\n ],\n messages: {\n preferFold: \"Prefer .fold() over if/else when working with {{type}} types\",\n preferFoldTernary: \"Consider using .fold() instead of ternary operator for {{type}}\",\n },\n },\n\n create(context) {\n const options = context.options[0] || {}\n const minComplexity = options.minComplexity || 2\n\n function extractBodyForFold(node: ASTNode, sourceCode: SourceCode): string {\n if (node.type === \"BlockStatement\") {\n const statements = node.body\n if (statements.length === 1 && statements[0].type === \"ReturnStatement\") {\n // Extract just the return value, not the return statement\n return sourceCode.getText(statements[0].argument)\n } else {\n // For complex blocks, keep the full structure but remove outer braces\n return sourceCode.getText(node).slice(1, -1).trim()\n }\n } else {\n return sourceCode.getText(node)\n }\n }\n\n function generateFoldFromIf(node: ASTNode): string | null {\n const sourceCode = context.sourceCode\n\n if (node.type !== \"IfStatement\") return null\n\n const test = node.test\n const consequent = node.consequent\n const alternate = node.alternate\n\n if (!consequent || !alternate) return null\n\n // Extract the monadic object from the test\n let monadicObj: string | null = null\n let isNegated = false\n\n // Handle patterns like option.isSome(), either.isLeft(), etc.\n if (test.type === \"CallExpression\" && test.callee.type === \"MemberExpression\") {\n const methodName = test.callee.property.name\n monadicObj = sourceCode.getText(test.callee.object)\n\n if (methodName === \"isSome\" || methodName === \"isRight\" || methodName === \"isSuccess\") {\n isNegated = false\n } else if (\n methodName === \"isNone\" ||\n methodName === \"isEmpty\" ||\n methodName === \"isLeft\" ||\n methodName === \"isFailure\"\n ) {\n isNegated = true\n }\n }\n\n if (!monadicObj) return null\n\n // Only handle simple cases - single return statements in blocks, no nested if statements\n if (consequent.type === \"BlockStatement\") {\n if (consequent.body.length !== 1 || consequent.body[0].type !== \"ReturnStatement\") {\n return null // Too complex, don't auto-fix\n }\n }\n\n if (alternate.type === \"BlockStatement\") {\n if (alternate.body.length !== 1 || alternate.body[0].type !== \"ReturnStatement\") {\n return null // Too complex, don't auto-fix\n }\n } else if (alternate.type === \"IfStatement\") {\n return null // Nested if/else is too complex for simple fold pattern\n }\n\n // Extract consequent and alternate bodies\n const thenBody = extractBodyForFold(consequent, sourceCode)\n const elseBody = extractBodyForFold(alternate, sourceCode)\n\n // Generate fold expression\n if (isNegated) {\n return `${monadicObj}.fold(() => ${thenBody}, () => ${elseBody})`\n } else {\n return `${monadicObj}.fold(() => ${elseBody}, (value) => ${thenBody})`\n }\n }\n\n function generateFoldFromTernary(node: ASTNode): string | null {\n const sourceCode = context.sourceCode\n\n if (node.type !== \"ConditionalExpression\") return null\n\n const test = node.test\n const consequent = node.consequent\n const alternate = node.alternate\n\n // Extract the monadic object from the test\n let monadicObj: string | null = null\n let isNegated = false\n\n if (test.type === \"CallExpression\" && test.callee.type === \"MemberExpression\") {\n const methodName = test.callee.property.name\n monadicObj = sourceCode.getText(test.callee.object)\n\n if (methodName === \"isSome\" || methodName === \"isRight\" || methodName === \"isSuccess\") {\n isNegated = false\n } else if (\n methodName === \"isNone\" ||\n methodName === \"isEmpty\" ||\n methodName === \"isLeft\" ||\n methodName === \"isFailure\"\n ) {\n isNegated = true\n }\n }\n\n if (!monadicObj) return null\n\n const thenExpr = sourceCode.getText(consequent)\n const elseExpr = sourceCode.getText(alternate)\n\n // Generate fold expression\n if (isNegated) {\n return `${monadicObj}.fold(() => ${thenExpr}, () => ${elseExpr})`\n } else {\n return `${monadicObj}.fold(() => ${elseExpr}, (value) => ${thenExpr})`\n }\n }\n\n function shouldAutoFix(node: ASTNode): boolean {\n // Only auto-fix when we detect functype method calls (indicating it's already a functype instance)\n if (node.type === \"CallExpression\" && node.callee.type === \"MemberExpression\") {\n const methodName = node.callee.property.name\n // These methods indicate the object is already a functype instance\n return [\"isSome\", \"isNone\", \"isEmpty\", \"isRight\", \"isLeft\", \"isSuccess\", \"isFailure\"].includes(methodName)\n }\n return false\n }\n\n function isMonadicCheck(node: ASTNode): { isMonadic: boolean; type: string } {\n const sourceCode = context.sourceCode\n const text = sourceCode.getText(node)\n\n // Check for common monadic type checks\n if (/\\.(isSome|isNone|isEmpty|isDefined)\\s*\\(\\s*\\)/.test(text)) {\n return { isMonadic: true, type: \"Option\" }\n }\n\n if (/\\.(isLeft|isRight)\\s*\\(\\s*\\)/.test(text)) {\n return { isMonadic: true, type: \"Either\" }\n }\n\n if (/\\.(isSuccess|isFailure)\\s*\\(\\s*\\)/.test(text)) {\n return { isMonadic: true, type: \"Result\" }\n }\n\n // Check for null/undefined checks on variables that might be Options\n if (node.type === \"BinaryExpression\") {\n if (\n (node.operator === \"===\" || node.operator === \"!==\") &&\n ((node.left.type === \"Literal\" && (node.left.value === null || node.left.value === undefined)) ||\n (node.right.type === \"Literal\" && (node.right.value === null || node.right.value === undefined)))\n ) {\n // This might be checking an Option that hasn't been properly typed\n return { isMonadic: true, type: \"Option\" }\n }\n\n // Check for == or != with undefined\n if (node.operator === \"==\" || node.operator === \"!=\" || node.operator === \"===\" || node.operator === \"!==\") {\n const leftIsUndefined =\n (node.left.type === \"Identifier\" && node.left.name === \"undefined\") ||\n (node.left.type === \"Literal\" && node.left.value === undefined)\n const rightIsUndefined =\n (node.right.type === \"Identifier\" && node.right.name === \"undefined\") ||\n (node.right.type === \"Literal\" && node.right.value === undefined)\n\n if (leftIsUndefined || rightIsUndefined) {\n return { isMonadic: true, type: \"Option\" }\n }\n }\n }\n\n return { isMonadic: false, type: \"\" }\n }\n\n function analyzeIfStatement(node: ASTNode) {\n const test = node.test\n const monadicInfo = isMonadicCheck(test)\n\n if (!monadicInfo.isMonadic) return\n\n // Don't analyze if this is part of a larger if/else chain\n // (only analyze the outermost if statement)\n if (node.parent && node.parent.type === \"IfStatement\") return\n\n // Count the complexity (if/else if/else chain)\n let complexity = 1\n let current = node\n while (current.alternate) {\n complexity++\n if (current.alternate.type === \"IfStatement\") {\n current = current.alternate\n } else {\n break\n }\n }\n\n if (complexity >= minComplexity) {\n context.report({\n node,\n messageId: \"preferFold\",\n data: { type: monadicInfo.type },\n fix(fixer) {\n // Only auto-fix if we can detect it's already a functype instance\n if (!shouldAutoFix(node.test)) {\n return null\n }\n const replacement = generateFoldFromIf(node)\n if (replacement) {\n return fixer.replaceText(node, replacement)\n }\n return null\n },\n })\n }\n }\n\n return {\n IfStatement(node: ASTNode) {\n analyzeIfStatement(node)\n },\n\n ConditionalExpression(node: ASTNode) {\n const monadicInfo = isMonadicCheck(node.test)\n if (monadicInfo.isMonadic) {\n context.report({\n node,\n messageId: \"preferFoldTernary\",\n data: { type: monadicInfo.type },\n fix(fixer) {\n // Only auto-fix if we can detect it's already a functype instance\n if (!shouldAutoFix(node.test)) {\n return null\n }\n const replacement = generateFoldFromTernary(node)\n if (replacement) {\n return fixer.replaceText(node, replacement)\n }\n return null\n },\n })\n }\n },\n }\n },\n}\n\nexport default rule\n"],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ import { Rule } from "eslint";
2
+
3
+ //#region src/rules/prefer-list.d.ts
4
+ declare const rule: Rule.RuleModule;
5
+ //#endregion
6
+ export { rule as default };
7
+ //# sourceMappingURL=prefer-list.d.ts.map
@@ -0,0 +1,2 @@
1
+ import{getFunctypeImportsLegacy as e,isFunctypeCall as t}from"../utils/functype-detection.js";const n={meta:{type:`suggestion`,docs:{description:`Prefer List<T> over native arrays for immutable collections`,recommended:!0},schema:[{type:`object`,properties:{allowArraysInTests:{type:`boolean`,default:!0},allowReadonlyArrays:{type:`boolean`,default:!0}},additionalProperties:!1}],messages:{preferList:`Prefer List<{{type}}> over array type {{arrayType}}`,preferListLiteral:`Prefer List.of(...) or List.from([...]) over array literal`}},create(n){let r=n.options[0]||{},i=r.allowArraysInTests!==!1,a=r.allowReadonlyArrays!==!1,o=e(n);function s(){let e=n.filename;return/\.(test|spec)\.(ts|js|tsx|jsx)$/.test(e)||e.includes(`__tests__`)||e.includes(`/test/`)||e.includes(`/tests/`)}function c(e,t){function n(e){if(e.type===`TSTypeParameterInstantiation`&&e.params&&e.params[0])return t.getText(e.params[0]);for(let t in e){if(t===`parent`)continue;let r=e[t];if(Array.isArray(r)){for(let e of r)if(e&&typeof e==`object`&&e.type){let t=n(e);if(t)return t}}else if(r&&typeof r==`object`&&r.type){let e=n(r);if(e)return e}}return null}return n(e)}return{TSArrayType(e){if(i&&s())return;let t=n.sourceCode,r=t.getText(e.elementType),a=t.getText(e);n.report({node:e,messageId:`preferList`,data:{type:r,arrayType:a}})},TSTypeReference(e){if(i&&s())return;let t=n.sourceCode;if(!e.typeName)return;let r=e.typeName.type===`Identifier`?e.typeName.name:t.getText(e.typeName);if(r===`Array`){let r=c(e,t),i=t.getText(e);if(a&&i.startsWith(`readonly`))return;n.report({node:e,messageId:`preferList`,data:{type:r||`T`,arrayType:i}})}if(r===`ReadonlyArray`){let r=c(e,t),i=t.getText(e);n.report({node:e,messageId:`preferList`,data:{type:r||`T`,arrayType:i}})}},ArrayExpression(e){if(i&&s()||e.elements.length===0)return;let r=e.parent;if(r&&t(r,o)||r&&r.type===`CallExpression`&&r.callee.type===`MemberExpression`&&r.callee.object.type===`Identifier`&&r.callee.object.name===`List`&&[`from`,`of`].includes(r.callee.property.name))return;for(r=e.parent;r;){if(r.type===`ArrayExpression`)return;r=r.parent}let a=!1;for(r=e.parent;r;){if(r.type===`VariableDeclarator`&&r.id?.typeAnnotation){a=!0;break}if(r.type===`TSTypeAnnotation`){a=!0;break}r=r.parent}a||n.report({node:e,messageId:`preferListLiteral`})}}}};export{n as default};
2
+ //# sourceMappingURL=prefer-list.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prefer-list.js","names":[],"sources":["../../src/rules/prefer-list.ts"],"sourcesContent":["import type { Rule } from \"eslint\"\n\nimport type { ASTNode } from \"../types/ast\"\nimport { getFunctypeImportsLegacy, isFunctypeCall } from \"../utils/functype-detection\"\n\nconst rule: Rule.RuleModule = {\n meta: {\n type: \"suggestion\",\n docs: {\n description: \"Prefer List<T> over native arrays for immutable collections\",\n recommended: true,\n },\n schema: [\n {\n type: \"object\",\n properties: {\n allowArraysInTests: {\n type: \"boolean\",\n default: true,\n },\n allowReadonlyArrays: {\n type: \"boolean\",\n default: true,\n },\n },\n additionalProperties: false,\n },\n ],\n messages: {\n preferList: \"Prefer List<{{type}}> over array type {{arrayType}}\",\n preferListLiteral: \"Prefer List.of(...) or List.from([...]) over array literal\",\n },\n },\n\n create(context) {\n const options = context.options[0] || {}\n const allowArraysInTests = options.allowArraysInTests !== false\n const allowReadonlyArrays = options.allowReadonlyArrays !== false\n\n // Get functype imports if available (but still apply rule even without explicit import)\n const functypeImports = getFunctypeImportsLegacy(context)\n\n function isInTestFile() {\n const filename = context.filename\n return (\n /\\.(test|spec)\\.(ts|js|tsx|jsx)$/.test(filename) ||\n filename.includes(\"__tests__\") ||\n filename.includes(\"/test/\") ||\n filename.includes(\"/tests/\")\n )\n }\n\n function findTypeParameter(node: ASTNode, sourceCode: typeof context.sourceCode): string | null {\n // Look for TSTypeParameterInstantiation child\n function findInNode(n: ASTNode): string | null {\n if (n.type === \"TSTypeParameterInstantiation\" && n.params && n.params[0]) {\n return sourceCode.getText(n.params[0])\n }\n\n // Recursively search child nodes\n for (const key in n) {\n if (key === \"parent\") continue\n const child = n[key]\n if (Array.isArray(child)) {\n for (const item of child) {\n if (item && typeof item === \"object\" && item.type) {\n const result = findInNode(item)\n if (result) return result\n }\n }\n } else if (child && typeof child === \"object\" && child.type) {\n const result = findInNode(child)\n if (result) return result\n }\n }\n\n return null\n }\n\n return findInNode(node)\n }\n\n return {\n TSArrayType(node: ASTNode) {\n if (allowArraysInTests && isInTestFile()) return\n\n const sourceCode = context.sourceCode\n const elementType = sourceCode.getText(node.elementType)\n const fullType = sourceCode.getText(node)\n\n context.report({\n node,\n messageId: \"preferList\",\n data: {\n type: elementType,\n arrayType: fullType,\n },\n })\n },\n\n TSTypeReference(node: ASTNode) {\n if (allowArraysInTests && isInTestFile()) return\n\n const sourceCode = context.sourceCode\n\n // Get type name - handle both simple identifiers and member expressions\n if (!node.typeName) return // No type name found\n\n const typeName = node.typeName.type === \"Identifier\" ? node.typeName.name : sourceCode.getText(node.typeName)\n\n // Handle Array<T> syntax\n if (typeName === \"Array\") {\n // Look for type parameters in child nodes\n const typeParam = findTypeParameter(node, sourceCode)\n const fullType = sourceCode.getText(node)\n\n // Skip if already readonly\n if (allowReadonlyArrays && fullType.startsWith(\"readonly\")) return\n\n context.report({\n node,\n messageId: \"preferList\",\n data: {\n type: typeParam || \"T\",\n arrayType: fullType,\n },\n })\n }\n\n // Handle ReadonlyArray<T> - suggest List even if allowing readonly arrays\n if (typeName === \"ReadonlyArray\") {\n const typeParam = findTypeParameter(node, sourceCode)\n const fullType = sourceCode.getText(node)\n\n context.report({\n node,\n messageId: \"preferList\",\n data: {\n type: typeParam || \"T\",\n arrayType: fullType,\n },\n })\n }\n },\n\n ArrayExpression(node: ASTNode) {\n if (allowArraysInTests && isInTestFile()) return\n\n // Only flag non-empty arrays to avoid noise\n if (node.elements.length === 0) return\n\n // Don't flag arrays that are already arguments to List.from() or other functype calls\n let parent = node.parent\n if (parent && isFunctypeCall(parent, functypeImports)) {\n return\n }\n\n // Additional specific check for List.from/List.of patterns\n if (\n parent &&\n parent.type === \"CallExpression\" &&\n parent.callee.type === \"MemberExpression\" &&\n parent.callee.object.type === \"Identifier\" &&\n parent.callee.object.name === \"List\" &&\n [\"from\", \"of\"].includes(parent.callee.property.name)\n ) {\n return\n }\n\n // Don't flag nested array literals - only flag the outermost one\n // Check if this array is inside another array literal\n parent = node.parent\n while (parent) {\n if (parent.type === \"ArrayExpression\") {\n return // Skip nested arrays, let the outer one handle it\n }\n parent = parent.parent\n }\n\n // Don't flag array literals that are already part of a type annotation context\n // (those should be handled by the type checking rules)\n let hasTypeAnnotation = false\n parent = node.parent\n while (parent) {\n if (parent.type === \"VariableDeclarator\" && parent.id?.typeAnnotation) {\n // Skip array literal if there's already a type annotation that would be flagged\n hasTypeAnnotation = true\n break\n }\n if (parent.type === \"TSTypeAnnotation\") {\n hasTypeAnnotation = true\n break\n }\n parent = parent.parent\n }\n\n if (hasTypeAnnotation) return\n\n context.report({\n node,\n messageId: \"preferListLiteral\",\n })\n },\n }\n },\n}\n\nexport default rule\n"],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ import { Rule } from "eslint";
2
+
3
+ //#region src/rules/prefer-map.d.ts
4
+ declare const rule: Rule.RuleModule;
5
+ //#endregion
6
+ export { rule as default };
7
+ //# sourceMappingURL=prefer-map.d.ts.map
@@ -0,0 +1,2 @@
1
+ const e={meta:{type:`suggestion`,docs:{description:`Prefer .map() over manual transformations and imperative patterns`,recommended:!0},fixable:`code`,schema:[{type:`object`,properties:{checkArrayMethods:{type:`boolean`,default:!0},checkForLoops:{type:`boolean`,default:!0}},additionalProperties:!1}],messages:{preferMapOverLoop:`Prefer .map() over for loop for transforming {{collection}}`,preferMapOverPush:`Prefer .map() over manual .push() in loop`,preferMapChain:`Consider using .map() for transformation instead of manual property access`}},create(e){let t=e.options[0]||{},n=t.checkArrayMethods!==!1,r=t.checkForLoops!==!1;function i(e){if(e.type!==`CallExpression`||e.callee.type!==`MemberExpression`||e.callee.property.name!==`forEach`)return!1;let t=e.arguments[0];return t&&(t.type===`ArrowFunctionExpression`||t.type===`FunctionExpression`)?t.body.type===`MemberExpression`:!1}function a(e){if(!e.body||e.body.type!==`BlockStatement`)return!1;let t=e.body.body;return t.length===0?!1:t.some(e=>{if(e.type===`ExpressionStatement`&&e.expression.type===`CallExpression`){let t=e.expression;return t.callee.type===`MemberExpression`&&t.callee.property.name===`push`}return!1})}function o(e){if(e.type===`CallExpression`&&e.callee.type===`MemberExpression`&&e.callee.property.name===`forEach`){let t=e.arguments[0];if(t&&(t.type===`ArrowFunctionExpression`||t.type===`FunctionExpression`)&&t.body.type===`MemberExpression`)return!0}return!1}return{ForStatement(t){r&&a(t)&&e.report({node:t,messageId:`preferMapOverLoop`,data:{collection:`array`}})},ForInStatement(t){r&&a(t)&&e.report({node:t,messageId:`preferMapOverLoop`,data:{collection:`object`}})},ForOfStatement(t){r&&a(t)&&e.report({node:t,messageId:`preferMapOverLoop`,data:{collection:`iterable`}})},CallExpression(t){if(n&&(t.callee.type===`MemberExpression`&&t.callee.property.name===`forEach`&&o(t)&&e.report({node:t,messageId:`preferMapChain`,fix(n){if(!i(t))return null;let r=e.sourceCode.getText(t).replace(/\.forEach\s*\(/g,`.map(`);return n.replaceText(t,r)}}),t.callee.type===`MemberExpression`&&t.callee.property.name===`push`)){let n=t.parent;for(;n;){if(n.type===`CallExpression`&&n.callee.type===`MemberExpression`&&(n.callee.property.name===`forEach`||n.callee.property.name===`for`)){e.report({node:t,messageId:`preferMapOverPush`});break}n=n.parent}}}}}};export{e as default};
2
+ //# sourceMappingURL=prefer-map.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prefer-map.js","names":[],"sources":["../../src/rules/prefer-map.ts"],"sourcesContent":["import type { Rule } from \"eslint\"\n\nimport type { ASTNode } from \"../types/ast\"\n\nconst rule: Rule.RuleModule = {\n meta: {\n type: \"suggestion\",\n docs: {\n description: \"Prefer .map() over manual transformations and imperative patterns\",\n recommended: true,\n },\n fixable: \"code\",\n schema: [\n {\n type: \"object\",\n properties: {\n checkArrayMethods: {\n type: \"boolean\",\n default: true,\n },\n checkForLoops: {\n type: \"boolean\",\n default: true,\n },\n },\n additionalProperties: false,\n },\n ],\n messages: {\n preferMapOverLoop: \"Prefer .map() over for loop for transforming {{collection}}\",\n preferMapOverPush: \"Prefer .map() over manual .push() in loop\",\n preferMapChain: \"Consider using .map() for transformation instead of manual property access\",\n },\n },\n\n create(context) {\n const options = context.options[0] || {}\n const checkArrayMethods = options.checkArrayMethods !== false\n const checkForLoops = options.checkForLoops !== false\n\n function isForEachToMapSafe(node: ASTNode): boolean {\n // Only auto-fix simple forEach → map transformations on expressions that return values\n // This is safe because both native arrays and functype Lists have these methods\n if (\n node.type !== \"CallExpression\" ||\n node.callee.type !== \"MemberExpression\" ||\n node.callee.property.name !== \"forEach\"\n ) {\n return false\n }\n\n // Check if the callback returns a value (simple property access pattern)\n const callback = node.arguments[0]\n if (callback && (callback.type === \"ArrowFunctionExpression\" || callback.type === \"FunctionExpression\")) {\n const body = callback.body\n // Simple property access in arrow function (e.g., item => item.name)\n return body.type === \"MemberExpression\"\n }\n return false\n }\n\n function isTransformationLoop(node: ASTNode): boolean {\n if (!node.body || node.body.type !== \"BlockStatement\") return false\n\n const statements = node.body.body\n if (statements.length === 0) return false\n\n // Look for patterns like: newArray.push(transform(item))\n return statements.some((stmt: ASTNode) => {\n if (stmt.type === \"ExpressionStatement\" && stmt.expression.type === \"CallExpression\") {\n const call = stmt.expression\n return call.callee.type === \"MemberExpression\" && call.callee.property.name === \"push\"\n }\n return false\n })\n }\n\n function isSimplePropertyAccess(node: ASTNode): boolean {\n // Check for patterns like: items.forEach(item => console.log(item.name))\n // These could often be: items.map(item => item.name)\n if (\n node.type === \"CallExpression\" &&\n node.callee.type === \"MemberExpression\" &&\n node.callee.property.name === \"forEach\"\n ) {\n const callback = node.arguments[0]\n if (callback && (callback.type === \"ArrowFunctionExpression\" || callback.type === \"FunctionExpression\")) {\n const body = callback.body\n // Simple property access in arrow function\n if (body.type === \"MemberExpression\") {\n return true\n }\n }\n }\n return false\n }\n\n return {\n ForStatement(node: ASTNode) {\n if (!checkForLoops) return\n\n if (isTransformationLoop(node)) {\n context.report({\n node,\n messageId: \"preferMapOverLoop\",\n data: { collection: \"array\" },\n })\n }\n },\n\n ForInStatement(node: ASTNode) {\n if (!checkForLoops) return\n\n if (isTransformationLoop(node)) {\n context.report({\n node,\n messageId: \"preferMapOverLoop\",\n data: { collection: \"object\" },\n })\n }\n },\n\n ForOfStatement(node: ASTNode) {\n if (!checkForLoops) return\n\n if (isTransformationLoop(node)) {\n context.report({\n node,\n messageId: \"preferMapOverLoop\",\n data: { collection: \"iterable\" },\n })\n }\n },\n\n CallExpression(node: ASTNode) {\n if (!checkArrayMethods) return\n\n // Check for forEach that could be map\n if (node.callee.type === \"MemberExpression\" && node.callee.property.name === \"forEach\") {\n if (isSimplePropertyAccess(node)) {\n context.report({\n node,\n messageId: \"preferMapChain\",\n fix(fixer) {\n // Only auto-fix safe forEach → map transformations\n if (!isForEachToMapSafe(node)) {\n return null\n }\n\n const sourceCode = context.sourceCode\n const text = sourceCode.getText(node)\n\n // Simple replacement: forEach -> map\n const fixedText = text.replace(/\\.forEach\\s*\\(/g, \".map(\")\n return fixer.replaceText(node, fixedText)\n },\n })\n }\n }\n\n // Check for manual push patterns in callbacks\n if (node.callee.type === \"MemberExpression\" && node.callee.property.name === \"push\") {\n // Check if we're inside a forEach or similar iteration\n let parent = node.parent\n while (parent) {\n if (\n parent.type === \"CallExpression\" &&\n parent.callee.type === \"MemberExpression\" &&\n (parent.callee.property.name === \"forEach\" || parent.callee.property.name === \"for\")\n ) {\n context.report({\n node,\n messageId: \"preferMapOverPush\",\n })\n break\n }\n parent = parent.parent\n }\n }\n },\n }\n },\n}\n\nexport default rule\n"],"mappings":"AAIA,MAAM,EAAwB,CAC5B,KAAM,CACJ,KAAM,aACN,KAAM,CACJ,YAAa,oEACb,YAAa,GACd,CACD,QAAS,OACT,OAAQ,CACN,CACE,KAAM,SACN,WAAY,CACV,kBAAmB,CACjB,KAAM,UACN,QAAS,GACV,CACD,cAAe,CACb,KAAM,UACN,QAAS,GACV,CACF,CACD,qBAAsB,GACvB,CACF,CACD,SAAU,CACR,kBAAmB,8DACnB,kBAAmB,4CACnB,eAAgB,6EACjB,CACF,CAED,OAAO,EAAS,CACd,IAAM,EAAU,EAAQ,QAAQ,IAAM,EAAE,CAClC,EAAoB,EAAQ,oBAAsB,GAClD,EAAgB,EAAQ,gBAAkB,GAEhD,SAAS,EAAmB,EAAwB,CAGlD,GACE,EAAK,OAAS,kBACd,EAAK,OAAO,OAAS,oBACrB,EAAK,OAAO,SAAS,OAAS,UAE9B,MAAO,GAIT,IAAM,EAAW,EAAK,UAAU,GAMhC,OALI,IAAa,EAAS,OAAS,2BAA6B,EAAS,OAAS,sBACnE,EAAS,KAEV,OAAS,mBAEhB,GAGT,SAAS,EAAqB,EAAwB,CACpD,GAAI,CAAC,EAAK,MAAQ,EAAK,KAAK,OAAS,iBAAkB,MAAO,GAE9D,IAAM,EAAa,EAAK,KAAK,KAI7B,OAHI,EAAW,SAAW,EAAU,GAG7B,EAAW,KAAM,GAAkB,CACxC,GAAI,EAAK,OAAS,uBAAyB,EAAK,WAAW,OAAS,iBAAkB,CACpF,IAAM,EAAO,EAAK,WAClB,OAAO,EAAK,OAAO,OAAS,oBAAsB,EAAK,OAAO,SAAS,OAAS,OAElF,MAAO,IACP,CAGJ,SAAS,EAAuB,EAAwB,CAGtD,GACE,EAAK,OAAS,kBACd,EAAK,OAAO,OAAS,oBACrB,EAAK,OAAO,SAAS,OAAS,UAC9B,CACA,IAAM,EAAW,EAAK,UAAU,GAChC,GAAI,IAAa,EAAS,OAAS,2BAA6B,EAAS,OAAS,uBACnE,EAAS,KAEb,OAAS,mBAChB,MAAO,GAIb,MAAO,GAGT,MAAO,CACL,aAAa,EAAe,CACrB,GAED,EAAqB,EAAK,EAC5B,EAAQ,OAAO,CACb,OACA,UAAW,oBACX,KAAM,CAAE,WAAY,QAAS,CAC9B,CAAC,EAIN,eAAe,EAAe,CACvB,GAED,EAAqB,EAAK,EAC5B,EAAQ,OAAO,CACb,OACA,UAAW,oBACX,KAAM,CAAE,WAAY,SAAU,CAC/B,CAAC,EAIN,eAAe,EAAe,CACvB,GAED,EAAqB,EAAK,EAC5B,EAAQ,OAAO,CACb,OACA,UAAW,oBACX,KAAM,CAAE,WAAY,WAAY,CACjC,CAAC,EAIN,eAAe,EAAe,CACvB,OAGD,EAAK,OAAO,OAAS,oBAAsB,EAAK,OAAO,SAAS,OAAS,WACvE,EAAuB,EAAK,EAC9B,EAAQ,OAAO,CACb,OACA,UAAW,iBACX,IAAI,EAAO,CAET,GAAI,CAAC,EAAmB,EAAK,CAC3B,OAAO,KAOT,IAAM,EAJa,EAAQ,WACH,QAAQ,EAAK,CAGd,QAAQ,kBAAmB,QAAQ,CAC1D,OAAO,EAAM,YAAY,EAAM,EAAU,EAE5C,CAAC,CAKF,EAAK,OAAO,OAAS,oBAAsB,EAAK,OAAO,SAAS,OAAS,QAAQ,CAEnF,IAAI,EAAS,EAAK,OAClB,KAAO,GAAQ,CACb,GACE,EAAO,OAAS,kBAChB,EAAO,OAAO,OAAS,qBACtB,EAAO,OAAO,SAAS,OAAS,WAAa,EAAO,OAAO,SAAS,OAAS,OAC9E,CACA,EAAQ,OAAO,CACb,OACA,UAAW,oBACZ,CAAC,CACF,MAEF,EAAS,EAAO,UAIvB,EAEJ"}
@@ -0,0 +1,7 @@
1
+ import { Rule } from "eslint";
2
+
3
+ //#region src/rules/prefer-option.d.ts
4
+ declare const rule: Rule.RuleModule;
5
+ //#endregion
6
+ export { rule as default };
7
+ //# sourceMappingURL=prefer-option.d.ts.map
@@ -0,0 +1,2 @@
1
+ import{getFunctypeImportsLegacy as e,isAlreadyUsingFunctype as t,isFunctypeType as n}from"../utils/functype-detection.js";const r={meta:{type:`suggestion`,docs:{description:`Prefer Option<T> over nullable types (T | null | undefined)`,recommended:!0},schema:[{type:`object`,properties:{allowNullableIntersections:{type:`boolean`,default:!1}},additionalProperties:!1}],messages:{preferOption:`Prefer Option<{{type}}> over nullable type '{{nullable}}'`,preferOptionReturn:`Prefer Option<{{type}}> as return type over nullable '{{nullable}}'`}},create(r){let i=e(r);return{TSUnionType(e){if(!e.types||e.types.length<2||!e.types.some(e=>e.type===`TSNullKeyword`||e.type===`TSUndefinedKeyword`))return;let a=e.types.filter(e=>e.type!==`TSNullKeyword`&&e.type!==`TSUndefinedKeyword`);if(a.length===1){let o=a[0];if(n(o,i)||t(e,i))return;let s=r.sourceCode,c=s.getText(o),l=s.getText(e);if(c.startsWith(`Option<`))return;r.report({node:e,messageId:`preferOption`,data:{type:c,nullable:l}})}}}}};export{r as default};
2
+ //# sourceMappingURL=prefer-option.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prefer-option.js","names":[],"sources":["../../src/rules/prefer-option.ts"],"sourcesContent":["import type { Rule } from \"eslint\"\n\nimport type { ASTNode } from \"../types/ast\"\nimport { getFunctypeImportsLegacy, isAlreadyUsingFunctype, isFunctypeType } from \"../utils/functype-detection\"\n\nconst rule: Rule.RuleModule = {\n meta: {\n type: \"suggestion\",\n docs: {\n description: \"Prefer Option<T> over nullable types (T | null | undefined)\",\n recommended: true,\n },\n schema: [\n {\n type: \"object\",\n properties: {\n allowNullableIntersections: {\n type: \"boolean\",\n default: false,\n },\n },\n additionalProperties: false,\n },\n ],\n messages: {\n preferOption: \"Prefer Option<{{type}}> over nullable type '{{nullable}}'\",\n preferOptionReturn: \"Prefer Option<{{type}}> as return type over nullable '{{nullable}}'\",\n },\n },\n\n create(context) {\n // const options = context.options[0] || {}\n // Remove unused variable\n // const _allowNullableIntersections = options.allowNullableIntersections || false\n\n // Get functype imports if available (but still apply rule even without explicit import)\n const functypeImports = getFunctypeImportsLegacy(context)\n\n return {\n TSUnionType(node: ASTNode) {\n if (!node.types || node.types.length < 2) return\n\n const hasNull = node.types.some(\n (type: ASTNode) => type.type === \"TSNullKeyword\" || type.type === \"TSUndefinedKeyword\",\n )\n\n if (!hasNull) return\n\n const nonNullTypes = node.types.filter(\n (type: ASTNode) => type.type !== \"TSNullKeyword\" && type.type !== \"TSUndefinedKeyword\",\n )\n\n if (nonNullTypes.length === 1) {\n const nonNullType = nonNullTypes[0]\n\n // Skip if it's already an Option type or other functype type\n if (isFunctypeType(nonNullType, functypeImports)) return\n\n // Skip if we're already in a functype context\n if (isAlreadyUsingFunctype(node, functypeImports)) return\n\n const sourceCode = context.sourceCode\n const nonNullTypeText = sourceCode.getText(nonNullType)\n const fullType = sourceCode.getText(node)\n\n // Skip if it's already an Option type (fallback check)\n if (nonNullTypeText.startsWith(\"Option<\")) return\n\n context.report({\n node,\n messageId: \"preferOption\",\n data: {\n type: nonNullTypeText,\n nullable: fullType,\n },\n })\n }\n },\n }\n },\n}\n\nexport default rule\n"],"mappings":"0HAKA,MAAM,EAAwB,CAC5B,KAAM,CACJ,KAAM,aACN,KAAM,CACJ,YAAa,8DACb,YAAa,GACd,CACD,OAAQ,CACN,CACE,KAAM,SACN,WAAY,CACV,2BAA4B,CAC1B,KAAM,UACN,QAAS,GACV,CACF,CACD,qBAAsB,GACvB,CACF,CACD,SAAU,CACR,aAAc,4DACd,mBAAoB,sEACrB,CACF,CAED,OAAO,EAAS,CAMd,IAAM,EAAkB,EAAyB,EAAQ,CAEzD,MAAO,CACL,YAAY,EAAe,CAOzB,GANI,CAAC,EAAK,OAAS,EAAK,MAAM,OAAS,GAMnC,CAJY,EAAK,MAAM,KACxB,GAAkB,EAAK,OAAS,iBAAmB,EAAK,OAAS,qBACnE,CAEa,OAEd,IAAM,EAAe,EAAK,MAAM,OAC7B,GAAkB,EAAK,OAAS,iBAAmB,EAAK,OAAS,qBACnE,CAED,GAAI,EAAa,SAAW,EAAG,CAC7B,IAAM,EAAc,EAAa,GAMjC,GAHI,EAAe,EAAa,EAAgB,EAG5C,EAAuB,EAAM,EAAgB,CAAE,OAEnD,IAAM,EAAa,EAAQ,WACrB,EAAkB,EAAW,QAAQ,EAAY,CACjD,EAAW,EAAW,QAAQ,EAAK,CAGzC,GAAI,EAAgB,WAAW,UAAU,CAAE,OAE3C,EAAQ,OAAO,CACb,OACA,UAAW,eACX,KAAM,CACJ,KAAM,EACN,SAAU,EACX,CACF,CAAC,GAGP,EAEJ"}
@@ -0,0 +1,12 @@
1
+ //#region src/types/ast.d.ts
2
+ /**
3
+ * ESLint AST Node type alias
4
+ *
5
+ * ESLint's AST node types are complex and not fully typed in the public API.
6
+ * Using `any` is the standard practice for ESLint rule development when working
7
+ * with AST nodes that need dynamic property access.
8
+ */
9
+ type ASTNode = any;
10
+ //#endregion
11
+ export { ASTNode };
12
+ //# sourceMappingURL=ast.d.ts.map
@@ -0,0 +1 @@
1
+ export{};