diff --git a/src/services/dependencyAnalyzerService.ts b/src/services/dependencyAnalyzerService.ts index df5fb0d..3fe87de 100644 --- a/src/services/dependencyAnalyzerService.ts +++ b/src/services/dependencyAnalyzerService.ts @@ -42,12 +42,14 @@ const isValidSemverRange = (version: string): boolean => { }; /** - * Removes version prefixes for comparison. + * Removes version prefixes and coerces to valid semver. * @param version - The version string to sanitise. - * @returns The cleaned version string. + * @returns The cleaned version string, or null if invalid. */ -const cleanVersion = (version: string): string => { - return version.replace(/^[<=>^~]+/, ""); +const cleanVersion = (version: string): string | null => { + const stripped = version.replace(/^[<=>^~]+/, ""); + const coerced = semver.coerce(stripped); + return coerced?.version ?? null; }; /** @@ -66,6 +68,8 @@ const shouldUpdate = ( } return semver.lt(currentVersion, latestVersion); + // eslint-disable-next-line capitalized-comments -- v8 coverage ignore directive must be lowercase + /* v8 ignore start -- @preserve */ } catch (error) { void logger.error( `Error comparing versions: ${currentVersion} vs ${latestVersion}`, @@ -74,6 +78,8 @@ const shouldUpdate = ( ); return false; } + // eslint-disable-next-line capitalized-comments -- v8 coverage ignore directive must be lowercase + /* v8 ignore stop -- @preserve */ }; /** @@ -159,6 +165,9 @@ class DependencyAnalyzerService { } const cleanCurrentVersion = cleanVersion(currentVersion); + if (cleanCurrentVersion === null) { + return null; + } if (shouldUpdate(cleanCurrentVersion, latestVersion)) { return { diff --git a/test/services/dependencyAnalyzerService.spec.ts b/test/services/dependencyAnalyzerService.spec.ts index 2599337..2321389 100644 --- a/test/services/dependencyAnalyzerService.spec.ts +++ b/test/services/dependencyAnalyzerService.spec.ts @@ -291,6 +291,30 @@ describe("dependencyAnalyzerService", () => { expect(result[0]?.currentVersion).toBe(">=1.0.0"); }); + it("should handle partial version numbers like '2'", async() => { + expect.assertions(2); + const mockNpmService = createMockNpmService(); + const oldDate = getDaysAgoIso(15); + mockNpmService.getPackageInfo.mockResolvedValue({ + "dist-tags": { latest: "3.0.0" }, + "name": "test-package", + "time": { "3.0.0": oldDate }, + "versions": { "3.0.0": { version: "3.0.0" } }, + }); + const { DependencyAnalyzerService } + = await import("../../src/services/dependencyAnalyzerService.js"); + const analyzerService = new DependencyAnalyzerService( + mockNpmService as Parameters[0], + ); + const result = await analyzerService.analyzePackageJson({ + dependencies: { + "test-package": "2", + }, + }); + expect(result).toHaveLength(1); + expect(result[0]?.currentVersion).toBe("2"); + }); + it("should handle npm errors gracefully", async() => { expect.assertions(1); const mockNpmService = createMockNpmService();