eslint-plugin-reliability 4.1.6 → 4.1.8

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/README.md CHANGED
@@ -205,6 +205,7 @@ Part of the **Interlace ESLint ecosystem** — AI-native rules with LLM-optimize
205
205
  | [`eslint-plugin-secure-coding`](https://www.npmjs.com/package/eslint-plugin-secure-coding) | [![downloads](https://img.shields.io/npm/dt/eslint-plugin-secure-coding.svg?style=flat-square)](https://www.npmjs.com/package/eslint-plugin-secure-coding) | Injection prevention. |
206
206
  | [`eslint-plugin-sequelize-security`](https://www.npmjs.com/package/eslint-plugin-sequelize-security) | [![downloads](https://img.shields.io/npm/dt/eslint-plugin-sequelize-security.svg?style=flat-square)](https://www.npmjs.com/package/eslint-plugin-sequelize-security) | Sequelize ORM security. |
207
207
  | [`eslint-plugin-sqlite-security`](https://www.npmjs.com/package/eslint-plugin-sqlite-security) | [![downloads](https://img.shields.io/npm/dt/eslint-plugin-sqlite-security.svg?style=flat-square)](https://www.npmjs.com/package/eslint-plugin-sqlite-security) | SQLite security. |
208
+ | [`eslint-plugin-supabase-security`](https://www.npmjs.com/package/eslint-plugin-supabase-security) | [![downloads](https://img.shields.io/npm/dt/eslint-plugin-supabase-security.svg?style=flat-square)](https://www.npmjs.com/package/eslint-plugin-supabase-security) | Supabase security. |
208
209
  | [`eslint-plugin-typeorm-security`](https://www.npmjs.com/package/eslint-plugin-typeorm-security) | [![downloads](https://img.shields.io/npm/dt/eslint-plugin-typeorm-security.svg?style=flat-square)](https://www.npmjs.com/package/eslint-plugin-typeorm-security) | TypeORM security. |
209
210
  | [`eslint-plugin-vercel-ai-security`](https://www.npmjs.com/package/eslint-plugin-vercel-ai-security) | [![downloads](https://img.shields.io/npm/dt/eslint-plugin-vercel-ai-security.svg?style=flat-square)](https://www.npmjs.com/package/eslint-plugin-vercel-ai-security) | AI SDK security. |
210
211
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eslint-plugin-reliability",
3
- "version": "4.1.6",
3
+ "version": "4.1.8",
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.6"},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.8"},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.noSilentErrors=void 0;const eslint_devkit_1=require("@interlace/eslint-devkit");const eslint_devkit_2=require("@interlace/eslint-devkit");function isEmptyCatchBlock(catchClause){const body=catchClause.body;if(!body||body.type!=="BlockStatement"){return true}const statements=body.body;if(statements.length===0){return true}const nonEmptyStatements=statements.filter(stmt=>stmt.type!=="EmptyStatement");return nonEmptyStatements.length===0}function hasExplanatoryComment(catchClause,sourceCode){const comments=sourceCode.getAllComments();const catchStart=catchClause.loc?.start;if(!catchStart||!comments.length){return false}const explanatoryPatterns=[/intentional/i,/expected/i,/ignore/i,/silent/i,/noop/i,/no-op/i,/by design/i,/known issue/i,/legacy/i,/third.?party/i,/framework/i,/library/i,/not implemented/i,/todo/i,/fixme/i];for(const comment of comments){if(comment.loc&&catchStart.line-comment.loc.end.line<=2){const commentText=comment.value.toLowerCase();if(explanatoryPatterns.some(pattern=>pattern.test(commentText))){return true}}}return false}exports.noSilentErrors=(0,eslint_devkit_2.createRule)({name:"no-silent-errors",meta:{type:"problem",docs:{url:"https://github.com/ofri-peretz/eslint/blob/main/packages/eslint-plugin-reliability/docs/rules/no-silent-errors.md",description:"Detects empty catch blocks"},hasSuggestions:true,messages:{silentError:(0,eslint_devkit_1.formatLLMMessage)({icon:eslint_devkit_1.MessageIcons.WARNING,issueName:"Silent error",description:"Empty catch block detected - errors are silently ignored",severity:"MEDIUM",fix:"Add error logging or handling in catch block",documentationLink:"https://rules.sonarsource.com/javascript/RSPEC-1186/"}),addErrorLogging:(0,eslint_devkit_1.formatLLMMessage)({icon:eslint_devkit_1.MessageIcons.INFO,issueName:"Add Error Logging",description:"Add error logging to catch block",severity:"LOW",fix:"catch (error) { console.error(error); }",documentationLink:"https://rules.sonarsource.com/javascript/RSPEC-1186/"}),addErrorHandling:(0,eslint_devkit_1.formatLLMMessage)({icon:eslint_devkit_1.MessageIcons.INFO,issueName:"Add Error Handling",description:"Add error handling to catch block",severity:"LOW",fix:"catch (error) { handleError(error); }",documentationLink:"https://rules.sonarsource.com/javascript/RSPEC-1186/"}),rethrowError:(0,eslint_devkit_1.formatLLMMessage)({icon:eslint_devkit_1.MessageIcons.INFO,issueName:"Rethrow Error",description:"Rethrow error if needed",severity:"LOW",fix:"catch (error) { throw new CustomError(error); }",documentationLink:"https://rules.sonarsource.com/javascript/RSPEC-1186/"})},schema:[{type:"object",properties:{allowWithComment:{type:"boolean",default:false,description:"Allow empty catch if comment explains why"},ignoreInTests:{type:"boolean",default:true,description:"Ignore in test files"}},additionalProperties:false}]},defaultOptions:[{allowWithComment:false,ignoreInTests:true}],create(context,[options={}]){const{allowWithComment=false,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;function checkCatchClause(node){if(!isEmptyCatchBlock(node)){return}if(allowWithComment&&hasExplanatoryComment(node,sourceCode)){return}context.report({node,messageId:"silentError",suggest:[{messageId:"addErrorLogging",fix:()=>null},{messageId:"addErrorHandling",fix:()=>null},{messageId:"rethrowError",fix:()=>null}]})}return{CatchClause:checkCatchClause}}});
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.noSilentErrors=void 0;const eslint_devkit_1=require("@interlace/eslint-devkit");const eslint_devkit_2=require("@interlace/eslint-devkit");function isEmptyCatchBlock(catchClause){const body=catchClause.body;if(!body||body.type!=="BlockStatement"){return true}const statements=body.body;if(statements.length===0){return true}const nonEmptyStatements=statements.filter(stmt=>stmt.type!=="EmptyStatement");return nonEmptyStatements.length===0}function hasExplanatoryComment(catchClause,sourceCode){const comments=sourceCode.getAllComments();const catchStart=catchClause.loc?.start;if(!catchStart||!comments.length){return false}const explanatoryPatterns=[/intentional/i,/expected/i,/ignore/i,/silent/i,/noop/i,/no-op/i,/by design/i,/known issue/i,/legacy/i,/third.?party/i,/framework/i,/library/i,/not implemented/i,/todo/i,/fixme/i];for(const comment of comments){const distance=catchStart.line-comment.loc.end.line;if(distance<0||distance>2)continue;const commentText=comment.value.toLowerCase();if(explanatoryPatterns.some(pattern=>pattern.test(commentText))){return true}}return false}exports.noSilentErrors=(0,eslint_devkit_2.createRule)({name:"no-silent-errors",meta:{type:"problem",docs:{url:"https://github.com/ofri-peretz/eslint/blob/main/packages/eslint-plugin-reliability/docs/rules/no-silent-errors.md",description:"Detects empty catch blocks"},hasSuggestions:true,messages:{silentError:(0,eslint_devkit_1.formatLLMMessage)({icon:eslint_devkit_1.MessageIcons.WARNING,issueName:"Silent error",description:"Empty catch block detected - errors are silently ignored",severity:"MEDIUM",fix:"Add error logging or handling in catch block",documentationLink:"https://rules.sonarsource.com/javascript/RSPEC-1186/"}),addErrorLogging:(0,eslint_devkit_1.formatLLMMessage)({icon:eslint_devkit_1.MessageIcons.INFO,issueName:"Add Error Logging",description:"Add error logging to catch block",severity:"LOW",fix:"catch (error) { console.error(error); }",documentationLink:"https://rules.sonarsource.com/javascript/RSPEC-1186/"}),addErrorHandling:(0,eslint_devkit_1.formatLLMMessage)({icon:eslint_devkit_1.MessageIcons.INFO,issueName:"Add Error Handling",description:"Add error handling to catch block",severity:"LOW",fix:"catch (error) { handleError(error); }",documentationLink:"https://rules.sonarsource.com/javascript/RSPEC-1186/"}),rethrowError:(0,eslint_devkit_1.formatLLMMessage)({icon:eslint_devkit_1.MessageIcons.INFO,issueName:"Rethrow Error",description:"Rethrow error if needed",severity:"LOW",fix:"catch (error) { throw new CustomError(error); }",documentationLink:"https://rules.sonarsource.com/javascript/RSPEC-1186/"})},schema:[{type:"object",properties:{allowWithComment:{type:"boolean",default:false,description:"Allow empty catch if comment explains why"},ignoreInTests:{type:"boolean",default:true,description:"Ignore in test files"}},additionalProperties:false}]},defaultOptions:[{allowWithComment:false,ignoreInTests:true}],create(context,[options={}]){const{allowWithComment=false,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;function checkCatchClause(node){if(!isEmptyCatchBlock(node)){return}if(allowWithComment&&hasExplanatoryComment(node,sourceCode)){return}context.report({node,messageId:"silentError",suggest:[{messageId:"addErrorLogging",fix:()=>null},{messageId:"addErrorHandling",fix:()=>null},{messageId:"rethrowError",fix:()=>null}]})}return{CatchClause:checkCatchClause}}});
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.noJsdocTerminatorInExample=void 0;exports.findTerminatorsInExamples=findTerminatorsInExamples;const eslint_devkit_1=require("@interlace/eslint-devkit");function findTerminatorsInExamples(commentText){const lines=commentText.split("\n");let inExample=false;const offsets=[];let currentOffset=0;for(const line of lines){const stripped=line.replace(/^\s*\*?\s?/,"");if(/^\s*@example\b/i.test(stripped)){inExample=true;currentOffset+=line.length+1;continue}if(/^\s*@\w+/.test(stripped)&&!stripped.startsWith("@example")){inExample=false;currentOffset+=line.length+1;continue}if(inExample){let searchStart=0;while(searchStart<line.length){const idx=line.indexOf("*/",searchStart);if(idx===-1)break;const absoluteOffset=currentOffset+idx;const remaining=commentText.substring(absoluteOffset+2).trim();if(remaining.length>0){offsets.push(absoluteOffset)}searchStart=idx+2}}currentOffset+=line.length+1}return offsets}exports.noJsdocTerminatorInExample=(0,eslint_devkit_1.createRule)({name:"no-jsdoc-terminator-in-example",meta:{type:"problem",docs:{url:"https://github.com/ofri-peretz/eslint/blob/main/packages/eslint-plugin-reliability/docs/rules/no-jsdoc-terminator-in-example.md",description:"Detects `*/` sequences inside JSDoc @example blocks that prematurely close the comment"},hasSuggestions:true,messages:{jsdocTerminatorInExample:(0,eslint_devkit_1.formatLLMMessage)({icon:eslint_devkit_1.MessageIcons.WARNING,issueName:"JSDoc Terminator in @example",description:"The `*/` sequence inside an @example block will prematurely close the JSDoc comment, causing compilation errors. Wrap the pattern in quotes or use an alternative representation.",severity:"HIGH",fix:"Wrap the pattern containing `*/` in quotes, e.g. `'*/*'` instead of `*/*`",documentationLink:"https://jsdoc.app/tags-example"}),wrapInQuotes:(0,eslint_devkit_1.formatLLMMessage)({icon:eslint_devkit_1.MessageIcons.INFO,issueName:"Wrap Pattern in Quotes",description:"Wrap the `*/` pattern in single quotes to prevent premature JSDoc termination",severity:"LOW",fix:"Replace `*/` with `'*/'` (single-quoted) inside the @example block",documentationLink:"https://jsdoc.app/tags-example"})},schema:[]},defaultOptions:[],create(context){const sourceCode=context.sourceCode;return{Program(){const comments=sourceCode.getAllComments();for(const comment of comments){if(comment.type!=="Block"){continue}const commentText=comment.value;if(!/@example\b/i.test(commentText)||!commentText.includes("*/")){continue}const offsets=findTerminatorsInExamples(commentText);for(const offset of offsets){const absoluteStart=comment.range[0]+2+offset;const absoluteEnd=absoluteStart+2;context.report({loc:{start:sourceCode.getLocFromIndex(absoluteStart),end:sourceCode.getLocFromIndex(absoluteEnd)},messageId:"jsdocTerminatorInExample",suggest:[{messageId:"wrapInQuotes",fix:fixer=>{return fixer.replaceTextRange([absoluteStart,absoluteEnd],"'*/'")}}]})}}}}}});
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.noJsdocTerminatorInExample=void 0;exports.findTerminatorsInExamples=findTerminatorsInExamples;const eslint_devkit_1=require("@interlace/eslint-devkit");function findTerminatorsInExamples(commentText){const lines=commentText.split("\n");let inExample=false;const offsets=[];let currentOffset=0;for(const line of lines){const stripped=line.replace(/^\s*\*?\s?/,"");if(/^\s*@example\b/i.test(stripped)){inExample=true;currentOffset+=line.length+1;continue}if(/^\s*@\w+/.test(stripped)&&!stripped.startsWith("@example")){inExample=false;currentOffset+=line.length+1;continue}if(inExample){let searchStart=0;while(searchStart<line.length){const idx=line.indexOf("*/",searchStart);if(idx===-1)break;const absoluteOffset=currentOffset+idx;const remaining=commentText.substring(absoluteOffset+2).trim();if(remaining.length>0){offsets.push(absoluteOffset)}searchStart=idx+2}}currentOffset+=line.length+1}return offsets}exports.noJsdocTerminatorInExample=(0,eslint_devkit_1.createRule)({name:"no-jsdoc-terminator-in-example",meta:{type:"problem",deprecated:true,docs:{url:"https://github.com/ofri-peretz/eslint/blob/main/packages/eslint-plugin-reliability/docs/rules/no-jsdoc-terminator-in-example.md",description:"Detects `*/` sequences inside JSDoc @example blocks that prematurely close the comment"},hasSuggestions:true,messages:{jsdocTerminatorInExample:(0,eslint_devkit_1.formatLLMMessage)({icon:eslint_devkit_1.MessageIcons.WARNING,issueName:"JSDoc Terminator in @example",description:"The `*/` sequence inside an @example block will prematurely close the JSDoc comment, causing compilation errors. Wrap the pattern in quotes or use an alternative representation.",severity:"HIGH",fix:"Wrap the pattern containing `*/` in quotes, e.g. `'*/*'` instead of `*/*`",documentationLink:"https://jsdoc.app/tags-example"}),wrapInQuotes:(0,eslint_devkit_1.formatLLMMessage)({icon:eslint_devkit_1.MessageIcons.INFO,issueName:"Wrap Pattern in Quotes",description:"Wrap the `*/` pattern in single quotes to prevent premature JSDoc termination",severity:"LOW",fix:"Replace `*/` with `'*/'` (single-quoted) inside the @example block",documentationLink:"https://jsdoc.app/tags-example"})},schema:[]},defaultOptions:[],create(context){const sourceCode=context.sourceCode;return{Program(){const comments=sourceCode.getAllComments();for(const comment of comments){if(comment.type!=="Block"){continue}const commentText=comment.value;if(!/@example\b/i.test(commentText)||!commentText.includes("*/")){continue}const offsets=findTerminatorsInExamples(commentText);for(const offset of offsets){const absoluteStart=comment.range[0]+2+offset;const absoluteEnd=absoluteStart+2;context.report({loc:{start:sourceCode.getLocFromIndex(absoluteStart),end:sourceCode.getLocFromIndex(absoluteEnd)},messageId:"jsdocTerminatorInExample",suggest:[{messageId:"wrapInQuotes",fix:fixer=>{return fixer.replaceTextRange([absoluteStart,absoluteEnd],"'*/'")}}]})}}}}}});
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.noUnsafeTypeNarrowing=void 0;const eslint_devkit_1=require("@interlace/eslint-devkit");const eslint_devkit_2=require("@interlace/eslint-devkit");function isUnsafeTypeAssertion(node){if(node.expression.type==="TSAsExpression"){const innerAssertion=node.expression;if(innerAssertion.typeAnnotation.type==="TSUnknownKeyword"){return true}if(innerAssertion.typeAnnotation.type==="TSAnyKeyword"){return true}}return false}function hasExplanatoryComment(node,sourceCode){const comments=sourceCode.getAllComments();const nodeStart=node.loc?.start;if(!nodeStart||!comments.length){return false}const explanatoryPatterns=[/type.?guard/i,/validated/i,/checked/i,/safe/i,/known/i,/intentional/i,/necessary/i,/framework/i,/library/i,/third.?party/i,/legacy/i,/todo/i,/fixme/i];for(const comment of comments){if(comment.loc&&nodeStart.line-comment.loc.end.line<=1){const commentText=comment.value.toLowerCase();if(explanatoryPatterns.some(pattern=>pattern.test(commentText))){return true}}}return false}exports.noUnsafeTypeNarrowing=(0,eslint_devkit_2.createRule)({name:"no-unsafe-type-narrowing",meta:{type:"problem",docs:{url:"https://github.com/ofri-peretz/eslint/blob/main/packages/eslint-plugin-reliability/docs/rules/no-unsafe-type-narrowing.md",description:"Detects unsafe type narrowing patterns"},hasSuggestions:true,messages:{unsafeTypeNarrowing:(0,eslint_devkit_1.formatLLMMessage)({icon:eslint_devkit_1.MessageIcons.WARNING,issueName:"Unsafe type narrowing",description:"Unsafe type assertion or narrowing detected",severity:"MEDIUM",fix:"Use type guards or proper validation before type assertion",documentationLink:"https://rules.sonarsource.com/javascript/RSPEC-4326/"}),useTypeGuard:(0,eslint_devkit_1.formatLLMMessage)({icon:eslint_devkit_1.MessageIcons.INFO,issueName:"Use Type Guard",description:"Use type guard function",severity:"LOW",fix:"function isType(value: unknown): value is Type { return ... }",documentationLink:"https://www.typescriptlang.org/docs/handbook/2/narrowing.html#using-type-predicates"}),useProperNarrowing:(0,eslint_devkit_1.formatLLMMessage)({icon:eslint_devkit_1.MessageIcons.INFO,issueName:"Use Type Narrowing",description:"Use proper type narrowing",severity:"LOW",fix:'if (typeof value === "string") { ... }',documentationLink:"https://www.typescriptlang.org/docs/handbook/2/narrowing.html"}),validateBeforeAssert:(0,eslint_devkit_1.formatLLMMessage)({icon:eslint_devkit_1.MessageIcons.INFO,issueName:"Validate First",description:"Validate before type assertion",severity:"LOW",fix:"if (isValid(value)) { const typed = value as Type; }",documentationLink:"https://www.typescriptlang.org/docs/handbook/2/narrowing.html"})},schema:[{type:"object",properties:{ignoreInTests:{type:"boolean",default:true,description:"Ignore in test files"},allowWithComment:{type:"boolean",default:false,description:"Allow type assertions with comments"}},additionalProperties:false}]},defaultOptions:[{ignoreInTests:true,allowWithComment:false}],create(context,[options={}]){const{ignoreInTests=true,allowWithComment=false}=options||{};const filename=context.filename;const isTestFile=ignoreInTests&&/\.(test|spec)\.(ts|tsx|js|jsx)$/.test(filename);if(isTestFile){return{}}const sourceCode=context.sourceCode;function checkTypeAssertion(node){if(!isUnsafeTypeAssertion(node)){return}if(allowWithComment&&hasExplanatoryComment(node,sourceCode)){return}context.report({node,messageId:"unsafeTypeNarrowing",suggest:[{messageId:"useTypeGuard",fix:()=>null},{messageId:"useProperNarrowing",fix:()=>null},{messageId:"validateBeforeAssert",fix:()=>null}]})}return{TSAsExpression:checkTypeAssertion}}});
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.noUnsafeTypeNarrowing=void 0;const eslint_devkit_1=require("@interlace/eslint-devkit");const eslint_devkit_2=require("@interlace/eslint-devkit");function isUnsafeTypeAssertion(node){if(node.expression.type==="TSAsExpression"){const innerAssertion=node.expression;if(innerAssertion.typeAnnotation.type==="TSUnknownKeyword"){return true}if(innerAssertion.typeAnnotation.type==="TSAnyKeyword"){return true}}return false}function hasExplanatoryComment(node,sourceCode){const comments=sourceCode.getAllComments();const nodeStart=node.loc?.start;if(!nodeStart||!comments.length){return false}const explanatoryPatterns=[/type.?guard/i,/validated/i,/checked/i,/\bsafe\b/i,/\bknown\b/i,/intentional/i,/necessary/i,/framework/i,/library/i,/third.?party/i,/legacy/i,/todo/i,/fixme/i];for(const comment of comments){const distance=nodeStart.line-comment.loc.end.line;if(distance<0||distance>1)continue;if(distance===1){const before=sourceCode.getTokenBefore(comment,{includeComments:true});if(before&&before.loc.end.line===comment.loc.start.line)continue}const commentText=comment.value.toLowerCase();if(explanatoryPatterns.some(pattern=>pattern.test(commentText))){return true}}return false}exports.noUnsafeTypeNarrowing=(0,eslint_devkit_2.createRule)({name:"no-unsafe-type-narrowing",meta:{type:"problem",docs:{url:"https://github.com/ofri-peretz/eslint/blob/main/packages/eslint-plugin-reliability/docs/rules/no-unsafe-type-narrowing.md",description:"Detects unsafe type narrowing patterns"},hasSuggestions:true,messages:{unsafeTypeNarrowing:(0,eslint_devkit_1.formatLLMMessage)({icon:eslint_devkit_1.MessageIcons.WARNING,issueName:"Unsafe type narrowing",description:"Unsafe type assertion or narrowing detected",severity:"MEDIUM",fix:"Use type guards or proper validation before type assertion",documentationLink:"https://rules.sonarsource.com/javascript/RSPEC-4326/"}),useTypeGuard:(0,eslint_devkit_1.formatLLMMessage)({icon:eslint_devkit_1.MessageIcons.INFO,issueName:"Use Type Guard",description:"Use type guard function",severity:"LOW",fix:"function isType(value: unknown): value is Type { return ... }",documentationLink:"https://www.typescriptlang.org/docs/handbook/2/narrowing.html#using-type-predicates"}),useProperNarrowing:(0,eslint_devkit_1.formatLLMMessage)({icon:eslint_devkit_1.MessageIcons.INFO,issueName:"Use Type Narrowing",description:"Use proper type narrowing",severity:"LOW",fix:'if (typeof value === "string") { ... }',documentationLink:"https://www.typescriptlang.org/docs/handbook/2/narrowing.html"}),validateBeforeAssert:(0,eslint_devkit_1.formatLLMMessage)({icon:eslint_devkit_1.MessageIcons.INFO,issueName:"Validate First",description:"Validate before type assertion",severity:"LOW",fix:"if (isValid(value)) { const typed = value as Type; }",documentationLink:"https://www.typescriptlang.org/docs/handbook/2/narrowing.html"})},schema:[{type:"object",properties:{ignoreInTests:{type:"boolean",default:true,description:"Ignore in test files"},allowWithComment:{type:"boolean",default:false,description:"Allow type assertions with comments"}},additionalProperties:false}]},defaultOptions:[{ignoreInTests:true,allowWithComment:false}],create(context,[options={}]){const{ignoreInTests=true,allowWithComment=false}=options||{};const filename=context.filename;const isTestFile=ignoreInTests&&/\.(test|spec)\.(ts|tsx|js|jsx)$/.test(filename);if(isTestFile){return{}}const sourceCode=context.sourceCode;function checkTypeAssertion(node){if(!isUnsafeTypeAssertion(node)){return}if(allowWithComment&&hasExplanatoryComment(node,sourceCode)){return}context.report({node,messageId:"unsafeTypeNarrowing",suggest:[{messageId:"useTypeGuard",fix:()=>null},{messageId:"useProperNarrowing",fix:()=>null},{messageId:"validateBeforeAssert",fix:()=>null}]})}return{TSAsExpression:checkTypeAssertion}}});