From 43ab18f937015bd5767be66a0c7f4401c861510c Mon Sep 17 00:00:00 2001 From: Natsuki Ikeguchi Date: Sat, 22 Jul 2023 17:50:32 +0900 Subject: [PATCH] feat: Add multi-constraint package support for yarn and pnpm --- src/Model/Package.php | 6 ++++++ src/Scanner/AbstractPackagePool.php | 16 +++++++++++++--- src/Scanner/Pnpm/PnpmLockParser.php | 18 ++++++++++-------- src/Scanner/Yarn/YarnLockParser.php | 4 ++-- tests/Scanner/AbstractPackagePoolTest.php | 19 +++++++++++++++++++ tests/Scanner/Pnpm/PnpmLockParserTest.php | 4 ++-- tests/Scanner/Yarn/YarnLockParserTest.php | 4 ++-- 7 files changed, 54 insertions(+), 17 deletions(-) diff --git a/src/Model/Package.php b/src/Model/Package.php index 8399ed7..67984e6 100644 --- a/src/Model/Package.php +++ b/src/Model/Package.php @@ -8,6 +8,7 @@ class Package { public function __construct( private readonly string $name, + private readonly ?string $constraint = null, ) { } @@ -15,4 +16,9 @@ public function getName(): string { return $this->name; } + + public function getConstraint(): ?string + { + return $this->constraint; + } } diff --git a/src/Scanner/AbstractPackagePool.php b/src/Scanner/AbstractPackagePool.php index c31c987..765abb9 100644 --- a/src/Scanner/AbstractPackagePool.php +++ b/src/Scanner/AbstractPackagePool.php @@ -16,13 +16,23 @@ public function __construct( ) { } - public function get(string $name): ?Package + public function get(string $name, ?string $constraint = null): ?Package { - return $this->packages[$name] ?? null; + return $this->packages[$this->getKey($name, $constraint)] ?? null; } public function add(Package $package): void { - $this->packages[$package->getName()] = $package; + $this->packages[$this->getKey($package->getName(), $package->getConstraint())] = $package; + } + + private function getKey(string $name, ?string $constraint): string + { + $key = $name; + if ($constraint !== null) { + $key .= '__' . $constraint; + } + + return $key; } } diff --git a/src/Scanner/Pnpm/PnpmLockParser.php b/src/Scanner/Pnpm/PnpmLockParser.php index 638b20f..f69a657 100644 --- a/src/Scanner/Pnpm/PnpmLockParser.php +++ b/src/Scanner/Pnpm/PnpmLockParser.php @@ -26,8 +26,8 @@ public function parse(?string $yaml): DependencyCollection /** * @var array{ - * dependencies?: array, - * devDependencies?: array, + * dependencies?: array, + * devDependencies?: array, * } $assoc */ $assoc = Yaml::parse($yaml) ?? []; @@ -35,17 +35,19 @@ public function parse(?string $yaml): DependencyCollection $dependencies = []; foreach ($packages as $name => $version) { - $package = $this->packagePool->get($name); + $constraint = null; + if (\is_array($version)) { + $constraint = $version['specifier'] ?? $version['specification'] ?? null; + $version = $version['version']; + } + + $package = $this->packagePool->get($name, $constraint); if (!$package instanceof Package) { - $package = new Package($name); + $package = new Package($name, $constraint); $this->packagePool->add($package); } - if (\is_array($version)) { - $version = $version['version']; - } - /** @var string $version */ $version = preg_replace('/\(.+\)/', '', $version); diff --git a/src/Scanner/Yarn/YarnLockParser.php b/src/Scanner/Yarn/YarnLockParser.php index f24c975..8000f98 100644 --- a/src/Scanner/Yarn/YarnLockParser.php +++ b/src/Scanner/Yarn/YarnLockParser.php @@ -30,10 +30,10 @@ public function parse(?string $lock): DependencyCollection /** @var ConstraintInterface $constraint */ foreach ($package->getConstraints()->all() as $constraint) { $name = $constraint->getName(); - $pkg = $this->packagePool->get($name); + $pkg = $this->packagePool->get($name, $constraint->getRange()); if (!$pkg instanceof Package) { - $pkg = new Package($name); + $pkg = new Package($name, $constraint->getRange()); $this->packagePool->add($pkg); } diff --git a/tests/Scanner/AbstractPackagePoolTest.php b/tests/Scanner/AbstractPackagePoolTest.php index 5b1d70b..bf14e71 100644 --- a/tests/Scanner/AbstractPackagePoolTest.php +++ b/tests/Scanner/AbstractPackagePoolTest.php @@ -27,6 +27,7 @@ public function test(): void $package = $this->prophesize(Package::class); $package->getName()->willReturn($name); + $package->getConstraint()->willReturn(null); $package = $package->reveal(); $this->pool->add($package); @@ -34,4 +35,22 @@ public function test(): void $this->assertSame($package, $this->pool->get($name)); $this->assertNull($this->pool->get('not/exists')); } + + public function testWithConstraint(): void + { + $name = 'dummy/dummy'; + $constraint = '^1.2.3'; + + $package = $this->prophesize(Package::class); + $package->getName()->willReturn($name); + $package->getConstraint()->willReturn($constraint); + $package = $package->reveal(); + + $this->pool->add($package); + + $this->assertSame($package, $this->pool->get($name, $constraint)); + $this->assertNull($this->pool->get($name), '^4.5.6'); + $this->assertNull($this->pool->get($name)); + $this->assertNull($this->pool->get('not/exists')); + } } diff --git a/tests/Scanner/Pnpm/PnpmLockParserTest.php b/tests/Scanner/Pnpm/PnpmLockParserTest.php index 344fbff..d0017a1 100644 --- a/tests/Scanner/Pnpm/PnpmLockParserTest.php +++ b/tests/Scanner/Pnpm/PnpmLockParserTest.php @@ -49,8 +49,8 @@ public function test(string $yaml): void $fooBarVersion = $this->prophesize(SemVerVersion::class)->reveal(); $barBazVersion = $this->prophesize(SemVerVersion::class)->reveal(); - $this->packagePool->get('foo')->willReturn(null); - $this->packagePool->get('bar')->willReturn($cache); + $this->packagePool->get('foo', Argument::any())->willReturn(null); + $this->packagePool->get('bar', Argument::any())->willReturn($cache); $this->packagePool->add(Argument::type(Package::class))->shouldBeCalledOnce(); $this->versionParser->parse('1.2.3-dev')->willReturn($fooBarVersion); diff --git a/tests/Scanner/Yarn/YarnLockParserTest.php b/tests/Scanner/Yarn/YarnLockParserTest.php index 22b75b6..84194a6 100644 --- a/tests/Scanner/Yarn/YarnLockParserTest.php +++ b/tests/Scanner/Yarn/YarnLockParserTest.php @@ -62,8 +62,8 @@ public function test(): void $fooBarVersion = $this->prophesize(SemVerVersion::class)->reveal(); $barBazVersion = $this->prophesize(SemVerVersion::class)->reveal(); - $this->packagePool->get('@types/node')->willReturn(null); - $this->packagePool->get('typescript')->willReturn($cache); + $this->packagePool->get('@types/node', '^18')->willReturn(null); + $this->packagePool->get('typescript', '^5')->willReturn($cache); $this->packagePool->add(Argument::type(Package::class))->shouldBeCalledOnce(); $this->versionParser->parse('18.16.16')->willReturn($fooBarVersion);