diff --git a/crates/oxc_linter/src/rules/eslint/curly.rs b/crates/oxc_linter/src/rules/eslint/curly.rs index 259092b8052a0..86c0685ad5436 100644 --- a/crates/oxc_linter/src/rules/eslint/curly.rs +++ b/crates/oxc_linter/src/rules/eslint/curly.rs @@ -391,8 +391,16 @@ fn is_lexical_declaration(node: &Statement) -> bool { #[expect(clippy::cast_possible_truncation)] fn get_next_char_offset(span: Span, ctx: &LintContext) -> Option { - let next_char = ctx.source_text()[(span.end as usize)..].chars().next(); - next_char.map(|c| span.end + c.len_utf8() as u32) + let src = ctx.source_text(); + let start = span.end as usize; + + if let Some(tail) = src.get(start..) { + if tail.starts_with("\r\n") || tail.starts_with("\n\r") { + return Some(span.end + 2); + } + } + + src[start..].chars().next().map(|c| span.end + c.len_utf8() as u32) } #[expect(clippy::cast_possible_truncation)] // for `as i32` @@ -801,6 +809,26 @@ fn test() { "if (a) while (cond) for (;;) for (key in obj) { if (b) foo(); } else bar();", Some(serde_json::json!(["multi"])), ), + ( + " const isIterable = (obj: any) : obj is Iterable => { + if (obj === null) return false; + else if (typeof obj === 'string') return false; + else return typeof value[Symbol.iterator] === 'function'; + };", + Some(serde_json::json!(["multi"])), + ), + ( + "const isIterable = (obj: any): obj is Iterable => {\r\n if (obj === null) return false;\r\n else if (typeof obj === 'string') return false;\r\n else return typeof value[Symbol.iterator] === 'function';\r\n};\r\n", + Some(serde_json::json!(["multi-line"])), + ), + ( + " const isIterable = (obj: any) : obj is Iterable => { + if (obj === null) return false; + else if (typeof obj === 'string') return false; + else return typeof value[Symbol.iterator] === 'function'; + };", + Some(serde_json::json!(["multi"])), + ), ]; let fail = vec![