Completed
Push — dependabot/github_actions/acti... ( 224e90...b9dbf4 )
by
unknown
205:16 queued 195:17
created

ApiSpecification   A

Complexity

Total Complexity 23

Size/Duplication

Total Lines 260
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 2

Importance

Changes 0
Metric Value
dl 0
loc 260
rs 10
c 0
b 0
f 0
wmc 23
lcom 1
cbo 2

13 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 27 1
A createFromArray() 0 17 1
A createDefault() 0 22 1
A withSource() 0 7 1
A setIgnore() 0 4 1
A offsetExists() 0 6 1
A offsetGet() 0 9 2
A offsetSet() 0 9 2
A offsetUnset() 0 9 2
A normalizePropertyName() 0 4 1
A getIgnoredTags() 0 4 1
A isVisibilityAllowed() 0 6 1
B calculateVisiblity() 0 37 8
1
<?php
2
3
declare(strict_types=1);
4
5
namespace phpDocumentor\Configuration;
6
7
use ArrayAccess;
8
use InvalidArgumentException;
9
use phpDocumentor\Dsn;
10
use phpDocumentor\Path;
11
use RuntimeException;
12
use function lcfirst;
13
use function property_exists;
14
use function sprintf;
15
use function str_replace;
16
use function ucwords;
17
18
/**
19
 * @implements ArrayAccess<String, mixed>
20
 */
21
final class ApiSpecification implements ArrayAccess
22
{
23
    public const VISIBILITY_PUBLIC = 1;
24
    public const VISIBILITY_PROTECTED = 2;
25
    public const VISIBILITY_PRIVATE = 4;
26
    public const VISIBILITY_INTERNAL = 8;
27
    public const VISIBILITY_API = 16;
28
29
    /** @var int by default ignore internal visibility but show others */
30
    public const VISIBILITY_DEFAULT = 7;
31
32
    /** @var array{dsn: Dsn, paths: array<Path>} */
33
    private $source;
34
35
    /** @var string */
36
    private $output;
37
38
    /** @var array{paths: array<Path>} */
39
    private $ignore;
40
41
    /** @var non-empty-list<string> */
42
    private $extensions;
43
44
    /** @var array<string> */
45
    private $visibility;
46
47
    /** @var string */
48
    private $defaultPackageName;
49
50
    /** @var bool */
51
    private $includeSource;
52
53
    /** @var array<string> */
54
    private $markers;
55
56
    /** @var array<string> */
57
    private $ignoreTags;
58
59
    /** @var array{dsn: Dsn, paths: list<string>}|null */
60
    private $examples;
61
62
    /** @var string */
63
    private $encoding;
64
65
    /** @var bool */
66
    private $validate;
67
68
    /**
69
     * @param array{dsn: Dsn, paths: array<Path>} $source
70
     * @param array{paths: array<Path>} $ignore
71
     * @param non-empty-list<string> $extensions
0 ignored issues
show
Documentation introduced by
The doc-type non-empty-list<string> could not be parsed: Unknown type name "non-empty-list" at position 0. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
72
     * @param array<string> $visibility
73
     * @param array<string> $markers
74
     * @param array<string> $ignoreTags
75
     * @param array{dsn: Dsn, paths: list<string>}|null $examples
76
     */
77
    private function __construct(
78
        array $source,
79
        string $output,
80
        array $ignore,
81
        array $extensions,
82
        array $visibility,
83
        string $defaultPackageName,
84
        bool $includeSource,
85
        array $markers,
86
        array $ignoreTags,
87
        ?array $examples,
88
        string $encoding,
89
        bool $validate
90
    ) {
91
        $this->source = $source;
92
        $this->output = $output;
93
        $this->ignore = $ignore;
94
        $this->extensions = $extensions;
95
        $this->visibility = $visibility;
96
        $this->defaultPackageName = $defaultPackageName;
97
        $this->includeSource = $includeSource;
98
        $this->markers = $markers;
99
        $this->ignoreTags = $ignoreTags;
100
        $this->examples = $examples;
101
        $this->encoding = $encoding;
102
        $this->validate = $validate;
103
    }
104
105
    //phpcs:disable Generic.Files.LineLength.TooLong
106
    /**
107
     * @param array{ignore-tags: array<string>, extensions: non-empty-array<string>, markers: non-empty-array<string>, visibility: non-empty-array<string>, source: array{dsn: Dsn, paths: array}, ignore: array{paths: array}, encoding: string, output: string, default-package-name: string, examples: array{dsn: Dsn, paths: array}, include-source: bool, validate: bool} $api
108
     */
109
    //phpcs:enable Generic.Files.LineLength.TooLong
110
    public static function createFromArray(array $api) : self
111
    {
112
        return new self(
113
            $api['source'],
114
            $api['output'],
115
            $api['ignore'],
116
            $api['extensions'],
117
            $api['visibility'],
118
            $api['default-package-name'],
119
            $api['include-source'],
120
            $api['markers'],
121
            $api['ignore-tags'],
122
            $api['examples'] ?? [],
123
            $api['encoding'],
124
            $api['validate']
125
        );
126
    }
127
128
    public static function createDefault() : ApiSpecification
129
    {
130
        return new self(
131
            [
132
                'dsn' => Dsn::createFromString('./'),
133
                'paths' => [new Path('./src')],
134
            ],
135
            './api',
136
            [
137
                'paths' => [],
138
            ],
139
            ['php'],
140
            [],
141
            '',
142
            false,
143
            [],
144
            [],
145
            null,
146
            'utf8',
147
            false
148
        );
149
    }
150
151
    /**
152
     * @param array{dsn: Dsn, paths: array<Path>} $source
153
     */
154
    public function withSource(array $source) : self
155
    {
156
        $clone = clone $this;
157
        $clone->source = $source;
158
159
        return $clone;
160
    }
161
162
    /**
163
     * @param array{paths: non-empty-array<Path>} $ignore
164
     */
165
    public function setIgnore(array $ignore) : void
166
    {
167
        $this->ignore = $ignore;
168
    }
169
170
    /** @param string $offset */
171
    public function offsetExists($offset) : bool
172
    {
173
        $property = $this->normalizePropertyName($offset);
174
175
        return property_exists($this, $property);
176
    }
177
178
    /**
179
     * @param string $offset
180
     *
181
     * @return mixed
182
     */
183
    public function offsetGet($offset)
184
    {
185
        $property = $this->normalizePropertyName($offset);
186
        if (!property_exists($this, $property)) {
187
            throw new InvalidArgumentException('Invalid property ' . $property);
188
        }
189
190
        return $this->$property;
191
    }
192
193
    /**
194
     * @param string $offset
195
     * @param mixed $value
196
     */
197
    public function offsetSet($offset, $value) : void
198
    {
199
        $property = $this->normalizePropertyName($offset);
200
        if (!property_exists($this, $property)) {
201
            throw new InvalidArgumentException('Invalid property ' . $property);
202
        }
203
204
        $this->{$property} = $value;
205
    }
206
207
    /** @param string $offset */
208
    public function offsetUnset($offset) : void
209
    {
210
        $property = $this->normalizePropertyName($offset);
211
        if (!property_exists($this, $property)) {
212
            throw new InvalidArgumentException('Invalid property ' . $property);
213
        }
214
215
        $this->$property = null;
216
    }
217
218
    private function normalizePropertyName(string $offset) : string
219
    {
220
        return lcfirst(str_replace('-', '', ucwords($offset, '-')));
221
    }
222
223
    /** @return string[] */
224
    public function getIgnoredTags() : array
225
    {
226
        return $this->ignoreTags;
227
    }
228
229
    public function calculateVisiblity() : int
230
    {
231
        $visibility = 0;
232
233
        foreach ($this->visibility as $item) {
234
            switch ($item) {
235
                case 'api':
236
                    $visibility |= self::VISIBILITY_API;
237
                    break;
238
                case 'public':
239
                    $visibility |= self::VISIBILITY_PUBLIC;
240
                    break;
241
                case 'protected':
242
                    $visibility |= self::VISIBILITY_PROTECTED;
243
                    break;
244
                case 'private':
245
                    $visibility |= self::VISIBILITY_PRIVATE;
246
                    break;
247
                case 'internal':
248
                    $visibility |= self::VISIBILITY_INTERNAL;
249
                    break;
250
                default:
251
                    throw new RuntimeException(
252
                        sprintf(
253
                            '%s is not a type of visibility, supported is: api, public, protected, private or internal',
254
                            $item
255
                        )
256
                    );
257
            }
258
        }
259
260
        if ($visibility === self::VISIBILITY_INTERNAL) {
261
            $visibility |= self::VISIBILITY_DEFAULT;
262
        }
263
264
        return $visibility;
265
    }
266
267
    /**
268
     * Checks whether the Project supports the given visibility.
269
     *
270
     * @see Settings for a list of the available VISIBILITY_* constants.
271
     *
272
     * @param int $visibility One of the VISIBILITY_* constants of the Settings class.
273
     */
274
    public function isVisibilityAllowed(int $visibility) : bool
275
    {
276
        $visibilityAllowed = $this->calculateVisiblity();
277
278
        return (bool) ($visibilityAllowed & $visibility);
279
    }
280
}
281