packages/sql-formatter/src/Core/Compact/Grouping.php
1<?php
2
3declare(strict_types=1);
4
5namespace SqlFormatter\Core\Compact;
6
7use SqlParser\Lexer\Token;
8use SqlParser\Parser\Node;
9
10/**
11 * Distinguishes expression grouping from row constructors, subqueries, and argument lists.
12 *
13 * @visibility SqlFormatter
14 */
15final class Grouping
16{
17 /**
18 * @param array<string, list<string>> $rules Parenthesis owner to expression children
19 */
20 public function __construct(private readonly array $rules)
21 {
22 }
23
24 /**
25 * Returns expression parentheses from the innermost group outward.
26 *
27 * @return list<array{int, int}>
28 */
29 public function pairs(Node $tree): array
30 {
31 $pairs = [];
32 foreach ($tree->children as $child) {
33 if ($child instanceof Node) {
34 array_push($pairs, ...$this->pairs($child));
35 }
36 }
37 $children = array_values(array_filter($tree->children, static fn (Node|Token $child): bool => $child instanceof Token || !$child->isEmpty()));
38 if (count($children) === 3 && isset($this->rules[$tree->name])
39 && $children[0] instanceof Token && $children[0]->text === '('
40 && $children[1] instanceof Node && in_array($children[1]->name, $this->rules[$tree->name], true)
41 && $children[2] instanceof Token && $children[2]->text === ')') {
42 $pairs[] = [$children[0]->offset, $children[2]->offset];
43 }
44 return $pairs;
45 }
46}
47