Passed
Push — master ( 351308...878789 )
by Alexander
02:24 queued 10s
created

Config::setSections()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 13
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 10
CRAP Score 2

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 2
eloc 8
c 1
b 0
f 0
nc 2
nop 1
dl 0
loc 13
ccs 10
cts 10
cp 1
crap 2
rs 10
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Vasoft\VersionIncrement;
6
7
use Vasoft\VersionIncrement\Commits\CommitCollection;
8
use Vasoft\VersionIncrement\Commits\Section;
9
use Vasoft\VersionIncrement\Contract\ChangelogFormatterInterface;
10
use Vasoft\VersionIncrement\Contract\CommitParserInterface;
11
use Vasoft\VersionIncrement\Contract\SectionRuleInterface;
12
use Vasoft\VersionIncrement\Contract\TagFormatterInterface;
13
use Vasoft\VersionIncrement\Contract\VcsExecutorInterface;
14
use Vasoft\VersionIncrement\Exceptions\UnknownPropertyException;
15
use Vasoft\VersionIncrement\SectionRules\DefaultRule;
16
17
/**
18
 * Class Config.
19
 *
20
 * Represents the configuration for the version increment tool. This class provides methods to configure various
21
 * aspects of the tool, such as sections, rules, version control settings, and formatters. It also manages default
22
 * configurations and ensures consistency across the application.
23
 */
24
final class Config
25
{
26
    private array $props = [];
27
    private string $squashedCommitMessage = 'Squashed commit of the following:';
28
    private bool $processDefaultSquashedCommit = false;
29
    private array $minorTypes = [
30
        'feat',
31
    ];
32
    private array $majorTypes = [];
33
    private array $sectionRules = [];
34
    public const DEFAULT_SECTION = 'other';
35
36
    private int $defaultOrder = 500;
37
    private bool $sored = true;
38
    private string $masterBranch = 'master';
39
    private string $releaseSection = 'chore';
40
41
    private string $releaseScope = 'release';
42
43
    private string $aggregateSection = '';
44
45
    private bool $enabledComposerVersioning = true;
46
47
    private ?ChangelogFormatterInterface $changelogFormatter = null;
48
    private ?CommitParserInterface $commitParser = null;
49
    private ?VcsExecutorInterface $vcsExecutor = null;
50
    private ?TagFormatterInterface $tagFormatter = null;
51
52
    private bool $hideDoubles = false;
53
54
    private bool $ignoreUntrackedFiles = false;
55
    private array $sections = [
56
        'feat' => [
57
            'title' => 'New features',
58
            'order' => 10,
59
            'hidden' => false,
60
        ],
61
        'fix' => [
62
            'title' => 'Fixes',
63
            'order' => 20,
64
            'hidden' => false,
65
        ],
66
        'chore' => [
67
            'title' => 'Other changes',
68
            'order' => 30,
69
            'hidden' => false,
70
        ],
71
        'docs' => [
72
            'title' => 'Documentation',
73
            'order' => 40,
74
            'hidden' => false,
75
        ],
76
        'style' => [
77
            'title' => 'Styling',
78
            'order' => 50,
79
            'hidden' => false,
80
        ],
81
        'refactor' => [
82
            'title' => 'Refactoring',
83
            'order' => 60,
84
            'hidden' => false,
85
        ],
86
        'test' => [
87
            'title' => 'Tests',
88
            'order' => 70,
89
            'hidden' => false,
90
        ],
91
        'perf' => [
92
            'title' => 'Performance',
93
            'order' => 80,
94
            'hidden' => false,
95
        ],
96
        'ci' => [
97
            'title' => 'Configure CI',
98
            'order' => 90,
99
            'hidden' => false,
100
        ],
101
        'build' => [
102
            'title' => 'Change build system',
103
            'order' => 100,
104
            'hidden' => false,
105
        ],
106
        'other' => [
107
            'title' => 'Other',
108
            'order' => 110,
109
            'hidden' => false,
110
        ],
111
    ];
112
113
    /**
114
     * Sets the sections configuration for the tool.
115
     *
116
     * This method allows you to define a custom set of sections, each with its own title, order, and visibility settings.
117
     * Existing sections are cleared before applying the new configuration. The order of sections is reset, and the default
118
     * section (`other`) will be added automatically if not explicitly defined.
119
     *
120
     * Each section can be configured with the following optional parameters:
121
     * - `title`: The display name of the section in the CHANGELOG (defaults to the section key).
122
     * - `order`: The sorting priority of the section (auto-incremented if not provided).
123
     * - `hidden`: Whether the section should be hidden in the CHANGELOG (defaults to `false`).
124
     *
125
     * @param array $sections an associative array where keys are section codes and values are arrays containing
126
     *                        the section's configuration (`title`, `order`, and `hidden`)
127
     *
128
     * @return $this this Config instance for method chaining
129
     */
130 5
    public function setSections(array $sections): self
131
    {
132 5
        $this->sored = false;
133 5
        $this->sections = [];
134 5
        foreach ($sections as $key => $value) {
135 5
            $this->sections[$key] = [
136 5
                'title' => $value['title'] ?? $key,
137 5
                'order' => $value['order'] ?? ++$this->defaultOrder,
138 5
                'hidden' => $value['hidden'] ?? false,
139 5
            ];
140
        }
141
142 5
        return $this;
143
    }
144
145
    /**
146
     * Sets or updates the configuration for a specific section.
147
     *
148
     * This method allows you to define or modify the settings of a section, such as its title, order, and visibility.
149
     * If the section already exists, its configuration is updated; otherwise, a new section is created. Existing values
150
     * for `order` and `hidden` are preserved unless explicitly overridden.
151
     *
152
     * @param string    $key    the unique identifier (code) of the section
153
     * @param string    $title  the display name of the section in the CHANGELOG
154
     * @param int       $order  The sorting priority of the section. Defaults to `-1`, which preserves the existing order
155
     *                          or assigns a new auto-incremented value if the section does not exist.
156
     * @param null|bool $hidden Whether the section should be hidden in the CHANGELOG. Defaults to `null`, which
157
     *                          preserves the existing visibility setting or sets it to `false` if the section
158
     *                          does not exist.
159
     *
160
     * @return $this this Config instance for method chaining
161
     */
162 4
    public function setSection(
163
        string $key,
164
        string $title,
165
        int $order = -1,
166
        ?bool $hidden = null,
167
    ): self {
168 4
        $this->sored = false;
169 4
        $exists = $this->sections[$key] ?? null;
170 4
        $this->sections[$key] = [
171 4
            'title' => $title,
172 4
            'order' => -1 === $order ? ($exists ? $exists['order'] : ++$this->defaultOrder) : $order,
173 4
            'hidden' => null !== $hidden ? $hidden : ($exists ? $exists['hidden'] : false),
174 4
        ];
175
176 4
        return $this;
177
    }
178
179
    /**
180
     * Retrieves the index of sections as an array with empty values.
181
     *
182
     * This method sorts the sections internally and returns an array where the keys are section names and the values
183
     * are empty arrays. This is useful for initializing data structures that require a predefined set of sections.
184
     *
185
     * @return array an associative array with section names as keys and empty arrays as values
186
     */
187 3
    public function getSectionIndex(): array
188
    {
189 3
        $this->sortSections();
190
191 3
        return array_fill_keys(array_keys($this->sections), []);
192
    }
193
194
    /**
195
     * Retrieves the commit collection based on the configured sections.
196
     *
197
     * This method creates a `CommitCollection` object by converting the configured sections into `Section` objects.
198
     * It ensures that all sections are sorted and that a default section exists if not explicitly defined.
199
     *
200
     * @return CommitCollection a collection of commits grouped by sections
201
     */
202 22
    public function getCommitCollection(): CommitCollection
203
    {
204 22
        $this->sortSections();
205 22
        $sections = [];
206 22
        $default = null;
207 22
        foreach ($this->sections as $key => $section) {
208 22
            $section = new Section(
209 22
                $key,
210 22
                $section['title'],
211 22
                $section['hidden'],
212 22
                $this->getSectionRules($key),
213 22
                in_array($key, $this->majorTypes, true),
214 22
                in_array($key, $this->minorTypes, true),
215 22
                $this,
216 22
            );
217 22
            if (self::DEFAULT_SECTION === $key) {
218 22
                $default = $section;
219
            }
220 22
            $sections[$key] = $section;
221
        }
222
223 22
        return new CommitCollection($sections, $default);
0 ignored issues
show
Bug introduced by
It seems like $default can also be of type null; however, parameter $defaultSection of Vasoft\VersionIncrement\...llection::__construct() does only seem to accept Vasoft\VersionIncrement\Commits\Section, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

223
        return new CommitCollection($sections, /** @scrutinizer ignore-type */ $default);
Loading history...
224
    }
225
226 30
    private function sortSections(): void
227
    {
228 30
        if (!$this->sored) {
229 9
            $this->checkDefaultSection();
230 9
            uasort($this->sections, static fn($a, $b) => $a['order'] <=> $b['order']);
231 9
            $this->sored = true;
232
        }
233
    }
234
235
    /**
236
     * Retrieves the descriptions of all configured sections.
237
     *
238
     * This method generates a list of section descriptions in the format "key - title".
239
     * The sections are sorted internally before generating the descriptions. Each description consists of the section's
240
     * unique identifier (key) and its display name (title).
241
     *
242
     * Used for --list option
243
     *
244
     * @return array an array of strings, where each string represents a section description in the format "key - title"
245
     */
246 5
    public function getSectionDescriptions(): array
247
    {
248 5
        $this->sortSections();
249 5
        $result = [];
250 5
        foreach ($this->sections as $key => $section) {
251 5
            $result[] = sprintf('%s - %s', $key, $section['title']);
252
        }
253
254 5
        return $result;
255
    }
256
257
    /**
258
     * Retrieves the title of a specific section.
259
     *
260
     * This method returns the title of the section identified by the given key. If the section does not exist, the key
261
     * itself is returned as the title.
262
     *
263
     * @param string $key the key of the section
264
     *
265
     * @return string the title of the section or the key if the section does not exist
266
     */
267 2
    public function getSectionTitle(string $key): string
268
    {
269 2
        return $this->sections[$key]['title'] ?? $key;
270
    }
271
272
    /**
273
     * Checks whether a specific section is hidden.
274
     *
275
     * This method determines if the section identified by the given key is marked as hidden in the configuration. If
276
     * the section does not exist, it is considered visible (not hidden).
277
     *
278
     * @param string $key the key of the section
279
     *
280
     * @return bool returns `true` if the section is hidden, `false` otherwise
281
     */
282 2
    public function isSectionHidden(string $key): bool
283
    {
284 2
        return $this->sections[$key]['hidden'] ?? false;
285
    }
286
287
    /**
288
     * Sets the section to be used for release commits.
289
     *
290
     * This method defines the section that will be associated with release-related commits. The specified section will be
291
     * used when generating release commit messages or determining the scope of a release.
292
     *
293
     * @param string $section The key of the section to be used for releases (e.g., 'release').
294
     *
295
     * @return $this this Config instance for method chaining
296
     */
297 1
    public function setReleaseSection(string $section): self
298
    {
299 1
        $this->releaseSection = $section;
300
301 1
        return $this;
302
    }
303
304
    /**
305
     * Retrieves the key of the section configured for release commits.
306
     *
307
     * This method returns the key of the section that is associated with release-related commits. If the configured
308
     * release section does not exist in the sections list, the default section (`other`) is returned instead.
309
     *
310
     * @return string the key of the release section or the default section if the configured release section is invalid
311
     */
312 20
    public function getReleaseSection(): string
313
    {
314 20
        return isset($this->sections[$this->releaseSection]) ? $this->releaseSection : self::DEFAULT_SECTION;
315
    }
316
317 9
    private function checkDefaultSection(): void
318
    {
319 9
        if (!isset($this->sections[self::DEFAULT_SECTION])) {
320 5
            $maxOrder = 0;
321 5
            foreach ($this->sections as $section) {
322 5
                $maxOrder = max($maxOrder, $section['order']);
323
            }
324 5
            $this->sections[self::DEFAULT_SECTION] = [
325 5
                'title' => 'Other',
326 5
                'order' => $maxOrder + 1000,
327 5
                'hidden' => false,
328 5
            ];
329
        }
330
    }
331
332
    /**
333
     * Retrieves the name of the main branch in the repository.
334
     *
335
     * By default, it is set to "master".
336
     *
337
     * @return string The name of the main branch (e.g., "main" or "master").
338
     */
339 28
    public function getMasterBranch(): string
340
    {
341 28
        return $this->masterBranch;
342
    }
343
344
    /**
345
     * Sets the name of the main branch in the repository.
346
     *
347
     * This method allows you to configure the name of the main branch (e.g., "main" or "master") used by the tool.
348
     *
349
     * @param string $masterBranch the name of the main branch
350
     *
351
     * @return $this this Config instance for method chaining
352
     */
353 4
    public function setMasterBranch(string $masterBranch): self
354
    {
355 4
        $this->masterBranch = $masterBranch;
356
357 4
        return $this;
358
    }
359
360
    /**
361
     * Sets the types of changes that trigger a minor version increment.
362
     *
363
     * This method configures the list of commit types that, when present, will cause the minor version to be
364
     * incremented during version updates.
365
     *
366
     * @param array $minorTypes An array of commit type codes (e.g., ['feat', 'fix']).
367
     *
368
     * @return $this this Config instance for method chaining
369
     */
370 1
    public function setMinorTypes(array $minorTypes): self
371
    {
372 1
        $this->minorTypes = $minorTypes;
373
374 1
        return $this;
375
    }
376
377
    /**
378
     * Sets the types of changes that trigger a major version increment.
379
     *
380
     * This method configures the list of commit types that, when present, will cause the major version to be
381
     * incremented during version updates.
382
     *
383
     * @param array $majorTypes An array of commit type codes (e.g., ['breaking']).
384
     *
385
     * @return $this this Config instance for method chaining
386
     */
387 1
    public function setMajorTypes(array $majorTypes): self
388
    {
389 1
        $this->majorTypes = $majorTypes;
390
391 1
        return $this;
392
    }
393
394
    /**
395
     * Sets the scope to be used for release commit messages.
396
     *
397
     * This method defines the scope that will be included in the description of release-related commits.
398
     * If an empty string is provided, no scope will be added to the release commit message.
399
     *
400
     * @param string $releaseScope The scope to be used for release commits (e.g., 'rel').
401
     *                             Use an empty string to omit the scope from the commit message.
402
     *
403
     * @return $this this Config instance for method chaining
404
     */
405 2
    public function setReleaseScope(string $releaseScope): self
406
    {
407 2
        $this->releaseScope = $releaseScope;
408
409 2
        return $this;
410
    }
411
412
    /**
413
     * Retrieves the scope configured for release commit messages.
414
     *
415
     * This method returns the scope that will be included in the description of release-related commits.
416
     * If no scope is configured, an empty string is returned, indicating that no scope will be added to the commit message.
417
     *
418
     * @return string the scope for release commit messages, or an empty string if no scope is configured
419
     */
420 19
    public function getReleaseScope(): string
421
    {
422 19
        return $this->releaseScope;
423
    }
424
425
    /**
426
     * Enables or disables ignoring untracked files in the repository.
427
     *
428
     * This method configures whether untracked files should be ignored when running the version increment tool.
429
     * By default, untracked files are not ignored, and their presence may cause the tool to fail.
430
     *
431
     * @param bool $ignoreUntrackedFiles Whether to ignore untracked files:
432
     *                                   - `true`: Ignore untracked files.
433
     *                                   - `false`: Do not ignore untracked files (default behavior).
434
     *
435
     * @return $this this Config instance for method chaining
436
     */
437 1
    public function setIgnoreUntrackedFiles(bool $ignoreUntrackedFiles): self
438
    {
439 1
        $this->ignoreUntrackedFiles = $ignoreUntrackedFiles;
440
441 1
        return $this;
442
    }
443
444
    /**
445
     * Checks whether untracked files are ignored in the repository.
446
     *
447
     * This method retrieves the current configuration for ignoring untracked files. If enabled, the tool will not
448
     * consider untracked files when performing operations.
449
     *
450
     * @return bool returns `true` if untracked files are ignored, `false` otherwise
451
     */
452 27
    public function mastIgnoreUntrackedFiles(): bool
453
    {
454 27
        return $this->ignoreUntrackedFiles;
455
    }
456
457
    /**
458
     * Adds a rule for determining whether a commit belongs to a specific section.
459
     *
460
     * This method associates a rule with a specific section. The rule is used to evaluate whether a commit should be
461
     * included in the specified section.
462
     *
463
     * @param string               $key  the key of the section
464
     * @param SectionRuleInterface $rule the rule to be added
465
     *
466
     * @return $this this Config instance for method chaining
467
     */
468 3
    public function addSectionRule(string $key, SectionRuleInterface $rule): self
469
    {
470 3
        $this->sectionRules[$key][] = $rule;
471
472 3
        return $this;
473
    }
474
475
    /**
476
     * Retrieves the rules associated with a specific section.
477
     *
478
     * This method returns an array of rules for the specified section. If no custom rules are defined, a default rule
479
     * is automatically added and returned.
480
     *
481
     * @param string $key the key of the section
482
     *
483
     * @return SectionRuleInterface[] an array of rules for the specified section
484
     */
485 22
    public function getSectionRules(string $key): array
486
    {
487 22
        $this->sectionRules[$key]['default'] = new DefaultRule($key);
488
489 22
        return $this->sectionRules[$key];
490
    }
491
492
    /**
493
     * Sets the section to be used for identifying squashed (aggregate) commits.
494
     *
495
     * This method configures the section that will be treated as a marker for squashed commits. When a commit is
496
     * associated with this section, it will be processed as a squashed commit. Squashed commits typically contain
497
     * a summary of multiple commits and are parsed accordingly to extract individual changes.
498
     *
499
     * @param string $aggregateSection The key of the section to be used for identifying squashed commits
500
     *                                 (e.g., 'aggregate').
501
     *
502
     * @return $this this Config instance for method chaining
503
     */
504 1
    public function setAggregateSection(string $aggregateSection): self
505
    {
506 1
        $this->aggregateSection = $aggregateSection;
507
508 1
        return $this;
509
    }
510
511
    /**
512
     * Retrieves the section configured for identifying squashed (aggregate) commits.
513
     *
514
     * This method returns the key of the section that is used to identify squashed commits. If no section has been
515
     * explicitly configured, an empty string is returned, indicating that no specific section is assigned for
516
     * identifying squashed commits.
517
     *
518
     * @return string the key of the section used for identifying squashed commits, or an empty string if no section
519
     *                is configured
520
     */
521 22
    public function getAggregateSection(): string
522
    {
523 22
        return $this->aggregateSection;
524
    }
525
526
    /**
527
     * Sets the commit message template for squashed commits.
528
     *
529
     * This method allows you to customize the message used to identify squashed commits in the repository.
530
     *
531
     * @param string $squashedCommitMessage the custom message template for squashed commits
532
     *
533
     * @return $this this Config instance for method chaining
534
     */
535 1
    public function setSquashedCommitMessage(string $squashedCommitMessage): self
536
    {
537 1
        $this->squashedCommitMessage = $squashedCommitMessage;
538
539 1
        return $this;
540
    }
541
542
    /**
543
     * Retrieves the commit message template for squashed commits.
544
     *
545
     * @return string the message template for squashed commits
546
     */
547 22
    public function getSquashedCommitMessage(): string
548
    {
549 22
        return $this->squashedCommitMessage;
550
    }
551
552
    /**
553
     * Enables or disables processing of default squashed commits.
554
     *
555
     * This method configures whether the tool should process default squashed commits (those matching the default
556
     * message template).
557
     *
558
     * @param bool $processDefaultSquashedCommit whether to enable processing of default squashed commits
559
     *
560
     * @return $this this Config instance for method chaining
561
     */
562 2
    public function setProcessDefaultSquashedCommit(bool $processDefaultSquashedCommit): self
563
    {
564 2
        $this->processDefaultSquashedCommit = $processDefaultSquashedCommit;
565
566 2
        return $this;
567
    }
568
569
    /**
570
     * Checks whether processing of default squashed commits is enabled.
571
     *
572
     * @return bool returns `true` if processing of default squashed commits is enabled, `false` otherwise
573
     */
574 22
    public function shouldProcessDefaultSquashedCommit(): bool
575
    {
576 22
        return $this->processDefaultSquashedCommit;
577
    }
578
579
    /**
580
     * Retrieves the changelog formatter instance.
581
     *
582
     * If no custom changelog formatter is set, a default instance of `DefaultFormatter` is created and configured.
583
     * The formatter's configuration is automatically updated to use the current `Config` instance.
584
     *
585
     * @return ChangelogFormatterInterface the changelog formatter instance
586
     */
587 22
    public function getChangelogFormatter(): ChangelogFormatterInterface
588
    {
589 22
        if (null === $this->changelogFormatter) {
590 21
            $this->changelogFormatter = new Changelog\DefaultFormatter();
591 21
            $this->changelogFormatter->setConfig($this);
592
        }
593
594 22
        return $this->changelogFormatter;
595
    }
596
597
    /**
598
     * Sets a custom changelog formatter for the configuration.
599
     *
600
     * The provided formatter will be used for all changelog-related operations. The formatter's configuration
601
     * is automatically updated to use the current `Config` instance.
602
     *
603
     * @param ChangelogFormatterInterface $changelogFormatter the custom changelog formatter to set
604
     *
605
     * @return $this this Config instance for method chaining
606
     */
607 1
    public function setChangelogFormatter(ChangelogFormatterInterface $changelogFormatter): self
608
    {
609 1
        $this->changelogFormatter = $changelogFormatter;
610 1
        $this->changelogFormatter->setConfig($this);
611
612 1
        return $this;
613
    }
614
615
    /**
616
     * Retrieves the VCS executor instance.
617
     *
618
     * If no custom VCS executor is set, a default instance of `GitExecutor` is created and used.
619
     *
620
     * @return VcsExecutorInterface the VCS executor instance
621
     */
622 29
    public function getVcsExecutor(): VcsExecutorInterface
623
    {
624 29
        if (null === $this->vcsExecutor) {
625 1
            $this->vcsExecutor = new GitExecutor();
626
        }
627
628 29
        return $this->vcsExecutor;
629
    }
630
631
    /**
632
     * Sets a custom VCS executor for the configuration.
633
     *
634
     * The provided executor will be used for all version control system operations.
635
     *
636
     * @param VcsExecutorInterface $vcsExecutor the custom VCS executor to set
637
     *
638
     * @return $this this Config instance for method chaining
639
     */
640 29
    public function setVcsExecutor(VcsExecutorInterface $vcsExecutor): self
641
    {
642 29
        $this->vcsExecutor = $vcsExecutor;
643
644 29
        return $this;
645
    }
646
647
    /**
648
     * Retrieves the commit parser instance.
649
     *
650
     * If no custom commit parser is set, a default instance of `ShortParser` is created and configured.
651
     * The parser's configuration is automatically updated to use the current `Config` instance.
652
     *
653
     * @return CommitParserInterface the commit parser instance
654
     */
655 25
    public function getCommitParser(): CommitParserInterface
656
    {
657 25
        if (null === $this->commitParser) {
658 24
            $this->commitParser = new Commits\ShortParser();
659 24
            $this->commitParser->setConfig($this);
660
        }
661
662 25
        return $this->commitParser;
663
    }
664
665
    /**
666
     * Sets a custom commit parser for the configuration.
667
     *
668
     * The provided parser will be used for all commit parsing operations. The parser's configuration is automatically
669
     * updated to use the current `Config` instance.
670
     *
671
     * @return $this this Config instance for method chaining
672
     */
673 1
    public function setCommitParser(CommitParserInterface $changelogFormatter): self
674
    {
675 1
        $this->commitParser = $changelogFormatter;
676 1
        $this->commitParser->setConfig($this);
677
678 1
        return $this;
679
    }
680
681
    /**
682
     * Retrieves the tag formatter instance.
683
     *
684
     * If no custom tag formatter is set, a default instance of `DefaultFormatter` is created and configured.
685
     *
686
     * @return TagFormatterInterface the tag formatter instance
687
     */
688 6
    public function getTagFormatter(): TagFormatterInterface
689
    {
690 6
        if (null === $this->tagFormatter) {
691 5
            $this->tagFormatter = new Tag\DefaultFormatter();
692 5
            $this->tagFormatter->setConfig($this);
693
        }
694
695 6
        return $this->tagFormatter;
696
    }
697
698
    /**
699
     * Sets a custom tag formatter for the configuration.
700
     *
701
     * The provided formatter will be used for all tag-related operations. The formatter's configuration
702
     * is automatically updated to use the current `Config` instance.
703
     *
704
     * @param TagFormatterInterface $tagFormatter the custom tag formatter to set
705
     *
706
     * @return $this this Config instance for method chaining
707
     */
708 1
    public function setTagFormatter(TagFormatterInterface $tagFormatter): self
709
    {
710 1
        $this->tagFormatter = $tagFormatter;
711 1
        $this->tagFormatter->setConfig($this);
712
713 1
        return $this;
714
    }
715
716
    /**
717
     * Enables or disables version management in the `composer.json` file.
718
     *
719
     * When disabled, version management will rely solely on Git tags instead of updating `composer.json`.
720
     *
721
     * @param bool $enabledComposerVersioning Whether to enable version management in `composer.json`.
722
     *                                        - `true`: Enable version management in `composer.json`.
723
     *                                        - `false`: Disable version management in `composer.json`.
724
     *
725
     * @return $this this Config instance for method chaining
726
     */
727 6
    public function setEnabledComposerVersioning(bool $enabledComposerVersioning): self
728
    {
729 6
        $this->enabledComposerVersioning = $enabledComposerVersioning;
730
731 6
        return $this;
732
    }
733
734
    /**
735
     * Checks whether version management in the `composer.json` file is enabled.
736
     *
737
     * @return bool Returns `true` if version management in `composer.json` is enabled, `false` otherwise.
738
     */
739 27
    public function isEnabledComposerVersioning(): bool
740
    {
741 27
        return $this->enabledComposerVersioning;
742
    }
743
744
    /**
745
     * Sets a custom property in the configuration.
746
     *
747
     * This method allows you to store custom key-value pairs in the configuration. These properties can be used to pass
748
     * additional parameters required by custom implementations (e.g., formatters, VCS executors, parsers, etc.).
749
     *
750
     * @param string $key   The name of the property to set. This should be a unique identifier for the property.
751
     * @param mixed  $value The value to associate with the property. This can be any type of data required by the custom
752
     *                      implementation.
753
     *
754
     * @return $this this Config instance for method chaining
755
     *
756
     * @example
757
     * ```php
758
     * return (new \Vasoft\VersionIncrement\Config())
759
     *     ->set('customParam', 'customValue');
760
     * ```
761
     */
762 5
    public function set(string $key, mixed $value): self
763
    {
764 5
        $this->props[$key] = $value;
765
766 5
        return $this;
767
    }
768
769
    /**
770
     * Retrieves the value of a custom property from the configuration.
771
     *
772
     * This method retrieves the value associated with the specified property key. If the property does not exist,
773
     * an exception is thrown to indicate that the property is unknown.
774
     *
775
     * @param string $key The name of the property to retrieve. This should match the key used when setting the property.
776
     *
777
     * @return mixed the value associated with the property
778
     *
779
     * @throws UnknownPropertyException if the specified property does not exist in the configuration
780
     */
781 6
    public function get(string $key): mixed
782
    {
783 6
        if (!isset($this->props[$key])) {
784 1
            throw new UnknownPropertyException($key);
785
        }
786
787 5
        return $this->props[$key];
788
    }
789
790
    /**
791
     * Enables or disables hiding of duplicate entries within the same section in the CHANGELOG.
792
     *
793
     * This method configures whether duplicate entries (lines with identical content) should be hidden in the generated
794
     * CHANGELOG. When enabled, only the first occurrence of a duplicate entry will be displayed within each section.
795
     *
796
     * @param bool $hideDoubles Whether to hide duplicate entries:
797
     *                          - `true`: Hide duplicate entries within the same section.
798
     *                          - `false`: Display all entries, including duplicates (default behavior).
799
     *
800
     * @return $this this Config instance for method chaining
801
     */
802 1
    public function setHideDoubles(bool $hideDoubles): self
803
    {
804 1
        $this->hideDoubles = $hideDoubles;
805
806 1
        return $this;
807
    }
808
809
    /**
810
     * Checks whether hiding of duplicate entries within the same section is enabled.
811
     *
812
     * This method retrieves the current configuration for hiding duplicate entries in the CHANGELOG. If enabled, duplicate
813
     * entries within the same section will be hidden during the generation of the CHANGELOG.
814
     *
815
     * @return bool returns `true` if hiding of duplicate entries is enabled, `false` otherwise
816
     */
817 22
    public function isHideDoubles(): bool
818
    {
819 22
        return $this->hideDoubles;
820
    }
821
}
822