{"version":3,"file":"compact-try-catch.mjs","names":[],"sources":["../../../src/rules/code-style/compact-try-catch.ts"],"sourcesContent":["import type {Rule} from 'eslint'\n\ntype BlockNode = Rule.Node & {\n  body: Rule.Node[]\n}\n\ntype CatchClause = Rule.Node & {\n  param: Rule.Node | null\n  body: BlockNode\n}\n\ntype TryStatement = Rule.Node & {\n  block: BlockNode\n  handler: CatchClause | null\n  finalizer: BlockNode | null\n}\n\nconst MAX_SINGLE_LINE_LENGTH = 120\n\nconst rule: Rule.RuleModule = {\n  meta: {\n    type: 'layout',\n    docs: {\n      description: 'Enforce compact try-catch-finally layout with independent block optimization',\n      recommended: false\n    },\n    fixable: 'whitespace',\n    messages: {\n      compactCatch: 'Catch clause should be on the same line as the try block\\'s closing brace',\n      compactFinally: 'Finally clause should be on the same line as the previous block\\'s closing brace',\n      preferSingleLineTry: 'Try block should be compressed to a single line',\n      preferSingleLineCatch: 'Catch block should be compressed to a single line',\n      preferSingleLineFinally: 'Finally block should be compressed to a single line'\n    },\n    schema: []\n  },\n  create(context) {\n    const {sourceCode} = context\n\n    function isSingleLine(node: Rule.Node): boolean {\n      const {loc} = node\n      if (!loc) return false\n      return loc.start.line === loc.end.line\n    }\n\n    function canBeSingleLine(block: Rule.Node | null): boolean {\n      if (block?.type !== 'BlockStatement') return false\n      const bNode = block as BlockNode\n      const {body} = bNode\n\n      if (body.length === 0) return true // 空块总是可以单行\n\n      if (body.length > 1) return false // 多于一条语句不能单行\n\n      const stmt = body[0] // 检查单条语句\n      const allowedTypes = ['ExpressionStatement', 'ReturnStatement', 'ThrowStatement', 'BreakStatement', 'ContinueStatement']\n      if (!allowedTypes.includes(stmt.type)) return false\n\n      const stmtLoc = stmt.loc // 语句本身必须是单行\n      if (!stmtLoc || stmtLoc.start.line !== stmtLoc.end.line) return false\n\n      const stmtText = sourceCode.getText(stmt).trim() // 检查语句文本长度（不包括块的花括号）\n      if (stmtText.length > 100) return false\n\n      const compactText = getCompactBlockText(bNode) // 检查压缩后的总长度\n      if (compactText.length > MAX_SINGLE_LINE_LENGTH) return false\n\n      return true\n    }\n\n    function getCompactBlockText(block: BlockNode): string {\n      const {body} = block\n\n      if (body.length === 0) return '{}' // 空块\n\n      const stmtText = sourceCode.getText(body[0]).trim().replace(/;$/, '') // 获取语句文本，移除尾部分号后重新添加\n      return `{ ${stmtText}; }`\n    }\n\n    return {\n      TryStatement(node: Rule.Node): void {\n        const tryNode = node as unknown as TryStatement\n        const tryBlock = tryNode.block\n        const {handler, finalizer} = tryNode\n\n        const tryCanBeSingle = canBeSingleLine(tryBlock) // 检查 try 块是否可以单行化\n        const tryIsSingle = isSingleLine(tryBlock)\n\n        if (tryCanBeSingle && !tryIsSingle) {\n          context.report({\n            node: tryBlock,\n            messageId: 'preferSingleLineTry',\n            fix: fixer => fixer.replaceTextRange(tryBlock.range as [number, number], getCompactBlockText(tryBlock))\n          })\n        }\n\n        if (handler !== null) { // 检查 catch 块\n          const catchBlock = handler.body\n          const catchCanBeSingle = canBeSingleLine(catchBlock)\n          const catchIsSingle = isSingleLine(catchBlock)\n\n          if (catchCanBeSingle && !catchIsSingle) { // 独立检查 catch 块是否可以单行化\n            context.report({\n              node: catchBlock,\n              messageId: 'preferSingleLineCatch',\n              fix: fixer => fixer.replaceTextRange(catchBlock.range as [number, number], getCompactBlockText(catchBlock))\n            })\n          }\n\n          const tryIsMultiLine = !tryIsSingle && !tryCanBeSingle // 检查 } catch 是否在同一行（仅当 try 是多行且不能单行化时）\n          const catchIsMultiLine = !catchIsSingle && !catchCanBeSingle\n\n          if (tryIsMultiLine && catchIsMultiLine) {\n            const tryCloseBrace = sourceCode.getLastToken(tryBlock)\n            const catchToken = sourceCode.getFirstToken(handler)\n\n            if (tryCloseBrace !== null && catchToken !== null && tryCloseBrace.loc !== null && catchToken.loc !== null) {\n              if (tryCloseBrace.loc.end.line !== catchToken.loc.start.line) {\n                const spaceBefore = sourceCode.getTokenBefore(catchToken)\n                if (spaceBefore !== null) {\n                  context.report({\n                    node: catchToken,\n                    messageId: 'compactCatch',\n                    fix: fixer => fixer.replaceTextRange([spaceBefore.range[1], catchToken.range[0]], ' ')\n                  })\n                }\n              }\n            }\n          }\n        }\n\n        if (finalizer === null) return\n\n        const finallyBlock = finalizer\n        const finallyCanBeSingle = canBeSingleLine(finallyBlock)\n        const finallyIsSingle = isSingleLine(finallyBlock)\n        if (finallyCanBeSingle && !finallyIsSingle) { // 独立检查 finally 块是否可以单行化\n          context.report({\n            node: finallyBlock,\n            messageId: 'preferSingleLineFinally',\n            fix: fixer => fixer.replaceTextRange(finallyBlock.range as [number, number], getCompactBlockText(finallyBlock))\n          })\n        }\n        const previousBlock = handler !== null ? handler.body : tryBlock\n        const prevCanBeSingle = canBeSingleLine(previousBlock)\n        const prevIsSingle = isSingleLine(previousBlock)\n        const prevIsMultiLine = !prevIsSingle && !prevCanBeSingle\n        const finallyIsMultiLine = !finallyIsSingle && !finallyCanBeSingle\n\n        if (!prevIsMultiLine || !finallyIsMultiLine) return\n\n        const prevCloseBrace = sourceCode.getLastToken(previousBlock)\n        const finallyToken = sourceCode.getFirstTokenBetween(\n          handler ?? tryBlock,\n          finallyBlock,\n          t => t.value === 'finally'\n        )\n        if (prevCloseBrace !== null && finallyToken !== null && prevCloseBrace.loc !== null && finallyToken.loc !== null) {\n          if (prevCloseBrace.loc.end.line !== finallyToken.loc.start.line) {\n            const spaceBefore = sourceCode.getTokenBefore(finallyToken)\n            if (spaceBefore !== null) {\n              context.report({\n                node: finallyToken,\n                messageId: 'compactFinally',\n                fix: fixer => fixer.replaceTextRange([spaceBefore.range[1], finallyToken.range[0]], ' ')\n              })\n            }\n          }\n        }\n      }\n    }\n  }\n}\n\nexport default rule\n"],"mappings":"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"}