From a27eba5d2babfe55f916f69830154d27cbea0e75 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Fern=C3=A1ndez?= Date: Thu, 13 Apr 2023 10:14:42 +0000 Subject: [PATCH 1/4] Drop compare-versions dependency The version check we needed is simple enough to implement ourselves, shaving off some bytes from the bundle size consumers will have when using the SDK --- package-lock.json | 8 -------- package.json | 3 --- rollup.config.js | 3 +-- src/discovery/recommended-server-discovery.ts | 6 +++--- src/utils/version-comparison.ts | 17 +++++++++++++++++ 5 files changed, 21 insertions(+), 16 deletions(-) create mode 100644 src/utils/version-comparison.ts diff --git a/package-lock.json b/package-lock.json index bb996c0d4..e920ae110 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,9 +8,6 @@ "name": "@jellyfin/sdk", "version": "0.8.2", "license": "MPL-2.0", - "dependencies": { - "compare-versions": "5.0.3" - }, "devDependencies": { "@openapitools/openapi-generator-cli": "2.6.0", "@rollup/plugin-typescript": "11.1.0", @@ -2506,11 +2503,6 @@ "node": ">= 12" } }, - "node_modules/compare-versions": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/compare-versions/-/compare-versions-5.0.3.tgz", - "integrity": "sha512-4UZlZP8Z99MGEY+Ovg/uJxJuvoXuN4M6B3hKaiackiHrgzQFEe3diJi1mf1PNHbFujM7FvLrK2bpgIaImbtZ1A==" - }, "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", diff --git a/package.json b/package.json index 565b0d590..97c7c5621 100644 --- a/package.json +++ b/package.json @@ -43,9 +43,6 @@ "typedoc": "0.24.4", "typescript": "5.0.4" }, - "dependencies": { - "compare-versions": "5.0.3" - }, "peerDependencies": { "axios": "^1.3.4" } diff --git a/rollup.config.js b/rollup.config.js index 00ca58ba6..a610cca17 100644 --- a/rollup.config.js +++ b/rollup.config.js @@ -28,8 +28,7 @@ export default { preserveModulesRoot: 'src' }, external: [ - 'axios', - 'compare-versions' + 'axios' ], plugins: [ typescript() ] }; diff --git a/src/discovery/recommended-server-discovery.ts b/src/discovery/recommended-server-discovery.ts index 5248f146d..9c68e411a 100644 --- a/src/discovery/recommended-server-discovery.ts +++ b/src/discovery/recommended-server-discovery.ts @@ -5,7 +5,6 @@ */ import type { AxiosError, AxiosResponse } from 'axios'; -import { compare } from 'compare-versions'; import type { PublicSystemInfo } from '../generated-client/models/public-system-info'; import type { Jellyfin } from '../jellyfin'; @@ -14,6 +13,7 @@ import { RecommendedServerInfoScore } from '../models/recommended-server-info'; import type { RecommendedServerIssue } from '../models/recommended-server-issue'; import { ProductNameIssue, SlowResponseIssue, SystemInfoIssue, VersionMissingIssue, VersionOutdatedIssue, VersionUnsupportedIssue } from '../models/recommended-server-issue'; import { getSystemApi } from '../utils/api/system-api'; +import { isVersionLess } from '../utils/version-comparison'; import { API_VERSION, MINIMUM_VERSION } from '../versions'; /** The result of a SystemInfo request. */ @@ -56,11 +56,11 @@ function toRecommendedServerInfo(result: SystemInfoResult): RecommendedServerInf // No version was returned issues.push(new VersionMissingIssue()); scores.push(RecommendedServerInfoScore.BAD); - } else if (compare(version, MINIMUM_VERSION, '<')) { + } else if (isVersionLess(version, MINIMUM_VERSION)) { // Version is less than the minimum supported issues.push(new VersionUnsupportedIssue(version)); scores.push(RecommendedServerInfoScore.OK); - } else if (compare(version, API_VERSION, '<')) { + } else if (isVersionLess(version, API_VERSION)) { // Version is less than the generated client, but above the minimum issues.push(new VersionOutdatedIssue(version)); scores.push(RecommendedServerInfoScore.GOOD); diff --git a/src/utils/version-comparison.ts b/src/utils/version-comparison.ts new file mode 100644 index 000000000..607e95ccb --- /dev/null +++ b/src/utils/version-comparison.ts @@ -0,0 +1,17 @@ +/** + * Check if given version is less than a baseline + * + * Versions must be in semver format: X.Y.Z (Major.Minor.Patch) + * @param check - The version to check + * @param baseline - The minimum version considered supported + */ +export function isVersionLess(check: string, baseline: string): boolean { + const [majorCheck, minorCheck, patchCheck] = check.split('.').map(Number); + const [majorBaseline, minorBaseline, patchBaseline] = baseline.split('.').map(Number); + + return ( + majorCheck < majorBaseline || + (majorCheck === majorBaseline && minorCheck < minorBaseline) || + (majorCheck === majorBaseline && minorCheck === minorBaseline && patchCheck < patchBaseline) + ); +} From 68c15ed817f1cbf3544c5e129514e234ab950081 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Fern=C3=A1ndez?= Date: Thu, 13 Apr 2023 16:45:12 +0000 Subject: [PATCH 2/4] Add tests for utils/versioning.ts Re-order the source tree a bit as well --- src/discovery/recommended-server-discovery.ts | 2 +- src/utils/__tests__/versioning.test.ts | 87 +++++++++++++++++++ src/utils/index.ts | 1 + src/utils/version-comparison.ts | 17 ---- src/utils/versioning.ts | 37 ++++++++ 5 files changed, 126 insertions(+), 18 deletions(-) create mode 100644 src/utils/__tests__/versioning.test.ts delete mode 100644 src/utils/version-comparison.ts create mode 100644 src/utils/versioning.ts diff --git a/src/discovery/recommended-server-discovery.ts b/src/discovery/recommended-server-discovery.ts index 9c68e411a..b3fea8763 100644 --- a/src/discovery/recommended-server-discovery.ts +++ b/src/discovery/recommended-server-discovery.ts @@ -13,7 +13,7 @@ import { RecommendedServerInfoScore } from '../models/recommended-server-info'; import type { RecommendedServerIssue } from '../models/recommended-server-issue'; import { ProductNameIssue, SlowResponseIssue, SystemInfoIssue, VersionMissingIssue, VersionOutdatedIssue, VersionUnsupportedIssue } from '../models/recommended-server-issue'; import { getSystemApi } from '../utils/api/system-api'; -import { isVersionLess } from '../utils/version-comparison'; +import { isVersionLess } from '../utils/versioning'; import { API_VERSION, MINIMUM_VERSION } from '../versions'; /** The result of a SystemInfo request. */ diff --git a/src/utils/__tests__/versioning.test.ts b/src/utils/__tests__/versioning.test.ts new file mode 100644 index 000000000..52519921f --- /dev/null +++ b/src/utils/__tests__/versioning.test.ts @@ -0,0 +1,87 @@ +/** + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +import { isVersionLess } from '..'; + +/** + * Versioning tests + * + * @group unit/utils + */ +describe('Versioning checks', () => { + it("doesn't allow versions with negative numbers", () => { + expect(() => isVersionLess('-10.5.3', '10.8.-9')).toThrow(TypeError); + }); + it("doesn't allow versions with non-numeric characters", () => { + expect(() => isVersionLess('10.2.7-beta', '15.8.9')).toThrow(TypeError); + }); + /** + * Equal + */ + it('false on equal version: 0.0.0', () => { + expect(isVersionLess('0.0.0', '0.0.0')).toBe(false); + }); + it('false on equal version: 0.0.5', () => { + expect(isVersionLess('0.0.5', '0.0.5')).toBe(false); + }); + it('false on equal version: 0.5.0', () => { + expect(isVersionLess('0.5.0', '0.5.0')).toBe(false); + }); + it('false on equal version: 5.0.0', () => { + expect(isVersionLess('5.0.0', '5.0.0')).toBe(false); + }); + it('false on equal version: 10.8.9', () => { + expect(isVersionLess('10.8.9', '10.8.9')).toBe(false); + }); + /** + * Greater + */ + it('1.0.0 is greater than 0.0.7', () => { + expect(isVersionLess('1.0.0', '0.0.7')).toBe(false); + }); + it('1.0.0 is greater than 0.5.0', () => { + expect(isVersionLess('1.0.0', '0.5.0')).toBe(false); + }); + it('1.0.0 is greater than 0.5.7', () => { + expect(isVersionLess('1.0.0', '0.5.7')).toBe(false); + }); + it('2.0.0 is greater than 1.0.0', () => { + expect(isVersionLess('2.0.0', '1.0.0')).toBe(false); + }); + it('0.5.0 is greater than 0.0.7', () => { + expect(isVersionLess('0.5.0', '0.0.7')).toBe(false); + }); + it('0.5.7 is greater than 0.0.7', () => { + expect(isVersionLess('0.5.7', '0.0.7')).toBe(false); + }); + it('2-digit versions: 12.25.34 is greater than 12.17.89', () => { + expect(isVersionLess('12.25.34', '12.17.89')).toBe(false); + }); + /** + * Less + */ + it('0.0.7 is less than 1.0.0', () => { + expect(isVersionLess('0.0.7', '1.0.0')).toBe(true); + }); + it('0.5.0 is less than 1.0.0', () => { + expect(isVersionLess('0.5.0', '1.0.0')).toBe(true); + }); + it('0.5.7 is less than 1.0.0', () => { + expect(isVersionLess('0.5.7', '1.0.0')).toBe(true); + }); + it('1.0.0 is less than 2.0.0', () => { + expect(isVersionLess('1.0.0', '2.0.0')).toBe(true); + }); + it('0.0.7 is less than 0.5.0', () => { + expect(isVersionLess('0.0.7', '0.5.0')).toBe(true); + }); + it('0.0.7 is less than 0.5.7', () => { + expect(isVersionLess('0.0.7', '0.5.7')).toBe(true); + }); + it('2-digit versions: 12.17.89 is less than 12.25.34', () => { + expect(isVersionLess('12.17.89', '12.25.34')).toBe(true); + }); +}); diff --git a/src/utils/index.ts b/src/utils/index.ts index d90ee7682..38591c9ae 100644 --- a/src/utils/index.ts +++ b/src/utils/index.ts @@ -8,3 +8,4 @@ export * from './address-candidates'; export * from './authentication'; export * from './url'; export * from './browser-profiles'; +export * from './versioning'; diff --git a/src/utils/version-comparison.ts b/src/utils/version-comparison.ts deleted file mode 100644 index 607e95ccb..000000000 --- a/src/utils/version-comparison.ts +++ /dev/null @@ -1,17 +0,0 @@ -/** - * Check if given version is less than a baseline - * - * Versions must be in semver format: X.Y.Z (Major.Minor.Patch) - * @param check - The version to check - * @param baseline - The minimum version considered supported - */ -export function isVersionLess(check: string, baseline: string): boolean { - const [majorCheck, minorCheck, patchCheck] = check.split('.').map(Number); - const [majorBaseline, minorBaseline, patchBaseline] = baseline.split('.').map(Number); - - return ( - majorCheck < majorBaseline || - (majorCheck === majorBaseline && minorCheck < minorBaseline) || - (majorCheck === majorBaseline && minorCheck === minorBaseline && patchCheck < patchBaseline) - ); -} diff --git a/src/utils/versioning.ts b/src/utils/versioning.ts new file mode 100644 index 000000000..34e9b3193 --- /dev/null +++ b/src/utils/versioning.ts @@ -0,0 +1,37 @@ +/** + * @returns - Array of 3 numbers or undefined + * (if the passed string it's not in the MAJOR.MINOR.PATCH numeric-only format) + */ +function parseVersion(version: string): number[] | undefined { + const arr = version.split('.').map(Number); + + if (arr.length === 3 && arr.every((n) => n >= 0)) { + return arr; + } +} + +/** + * Check if given version is less than a baseline + * + * Versions must be in semver format: X.Y.Z (Major.Minor.Patch) + * @throws If version is not in a numeric-only semver format + * @param check - The version to check + * @param baseline - The minimum version considered supported + */ +export function isVersionLess(check: string, baseline: string): boolean { + const parsedCheck = parseVersion(check); + const parsedBaseline = parseVersion(baseline); + + if (!parsedCheck || !parsedBaseline) { + throw new TypeError("Version doesn't match a numeric-only semver format"); + } + + const [majorCheck, minorCheck, patchCheck] = parsedCheck; + const [majorBaseline, minorBaseline, patchBaseline] = parsedBaseline; + + return ( + majorCheck < majorBaseline || + (majorCheck === majorBaseline && minorCheck < minorBaseline) || + (majorCheck === majorBaseline && minorCheck === minorBaseline && patchCheck < patchBaseline) + ); +} From e8b289f8ef948b6433648f8ca34c9c1ec34a2fb5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Fern=C3=A1ndez?= Date: Thu, 27 Apr 2023 12:46:01 +0000 Subject: [PATCH 3/4] Add VersionUnsupportedIssue to versions that don't match expected schema --- src/discovery/recommended-server-discovery.ts | 31 ++++++++++++------- 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/src/discovery/recommended-server-discovery.ts b/src/discovery/recommended-server-discovery.ts index b3fea8763..87c7c177c 100644 --- a/src/discovery/recommended-server-discovery.ts +++ b/src/discovery/recommended-server-discovery.ts @@ -52,18 +52,25 @@ function toRecommendedServerInfo(result: SystemInfoResult): RecommendedServerInf } const version = result.response?.data.Version; - if (!version) { - // No version was returned - issues.push(new VersionMissingIssue()); - scores.push(RecommendedServerInfoScore.BAD); - } else if (isVersionLess(version, MINIMUM_VERSION)) { - // Version is less than the minimum supported - issues.push(new VersionUnsupportedIssue(version)); - scores.push(RecommendedServerInfoScore.OK); - } else if (isVersionLess(version, API_VERSION)) { - // Version is less than the generated client, but above the minimum - issues.push(new VersionOutdatedIssue(version)); - scores.push(RecommendedServerInfoScore.GOOD); + try { + if (!version) { + // No version was returned + issues.push(new VersionMissingIssue()); + scores.push(RecommendedServerInfoScore.BAD); + } else if (isVersionLess(version, MINIMUM_VERSION)) { + // Version is less than the minimum supported + issues.push(new VersionUnsupportedIssue(version)); + scores.push(RecommendedServerInfoScore.OK); + } else if (isVersionLess(version, API_VERSION)) { + // Version is less than the generated client, but above the minimum + issues.push(new VersionOutdatedIssue(version)); + scores.push(RecommendedServerInfoScore.GOOD); + } + } catch (error) { + if (error instanceof TypeError) { + issues.push(new VersionUnsupportedIssue(version ?? 'Unknown')); + scores.push(RecommendedServerInfoScore.OK); + } } if (result.responseTime > SLOW_RESPONSE_TIME) { From a6acce1a15e8ae981ba809eeb16edd4ff709154e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Fern=C3=A1ndez?= Date: Wed, 10 May 2023 15:52:22 +0000 Subject: [PATCH 4/4] refactor: throw VersionMissingIssue when `isVersionLess` throws on unrecognised version --- src/discovery/recommended-server-discovery.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/discovery/recommended-server-discovery.ts b/src/discovery/recommended-server-discovery.ts index 87c7c177c..d98911b6c 100644 --- a/src/discovery/recommended-server-discovery.ts +++ b/src/discovery/recommended-server-discovery.ts @@ -68,8 +68,8 @@ function toRecommendedServerInfo(result: SystemInfoResult): RecommendedServerInf } } catch (error) { if (error instanceof TypeError) { - issues.push(new VersionUnsupportedIssue(version ?? 'Unknown')); - scores.push(RecommendedServerInfoScore.OK); + issues.push(new VersionMissingIssue()); + scores.push(RecommendedServerInfoScore.BAD); } }