UNPKG

@truenine/eslint9-config

Version:

ESLint 9 configuration package for Compose Client projects with TypeScript, Vue, and modern JavaScript support

1 lines 9.6 kB
{"version":3,"file":"compact-try-catch.cjs","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":";;AAiBA,MAAM,yBAAyB;AAE/B,MAAM,OAAwB;CAC5B,MAAM;EACJ,MAAM;EACN,MAAM;GACJ,aAAa;GACb,aAAa;GACd;EACD,SAAS;EACT,UAAU;GACR,cAAc;GACd,gBAAgB;GAChB,qBAAqB;GACrB,uBAAuB;GACvB,yBAAyB;GAC1B;EACD,QAAQ,EAAE;EACX;CACD,OAAO,SAAS;EACd,MAAM,EAAC,eAAc;EAErB,SAAS,aAAa,MAA0B;GAC9C,MAAM,EAAC,QAAO;AACd,OAAI,CAAC,IAAK,QAAO;AACjB,UAAO,IAAI,MAAM,SAAS,IAAI,IAAI;;EAGpC,SAAS,gBAAgB,OAAkC;AACzD,OAAI,OAAO,SAAS,iBAAkB,QAAO;GAC7C,MAAM,QAAQ;GACd,MAAM,EAAC,SAAQ;AAEf,OAAI,KAAK,WAAW,EAAG,QAAO;AAE9B,OAAI,KAAK,SAAS,EAAG,QAAO;GAE5B,MAAM,OAAO,KAAK;AAElB,OAAI,CADiB;IAAC;IAAuB;IAAmB;IAAkB;IAAkB;IAAoB,CACtG,SAAS,KAAK,KAAK,CAAE,QAAO;GAE9C,MAAM,UAAU,KAAK;AACrB,OAAI,CAAC,WAAW,QAAQ,MAAM,SAAS,QAAQ,IAAI,KAAM,QAAO;AAGhE,OADiB,WAAW,QAAQ,KAAK,CAAC,MAAM,CACnC,SAAS,IAAK,QAAO;AAGlC,OADoB,oBAAoB,MAAM,CAC9B,SAAS,uBAAwB,QAAO;AAExD,UAAO;;EAGT,SAAS,oBAAoB,OAA0B;GACrD,MAAM,EAAC,SAAQ;AAEf,OAAI,KAAK,WAAW,EAAG,QAAO;AAG9B,UAAO,KADU,WAAW,QAAQ,KAAK,GAAG,CAAC,MAAM,CAAC,QAAQ,MAAM,GAAG,CAChD;;AAGvB,SAAO,EACL,aAAa,MAAuB;GAClC,MAAM,UAAU;GAChB,MAAM,WAAW,QAAQ;GACzB,MAAM,EAAC,SAAS,cAAa;GAE7B,MAAM,iBAAiB,gBAAgB,SAAS;GAChD,MAAM,cAAc,aAAa,SAAS;AAE1C,OAAI,kBAAkB,CAAC,YACrB,SAAQ,OAAO;IACb,MAAM;IACN,WAAW;IACX,MAAK,UAAS,MAAM,iBAAiB,SAAS,OAA2B,oBAAoB,SAAS,CAAC;IACxG,CAAC;AAGJ,OAAI,YAAY,MAAM;IACpB,MAAM,aAAa,QAAQ;IAC3B,MAAM,mBAAmB,gBAAgB,WAAW;IACpD,MAAM,gBAAgB,aAAa,WAAW;AAE9C,QAAI,oBAAoB,CAAC,cACvB,SAAQ,OAAO;KACb,MAAM;KACN,WAAW;KACX,MAAK,UAAS,MAAM,iBAAiB,WAAW,OAA2B,oBAAoB,WAAW,CAAC;KAC5G,CAAC;AAMJ,QAHuB,CAAC,eAAe,CAAC,kBACf,CAAC,iBAAiB,CAAC,kBAEJ;KACtC,MAAM,gBAAgB,WAAW,aAAa,SAAS;KACvD,MAAM,aAAa,WAAW,cAAc,QAAQ;AAEpD,SAAI,kBAAkB,QAAQ,eAAe,QAAQ,cAAc,QAAQ,QAAQ,WAAW,QAAQ,MACpG;UAAI,cAAc,IAAI,IAAI,SAAS,WAAW,IAAI,MAAM,MAAM;OAC5D,MAAM,cAAc,WAAW,eAAe,WAAW;AACzD,WAAI,gBAAgB,KAClB,SAAQ,OAAO;QACb,MAAM;QACN,WAAW;QACX,MAAK,UAAS,MAAM,iBAAiB,CAAC,YAAY,MAAM,IAAI,WAAW,MAAM,GAAG,EAAE,IAAI;QACvF,CAAC;;;;;AAOZ,OAAI,cAAc,KAAM;GAExB,MAAM,eAAe;GACrB,MAAM,qBAAqB,gBAAgB,aAAa;GACxD,MAAM,kBAAkB,aAAa,aAAa;AAClD,OAAI,sBAAsB,CAAC,gBACzB,SAAQ,OAAO;IACb,MAAM;IACN,WAAW;IACX,MAAK,UAAS,MAAM,iBAAiB,aAAa,OAA2B,oBAAoB,aAAa,CAAC;IAChH,CAAC;GAEJ,MAAM,gBAAgB,YAAY,OAAO,QAAQ,OAAO;GACxD,MAAM,kBAAkB,gBAAgB,cAAc;AAKtD,OAAI,EAHoB,CADH,aAAa,cAAc,IACP,CAAC,oBAGlB,EAFG,CAAC,mBAAmB,CAAC,oBAEH;GAE7C,MAAM,iBAAiB,WAAW,aAAa,cAAc;GAC7D,MAAM,eAAe,WAAW,qBAC9B,WAAW,UACX,eACA,MAAK,EAAE,UAAU,UAClB;AACD,OAAI,mBAAmB,QAAQ,iBAAiB,QAAQ,eAAe,QAAQ,QAAQ,aAAa,QAAQ,MAC1G;QAAI,eAAe,IAAI,IAAI,SAAS,aAAa,IAAI,MAAM,MAAM;KAC/D,MAAM,cAAc,WAAW,eAAe,aAAa;AAC3D,SAAI,gBAAgB,KAClB,SAAQ,OAAO;MACb,MAAM;MACN,WAAW;MACX,MAAK,UAAS,MAAM,iBAAiB,CAAC,YAAY,MAAM,IAAI,aAAa,MAAM,GAAG,EAAE,IAAI;MACzF,CAAC;;;KAKX;;CAEJ"}