eslint-plugin-reliability 4.1.3 → 4.1.4

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-reliability",
3
- "version": "4.1.3",
3
+ "version": "4.1.4",
4
4
  "description": "ESLint plugin for runtime reliability — enforces error handling, network timeouts, null checks, and safe type narrowing.",
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"no-unhandled-promise"(){return require("./rules/error-handling/no-unhandled-promise").noUnhandledPromise},get"no-silent-errors"(){return require("./rules/error-handling/no-silent-errors").noSilentErrors},get"no-missing-error-context"(){return require("./rules/error-handling/no-missing-error-context").noMissingErrorContext},get"error-message"(){return require("./rules/error-handling/error-message").errorMessage},get"no-missing-null-checks"(){return require("./rules/reliability/no-missing-null-checks").noMissingNullChecks},get"no-unsafe-type-narrowing"(){return require("./rules/reliability/no-unsafe-type-narrowing").noUnsafeTypeNarrowing},get"require-network-timeout"(){return require("./rules/reliability/require-network-timeout").requireNetworkTimeout},get"no-await-in-loop"(){return require("./rules/reliability/no-await-in-loop").noAwaitInLoop},get"no-jsdoc-terminator-in-example"(){return require("./rules/reliability/no-jsdoc-terminator-in-example").noJsdocTerminatorInExample},get"error-handling/no-unhandled-promise"(){return require("./rules/error-handling/no-unhandled-promise").noUnhandledPromise},get"error-handling/no-silent-errors"(){return require("./rules/error-handling/no-silent-errors").noSilentErrors},get"error-handling/no-missing-error-context"(){return require("./rules/error-handling/no-missing-error-context").noMissingErrorContext},get"error-handling/error-message"(){return require("./rules/error-handling/error-message").errorMessage},get"reliability/no-missing-null-checks"(){return require("./rules/reliability/no-missing-null-checks").noMissingNullChecks},get"reliability/no-unsafe-type-narrowing"(){return require("./rules/reliability/no-unsafe-type-narrowing").noUnsafeTypeNarrowing},get"reliability/require-network-timeout"(){return require("./rules/reliability/require-network-timeout").requireNetworkTimeout},get"reliability/no-await-in-loop"(){return require("./rules/reliability/no-await-in-loop").noAwaitInLoop},get"reliability/no-jsdoc-terminator-in-example"(){return require("./rules/reliability/no-jsdoc-terminator-in-example").noJsdocTerminatorInExample}};(0,eslint_devkit_1.withCanonicalDocsUrls)("plugin-reliability",exports.rules);exports.plugin={meta:{name:"eslint-plugin-reliability",version:"4.1.3"},rules:exports.rules};exports.configs={recommended:{plugins:{reliability:exports.plugin},rules:{"reliability/no-silent-errors":"error","reliability/no-missing-null-checks":"warn","reliability/require-network-timeout":"error"}}};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"no-unhandled-promise"(){return require("./rules/error-handling/no-unhandled-promise").noUnhandledPromise},get"no-silent-errors"(){return require("./rules/error-handling/no-silent-errors").noSilentErrors},get"no-missing-error-context"(){return require("./rules/error-handling/no-missing-error-context").noMissingErrorContext},get"error-message"(){return require("./rules/error-handling/error-message").errorMessage},get"no-missing-null-checks"(){return require("./rules/reliability/no-missing-null-checks").noMissingNullChecks},get"no-unsafe-type-narrowing"(){return require("./rules/reliability/no-unsafe-type-narrowing").noUnsafeTypeNarrowing},get"require-network-timeout"(){return require("./rules/reliability/require-network-timeout").requireNetworkTimeout},get"no-await-in-loop"(){return require("./rules/reliability/no-await-in-loop").noAwaitInLoop},get"no-jsdoc-terminator-in-example"(){return require("./rules/reliability/no-jsdoc-terminator-in-example").noJsdocTerminatorInExample},get"error-handling/no-unhandled-promise"(){return require("./rules/error-handling/no-unhandled-promise").noUnhandledPromise},get"error-handling/no-silent-errors"(){return require("./rules/error-handling/no-silent-errors").noSilentErrors},get"error-handling/no-missing-error-context"(){return require("./rules/error-handling/no-missing-error-context").noMissingErrorContext},get"error-handling/error-message"(){return require("./rules/error-handling/error-message").errorMessage},get"reliability/no-missing-null-checks"(){return require("./rules/reliability/no-missing-null-checks").noMissingNullChecks},get"reliability/no-unsafe-type-narrowing"(){return require("./rules/reliability/no-unsafe-type-narrowing").noUnsafeTypeNarrowing},get"reliability/require-network-timeout"(){return require("./rules/reliability/require-network-timeout").requireNetworkTimeout},get"reliability/no-await-in-loop"(){return require("./rules/reliability/no-await-in-loop").noAwaitInLoop},get"reliability/no-jsdoc-terminator-in-example"(){return require("./rules/reliability/no-jsdoc-terminator-in-example").noJsdocTerminatorInExample}};(0,eslint_devkit_1.withCanonicalDocsUrls)("plugin-reliability",exports.rules);exports.plugin={meta:{name:"eslint-plugin-reliability",version:"4.1.4"},rules:exports.rules};exports.configs={recommended:{plugins:{reliability:exports.plugin},rules:{"reliability/no-silent-errors":"error","reliability/no-missing-null-checks":"warn","reliability/require-network-timeout":"error"}}};exports.default=exports.plugin;
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.noMissingNullChecks=void 0;exports.hasNullCheck=hasNullCheck;const eslint_devkit_1=require("@interlace/eslint-devkit");const eslint_devkit_2=require("@interlace/eslint-devkit");function assignedValue(init){let current=init;while(current?.type==="AssignmentExpression"&&current.operator==="="){current=current.right}return current}const NULLABLE_RETURNS=new Set(["find","findLast","pop","shift","match","exec","getElementById","querySelector","closest","getAttribute","getNamedItem"]);function isShadowedBinding(scope,name){for(let s=scope;s;s=s.upper){const variable=s.variables.find(v=>v.name===name);if(variable)return variable.defs.length>0}return false}function nullabilityEvidence(ident,scope,seen=new Set){const readAt=ident.range?.[0]??Number.POSITIVE_INFINITY;if(seen.has(ident.name))return null;seen.add(ident.name);let s=scope;while(s){const variable=s.variables.find(v=>v.name===ident.name);if(!variable){s=s.upper;continue}if(variable.defs.length!==1)return null;const[def]=variable.defs;if(def.type!=="Variable"||def.node?.type!=="VariableDeclarator")return null;const declarator=def.node;const init=assignedValue(declarator.init);if(init===null){const declParent=declarator.parent;const loopParent=declParent?.parent;if(loopParent?.type==="ForOfStatement"||loopParent?.type==="ForInStatement"){return null}const written=variable.references.some(reference=>reference.isWrite()&&!reference.init&&reference.identifier.range[0]<readAt);if(written)return null;return"declared-without-initializer"}const reassigned=variable.references.some(reference=>reference.isWrite()&&!reference.init&&reference.identifier.range[0]<readAt);if(reassigned)return null;if(init.type==="Literal"&&init.value===null)return"assigned-null";if(init.type==="Identifier"&&init.name==="undefined"&&!isShadowedBinding(s,"undefined")){return"assigned-null"}if(init.type==="Identifier"){return nullabilityEvidence(init,s,seen)}if(init.type==="ConditionalExpression"){for(const arm of[init.consequent,init.alternate]){if(arm.type==="Literal"&&arm.value===null)return"assigned-null";if(arm.type==="Identifier"&&arm.name==="undefined"&&!isShadowedBinding(s,"undefined")){return"assigned-null"}if(arm.type==="Identifier"){const viaArm=nullabilityEvidence(arm,s,seen);if(viaArm)return viaArm}if(arm.type==="CallExpression"&&arm.callee.type==="MemberExpression"&&(0,eslint_devkit_1.namesOneOf)((0,eslint_devkit_1.propertyName)(arm.callee),NULLABLE_RETURNS)){return"nullable-return"}}return null}if(init.type==="CallExpression"&&init.callee.type==="MemberExpression"&&(0,eslint_devkit_1.namesOneOf)((0,eslint_devkit_1.propertyName)(init.callee),NULLABLE_RETURNS)){return"nullable-return"}return null}return null}function baseHasNullabilityEvidence(objectNode,scope){let base=objectNode;while(base.type==="MemberExpression"){base=base.object}if(base.type!=="Identifier")return false;return nullabilityEvidence(base,scope)!==null}function hasNullCheck(node,sourceCode){if(node.optional){return true}const parent=node.parent;if(parent&&parent.type==="ChainExpression"){return true}if(usesNullishCoalescing(node)){return true}const objectText=sourceCode.getText(node.object);const immediateParent=parent;const nodeOrCall=immediateParent?.type==="CallExpression"&&immediateParent.callee===node?immediateParent:node;const andParent=nodeOrCall.parent;if(andParent?.type==="LogicalExpression"&&andParent.operator==="&&"&&andParent.right===nodeOrCall){const leftText=sourceCode.getText(andParent.left);if(leftText===objectText)return true}let cur=node;for(let depth=0;depth<8;depth++){const p=cur.parent;if(!p)break;if(p.type==="ConditionalExpression"&&p.consequent===cur){if(sourceCode.getText(p.test)===objectText){return true}}cur=p}if(hasExplicitNullCheck(node,sourceCode)){return true}return false}function hasExplicitNullCheck(node,sourceCode){let current=node;let depth=0;const maxDepth=10;while(current&&depth<maxDepth){const parent=current.parent;if(parent&&parent.type==="IfStatement"){const test=parent.test;if(isNullCheckForObject(test,node.object,sourceCode)){return true}}current=parent;depth++}return false}function isNullCheckForObject(test,object,sourceCode){const objectText=sourceCode.getText(object);if(test.type==="Identifier"||test.type==="MemberExpression"){const testText=sourceCode.getText(test);if(testText===objectText||objectText.startsWith(testText+".")){return true}}if(test.type==="BinaryExpression"){const{left,right,operator}=test;if(operator==="!=="||operator==="!="||operator==="==="||operator==="=="){const leftText=sourceCode.getText(left);const rightText=sourceCode.getText(right);if(leftText===objectText&&(rightText==="null"||rightText==="undefined")||rightText===objectText&&(leftText==="null"||leftText==="undefined")){return true}}}if(test.type==="LogicalExpression"){return isNullCheckForObject(test.left,object,sourceCode)||isNullCheckForObject(test.right,object,sourceCode)}return false}function usesNullishCoalescing(node){let current=node;let depth=0;const maxDepth=5;while(current&&depth<maxDepth){const parent=current.parent;if(parent&&parent.type==="LogicalExpression"&&parent.operator==="??"){return true}current=parent;depth++}return false}exports.noMissingNullChecks=(0,eslint_devkit_2.createRule)({name:"no-missing-null-checks",meta:{type:"problem",docs:{url:"https://github.com/ofri-peretz/eslint/blob/main/packages/eslint-plugin-reliability/docs/rules/no-missing-null-checks.md",description:"Detects potential null pointer dereferences",cwe:"CWE-476",cvss:7.5},hasSuggestions:true,messages:{missingNullCheck:(0,eslint_devkit_1.formatLLMMessage)({icon:eslint_devkit_1.MessageIcons.WARNING,issueName:"Missing null check",cwe:"CWE-476",description:"Potential null/undefined dereference detected",severity:"HIGH",fix:"Use optional chaining (?.) or add explicit null check",documentationLink:"https://rules.sonarsource.com/javascript/RSPEC-2259/"}),useOptionalChaining:(0,eslint_devkit_1.formatLLMMessage)({icon:eslint_devkit_1.MessageIcons.INFO,issueName:"Use Optional Chaining",description:"Use optional chaining operator",severity:"LOW",fix:"obj?.property?.method()",documentationLink:"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Optional_chaining"}),useNullishCoalescing:(0,eslint_devkit_1.formatLLMMessage)({icon:eslint_devkit_1.MessageIcons.INFO,issueName:"Use Nullish Coalescing",description:"Use nullish coalescing operator",severity:"LOW",fix:"value ?? defaultValue",documentationLink:"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Nullish_coalescing"}),addExplicitCheck:(0,eslint_devkit_1.formatLLMMessage)({icon:eslint_devkit_1.MessageIcons.INFO,issueName:"Add Explicit Check",description:"Add explicit null check",severity:"LOW",fix:"if (obj !== null) { obj.property }",documentationLink:"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/null"})},schema:[{type:"object",properties:{ignoreInTests:{type:"boolean",default:true,description:"Ignore in test files"},requireExplicitChecks:{type:"boolean",default:false,description:"Require explicit null checks"}},additionalProperties:false}]},defaultOptions:[{ignoreInTests:true,requireExplicitChecks:false}],create(context,[options={}]){const{ignoreInTests=true}=options||{};const filename=context.filename;const isTestFile=ignoreInTests&&/\.(test|spec)\.(ts|tsx|js|jsx)$/.test(filename);if(isTestFile){return{}}const sourceCode=context.sourceCode;const reportedMemberExpressions=new Set;function getMemberExpressionKey(node){if(node.range&&Array.isArray(node.range)&&node.range.length>=2){return`me-${node.range[0]}-${node.range[1]}`}const loc=node.loc;if(loc&&loc.start){return`me-${loc.start.line}-${loc.start.column}-${loc.end?.line||loc.start.line}-${loc.end?.column||loc.start.column}`}return`me-${JSON.stringify(node).slice(0,50)}`}function checkMemberExpression(node){if(node.optional){return}const parent=node.parent;if(parent&&parent.type==="ChainExpression"){return}if(parent&&parent.type==="MemberExpression"&&parent.object===node){return}const objectNode=node.object;let shouldCheck=false;shouldCheck=baseHasNullabilityEvidence(objectNode,sourceCode.getScope(node));if(shouldCheck&&!hasNullCheck(node,sourceCode)){const nodeKey=getMemberExpressionKey(node);if(reportedMemberExpressions.has(nodeKey)){return}try{reportedMemberExpressions.add(nodeKey);context.report({node,messageId:"missingNullCheck",suggest:[{messageId:"useOptionalChaining",fix:()=>null},{messageId:"useNullishCoalescing",fix:()=>null},{messageId:"addExplicitCheck",fix:()=>null}]})}catch{return}}}function checkCallExpression(node){if(node.type!=="CallExpression"){return}if(node.callee.type==="MemberExpression"){const memberExpr=node.callee;if(memberExpr.optional){return}const parent=memberExpr.parent;if(parent&&parent.type==="ChainExpression"){return}const objectNode=memberExpr.object;let shouldCheck=false;shouldCheck=baseHasNullabilityEvidence(objectNode,sourceCode.getScope(memberExpr));if(shouldCheck&&!hasNullCheck(memberExpr,sourceCode)){const nodeKey=getMemberExpressionKey(memberExpr);if(reportedMemberExpressions.has(nodeKey)){return}try{reportedMemberExpressions.add(nodeKey);context.report({node:memberExpr,messageId:"missingNullCheck",suggest:[{messageId:"useOptionalChaining",fix:()=>null},{messageId:"useNullishCoalescing",fix:()=>null},{messageId:"addExplicitCheck",fix:()=>null}]})}catch{return}}}}return{MemberExpression:checkMemberExpression,CallExpression:checkCallExpression}}});
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.noMissingNullChecks=void 0;exports.hasNullCheck=hasNullCheck;const eslint_devkit_1=require("@interlace/eslint-devkit");const eslint_devkit_2=require("@interlace/eslint-devkit");function assignedValue(init){let current=init;while(current?.type==="AssignmentExpression"&&current.operator==="="){current=current.right}return current}const NULLABLE_RETURNS=new Set(["find","findLast","pop","shift","match","exec","getElementById","querySelector","closest","getAttribute","getNamedItem"]);function isShadowedBinding(scope,name){for(let s=scope;s;s=s.upper){const variable=s.variables.find(v=>v.name===name);if(variable)return variable.defs.length>0}return false}function nullabilityEvidence(ident,scope,seen=new Set){const readAt=ident.range?.[0]??Number.POSITIVE_INFINITY;if(seen.has(ident.name))return null;seen.add(ident.name);let s=scope;while(s){const variable=s.variables.find(v=>v.name===ident.name);if(!variable){s=s.upper;continue}if(variable.defs.length!==1)return null;const[def]=variable.defs;if(def.type!=="Variable"||def.node?.type!=="VariableDeclarator")return null;const declarator=def.node;const declaration=def.parent;if(declaration?.type==="VariableDeclaration"&&declaration.declare){return null}const init=assignedValue(declarator.init);if(init===null){const declParent=declarator.parent;const loopParent=declParent?.parent;if(loopParent?.type==="ForOfStatement"||loopParent?.type==="ForInStatement"){return null}const written=variable.references.some(reference=>reference.isWrite()&&!reference.init&&reference.identifier.range[0]<readAt);if(written)return null;return"declared-without-initializer"}const reassigned=variable.references.some(reference=>reference.isWrite()&&!reference.init&&reference.identifier.range[0]<readAt);if(reassigned)return null;if(init.type==="Literal"&&init.value===null)return"assigned-null";if(init.type==="Identifier"&&init.name==="undefined"&&!isShadowedBinding(s,"undefined")){return"assigned-null"}if(init.type==="Identifier"){return nullabilityEvidence(init,s,seen)}if(init.type==="ConditionalExpression"){for(const arm of[init.consequent,init.alternate]){if(arm.type==="Literal"&&arm.value===null)return"assigned-null";if(arm.type==="Identifier"&&arm.name==="undefined"&&!isShadowedBinding(s,"undefined")){return"assigned-null"}if(arm.type==="Identifier"){const viaArm=nullabilityEvidence(arm,s,seen);if(viaArm)return viaArm}if(arm.type==="CallExpression"&&arm.callee.type==="MemberExpression"&&(0,eslint_devkit_1.namesOneOf)((0,eslint_devkit_1.propertyName)(arm.callee),NULLABLE_RETURNS)){return"nullable-return"}}return null}if(init.type==="CallExpression"&&init.callee.type==="MemberExpression"&&(0,eslint_devkit_1.namesOneOf)((0,eslint_devkit_1.propertyName)(init.callee),NULLABLE_RETURNS)){return"nullable-return"}return null}return null}function baseHasNullabilityEvidence(objectNode,scope){let base=objectNode;while(base.type==="MemberExpression"){base=base.object}if(base.type!=="Identifier")return false;return nullabilityEvidence(base,scope)!==null}function hasNullCheck(node,sourceCode){if(node.optional){return true}const parent=node.parent;if(parent&&parent.type==="ChainExpression"){return true}if(usesNullishCoalescing(node)){return true}const objectText=sourceCode.getText(node.object);const immediateParent=parent;const nodeOrCall=immediateParent?.type==="CallExpression"&&immediateParent.callee===node?immediateParent:node;const andParent=nodeOrCall.parent;if(andParent?.type==="LogicalExpression"&&andParent.operator==="&&"&&andParent.right===nodeOrCall){const leftText=sourceCode.getText(andParent.left);if(leftText===objectText)return true}let cur=node;for(let depth=0;depth<8;depth++){const p=cur.parent;if(!p)break;if(p.type==="ConditionalExpression"&&p.consequent===cur){if(sourceCode.getText(p.test)===objectText){return true}}cur=p}if(hasExplicitNullCheck(node,sourceCode)){return true}if(isGuardedByEarlyExit(node,sourceCode)){return true}return false}function endsInExit(stmt){switch(stmt.type){case"ReturnStatement":case"ThrowStatement":case"ContinueStatement":case"BreakStatement":return true;case"BlockStatement":{const last=stmt.body[stmt.body.length-1];return last!==void 0&&endsInExit(last)}default:return false}}function falsyGuardTargets(test){if(test.type==="UnaryExpression"&&test.operator==="!"){return[test.argument]}if(test.type==="BinaryExpression"&&(test.operator==="=="||test.operator==="===")){const isNil=e=>e.type==="Literal"&&e.value===null||e.type==="Identifier"&&e.name==="undefined";if(isNil(test.right))return[test.left];if(isNil(test.left))return[test.right];return[]}if(test.type==="LogicalExpression"&&test.operator==="||"){return[...falsyGuardTargets(test.left),...falsyGuardTargets(test.right)]}return[]}function rootBinding(expr,sourceCode){let base=expr;while(base.type==="MemberExpression")base=base.object;const name=base.name;for(let s=sourceCode.getScope(base);s;s=s.upper){const variable=s.variables.find(v=>v.name===name);if(variable)return variable}return null}function guardsSameValue(guarded,object,sourceCode){const binding=rootBinding(guarded,sourceCode);return binding!==null&&binding===rootBinding(object,sourceCode)&&sourceCode.getText(guarded)===sourceCode.getText(object)}function statementListOf(node){switch(node.type){case"Program":case"BlockStatement":return node.body;case"SwitchCase":return node.consequent;default:return null}}function isGuardedByEarlyExit(node,sourceCode){let child=node;let parent=child.parent;while(parent){const list=statementListOf(parent);if(list){const index=list.indexOf(child);for(let i=0;i<index;i++){const stmt=list[i];if(stmt.type==="IfStatement"&&endsInExit(stmt.consequent)&&falsyGuardTargets(stmt.test).some(guarded=>guardsSameValue(guarded,node.object,sourceCode))){return true}}}child=parent;parent=child.parent}return false}function hasExplicitNullCheck(node,sourceCode){let current=node;let depth=0;const maxDepth=10;while(current&&depth<maxDepth){const parent=current.parent;if(parent&&parent.type==="IfStatement"){const test=parent.test;if(isNullCheckForObject(test,node.object,sourceCode)){return true}}current=parent;depth++}return false}function isNullCheckForObject(test,object,sourceCode){const objectText=sourceCode.getText(object);if(test.type==="Identifier"||test.type==="MemberExpression"){const testText=sourceCode.getText(test);if(testText===objectText||objectText.startsWith(testText+".")){return true}}if(test.type==="BinaryExpression"){const{left,right,operator}=test;if(operator==="!=="||operator==="!="||operator==="==="||operator==="=="){const leftText=sourceCode.getText(left);const rightText=sourceCode.getText(right);if(leftText===objectText&&(rightText==="null"||rightText==="undefined")||rightText===objectText&&(leftText==="null"||leftText==="undefined")){return true}}}if(test.type==="LogicalExpression"){return isNullCheckForObject(test.left,object,sourceCode)||isNullCheckForObject(test.right,object,sourceCode)}return false}function usesNullishCoalescing(node){let current=node;let depth=0;const maxDepth=5;while(current&&depth<maxDepth){const parent=current.parent;if(parent&&parent.type==="LogicalExpression"&&parent.operator==="??"){return true}current=parent;depth++}return false}exports.noMissingNullChecks=(0,eslint_devkit_2.createRule)({name:"no-missing-null-checks",meta:{type:"problem",docs:{url:"https://github.com/ofri-peretz/eslint/blob/main/packages/eslint-plugin-reliability/docs/rules/no-missing-null-checks.md",description:"Detects potential null pointer dereferences",cwe:"CWE-476",cvss:7.5},hasSuggestions:true,messages:{missingNullCheck:(0,eslint_devkit_1.formatLLMMessage)({icon:eslint_devkit_1.MessageIcons.WARNING,issueName:"Missing null check",cwe:"CWE-476",description:"Potential null/undefined dereference detected",severity:"HIGH",fix:"Use optional chaining (?.) or add explicit null check",documentationLink:"https://rules.sonarsource.com/javascript/RSPEC-2259/"}),useOptionalChaining:(0,eslint_devkit_1.formatLLMMessage)({icon:eslint_devkit_1.MessageIcons.INFO,issueName:"Use Optional Chaining",description:"Use optional chaining operator",severity:"LOW",fix:"obj?.property?.method()",documentationLink:"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Optional_chaining"}),useNullishCoalescing:(0,eslint_devkit_1.formatLLMMessage)({icon:eslint_devkit_1.MessageIcons.INFO,issueName:"Use Nullish Coalescing",description:"Use nullish coalescing operator",severity:"LOW",fix:"value ?? defaultValue",documentationLink:"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Nullish_coalescing"}),addExplicitCheck:(0,eslint_devkit_1.formatLLMMessage)({icon:eslint_devkit_1.MessageIcons.INFO,issueName:"Add Explicit Check",description:"Add explicit null check",severity:"LOW",fix:"if (obj !== null) { obj.property }",documentationLink:"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/null"})},schema:[{type:"object",properties:{ignoreInTests:{type:"boolean",default:true,description:"Ignore in test files"},requireExplicitChecks:{type:"boolean",default:false,description:"Require explicit null checks"}},additionalProperties:false}]},defaultOptions:[{ignoreInTests:true,requireExplicitChecks:false}],create(context,[options={}]){const{ignoreInTests=true}=options||{};const filename=context.filename;const isTestFile=ignoreInTests&&/\.(test|spec)\.(ts|tsx|js|jsx)$/.test(filename);if(isTestFile){return{}}const sourceCode=context.sourceCode;const services=(0,eslint_devkit_1.hasParserServices)(context)?(0,eslint_devkit_1.getParserServices)(context):null;function typeSaysNonNullable(objectNode){if(!services)return false;const type=(0,eslint_devkit_1.getTypeOfNode)(objectNode,services);if((0,eslint_devkit_1.isAnyType)(type)||(0,eslint_devkit_1.isUnknownType)(type))return false;return!(0,eslint_devkit_1.isNullableType)(type)}const reportedMemberExpressions=new Set;function getMemberExpressionKey(node){if(node.range&&Array.isArray(node.range)&&node.range.length>=2){return`me-${node.range[0]}-${node.range[1]}`}const loc=node.loc;if(loc&&loc.start){return`me-${loc.start.line}-${loc.start.column}-${loc.end?.line||loc.start.line}-${loc.end?.column||loc.start.column}`}return`me-${JSON.stringify(node).slice(0,50)}`}function checkMemberExpression(node){if(node.optional){return}const parent=node.parent;if(parent&&parent.type==="ChainExpression"){return}if(parent&&parent.type==="MemberExpression"&&parent.object===node){return}const objectNode=node.object;let shouldCheck=false;shouldCheck=baseHasNullabilityEvidence(objectNode,sourceCode.getScope(node))&&!typeSaysNonNullable(objectNode);if(shouldCheck&&!hasNullCheck(node,sourceCode)){const nodeKey=getMemberExpressionKey(node);if(reportedMemberExpressions.has(nodeKey)){return}try{reportedMemberExpressions.add(nodeKey);context.report({node,messageId:"missingNullCheck",suggest:[{messageId:"useOptionalChaining",fix:()=>null},{messageId:"useNullishCoalescing",fix:()=>null},{messageId:"addExplicitCheck",fix:()=>null}]})}catch{return}}}function checkCallExpression(node){if(node.type!=="CallExpression"){return}if(node.callee.type==="MemberExpression"){const memberExpr=node.callee;if(memberExpr.optional){return}const parent=memberExpr.parent;if(parent&&parent.type==="ChainExpression"){return}const objectNode=memberExpr.object;let shouldCheck=false;shouldCheck=baseHasNullabilityEvidence(objectNode,sourceCode.getScope(memberExpr))&&!typeSaysNonNullable(objectNode);if(shouldCheck&&!hasNullCheck(memberExpr,sourceCode)){const nodeKey=getMemberExpressionKey(memberExpr);if(reportedMemberExpressions.has(nodeKey)){return}try{reportedMemberExpressions.add(nodeKey);context.report({node:memberExpr,messageId:"missingNullCheck",suggest:[{messageId:"useOptionalChaining",fix:()=>null},{messageId:"useNullishCoalescing",fix:()=>null},{messageId:"addExplicitCheck",fix:()=>null}]})}catch{return}}}}return{MemberExpression:checkMemberExpression,CallExpression:checkCallExpression}}});