From 6008ff7896aa9c3aa578e68ff973468f9c93a143 Mon Sep 17 00:00:00 2001 From: Sergei Zharinov Date: Fri, 19 May 2023 15:50:40 +0300 Subject: [PATCH 1/3] refactor(npm): Use schema for `PackageSource` parsing --- lib/modules/datasource/npm/get.ts | 64 ++++++++++++++++++------------- 1 file changed, 38 insertions(+), 26 deletions(-) diff --git a/lib/modules/datasource/npm/get.ts b/lib/modules/datasource/npm/get.ts index f83725b742d1c4..2a7ab6df9c2f88 100644 --- a/lib/modules/datasource/npm/get.ts +++ b/lib/modules/datasource/npm/get.ts @@ -1,6 +1,7 @@ import url from 'node:url'; import is from '@sindresorhus/is'; import { DateTime } from 'luxon'; +import { z } from 'zod'; import { GlobalConfig } from '../../../config/global'; import { HOST_DISABLED } from '../../../constants/error-messages'; import { logger } from '../../../logger'; @@ -13,11 +14,6 @@ import { joinUrlParts } from '../../../util/url'; import type { Release, ReleaseResult } from '../types'; import type { CachedReleaseResult, NpmResponse } from './types'; -interface PackageSource { - sourceUrl?: string; - sourceDirectory?: string; -} - const SHORT_REPO_REGEX = regEx( /^((?bitbucket|github|gitlab):)?(?[A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+)$/ ); @@ -28,27 +24,43 @@ const platformMapping: Record = { gitlab: 'https://gitlab.com/', }; -function getPackageSource(repository: any): PackageSource { - const res: PackageSource = {}; - if (repository) { - if (is.nonEmptyString(repository)) { - const shortMatch = repository.match(SHORT_REPO_REGEX); - if (shortMatch?.groups) { - const { platform = 'github', shortRepo } = shortMatch.groups; - res.sourceUrl = platformMapping[platform] + shortRepo; - } else { - res.sourceUrl = repository; - } - } else if (is.nonEmptyString(repository.url)) { - res.sourceUrl = repository.url; - } - if (is.nonEmptyString(repository.directory)) { - res.sourceDirectory = repository.directory; - } - } - return res; +interface PackageSource { + sourceUrl?: string; + sourceDirectory?: string; } +const PackageSource = z + .union([ + z + .string() + .nonempty() + .transform((repository): PackageSource => { + const shortMatch = repository.match(SHORT_REPO_REGEX); + if (shortMatch?.groups) { + const { platform = 'github', shortRepo } = shortMatch.groups; + return { sourceUrl: platformMapping[platform] + shortRepo }; + } else { + return { sourceUrl: repository }; + } + }), + z + .object({ + url: z.string().nonempty().optional(), + directory: z.string().nonempty().optional(), + }) + .transform(({ url, directory }) => { + const res: PackageSource = {}; + if (url) { + res.sourceUrl = url; + } + if (directory) { + res.sourceDirectory = directory; + } + return res; + }), + ]) + .catch({}); + export async function getDependency( http: Http, registryUrl: string, @@ -124,7 +136,7 @@ export async function getDependency( res.repository ??= latestVersion?.repository; res.homepage ??= latestVersion?.homepage; - const { sourceUrl, sourceDirectory } = getPackageSource(res.repository); + const { sourceUrl, sourceDirectory } = PackageSource.parse(res.repository); // Simplify response before caching and returning const dep: ReleaseResult = { @@ -152,7 +164,7 @@ export async function getDependency( if (res.versions?.[version].deprecated) { release.isDeprecated = true; } - const source = getPackageSource(res.versions?.[version].repository); + const source = PackageSource.parse(res.versions?.[version].repository); if (source.sourceUrl && source.sourceUrl !== dep.sourceUrl) { release.sourceUrl = source.sourceUrl; } From 15a4c9947db62d3a9f417a4c1cdf5e1533f09aa7 Mon Sep 17 00:00:00 2001 From: Sergei Zharinov Date: Fri, 19 May 2023 16:28:05 +0300 Subject: [PATCH 2/3] Fix for test --- lib/modules/datasource/npm/get.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/modules/datasource/npm/get.ts b/lib/modules/datasource/npm/get.ts index 2a7ab6df9c2f88..44ddd035586e59 100644 --- a/lib/modules/datasource/npm/get.ts +++ b/lib/modules/datasource/npm/get.ts @@ -45,8 +45,8 @@ const PackageSource = z }), z .object({ - url: z.string().nonempty().optional(), - directory: z.string().nonempty().optional(), + url: z.string().nonempty().nullish(), + directory: z.string().nonempty().nullish(), }) .transform(({ url, directory }) => { const res: PackageSource = {}; From 92e1221a2a0cadd719d75d9cf8eff14d792e5e9b Mon Sep 17 00:00:00 2001 From: Sergei Zharinov Date: Fri, 19 May 2023 16:42:09 +0300 Subject: [PATCH 3/3] Make it nullish --- lib/modules/datasource/npm/get.ts | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/lib/modules/datasource/npm/get.ts b/lib/modules/datasource/npm/get.ts index 44ddd035586e59..94109fcb1d2cd6 100644 --- a/lib/modules/datasource/npm/get.ts +++ b/lib/modules/datasource/npm/get.ts @@ -25,8 +25,8 @@ const platformMapping: Record = { }; interface PackageSource { - sourceUrl?: string; - sourceDirectory?: string; + sourceUrl: string | null; + sourceDirectory: string | null; } const PackageSource = z @@ -35,13 +35,16 @@ const PackageSource = z .string() .nonempty() .transform((repository): PackageSource => { + let sourceUrl: string | null = null; + const sourceDirectory = null; const shortMatch = repository.match(SHORT_REPO_REGEX); if (shortMatch?.groups) { const { platform = 'github', shortRepo } = shortMatch.groups; - return { sourceUrl: platformMapping[platform] + shortRepo }; + sourceUrl = platformMapping[platform] + shortRepo; } else { - return { sourceUrl: repository }; + sourceUrl = repository; } + return { sourceUrl, sourceDirectory }; }), z .object({ @@ -49,17 +52,20 @@ const PackageSource = z directory: z.string().nonempty().nullish(), }) .transform(({ url, directory }) => { - const res: PackageSource = {}; + const res: PackageSource = { sourceUrl: null, sourceDirectory: null }; + if (url) { res.sourceUrl = url; } + if (directory) { res.sourceDirectory = directory; } + return res; }), ]) - .catch({}); + .catch({ sourceUrl: null, sourceDirectory: null }); export async function getDependency( http: Http, @@ -141,13 +147,19 @@ export async function getDependency( // Simplify response before caching and returning const dep: ReleaseResult = { homepage: res.homepage, - sourceUrl, - sourceDirectory, releases: [], tags: res['dist-tags'], registryUrl, }; + if (sourceUrl) { + dep.sourceUrl = sourceUrl; + } + + if (sourceDirectory) { + dep.sourceDirectory = sourceDirectory; + } + if (latestVersion?.deprecated) { dep.deprecationMessage = `On registry \`${registryUrl}\`, the "latest" version of dependency \`${packageName}\` has the following deprecation notice:\n\n\`${latestVersion.deprecated}\`\n\nMarking the latest version of an npm package as deprecated results in the entire package being considered deprecated, so contact the package author you think this is a mistake.`; }