Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
10 / 10
100.00% covered (success)
100.00%
3 / 3
CRAP
100.00% covered (success)
100.00%
1 / 1
Merger
100.00% covered (success)
100.00%
10 / 10
100.00% covered (success)
100.00%
3 / 3
5
100.00% covered (success)
100.00%
1 / 1
 __construct
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 merge
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
2
 patterns
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
2
1<?php
2
3declare(strict_types=1);
4
5/**
6 * Fast Forward Development Tools for PHP projects.
7 *
8 * This file is part of fast-forward/dev-tools project.
9 *
10 * @author   Felipe SayĆ£o Lobato Abreu <github@mentordosnerds.com>
11 * @license  https://opensource.org/licenses/MIT MIT License
12 *
13 * @see      https://github.com/php-fast-forward/
14 * @see      https://github.com/php-fast-forward/dev-tools
15 * @see      https://github.com/php-fast-forward/dev-tools/issues
16 * @see      https://php-fast-forward.github.io/dev-tools/
17 * @see      https://datatracker.ietf.org/doc/html/rfc2119
18 */
19
20namespace FastForward\DevTools\GitIgnore;
21
22/**
23 * Merges ordered .gitignore rules with canonical defaults before consumer overrides.
24 *
25 * Existing patterns MUST retain their order, whitespace and repeated occurrences.
26 */
27  class Merger implements MergerInterface
28{
29    /**
30     * Retains the classifier constructor parameter for compatibility with consumers.
31     *
32     * @param ClassifierInterface $classifier
33     */
34    public function __construct(
35        private ClassifierInterface $classifier = new Classifier()
36    ) {}
37
38    /**
39     * Prepends canonical defaults once, allowing later consumer rules to override them.
40     *
41     * @param GitIgnoreInterface $canonical the canonical baseline
42     * @param GitIgnoreInterface $project the consumer rules and destination path
43     */
44    public function merge(GitIgnoreInterface $canonical, GitIgnoreInterface $project): GitIgnoreInterface
45    {
46        $canonicalEntries = $this->patterns($canonical->entries());
47        $projectEntries = $this->patterns($project->entries());
48
49        if (\array_slice($projectEntries, 0, \count($canonicalEntries)) === $canonicalEntries) {
50            return new GitIgnore($project->path(), $projectEntries);
51        }
52
53        return new GitIgnore($project->path(), [...$canonicalEntries, ...$projectEntries]);
54    }
55
56    /**
57     * Removes only blank lines and comments, never normalizing pattern whitespace.
58     *
59     * @param list<string> $entries the raw rules
60     *
61     * @return list<string>
62     */
63    private function patterns(array $entries): array
64    {
65        return array_values(array_filter(
66            $entries,
67            static fn(string $entry): bool => '' !== trim($entry) && ! str_starts_with($entry, '#'),
68        ));
69    }
70}