• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

eliashaeussler / version-bumper / 15444603054

04 Jun 2025 02:09PM UTC coverage: 88.7% (-1.1%) from 89.773%
15444603054

push

github

eliashaeussler
[FEATURE] Auto-detect package name from `package.json` file

30 of 42 new or added lines in 3 files covered. (71.43%)

2 existing lines in 1 file now uncovered.

887 of 1000 relevant lines covered (88.7%)

4.85 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

92.06
/src/Config/Preset/NpmPackagePreset.php
1
<?php
2

3
declare(strict_types=1);
4

5
/*
6
 * This file is part of the Composer package "eliashaeussler/version-bumper".
7
 *
8
 * Copyright (C) 2024-2025 Elias Häußler <elias@haeussler.dev>
9
 *
10
 * This program is free software: you can redistribute it and/or modify
11
 * it under the terms of the GNU General Public License as published by
12
 * the Free Software Foundation, either version 3 of the License, or
13
 * (at your option) any later version.
14
 *
15
 * This program is distributed in the hope that it will be useful,
16
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18
 * GNU General Public License for more details.
19
 *
20
 * You should have received a copy of the GNU General Public License
21
 * along with this program. If not, see <https://www.gnu.org/licenses/>.
22
 */
23

24
namespace EliasHaeussler\VersionBumper\Config\Preset;
25

26
use EliasHaeussler\VersionBumper\Config;
27
use EliasHaeussler\VersionBumper\Exception;
28
use JsonException;
29
use stdClass;
30
use Symfony\Component\Filesystem;
31
use Symfony\Component\OptionsResolver;
32

33
use function is_string;
34
use function ltrim;
35
use function property_exists;
36
use function sprintf;
37

38
/**
39
 * NpmPackagePreset.
40
 *
41
 * @author Elias Häußler <elias@haeussler.dev>
42
 * @license GPL-3.0-or-later
43
 *
44
 * @extends BasePreset<array{packageName: string|null, path: string}>
45
 */
46
final class NpmPackagePreset extends BasePreset
47
{
48
    private readonly Filesystem\Filesystem $filesystem;
49

50
    public function __construct(array $options)
9✔
51
    {
52
        $this->filesystem = new Filesystem\Filesystem();
9✔
53
        $this->options = $this->resolveOptions($options);
9✔
54
    }
55

56
    /**
57
     * @throws Exception\FileDoesNotExist
58
     * @throws Exception\FileIsNotReadable
59
     * @throws Exception\FilePatternIsInvalid
60
     * @throws Exception\ManifestFileIsMalformed
61
     * @throws Exception\PackageNameIsMissing
62
     */
63
    public function getConfig(?Config\VersionBumperConfig $rootConfig = null): Config\VersionBumperConfig
9✔
64
    {
65
        $packageJsonFile = new Config\FileToModify(
9✔
66
            $this->resolvePath('package.json'),
9✔
67
            [
9✔
68
                new Config\FilePattern('"version": "{%version%}"'),
9✔
69
            ],
9✔
70
            true,
9✔
71
        );
9✔
72

73
        if (null !== $this->options['packageName']) {
9✔
74
            $packageName = $this->options['packageName'];
1✔
75
        } elseif (null !== $rootConfig && null !== $rootConfig->rootPath()) {
8✔
76
            $packageName = $this->resolvePackageName($packageJsonFile->fullPath($rootConfig->rootPath()));
6✔
77
        } else {
78
            throw new Exception\PackageNameIsMissing($packageJsonFile->path());
2✔
79
        }
80

81
        $filesToModify = [
2✔
82
            $packageJsonFile,
2✔
83
            new Config\FileToModify(
2✔
84
                $this->resolvePath('package-lock.json'),
2✔
85
                [
2✔
86
                    new Config\FilePattern(
2✔
87
                        sprintf(
2✔
88
                            '"name": "%s",\s+"version": "{%%version%%}"',
2✔
89
                            $packageName,
2✔
90
                        ),
2✔
91
                    ),
2✔
92
                ],
2✔
93
                true,
2✔
94
            ),
2✔
95
        ];
2✔
96

97
        return new Config\VersionBumperConfig(filesToModify: $filesToModify);
2✔
98
    }
99

UNCOV
100
    public static function getIdentifier(): string
×
101
    {
UNCOV
102
        return 'npm-package';
×
103
    }
104

105
    public static function getDescription(): string
×
106
    {
107
        return 'NPM package, managed by package.json and package-lock.json';
×
108
    }
109

110
    private function resolvePath(string $filename): string
9✔
111
    {
112
        return ltrim($this->options['path'].'/'.$filename, '/');
9✔
113
    }
114

115
    /**
116
     * @throws Exception\FileDoesNotExist
117
     * @throws Exception\FileIsNotReadable
118
     * @throws Exception\ManifestFileIsMalformed
119
     */
120
    private function resolvePackageName(string $path): string
6✔
121
    {
122
        if (!$this->filesystem->exists($path)) {
6✔
123
            throw new Exception\FileDoesNotExist($path);
1✔
124
        }
125

126
        $contents = file_get_contents($path);
5✔
127

128
        if (false === $contents) {
5✔
NEW
129
            throw new Exception\FileIsNotReadable($path);
×
130
        }
131

132
        try {
133
            $packageJson = json_decode($contents, flags: JSON_THROW_ON_ERROR);
5✔
134
        } catch (JsonException $exception) {
1✔
135
            throw new Exception\ManifestFileIsMalformed($path, $exception);
1✔
136
        }
137

138
        if (!($packageJson instanceof stdClass)
4✔
139
            || !property_exists($packageJson, 'name')
4✔
140
            || !is_string($packageJson->name)
4✔
141
        ) {
142
            throw new Exception\ManifestFileIsMalformed($path);
3✔
143
        }
144

145
        return $packageJson->name;
1✔
146
    }
147

148
    protected function createOptionsResolver(): OptionsResolver\OptionsResolver
9✔
149
    {
150
        $optionsResolver = new OptionsResolver\OptionsResolver();
9✔
151
        $optionsResolver->define('packageName')
9✔
152
            ->allowedTypes('string', 'null')
9✔
153
            ->default(null)
9✔
154
        ;
9✔
155
        $optionsResolver->define('path')
9✔
156
            ->allowedTypes('string')
9✔
157
            ->default('')
9✔
158
        ;
9✔
159

160
        return $optionsResolver;
9✔
161
    }
162
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc