eslint-plugin-maintainability 3.2.11 → 3.2.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eslint-plugin-maintainability",
3
- "version": "3.2.11",
3
+ "version": "3.2.12",
4
4
  "description": "ESLint plugin for maintainable code — limits cognitive complexity, nesting depth, parameter counts, duplicate functions, and unhandled or silent errors.",
5
5
  "type": "commonjs",
6
6
  "main": "./src/index.js",
package/src/index.js CHANGED
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.configs=exports.plugin=exports.rules=void 0;const eslint_devkit_1=require("@interlace/eslint-devkit");exports.rules={get"cognitive-complexity"(){return require("./rules/maintainability/cognitive-complexity").cognitiveComplexity},get"nested-complexity-hotspots"(){return require("./rules/maintainability/nested-complexity-hotspots").nestedComplexityHotspots},get"identical-functions"(){return require("./rules/maintainability/identical-functions").identicalFunctions},get"max-parameters"(){return require("./rules/maintainability/max-parameters").maxParameters},get"no-lonely-if"(){return require("./rules/maintainability/no-lonely-if").noLonelyIf},get"no-nested-ternary"(){return require("./rules/maintainability/no-nested-ternary").noNestedTernary},get"consistent-function-scoping"(){return require("./rules/maintainability/consistent-function-scoping").consistentFunctionScoping},get"no-unreadable-iife"(){return require("./rules/maintainability/no-unreadable-iife").noUnreadableIife},get"error-message"(){return require("./rules/error-handling/error-message").errorMessage},get"no-missing-error-context"(){return require("./rules/error-handling/no-missing-error-context").noMissingErrorContext},get"no-silent-errors"(){return require("./rules/error-handling/no-silent-errors").noSilentErrors},get"no-unhandled-promise"(){return require("./rules/error-handling/no-unhandled-promise").noUnhandledPromise},get"maintainability/cognitive-complexity"(){return require("./rules/maintainability/cognitive-complexity").cognitiveComplexity},get"maintainability/nested-complexity-hotspots"(){return require("./rules/maintainability/nested-complexity-hotspots").nestedComplexityHotspots},get"maintainability/identical-functions"(){return require("./rules/maintainability/identical-functions").identicalFunctions},get"maintainability/max-parameters"(){return require("./rules/maintainability/max-parameters").maxParameters},get"maintainability/no-lonely-if"(){return require("./rules/maintainability/no-lonely-if").noLonelyIf},get"maintainability/no-nested-ternary"(){return require("./rules/maintainability/no-nested-ternary").noNestedTernary},get"maintainability/consistent-function-scoping"(){return require("./rules/maintainability/consistent-function-scoping").consistentFunctionScoping},get"maintainability/no-unreadable-iife"(){return require("./rules/maintainability/no-unreadable-iife").noUnreadableIife},get"maintainability/error-message"(){return require("./rules/error-handling/error-message").errorMessage},get"maintainability/no-missing-error-context"(){return require("./rules/error-handling/no-missing-error-context").noMissingErrorContext},get"maintainability/no-silent-errors"(){return require("./rules/error-handling/no-silent-errors").noSilentErrors},get"maintainability/no-unhandled-promise"(){return require("./rules/error-handling/no-unhandled-promise").noUnhandledPromise}};(0,eslint_devkit_1.withCanonicalDocsUrls)("plugin-maintainability",exports.rules);exports.plugin={meta:{name:"eslint-plugin-maintainability",version:"3.2.11"},rules:exports.rules};exports.configs={recommended:{plugins:{"maintainability":exports.plugin},rules:{"maintainability/cognitive-complexity":"warn","maintainability/identical-functions":"warn","maintainability/max-parameters":"warn"}}};exports.default=exports.plugin;
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.configs=exports.plugin=exports.rules=void 0;const eslint_devkit_1=require("@interlace/eslint-devkit");exports.rules={get"cognitive-complexity"(){return require("./rules/maintainability/cognitive-complexity").cognitiveComplexity},get"nested-complexity-hotspots"(){return require("./rules/maintainability/nested-complexity-hotspots").nestedComplexityHotspots},get"identical-functions"(){return require("./rules/maintainability/identical-functions").identicalFunctions},get"max-parameters"(){return require("./rules/maintainability/max-parameters").maxParameters},get"no-lonely-if"(){return require("./rules/maintainability/no-lonely-if").noLonelyIf},get"no-nested-ternary"(){return require("./rules/maintainability/no-nested-ternary").noNestedTernary},get"consistent-function-scoping"(){return require("./rules/maintainability/consistent-function-scoping").consistentFunctionScoping},get"no-unreadable-iife"(){return require("./rules/maintainability/no-unreadable-iife").noUnreadableIife},get"error-message"(){return require("./rules/error-handling/error-message").errorMessage},get"no-missing-error-context"(){return require("./rules/error-handling/no-missing-error-context").noMissingErrorContext},get"no-silent-errors"(){return require("./rules/error-handling/no-silent-errors").noSilentErrors},get"no-unhandled-promise"(){return require("./rules/error-handling/no-unhandled-promise").noUnhandledPromise},get"maintainability/cognitive-complexity"(){return require("./rules/maintainability/cognitive-complexity").cognitiveComplexity},get"maintainability/nested-complexity-hotspots"(){return require("./rules/maintainability/nested-complexity-hotspots").nestedComplexityHotspots},get"maintainability/identical-functions"(){return require("./rules/maintainability/identical-functions").identicalFunctions},get"maintainability/max-parameters"(){return require("./rules/maintainability/max-parameters").maxParameters},get"maintainability/no-lonely-if"(){return require("./rules/maintainability/no-lonely-if").noLonelyIf},get"maintainability/no-nested-ternary"(){return require("./rules/maintainability/no-nested-ternary").noNestedTernary},get"maintainability/consistent-function-scoping"(){return require("./rules/maintainability/consistent-function-scoping").consistentFunctionScoping},get"maintainability/no-unreadable-iife"(){return require("./rules/maintainability/no-unreadable-iife").noUnreadableIife},get"maintainability/error-message"(){return require("./rules/error-handling/error-message").errorMessage},get"maintainability/no-missing-error-context"(){return require("./rules/error-handling/no-missing-error-context").noMissingErrorContext},get"maintainability/no-silent-errors"(){return require("./rules/error-handling/no-silent-errors").noSilentErrors},get"maintainability/no-unhandled-promise"(){return require("./rules/error-handling/no-unhandled-promise").noUnhandledPromise}};(0,eslint_devkit_1.withCanonicalDocsUrls)("plugin-maintainability",exports.rules);exports.plugin={meta:{name:"eslint-plugin-maintainability",version:"3.2.12"},rules:exports.rules};exports.configs={recommended:{plugins:{"maintainability":exports.plugin},rules:{"maintainability/cognitive-complexity":"warn","maintainability/identical-functions":"warn","maintainability/max-parameters":"warn"}}};exports.default=exports.plugin;
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.noMissingErrorContext=void 0;const eslint_devkit_1=require("@interlace/eslint-devkit");const eslint_devkit_2=require("@interlace/eslint-devkit");const BUILTIN_ERROR_CONSTRUCTORS=new Set(["Error","TypeError","RangeError","SyntaxError","ReferenceError","EvalError","URIError","AggregateError"]);function isProvablyString(node){if(node.type==="TemplateLiteral")return true;if(node.type==="Literal"){return typeof node.value==="string"&&node.value.length>0}if(node.type==="LogicalExpression"){return node.operator==="&&"?isProvablyString(node.right):isProvablyString(node.left)||isProvablyString(node.right)}if(node.type==="ConditionalExpression"){return isProvablyString(node.consequent)||isProvablyString(node.alternate)}if(node.type==="BinaryExpression"&&node.operator==="+"){return isProvablyString(node.left)||isProvablyString(node.right)}return false}function hasErrorMessage(node){if(!node.argument){return false}if(node.argument.type==="Identifier"&&node.argument.name!=="undefined"&&node.argument.name!=="NaN"&&node.argument.name!=="Infinity"){return true}const constructed=node.argument.type==="NewExpression"||node.argument.type==="CallExpression"?node.argument:null;if(constructed!==null&&constructed.callee.type==="Identifier"){if(constructed.type==="CallExpression"&&!BUILTIN_ERROR_CONSTRUCTORS.has(constructed.callee.name)){return false}if(constructed.arguments.length===0){return false}const firstArg=constructed.arguments[0];const staticText=(0,eslint_devkit_1.staticString)(firstArg);if(staticText!==null){return staticText.length>0}if(!BUILTIN_ERROR_CONSTRUCTORS.has(constructed.callee.name)){return true}return isProvablyString(firstArg)}if(node.argument.type==="Literal"&&typeof node.argument.value==="string"){return node.argument.value.length>0}if(node.argument.type==="TemplateLiteral"){return true}return false}function hasErrorStack(node){if(!node.argument){return false}if(node.argument.type==="Identifier"&&node.argument.name!=="undefined"&&node.argument.name!=="NaN"&&node.argument.name!=="Infinity"){return true}if((node.argument.type==="NewExpression"||node.argument.type==="CallExpression")&&node.argument.callee.type==="Identifier"){const calleeName=node.argument.callee.name;if(calleeName==="Error"||calleeName.endsWith("Error")){return true}}return false}exports.noMissingErrorContext=(0,eslint_devkit_2.createRule)({name:"no-missing-error-context",meta:{type:"suggestion",docs:{url:"https://github.com/ofri-peretz/eslint/blob/main/packages/eslint-plugin-maintainability/docs/rules/no-missing-error-context.md",description:"Detects thrown errors without context"},hasSuggestions:true,messages:{missingErrorContext:(0,eslint_devkit_1.formatLLMMessage)({icon:eslint_devkit_1.MessageIcons.WARNING,issueName:"Missing error context",description:"Thrown error missing {{missing}}",severity:"MEDIUM",fix:"Add error message and use Error class for stack trace",documentationLink:"https://rules.sonarsource.com/javascript/RSPEC-1128/"}),addErrorMessage:(0,eslint_devkit_1.formatLLMMessage)({icon:eslint_devkit_1.MessageIcons.INFO,issueName:"Add Error Message",description:"Add descriptive error message",severity:"LOW",fix:'throw new Error("descriptive message")',documentationLink:"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error"}),addErrorStack:(0,eslint_devkit_1.formatLLMMessage)({icon:eslint_devkit_1.MessageIcons.INFO,issueName:"Use Error Class",description:"Use Error class for stack trace",severity:"LOW",fix:"throw new Error(message) instead of throw message",documentationLink:"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error"}),useErrorClass:(0,eslint_devkit_1.formatLLMMessage)({icon:eslint_devkit_1.MessageIcons.INFO,issueName:"Use Specific Error",description:"Use specific error class",severity:"LOW",fix:'throw new TypeError("message") or throw new RangeError("message")',documentationLink:"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypeError"})},schema:[{type:"object",properties:{requireMessage:{type:"boolean",default:true,description:"Require error message"},requireStackTrace:{type:"boolean",default:false,description:"Require stack trace"},ignoreInTests:{type:"boolean",default:true,description:"Ignore in test files"}},additionalProperties:false}]},defaultOptions:[{requireMessage:true,requireStackTrace:false,ignoreInTests:true}],create(context,[options={}]){const{requireMessage=true,requireStackTrace=false,ignoreInTests=true}=options||{};const filename=context.filename;const isTestFile=ignoreInTests&&/\.(test|spec)\.(ts|tsx|js|jsx)$/.test(filename);if(isTestFile){return{}}function checkThrowStatement(node){const missing=[];if(requireMessage&&!hasErrorMessage(node)){missing.push("message")}if(requireStackTrace&&!hasErrorStack(node)){missing.push("stack trace")}if(missing.length===0){return}context.report({node,messageId:"missingErrorContext",data:{missing:missing.join(" and ")},suggest:[{messageId:"addErrorMessage",fix:()=>null},{messageId:"addErrorStack",fix:()=>null},{messageId:"useErrorClass",fix:()=>null}]})}return{ThrowStatement:checkThrowStatement}}});
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.noMissingErrorContext=void 0;const eslint_devkit_1=require("@interlace/eslint-devkit");const eslint_devkit_2=require("@interlace/eslint-devkit");const BUILTIN_ERROR_CONSTRUCTORS=new Set(["Error","TypeError","RangeError","SyntaxError","ReferenceError","EvalError","URIError","AggregateError"]);function isProvablyString(node,sourceCode){if(node.type==="TemplateLiteral")return true;if(node.type==="Identifier"){const init=constInitializer(node,sourceCode);return init!==null&&isProvablyString(init,sourceCode)}if(node.type==="Literal"){return typeof node.value==="string"&&node.value.length>0}if(node.type==="LogicalExpression"){return node.operator==="&&"?isProvablyString(node.right,sourceCode):isProvablyString(node.left,sourceCode)||isProvablyString(node.right,sourceCode)}if(node.type==="ConditionalExpression"){return isProvablyString(node.consequent,sourceCode)||isProvablyString(node.alternate,sourceCode)}if(node.type==="BinaryExpression"&&node.operator==="+"){return isProvablyString(node.left,sourceCode)||isProvablyString(node.right,sourceCode)}return false}function constInitializer(node,sourceCode){let scope=sourceCode.getScope(node);let variable;while(scope&&!variable){variable=scope.set?.get(node.name);scope=scope.upper}if(!variable||variable.defs.length!==1)return null;const def=variable.defs[0];if(def?.type!=="Variable"||def.parent.kind!=="const")return null;return def.node.init??null}function hasErrorMessage(node,sourceCode){if(!node.argument){return false}if(node.argument.type==="Identifier"&&node.argument.name!=="undefined"&&node.argument.name!=="NaN"&&node.argument.name!=="Infinity"){return true}const constructed=node.argument.type==="NewExpression"||node.argument.type==="CallExpression"?node.argument:null;if(constructed!==null&&constructed.callee.type==="Identifier"){if(constructed.type==="CallExpression"&&!BUILTIN_ERROR_CONSTRUCTORS.has(constructed.callee.name)){return false}if(constructed.arguments.length===0){return false}const firstArg=constructed.arguments[0];const staticText=(0,eslint_devkit_1.staticString)(firstArg);if(staticText!==null){return staticText.length>0}if(!BUILTIN_ERROR_CONSTRUCTORS.has(constructed.callee.name)){return true}return isProvablyString(firstArg,sourceCode)}if(node.argument.type==="Literal"&&typeof node.argument.value==="string"){return node.argument.value.length>0}if(node.argument.type==="TemplateLiteral"){return true}return false}function hasErrorStack(node){if(!node.argument){return false}if(node.argument.type==="Identifier"&&node.argument.name!=="undefined"&&node.argument.name!=="NaN"&&node.argument.name!=="Infinity"){return true}if((node.argument.type==="NewExpression"||node.argument.type==="CallExpression")&&node.argument.callee.type==="Identifier"){const calleeName=node.argument.callee.name;if(calleeName==="Error"||calleeName.endsWith("Error")){return true}}return false}exports.noMissingErrorContext=(0,eslint_devkit_2.createRule)({name:"no-missing-error-context",meta:{type:"suggestion",docs:{url:"https://github.com/ofri-peretz/eslint/blob/main/packages/eslint-plugin-maintainability/docs/rules/no-missing-error-context.md",description:"Detects thrown errors without context"},hasSuggestions:true,messages:{missingErrorContext:(0,eslint_devkit_1.formatLLMMessage)({icon:eslint_devkit_1.MessageIcons.WARNING,issueName:"Missing error context",description:"Thrown error missing {{missing}}",severity:"MEDIUM",fix:"Add error message and use Error class for stack trace",documentationLink:"https://rules.sonarsource.com/javascript/RSPEC-1128/"}),addErrorMessage:(0,eslint_devkit_1.formatLLMMessage)({icon:eslint_devkit_1.MessageIcons.INFO,issueName:"Add Error Message",description:"Add descriptive error message",severity:"LOW",fix:'throw new Error("descriptive message")',documentationLink:"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error"}),addErrorStack:(0,eslint_devkit_1.formatLLMMessage)({icon:eslint_devkit_1.MessageIcons.INFO,issueName:"Use Error Class",description:"Use Error class for stack trace",severity:"LOW",fix:"throw new Error(message) instead of throw message",documentationLink:"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error"}),useErrorClass:(0,eslint_devkit_1.formatLLMMessage)({icon:eslint_devkit_1.MessageIcons.INFO,issueName:"Use Specific Error",description:"Use specific error class",severity:"LOW",fix:'throw new TypeError("message") or throw new RangeError("message")',documentationLink:"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypeError"})},schema:[{type:"object",properties:{requireMessage:{type:"boolean",default:true,description:"Require error message"},requireStackTrace:{type:"boolean",default:false,description:"Require stack trace"},ignoreInTests:{type:"boolean",default:true,description:"Ignore in test files"}},additionalProperties:false}]},defaultOptions:[{requireMessage:true,requireStackTrace:false,ignoreInTests:true}],create(context,[options={}]){const{requireMessage=true,requireStackTrace=false,ignoreInTests=true}=options||{};const filename=context.filename;const isTestFile=ignoreInTests&&/\.(test|spec)\.(ts|tsx|js|jsx)$/.test(filename);if(isTestFile){return{}}function checkThrowStatement(node){const missing=[];if(requireMessage&&!hasErrorMessage(node,context.sourceCode)){missing.push("message")}if(requireStackTrace&&!hasErrorStack(node)){missing.push("stack trace")}if(missing.length===0){return}context.report({node,messageId:"missingErrorContext",data:{missing:missing.join(" and ")},suggest:[{messageId:"addErrorMessage",fix:()=>null},{messageId:"addErrorStack",fix:()=>null},{messageId:"useErrorClass",fix:()=>null}]})}return{ThrowStatement:checkThrowStatement}}});
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.cognitiveComplexity=void 0;const eslint_devkit_1=require("@interlace/eslint-devkit");const eslint_devkit_2=require("@interlace/eslint-devkit");const eslint_devkit_3=require("@interlace/eslint-devkit");exports.cognitiveComplexity=(0,eslint_devkit_2.createRule)({name:"cognitive-complexity",skipGeneratedFiles:true,meta:{type:"suggestion",docs:{url:"https://github.com/ofri-peretz/eslint/blob/main/packages/eslint-plugin-maintainability/docs/rules/cognitive-complexity.md",description:"Enforces a maximum cognitive complexity threshold with refactoring guidance",cwe:"CWE-1104",cvss:7.5},hasSuggestions:true,messages:{highCognitiveComplexity:(0,eslint_devkit_1.formatLLMMessage)({icon:eslint_devkit_1.MessageIcons.COMPLEXITY,issueName:"High cognitive complexity",cwe:"CWE-1104",description:"{{functionName}}: {{complexity}}/{{max}} ({{overBy}} over)",severity:"HIGH",fix:"Extract logic to helpers",documentationLink:"https://en.wikipedia.org/wiki/Cognitive_complexity"}),extractMethod:(0,eslint_devkit_1.formatLLMMessage)({icon:eslint_devkit_1.MessageIcons.INFO,issueName:"Extract Method",description:"Extract nested logic to separate method",severity:"LOW",fix:'Extract to "{{methodName}}" (reduces complexity by ~{{reduction}})',documentationLink:"https://refactoring.guru/extract-method"}),simplifyLogic:(0,eslint_devkit_1.formatLLMMessage)({icon:eslint_devkit_1.MessageIcons.INFO,issueName:"Simplify Logic",description:"Simplify conditional logic",severity:"LOW",fix:"Use guard clauses and early returns",documentationLink:"https://refactoring.guru/replace-nested-conditional-with-guard-clauses"}),useStrategy:(0,eslint_devkit_1.formatLLMMessage)({icon:eslint_devkit_1.MessageIcons.INFO,issueName:"Use Strategy Pattern",description:"Apply design pattern to reduce complexity",severity:"LOW",fix:"Apply {{pattern}} pattern",documentationLink:"https://refactoring.guru/design-patterns/strategy"})},schema:[{type:"object",properties:{maxComplexity:{type:"number",default:15,minimum:1},includeMetrics:{type:"boolean",default:true}},additionalProperties:false}]},defaultOptions:[{maxComplexity:15,includeMetrics:true}],create(context){const{maxComplexity=15}=context.options[0]||{};const filename=context.filename;function calculateCognitiveComplexity(node){let complexity=0;const breakdown={conditionals:0,loops:0,switches:0,nesting:0,logicalOperators:0,catches:0,recursion:0};const functionName=node.type==="FunctionDeclaration"&&node.id?node.id.name:"anonymous";function traverse(n,currentNesting){if(n.type==="IfStatement"){complexity+=1+currentNesting;breakdown.conditionals++;traverse(n.test,currentNesting);traverse(n.consequent,currentNesting+1);if(n.alternate){if(n.alternate.type==="IfStatement"){traverse(n.alternate,currentNesting)}else{complexity+=1;traverse(n.alternate,currentNesting+1)}}return}if(n.type==="ForStatement"||n.type==="ForInStatement"||n.type==="ForOfStatement"||n.type==="WhileStatement"||n.type==="DoWhileStatement"){complexity+=1+currentNesting;breakdown.loops++;if(n.type==="ForStatement"){if(n.init)traverse(n.init,currentNesting);if(n.test)traverse(n.test,currentNesting);if(n.update)traverse(n.update,currentNesting);traverse(n.body,currentNesting+1)}else if(n.type==="WhileStatement"||n.type==="DoWhileStatement"){traverse(n.test,currentNesting);traverse(n.body,currentNesting+1)}else{if("left"in n)traverse(n.left,currentNesting);if("right"in n)traverse(n.right,currentNesting);traverse(n.body,currentNesting+1)}return}if(n.type==="SwitchStatement"){complexity+=1+currentNesting;breakdown.switches++;traverse(n.discriminant,currentNesting);n.cases.forEach(c=>traverse(c,currentNesting+1));return}if(n.type==="LogicalExpression"){if(n.operator==="&&"||n.operator==="||"||n.operator==="??"){const parent=n.parent;const continuesSequence=parent?.type==="LogicalExpression"&&parent.operator===n.operator;if(!continuesSequence){complexity+=1;breakdown.logicalOperators++}}}if(n.type==="CatchClause"){complexity+=1+currentNesting;breakdown.catches++;traverse(n.body,currentNesting+1);return}if(n.type==="ConditionalExpression"){complexity+=1+currentNesting;breakdown.conditionals++}if(n.type==="CallExpression"){if(n.callee.type==="Identifier"&&n.callee.name===functionName){complexity+=1;breakdown.recursion++}}if(n.type==="BlockStatement"||n.type==="FunctionDeclaration"||n.type==="FunctionExpression"||n.type==="ArrowFunctionExpression"){breakdown.nesting=Math.max(breakdown.nesting,currentNesting)}const visited=new Set;function traverseChild(child){if(child&&typeof child==="object"&&"type"in child){const childNode=child;if(!visited.has(childNode)){visited.add(childNode);traverse(childNode,currentNesting)}}}const childKeys=["body","test","consequent","alternate","init","update","left","right","argument","arguments","callee","object","property","elements","properties","expression","expressions","declarations","declaration","specifiers","source","key","value","handler","block","finalizer"];for(const key of childKeys){const child=n[key];if(child){if(Array.isArray(child)){child.forEach(traverseChild)}else{traverseChild(child)}}}}if(node.body){traverse(node.body,0)}return{total:complexity,breakdown}}function suggestExtractions(node,breakdown){const suggestions=[];if(breakdown.nesting>=4&&node.loc){suggestions.push({name:"extractNestedLogic",reason:`Nesting depth of ${breakdown.nesting} makes code hard to follow`,lineRange:[node.loc.start.line,node.loc.end.line],estimatedComplexityReduction:Math.floor(breakdown.nesting*1.5)})}if(breakdown.switches>=2&&node.loc){suggestions.push({name:"refactorSwitchToStrategy",reason:`${breakdown.switches} switch statements suggest strategy pattern`,lineRange:[node.loc.start.line,node.loc.end.line],estimatedComplexityReduction:breakdown.switches*2})}if(breakdown.loops>=3&&node.loc){suggestions.push({name:"extractLoopLogic",reason:`${breakdown.loops} loops can be extracted to separate methods`,lineRange:[node.loc.start.line,node.loc.end.line],estimatedComplexityReduction:breakdown.loops*2})}if(breakdown.conditionals>=5&&node.loc){suggestions.push({name:"simplifyConditionals",reason:`${breakdown.conditionals} conditional branches could use Guard Clauses`,lineRange:[node.loc.start.line,node.loc.end.line],estimatedComplexityReduction:Math.floor(breakdown.conditionals*.8)})}return suggestions}function suggestPattern(breakdown){if(breakdown.switches>=2)return"Strategy Pattern";if(breakdown.conditionals>=5)return"Guard Clauses + Early Return";if(breakdown.loops>=3)return"Extract Method + Pipeline";if(breakdown.nesting>=4)return"Extract Method + Composed Functions";return"Extract Method"}function estimateRefactoringTime(complexity,breakdown){const baseTime=Math.floor((complexity-maxComplexity)*3);const nestingPenalty=breakdown.nesting>=4?15:0;const totalMinutes=baseTime+nestingPenalty;if(totalMinutes<30)return`${totalMinutes} minutes`;if(totalMinutes<60)return"30-60 minutes";return`${Math.ceil(totalMinutes/60)} hours`}function checkFunction(node){const{total:complexity,breakdown}=calculateCognitiveComplexity(node);if(complexity<=maxComplexity)return;const functionSignature=(0,eslint_devkit_3.extractFunctionSignature)(node);const suggestions=suggestExtractions(node,breakdown);const pattern=suggestPattern(breakdown);const estimatedTime=estimateRefactoringTime(complexity,breakdown);context.report({node,messageId:"highCognitiveComplexity",data:{functionName:functionSignature,complexity:String(complexity),max:String(maxComplexity),overBy:String(complexity-maxComplexity),current:String(complexity),filePath:filename,line:String(node.loc?.start.line??0),conditionals:String(breakdown.conditionals),loops:String(breakdown.loops),nesting:String(breakdown.nesting),pattern,estimatedTime},suggest:suggestions.length>0?suggestions.map((suggestion,index)=>{const messageId=index===0?"extractMethod":index===1?"useStrategy":"simplifyLogic";return{messageId,data:{methodName:suggestion.name,pattern,reduction:String(suggestion.estimatedComplexityReduction)},fix:()=>null}}):void 0})}return{FunctionDeclaration:checkFunction,FunctionExpression:checkFunction,ArrowFunctionExpression:checkFunction}}});
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.cognitiveComplexity=void 0;const eslint_devkit_1=require("@interlace/eslint-devkit");const eslint_devkit_2=require("@interlace/eslint-devkit");const eslint_devkit_3=require("@interlace/eslint-devkit");exports.cognitiveComplexity=(0,eslint_devkit_2.createRule)({name:"cognitive-complexity",skipGeneratedFiles:true,meta:{type:"suggestion",docs:{url:"https://github.com/ofri-peretz/eslint/blob/main/packages/eslint-plugin-maintainability/docs/rules/cognitive-complexity.md",description:"Enforces a maximum cognitive complexity threshold with refactoring guidance",cwe:"CWE-1104",cvss:7.5},hasSuggestions:true,messages:{highCognitiveComplexity:(0,eslint_devkit_1.formatLLMMessage)({icon:eslint_devkit_1.MessageIcons.COMPLEXITY,issueName:"High cognitive complexity",cwe:"CWE-1104",description:"{{functionName}}: {{complexity}}/{{max}} ({{overBy}} over)",severity:"HIGH",fix:"Extract logic to helpers",documentationLink:"https://en.wikipedia.org/wiki/Cognitive_complexity"}),extractMethod:(0,eslint_devkit_1.formatLLMMessage)({icon:eslint_devkit_1.MessageIcons.INFO,issueName:"Extract Method",description:"Extract nested logic to separate method",severity:"LOW",fix:'Extract to "{{methodName}}" (reduces complexity by ~{{reduction}})',documentationLink:"https://refactoring.guru/extract-method"}),simplifyLogic:(0,eslint_devkit_1.formatLLMMessage)({icon:eslint_devkit_1.MessageIcons.INFO,issueName:"Simplify Logic",description:"Simplify conditional logic",severity:"LOW",fix:"Use guard clauses and early returns",documentationLink:"https://refactoring.guru/replace-nested-conditional-with-guard-clauses"}),useStrategy:(0,eslint_devkit_1.formatLLMMessage)({icon:eslint_devkit_1.MessageIcons.INFO,issueName:"Use Strategy Pattern",description:"Apply design pattern to reduce complexity",severity:"LOW",fix:"Apply {{pattern}} pattern",documentationLink:"https://refactoring.guru/design-patterns/strategy"})},schema:[{type:"object",properties:{maxComplexity:{type:"number",default:15,minimum:1},includeMetrics:{type:"boolean",default:true}},additionalProperties:false}]},defaultOptions:[{maxComplexity:15,includeMetrics:true}],create(context){const{maxComplexity=15}=context.options[0]||{};const filename=context.filename;function calculateCognitiveComplexity(node){let complexity=0;const breakdown={conditionals:0,loops:0,switches:0,nesting:0,logicalOperators:0,catches:0,recursion:0};const functionName=node.type==="FunctionDeclaration"&&node.id?node.id.name:"anonymous";function traverse(n,currentNesting){if(n.type==="FunctionDeclaration"||n.type==="FunctionExpression"||n.type==="ArrowFunctionExpression"){return}if(n.type==="IfStatement"){complexity+=1+currentNesting;breakdown.conditionals++;traverse(n.test,currentNesting);traverse(n.consequent,currentNesting+1);if(n.alternate){if(n.alternate.type==="IfStatement"){traverse(n.alternate,currentNesting)}else{complexity+=1;traverse(n.alternate,currentNesting+1)}}return}if(n.type==="ForStatement"||n.type==="ForInStatement"||n.type==="ForOfStatement"||n.type==="WhileStatement"||n.type==="DoWhileStatement"){complexity+=1+currentNesting;breakdown.loops++;if(n.type==="ForStatement"){if(n.init)traverse(n.init,currentNesting);if(n.test)traverse(n.test,currentNesting);if(n.update)traverse(n.update,currentNesting);traverse(n.body,currentNesting+1)}else if(n.type==="WhileStatement"||n.type==="DoWhileStatement"){traverse(n.test,currentNesting);traverse(n.body,currentNesting+1)}else{if("left"in n)traverse(n.left,currentNesting);if("right"in n)traverse(n.right,currentNesting);traverse(n.body,currentNesting+1)}return}if(n.type==="SwitchStatement"){complexity+=1+currentNesting;breakdown.switches++;traverse(n.discriminant,currentNesting);n.cases.forEach(c=>traverse(c,currentNesting+1));return}if(n.type==="LogicalExpression"){if(n.operator==="&&"||n.operator==="||"||n.operator==="??"){const parent=n.parent;const continuesSequence=parent?.type==="LogicalExpression"&&parent.operator===n.operator;if(!continuesSequence){complexity+=1;breakdown.logicalOperators++}}}if(n.type==="CatchClause"){complexity+=1+currentNesting;breakdown.catches++;traverse(n.body,currentNesting+1);return}if(n.type==="ConditionalExpression"){complexity+=1+currentNesting;breakdown.conditionals++}if(n.type==="CallExpression"){if(n.callee.type==="Identifier"&&n.callee.name===functionName){complexity+=1;breakdown.recursion++}}if(n.type==="BlockStatement"){breakdown.nesting=Math.max(breakdown.nesting,currentNesting)}const visited=new Set;function traverseChild(child){if(child&&typeof child==="object"&&"type"in child){const childNode=child;if(!visited.has(childNode)){visited.add(childNode);traverse(childNode,currentNesting)}}}const childKeys=["body","test","consequent","alternate","init","update","left","right","argument","arguments","callee","object","property","elements","properties","expression","expressions","declarations","declaration","specifiers","source","key","value","handler","block","finalizer"];for(const key of childKeys){const child=n[key];if(child){if(Array.isArray(child)){child.forEach(traverseChild)}else{traverseChild(child)}}}}if(node.body){traverse(node.body,0)}return{total:complexity,breakdown}}function suggestExtractions(node,breakdown){const suggestions=[];if(breakdown.nesting>=4&&node.loc){suggestions.push({name:"extractNestedLogic",reason:`Nesting depth of ${breakdown.nesting} makes code hard to follow`,lineRange:[node.loc.start.line,node.loc.end.line],estimatedComplexityReduction:Math.floor(breakdown.nesting*1.5)})}if(breakdown.switches>=2&&node.loc){suggestions.push({name:"refactorSwitchToStrategy",reason:`${breakdown.switches} switch statements suggest strategy pattern`,lineRange:[node.loc.start.line,node.loc.end.line],estimatedComplexityReduction:breakdown.switches*2})}if(breakdown.loops>=3&&node.loc){suggestions.push({name:"extractLoopLogic",reason:`${breakdown.loops} loops can be extracted to separate methods`,lineRange:[node.loc.start.line,node.loc.end.line],estimatedComplexityReduction:breakdown.loops*2})}if(breakdown.conditionals>=5&&node.loc){suggestions.push({name:"simplifyConditionals",reason:`${breakdown.conditionals} conditional branches could use Guard Clauses`,lineRange:[node.loc.start.line,node.loc.end.line],estimatedComplexityReduction:Math.floor(breakdown.conditionals*.8)})}return suggestions}function suggestPattern(breakdown){if(breakdown.switches>=2)return"Strategy Pattern";if(breakdown.conditionals>=5)return"Guard Clauses + Early Return";if(breakdown.loops>=3)return"Extract Method + Pipeline";if(breakdown.nesting>=4)return"Extract Method + Composed Functions";return"Extract Method"}function estimateRefactoringTime(complexity,breakdown){const baseTime=Math.floor((complexity-maxComplexity)*3);const nestingPenalty=breakdown.nesting>=4?15:0;const totalMinutes=baseTime+nestingPenalty;if(totalMinutes<30)return`${totalMinutes} minutes`;if(totalMinutes<60)return"30-60 minutes";return`${Math.ceil(totalMinutes/60)} hours`}function checkFunction(node){const{total:complexity,breakdown}=calculateCognitiveComplexity(node);if(complexity<=maxComplexity)return;const functionSignature=(0,eslint_devkit_3.extractFunctionSignature)(node);const suggestions=suggestExtractions(node,breakdown);const pattern=suggestPattern(breakdown);const estimatedTime=estimateRefactoringTime(complexity,breakdown);context.report({node,messageId:"highCognitiveComplexity",data:{functionName:functionSignature,complexity:String(complexity),max:String(maxComplexity),overBy:String(complexity-maxComplexity),current:String(complexity),filePath:filename,line:String(node.loc?.start.line??0),conditionals:String(breakdown.conditionals),loops:String(breakdown.loops),nesting:String(breakdown.nesting),pattern,estimatedTime},suggest:suggestions.length>0?suggestions.map((suggestion,index)=>{const messageId=index===0?"extractMethod":index===1?"useStrategy":"simplifyLogic";return{messageId,data:{methodName:suggestion.name,pattern,reduction:String(suggestion.estimatedComplexityReduction)},fix:()=>null}}):void 0})}return{FunctionDeclaration:checkFunction,FunctionExpression:checkFunction,ArrowFunctionExpression:checkFunction}}});
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.consistentFunctionScoping=void 0;const eslint_devkit_1=require("@interlace/eslint-devkit");const eslint_devkit_2=require("@interlace/eslint-devkit");const BINDING_WRAPPERS=new Set(["VariableDeclarator","VariableDeclaration","TSAsExpression","TSSatisfiesExpression","TSNonNullExpression","TSTypeAssertion"]);exports.consistentFunctionScoping=(0,eslint_devkit_1.createRule)({name:"consistent-function-scoping",meta:{type:"suggestion",docs:{url:"https://github.com/ofri-peretz/eslint/blob/main/packages/eslint-plugin-maintainability/docs/rules/consistent-function-scoping.md",description:"Move function definitions to the highest possible scope to improve readability and performance"},hasSuggestions:true,messages:{inconsistentFunctionScoping:(0,eslint_devkit_2.formatLLMMessage)({icon:eslint_devkit_2.MessageIcons.ARCHITECTURE,issueName:"Inconsistent Function Scoping",description:"Function can be moved to higher scope as it doesn't capture outer variables",severity:"MEDIUM",fix:"Move function declaration to module scope",documentationLink:"https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/consistent-function-scoping.md"}),moveToModuleScope:(0,eslint_devkit_2.formatLLMMessage)({icon:eslint_devkit_2.MessageIcons.ARCHITECTURE,issueName:"Function Scoping Optimization",description:"Function does not use variables from its containing scope and can be moved to module level",severity:"MEDIUM",fix:'Move function outside current scope: extract `function helper() { return "value"; }` to module level before the containing function/class',documentationLink:"https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/consistent-function-scoping.md"})},schema:[{type:"object",properties:{checkArrowFunctions:{type:"boolean",default:true}},additionalProperties:false}]},defaultOptions:[{checkArrowFunctions:true}],create(context){const[options]=context.options;const{checkArrowFunctions=true}=options||{};const scopeStack=[new Set];function enterScope(){scopeStack.push(new Set)}function exitScope(){scopeStack.pop()}function addVariableToCurrentScope(name){const currentScope=scopeStack[scopeStack.length-1];if(currentScope){currentScope.add(name)}}function hoistFunctionDeclarations(body){for(const statement of body){if(statement.type===eslint_devkit_1.AST_NODE_TYPES.FunctionDeclaration&&statement.id){addVariableToCurrentScope(statement.id.name)}}}function addBindingToCurrentScope(target){switch(target.type){case"Identifier":addVariableToCurrentScope(target.name);break;case"ObjectPattern":for(const prop of target.properties){addBindingToCurrentScope(prop.type==="RestElement"?prop.argument:prop.value)}break;case"ArrayPattern":for(const element of target.elements){if(element)addBindingToCurrentScope(element)}break;case"AssignmentPattern":addBindingToCurrentScope(target.left);break;case"RestElement":addBindingToCurrentScope(target.argument);break;case"TSParameterProperty":addBindingToCurrentScope(target.parameter);break}}const MODULE_SCOPE_DEPTH=2;function getOuterScopeVariables(){const outerScopes=scopeStack.slice(0,-1).slice(MODULE_SCOPE_DEPTH);const outerVars=new Set;for(const scope of outerScopes){for(const varName of scope){outerVars.add(varName)}}return outerVars}function capturesThis(node){if(node.type==="ThisExpression")return true;for(const key in node){if(key==="parent")continue;const value=node[key];const children=Array.isArray(value)?value:[value];for(const child of children){if(!child||typeof child!=="object")continue;const childNode=child;if(typeof childNode.type!=="string")continue;if(childNode.type==="ClassDeclaration"||childNode.type==="ClassExpression"){if(childNode.superClass&&capturesThis(childNode.superClass)){return true}for(const member of childNode.body.body){if("computed"in member&&member.computed&&capturesThis(member.key)){return true}}continue}if(childNode.type==="FunctionDeclaration"||childNode.type==="FunctionExpression"){continue}if(capturesThis(childNode))return true}}return false}function analyzeFunction(node){let ancestor=node.parent;while(ancestor&&BINDING_WRAPPERS.has(ancestor.type)){ancestor=ancestor.parent}if(ancestor?.type==="Program"||ancestor?.type==="ExportNamedDeclaration"||ancestor?.type==="ExportDefaultDeclaration"){return}const p=node.parent;if(p?.type==="MethodDefinition"||p?.type==="PropertyDefinition"){return}if(node.type==="ArrowFunctionExpression"&&capturesThis(node)){return}if(p?.type==="CallExpression"||p?.type==="NewExpression"){return}if(p?.type==="Property"){return}const referencedVars=new Set;function collectReferences(astNode,depth=0){if(astNode.type==="Identifier"){referencedVars.add(astNode.name)}if(depth<10){for(const key in astNode){if(key==="parent")continue;const child=astNode[key];if(child&&typeof child==="object"){if(Array.isArray(child)){child.forEach(item=>{if(item&&typeof item==="object"&&"type"in item){collectReferences(item,depth+1)}})}else if("type"in child){collectReferences(child,depth+1)}}}}}if(node.body.type==="BlockStatement"){node.body.body.forEach(stmt=>collectReferences(stmt))}else{collectReferences(node.body)}node.params.forEach(param=>{collectReferences(param)});const outerVars=getOuterScopeVariables();const boundNames=new Set(context.sourceCode.getDeclaredVariables(node).map(v=>v.name));let capturesOuterVar=false;for(const ref of referencedVars){if(!boundNames.has(ref)&&outerVars.has(ref)){capturesOuterVar=true;break}}if(!capturesOuterVar){const functionName=node.type==="FunctionDeclaration"?node.id?.name:void 0;const moduleScope=scopeStack[0];if(!functionName||!moduleScope.has(functionName)){context.report({node,messageId:"inconsistentFunctionScoping",data:{functionName:functionName||"anonymous function"},suggest:[{messageId:"moveToModuleScope",fix(fixer){return fixer.insertTextBefore(node,"// TODO: Move this function to module scope - it doesn't capture outer variables\n")}}]})}}}return{Program(){enterScope()},"Program:exit"(){exitScope()},FunctionDeclaration(node){enterScope();node.params.forEach(param=>{addBindingToCurrentScope(param)});hoistFunctionDeclarations(node.body.body);analyzeFunction(node)},"FunctionDeclaration:exit"(){exitScope()},FunctionExpression(node){enterScope();node.params.forEach(param=>{addBindingToCurrentScope(param)});hoistFunctionDeclarations(node.body.body);analyzeFunction(node)},"FunctionExpression:exit"(){exitScope()},ArrowFunctionExpression(node){enterScope();node.params.forEach(param=>{addBindingToCurrentScope(param)});if(checkArrowFunctions){analyzeFunction(node)}},"ArrowFunctionExpression:exit"(){exitScope()},VariableDeclaration(node){node.declarations.forEach(decl=>{addBindingToCurrentScope(decl.id)})}}}});
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.consistentFunctionScoping=void 0;const eslint_devkit_1=require("@interlace/eslint-devkit");const eslint_devkit_2=require("@interlace/eslint-devkit");const BINDING_WRAPPERS=new Set(["VariableDeclarator","VariableDeclaration","TSAsExpression","TSSatisfiesExpression","TSNonNullExpression","TSTypeAssertion","ExpressionStatement","AssignmentExpression","ConditionalExpression","LogicalExpression"]);exports.consistentFunctionScoping=(0,eslint_devkit_1.createRule)({name:"consistent-function-scoping",meta:{type:"suggestion",docs:{url:"https://github.com/ofri-peretz/eslint/blob/main/packages/eslint-plugin-maintainability/docs/rules/consistent-function-scoping.md",description:"Move function definitions to the highest possible scope to improve readability and performance"},hasSuggestions:true,messages:{inconsistentFunctionScoping:(0,eslint_devkit_2.formatLLMMessage)({icon:eslint_devkit_2.MessageIcons.ARCHITECTURE,issueName:"Inconsistent Function Scoping",description:"Function can be moved to higher scope as it doesn't capture outer variables",severity:"MEDIUM",fix:"Move function declaration to module scope",documentationLink:"https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/consistent-function-scoping.md"}),moveToModuleScope:(0,eslint_devkit_2.formatLLMMessage)({icon:eslint_devkit_2.MessageIcons.ARCHITECTURE,issueName:"Function Scoping Optimization",description:"Function does not use variables from its containing scope and can be moved to module level",severity:"MEDIUM",fix:'Move function outside current scope: extract `function helper() { return "value"; }` to module level before the containing function/class',documentationLink:"https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/consistent-function-scoping.md"})},schema:[{type:"object",properties:{checkArrowFunctions:{type:"boolean",default:true}},additionalProperties:false}]},defaultOptions:[{checkArrowFunctions:true}],create(context){const[options]=context.options;const{checkArrowFunctions=true}=options||{};const scopeStack=[new Set];function enterScope(){scopeStack.push(new Set)}function exitScope(){scopeStack.pop()}function addVariableToCurrentScope(name){const currentScope=scopeStack[scopeStack.length-1];if(currentScope){currentScope.add(name)}}function hoistFunctionDeclarations(body){for(const statement of body){if(statement.type===eslint_devkit_1.AST_NODE_TYPES.FunctionDeclaration&&statement.id){addVariableToCurrentScope(statement.id.name)}}}function addBindingToCurrentScope(target){switch(target.type){case"Identifier":addVariableToCurrentScope(target.name);break;case"ObjectPattern":for(const prop of target.properties){addBindingToCurrentScope(prop.type==="RestElement"?prop.argument:prop.value)}break;case"ArrayPattern":for(const element of target.elements){if(element)addBindingToCurrentScope(element)}break;case"AssignmentPattern":addBindingToCurrentScope(target.left);break;case"RestElement":addBindingToCurrentScope(target.argument);break;case"TSParameterProperty":addBindingToCurrentScope(target.parameter);break}}const MODULE_SCOPE_DEPTH=2;function getOuterScopeVariables(){const outerScopes=scopeStack.slice(0,-1).slice(MODULE_SCOPE_DEPTH);const outerVars=new Set;for(const scope of outerScopes){for(const varName of scope){outerVars.add(varName)}}return outerVars}function capturesThis(node){if(node.type==="ThisExpression")return true;for(const key in node){if(key==="parent")continue;const value=node[key];const children=Array.isArray(value)?value:[value];for(const child of children){if(!child||typeof child!=="object")continue;const childNode=child;if(typeof childNode.type!=="string")continue;if(childNode.type==="ClassDeclaration"||childNode.type==="ClassExpression"){if(childNode.superClass&&capturesThis(childNode.superClass)){return true}for(const member of childNode.body.body){if("computed"in member&&member.computed&&capturesThis(member.key)){return true}}continue}if(childNode.type==="FunctionDeclaration"||childNode.type==="FunctionExpression"){continue}if(capturesThis(childNode))return true}}return false}function analyzeFunction(node){let ancestor=node.parent;while(ancestor&&BINDING_WRAPPERS.has(ancestor.type)){ancestor=ancestor.parent}if(ancestor?.type==="Program"||ancestor?.type==="ExportNamedDeclaration"||ancestor?.type==="ExportDefaultDeclaration"){return}const p=node.parent;if(p?.type==="MethodDefinition"||p?.type==="PropertyDefinition"){return}if(node.type==="ArrowFunctionExpression"&&capturesThis(node)){return}if(p?.type==="CallExpression"||p?.type==="NewExpression"){return}if(p?.type==="Property"){return}const referencedVars=new Set;function collectReferences(astNode,depth=0){if(astNode.type==="Identifier"){referencedVars.add(astNode.name)}if(depth<10){for(const key in astNode){if(key==="parent")continue;const child=astNode[key];if(child&&typeof child==="object"){if(Array.isArray(child)){child.forEach(item=>{if(item&&typeof item==="object"&&"type"in item){collectReferences(item,depth+1)}})}else if("type"in child){collectReferences(child,depth+1)}}}}}if(node.body.type==="BlockStatement"){node.body.body.forEach(stmt=>collectReferences(stmt))}else{collectReferences(node.body)}node.params.forEach(param=>{collectReferences(param)});const outerVars=getOuterScopeVariables();const boundNames=new Set(context.sourceCode.getDeclaredVariables(node).map(v=>v.name));let capturesOuterVar=false;for(const ref of referencedVars){if(!boundNames.has(ref)&&outerVars.has(ref)){capturesOuterVar=true;break}}if(!capturesOuterVar){const functionName=node.type==="FunctionDeclaration"?node.id?.name:void 0;const moduleScope=scopeStack[0];if(!functionName||!moduleScope.has(functionName)){context.report({node,messageId:"inconsistentFunctionScoping",data:{functionName:functionName||"anonymous function"},suggest:[{messageId:"moveToModuleScope",fix(fixer){return fixer.insertTextBefore(node,"// TODO: Move this function to module scope - it doesn't capture outer variables\n")}}]})}}}return{Program(){enterScope()},"Program:exit"(){exitScope()},FunctionDeclaration(node){enterScope();node.params.forEach(param=>{addBindingToCurrentScope(param)});hoistFunctionDeclarations(node.body.body);analyzeFunction(node)},"FunctionDeclaration:exit"(){exitScope()},FunctionExpression(node){enterScope();node.params.forEach(param=>{addBindingToCurrentScope(param)});hoistFunctionDeclarations(node.body.body);analyzeFunction(node)},"FunctionExpression:exit"(){exitScope()},ArrowFunctionExpression(node){enterScope();node.params.forEach(param=>{addBindingToCurrentScope(param)});if(checkArrowFunctions){analyzeFunction(node)}},"ArrowFunctionExpression:exit"(){exitScope()},VariableDeclaration(node){node.declarations.forEach(decl=>{addBindingToCurrentScope(decl.id)})}}}});