Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
32 / 32
100.00% covered (success)
100.00%
4 / 4
CRAP
100.00% covered (success)
100.00%
1 / 1
FundingYamlCodec
100.00% covered (success)
100.00%
32 / 32
100.00% covered (success)
100.00%
4 / 4
15
100.00% covered (success)
100.00%
1 / 1
 parse
100.00% covered (success)
100.00%
15 / 15
100.00% covered (success)
100.00%
1 / 1
4
 dump
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
3
 normalizeList
100.00% covered (success)
100.00%
10 / 10
100.00% covered (success)
100.00%
1 / 1
6
 denormalizeList
100.00% covered (success)
100.00%
1 / 1
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\Funding;
21
22use Symfony\Component\Yaml\Yaml;
23
24use function array_filter;
25use function array_values;
26use function trim;
27
28/**
29 * Parses and renders GitHub funding YAML metadata.
30 */
31  class FundingYamlCodec
32{
33    /**
34     * Parses a GitHub funding YAML payload into a normalized profile.
35     *
36     * @param string|null $contents the YAML contents, or null when the file does not exist
37     *
38     * @return FundingProfile the normalized funding profile
39     */
40    public function parse(?string $contents): FundingProfile
41    {
42        if (null === $contents || '' === trim($contents)) {
43            return new FundingProfile();
44        }
45
46        $data = Yaml::parse($contents);
47
48        if (! \is_array($data)) {
49            return new FundingProfile();
50        }
51
52        $unsupported = array_filter(
53            $data,
54            static fn(string $key): bool => ! \in_array($key, ['github', 'custom'], true),
55            \ARRAY_FILTER_USE_KEY,
56        );
57
58        return new FundingProfile(
59            $this->normalizeList($data['github'] ?? []),
60            $this->normalizeList($data['custom'] ?? []),
61            $unsupported,
62        );
63    }
64
65    /**
66     * Renders a normalized funding profile into GitHub funding YAML.
67     *
68     * @param FundingProfile $profile the profile to render
69     *
70     * @return string the YAML document contents
71     */
72    public function dump(FundingProfile $profile): string
73    {
74        $data = $profile->getUnsupportedYamlEntries();
75
76        if ([] !== $profile->getGithubSponsors()) {
77            $data['github'] = $this->denormalizeList($profile->getGithubSponsors());
78        }
79
80        if ([] !== $profile->getCustomUrls()) {
81            $data['custom'] = $profile->getCustomUrls();
82        }
83
84        return Yaml::dump($data, 4, 2);
85    }
86
87    /**
88     * Normalizes a scalar-or-list YAML node into a string list.
89     *
90     * @param mixed $value the YAML node to normalize
91     *
92     * @return array<int, string> the normalized string list
93     */
94    private function normalizeList(mixed $value): array
95    {
96        if (\is_string($value) && '' !== trim($value)) {
97            return [trim($value)];
98        }
99
100        if (! \is_array($value)) {
101            return [];
102        }
103
104        return array_values(array_filter(
105            array_map(
106                static fn(mixed $entry): ?string => \is_string($entry) && '' !== trim($entry) ? trim($entry) : null,
107                $value,
108            ),
109        ));
110    }
111
112    /**
113     * Converts a normalized list into the compact YAML representation.
114     *
115     * @param array<int, string> $values the normalized values
116     *
117     * @return string|array<int, string> the scalar-or-list YAML node
118     */
119    private function denormalizeList(array $values): string|array
120    {
121        return 1 === \count($values) ? $values[0] : $values;
122    }
123}