Issues (3)

src/Helpers/Split.php (1 issue)

Severity
1
<?php declare(strict_types=1);
2
3
namespace Stratadox\Parser\Helpers;
4
5
use Closure;
6
use Stratadox\Parser\Parser;
7
use Stratadox\Parser\Parsers\Repeatable;
8
use Stratadox\Parser\Parsers\Either;
9
use Stratadox\Parser\Parsers\Map;
10
use Stratadox\Parser\Parsers\Sequence;
11
use function array_filter;
12
use function array_map;
13
use function array_reduce;
14
use function count;
15
use function is_array;
16
17
/**
18
 * Split
19
 *
20
 * Splits content based on a separator.
21
 */
22
final class Split
23
{
24
    public static function with(Parser|string $separator, Parser|string $subject): Parser
25
    {
26
        return self::make(
27
            $separator,
28
            $subject,
29
            self::defaultMap(),
30
            1,
31
        );
32
    }
33
34
    public static function optional(Parser|string $separator, Parser|string $subject): Parser
35
    {
36
        return self::make(
37
            $separator,
38
            $subject,
39
            self::defaultMap(),
40
            0,
41
        );
42
    }
43
44
    private static function defaultMap(): Closure
45
    {
46
        return fn(array $r) => count($r) > 1 ? [$r[0], ...array_map(
47
            fn($x) => $x[1],
48
            array_filter($r[1], fn($x) => count($x) > 1)
49
        )] : array_map(
50
            fn($x) => $x[1],
51
            array_filter($r[0], fn($x) => count($x) > 1)
52
        );
53
    }
54
55
    private static function make(
56
        Parser|string $separator,
57
        Parser|string $subject,
58
        Closure $mapping,
59
        int $min,
60
    ): Parser {
61
        return Map::the(Sequence::of(
62
            $subject,
63
            AtLeast::results($min, Repeatable::parser(Sequence::of($separator, $subject))),
64
        ), $mapping);
65
    }
66
67
    public static function keep(
68
        Parser|string|array $separator,
69
        Parser|string $subject,
70
        ?Closure $map = null
71
    ): Parser {
72
        $map = $map ?: fn($op, $left, $right) => [$op => [$left, $right]];
73
        return self::make(
74
            is_array($separator) ? Either::of(...$separator) : $separator,
0 ignored issues
show
The condition is_array($separator) is always true.
Loading history...
75
            $subject,
76
            fn(array $a) => array_reduce(
77
                [$a[0], ...$a[1]],
78
                fn($carry, $x) => is_array($x) && isset($x[0]) ? $map($x[0], $carry, $x[1]) : $x,
79
            ),
80
            1,
81
        );
82
    }
83
}
84