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