(P: ParseState)
| 3348 | } |
| 3349 | |
| 3350 | function parseCaseItem(P: ParseState): TsNode | null { |
| 3351 | skipBlanks(P.L) |
| 3352 | const start = P.L.b |
| 3353 | const kids: TsNode[] = [] |
| 3354 | // Optional leading '(' before pattern — bash allows (pattern) syntax |
| 3355 | if (peek(P.L) === '(') { |
| 3356 | const s = P.L.b |
| 3357 | advance(P.L) |
| 3358 | kids.push(mk(P, '(', s, P.L.b, [])) |
| 3359 | } |
| 3360 | // Pattern(s) |
| 3361 | let isFirstAlt = true |
| 3362 | while (true) { |
| 3363 | skipBlanks(P.L) |
| 3364 | const c = peek(P.L) |
| 3365 | if (c === ')' || c === '') break |
| 3366 | const pats = parseCasePattern(P) |
| 3367 | if (pats.length === 0) break |
| 3368 | // tree-sitter quirk: first alternative with quotes is inlined as flat |
| 3369 | // siblings; subsequent alternatives are wrapped in (concatenation) with |
| 3370 | // `word` instead of `extglob_pattern` for bare segments. |
| 3371 | if (!isFirstAlt && pats.length > 1) { |
| 3372 | const rewritten = pats.map(p => |
| 3373 | p.type === 'extglob_pattern' |
| 3374 | ? mk(P, 'word', p.startIndex, p.endIndex, []) |
| 3375 | : p, |
| 3376 | ) |
| 3377 | const first = rewritten[0]! |
| 3378 | const last = rewritten[rewritten.length - 1]! |
| 3379 | kids.push( |
| 3380 | mk(P, 'concatenation', first.startIndex, last.endIndex, rewritten), |
| 3381 | ) |
| 3382 | } else { |
| 3383 | kids.push(...pats) |
| 3384 | } |
| 3385 | isFirstAlt = false |
| 3386 | skipBlanks(P.L) |
| 3387 | // \<newline> line continuation between alternatives |
| 3388 | if (peek(P.L) === '\\' && peek(P.L, 1) === '\n') { |
| 3389 | advance(P.L) |
| 3390 | advance(P.L) |
| 3391 | skipBlanks(P.L) |
| 3392 | } |
| 3393 | if (peek(P.L) === '|') { |
| 3394 | const s = P.L.b |
| 3395 | advance(P.L) |
| 3396 | kids.push(mk(P, '|', s, P.L.b, [])) |
| 3397 | // \<newline> after | is also a line continuation |
| 3398 | if (peek(P.L) === '\\' && peek(P.L, 1) === '\n') { |
| 3399 | advance(P.L) |
| 3400 | advance(P.L) |
| 3401 | } |
| 3402 | } else { |
| 3403 | break |
| 3404 | } |
| 3405 | } |
| 3406 | if (peek(P.L) === ')') { |
| 3407 | const s = P.L.b |
no test coverage detected