renovate 43.213.2 → 43.213.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/modules/datasource/conda/schema.js +4 -4
- package/dist/modules/datasource/conda/schema.js.map +1 -1
- package/dist/modules/datasource/pypi/index.js +1 -1
- package/dist/modules/datasource/pypi/index.js.map +1 -1
- package/dist/modules/datasource/pypi/schema.js +7 -6
- package/dist/modules/datasource/pypi/schema.js.map +1 -1
- package/dist/util/schema-utils/index.js +9 -1
- package/dist/util/schema-utils/index.js.map +1 -1
- package/package.json +1 -1
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import { LooseArray } from "../../../util/schema-utils/index.js";
|
|
1
|
+
import { LooseArray, Nullish } from "../../../util/schema-utils/index.js";
|
|
2
2
|
import { z } from "zod/v4";
|
|
3
3
|
//#region lib/modules/datasource/conda/schema.ts
|
|
4
4
|
const CondaFile = z.object({
|
|
5
5
|
version: z.string(),
|
|
6
|
-
upload_time: z.string()
|
|
6
|
+
upload_time: Nullish(z.string())
|
|
7
7
|
});
|
|
8
8
|
const CondaPackage = z.object({
|
|
9
|
-
html_url: z.string()
|
|
10
|
-
dev_url: z.string()
|
|
9
|
+
html_url: Nullish(z.string()),
|
|
10
|
+
dev_url: Nullish(z.string()),
|
|
11
11
|
files: LooseArray(CondaFile).optional(),
|
|
12
12
|
versions: z.array(z.string()).optional()
|
|
13
13
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schema.js","names":[],"sources":["../../../../lib/modules/datasource/conda/schema.ts"],"sourcesContent":["import { z } from 'zod/v4';\nimport { LooseArray } from '../../../util/schema-utils/index.ts';\n\nexport const CondaFile = z.object({\n version: z.string(),\n upload_time: z.string()
|
|
1
|
+
{"version":3,"file":"schema.js","names":[],"sources":["../../../../lib/modules/datasource/conda/schema.ts"],"sourcesContent":["import { z } from 'zod/v4';\nimport { LooseArray, Nullish } from '../../../util/schema-utils/index.ts';\n\nexport const CondaFile = z.object({\n version: z.string(),\n upload_time: Nullish(z.string()),\n});\n\nexport const CondaPackage = z.object({\n html_url: Nullish(z.string()),\n dev_url: Nullish(z.string()),\n files: LooseArray(CondaFile).optional(),\n versions: z.array(z.string()).optional(),\n});\n\nexport type CondaPackage = z.infer<typeof CondaPackage>;\n"],"mappings":";;;AAGA,MAAa,YAAY,EAAE,OAAO;CAChC,SAAS,EAAE,OAAO;CAClB,aAAa,QAAQ,EAAE,OAAO,CAAC;AACjC,CAAC;AAED,MAAa,eAAe,EAAE,OAAO;CACnC,UAAU,QAAQ,EAAE,OAAO,CAAC;CAC5B,SAAS,QAAQ,EAAE,OAAO,CAAC;CAC3B,OAAO,WAAW,SAAS,EAAE,SAAS;CACtC,UAAU,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,SAAS;AACzC,CAAC"}
|
|
@@ -107,7 +107,7 @@ var PypiDatasource = class PypiDatasource extends Datasource {
|
|
|
107
107
|
}
|
|
108
108
|
if (dep.info?.project_urls) for (const [name, projectUrl] of Object.entries(dep.info.project_urls)) {
|
|
109
109
|
const lower = name.toLowerCase();
|
|
110
|
-
if (!dependency.sourceUrl && (lower.startsWith("repo") || lower === "code" || lower === "source" || isGitHubRepo(projectUrl))) dependency.sourceUrl = projectUrl;
|
|
110
|
+
if (projectUrl && !dependency.sourceUrl && (lower.startsWith("repo") || lower === "code" || lower === "source" || isGitHubRepo(projectUrl))) dependency.sourceUrl = projectUrl;
|
|
111
111
|
if (!dependency.changelogUrl && ([
|
|
112
112
|
"changelog",
|
|
113
113
|
"change log",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["pep440.id"],"sources":["../../../../lib/modules/datasource/pypi/index.ts"],"sourcesContent":["import { isString } from '@sindresorhus/is';\nimport changelogFilenameRegex from 'changelog-filename-regex';\nimport { logger } from '../../../logger/index.ts';\nimport { coerceArray } from '../../../util/array.ts';\nimport { getEnv } from '../../../util/env.ts';\nimport { parse } from '../../../util/html.ts';\nimport type { OutgoingHttpHeaders } from '../../../util/http/types.ts';\nimport { regEx } from '../../../util/regex.ts';\nimport { asTimestamp } from '../../../util/timestamp.ts';\nimport { ensureTrailingSlash, parseUrl } from '../../../util/url.ts';\nimport * as pep440 from '../../versioning/pep440/index.ts';\nimport { Datasource } from '../datasource.ts';\nimport type { GetReleasesConfig, Release, ReleaseResult } from '../types.ts';\nimport { getGoogleAuthToken } from '../util.ts';\nimport { isGitHubRepo, normalizePythonDepName } from './common.ts';\nimport type { PypiRelease } from './schema.ts';\nimport { PypiResponse } from './schema.ts';\nimport type { Releases } from './types.ts';\n\nexport class PypiDatasource extends Datasource {\n static readonly id = 'pypi';\n\n constructor() {\n super(PypiDatasource.id);\n }\n\n override readonly caching = true;\n\n override readonly customRegistrySupport = true;\n\n static readonly defaultURL =\n getEnv().PIP_INDEX_URL ?? 'https://pypi.org/pypi/';\n override readonly defaultRegistryUrls = [PypiDatasource.defaultURL];\n\n override readonly defaultVersioning = pep440.id;\n\n override readonly registryStrategy = 'merge';\n\n override readonly releaseTimestampSupport = true;\n override readonly releaseTimestampNote =\n 'The relase timestamp is determined from the `upload_time` field in the results. This field is not available when using the simple API.';\n override readonly sourceUrlSupport = 'release';\n override readonly sourceUrlNote =\n 'The source URL is determined from the `homepage` field if it is a github repository, else we use the `project_urls` field.';\n\n async getReleases({\n packageName,\n registryUrl,\n }: GetReleasesConfig): Promise<ReleaseResult | null> {\n let dependency: ReleaseResult | null = null;\n // TODO: null check (#22198)\n const hostUrl = ensureTrailingSlash(\n registryUrl!.replace('https://pypi.org/simple', 'https://pypi.org/pypi'),\n );\n const normalizedLookupName = normalizePythonDepName(packageName);\n\n // not all simple indexes use this identifier, but most do\n if (hostUrl.endsWith('/simple/') || hostUrl.endsWith('/+simple/')) {\n logger.trace(\n { packageName, hostUrl },\n 'Looking up pypi simple dependency',\n );\n dependency = await this.getSimpleDependency(\n normalizedLookupName,\n hostUrl,\n );\n } else {\n logger.trace({ packageName, hostUrl }, 'Looking up pypi api dependency');\n try {\n // we need to resolve early here so we can catch any 404s and fallback to a simple lookup\n dependency = await this.getDependency(normalizedLookupName, hostUrl);\n } catch (err) {\n // error contacting json-style api -- attempt to fallback to a simple-style api\n logger.trace(\n { packageName, hostUrl, err },\n 'Looking up pypi simple dependency via fallback',\n );\n dependency = await this.getSimpleDependency(\n normalizedLookupName,\n hostUrl,\n );\n }\n }\n return dependency;\n }\n\n private sanitizeLookupUrl(lookupUrl: string, parsedUrl: URL): string {\n if (!parsedUrl.username && !parsedUrl.password) {\n return lookupUrl;\n }\n\n parsedUrl.username = '';\n parsedUrl.password = '';\n return parsedUrl.toString();\n }\n\n private async getAuthHeaders(\n lookupUrl: string,\n ): Promise<{ headers: OutgoingHttpHeaders; lookupUrl: string }> {\n const parsedUrl = parseUrl(lookupUrl);\n // v8 ignore if -- TODO: refactor to cover this branch through public behavior again\n if (!parsedUrl) {\n logger.once.debug({ lookupUrl }, 'Failed to parse URL');\n return { headers: {}, lookupUrl };\n }\n if (parsedUrl.hostname.endsWith('.pkg.dev')) {\n const auth = await getGoogleAuthToken();\n if (auth) {\n const sanitizedLookupUrl = this.sanitizeLookupUrl(lookupUrl, parsedUrl);\n return {\n headers: { authorization: `Basic ${auth}` },\n lookupUrl: sanitizedLookupUrl,\n };\n }\n logger.once.debug({ lookupUrl }, 'Could not get Google access token');\n return { headers: {}, lookupUrl };\n }\n return { headers: {}, lookupUrl };\n }\n\n private async getDependency(\n packageName: string,\n hostUrl: string,\n ): Promise<ReleaseResult | null> {\n const lookupUrl = new URL(\n `${normalizePythonDepName(packageName)}/json`,\n hostUrl,\n ).href;\n const dependency: ReleaseResult = { releases: [] };\n logger.trace({ lookupUrl }, 'Pypi api got lookup');\n const { headers, lookupUrl: sanitizedUrl } =\n await this.getAuthHeaders(lookupUrl);\n const rep = await this.http.getJson(\n sanitizedUrl,\n { headers },\n PypiResponse,\n );\n const dep = rep?.body;\n if (rep.authorization) {\n dependency.isPrivate = true;\n }\n logger.trace({ lookupUrl }, 'Got pypi api result');\n\n if (dep.info?.home_page) {\n dependency.homepage = dep.info.home_page;\n if (isGitHubRepo(dep.info.home_page)) {\n dependency.sourceUrl = dep.info.home_page.replace(\n 'http://',\n 'https://',\n );\n }\n }\n\n if (dep.info?.project_urls) {\n for (const [name, projectUrl] of Object.entries(dep.info.project_urls)) {\n const lower = name.toLowerCase();\n\n if (\n !dependency.sourceUrl &&\n (lower.startsWith('repo') ||\n lower === 'code' ||\n lower === 'source' ||\n isGitHubRepo(projectUrl))\n ) {\n dependency.sourceUrl = projectUrl;\n }\n\n if (\n !dependency.changelogUrl &&\n ([\n 'changelog',\n 'change log',\n 'changes',\n 'release notes',\n 'news',\n \"what's new\",\n ].includes(lower) ||\n changelogFilenameRegex.exec(lower))\n ) {\n // from https://github.com/pypa/warehouse/blob/418c7511dc367fb410c71be139545d0134ccb0df/warehouse/templates/packaging/detail.html#L24\n dependency.changelogUrl = projectUrl;\n }\n }\n }\n\n if (dep.releases) {\n const versions = Object.keys(dep.releases);\n dependency.releases = versions.map((version) => {\n const releases = coerceArray(dep.releases?.[version]);\n const { upload_time: releaseTimestamp } = releases[0] || {};\n const isDeprecated = releases.some(({ yanked }) => yanked);\n const result: Release = {\n version,\n releaseTimestamp: asTimestamp(releaseTimestamp),\n };\n if (isDeprecated) {\n result.isDeprecated = isDeprecated;\n }\n // There may be multiple releases with different requires_python, so we return all in an array\n const pythonConstraints = releases\n .map(({ requires_python }) => requires_python)\n .filter(isString);\n result.constraints = {\n python: Array.from(new Set(pythonConstraints)),\n };\n return result;\n });\n }\n return dependency;\n }\n\n private static extractVersionFromLinkText(\n text: string,\n packageName: string,\n ): string | null {\n // source packages\n const lcText = text.toLowerCase();\n const normalizedSrcText = normalizePythonDepName(text);\n const srcPrefix = `${packageName}-`;\n\n // source distribution format: `{name}-{version}.tar.gz` (https://packaging.python.org/en/latest/specifications/source-distribution-format/#source-distribution-file-name)\n // binary distribution: `{distribution}-{version}(-{build tag})?-{python tag}-{abi tag}-{platform tag}.whl` (https://packaging.python.org/en/latest/specifications/binary-distribution-format/#file-name-convention)\n // officially both `name` and `distribution` should be normalized and then the - replaced with _, but in reality this is not the case\n // We therefore normalize the name we have (replacing `_-.` with -) and then check if the text starts with the normalized name\n\n if (!normalizedSrcText.startsWith(srcPrefix)) {\n return null;\n }\n\n // strip off the prefix using the prefix length as we may have normalized the srcPrefix/packageName\n // We assume that neither the version nor the suffix contains multiple `-` like `0.1.2---rc1.tar.gz`\n // and use the difference in length to strip off the prefix in case the name contains double `--` characters\n const normalizedLengthDiff = lcText.length - normalizedSrcText.length;\n const res = lcText.slice(srcPrefix.length + normalizedLengthDiff);\n\n // source distribution\n const srcSuffixes = ['.tar.gz', '.tar.bz2', '.tar.xz', '.zip', '.tgz'];\n const srcSuffix = srcSuffixes.find((suffix) => lcText.endsWith(suffix));\n if (srcSuffix) {\n // strip off the suffix using character length\n return res.slice(0, -srcSuffix.length);\n }\n\n // binary distribution\n // for binary distributions the version is the first part after the removed distribution name\n const wheelSuffix = '.whl';\n if (lcText.endsWith(wheelSuffix) && lcText.split('-').length > 2) {\n return res.split('-')[0];\n }\n return null;\n }\n\n private static cleanSimpleHtml(html: string): string {\n return (\n html\n .replace(regEx(/<\\/?pre>/), '')\n // Certain simple repositories like artifactory don't escape > and <\n .replace(\n regEx(/data-requires-python=\"([^\"]*?)>([^\"]*?)\"/g),\n 'data-requires-python=\"$1>$2\"',\n )\n .replace(\n regEx(/data-requires-python=\"([^\"]*?)<([^\"]*?)\"/g),\n 'data-requires-python=\"$1<$2\"',\n )\n );\n }\n\n private async getSimpleDependency(\n packageName: string,\n hostUrl: string,\n ): Promise<ReleaseResult | null> {\n const lookupUrl = new URL(\n ensureTrailingSlash(normalizePythonDepName(packageName)),\n hostUrl,\n ).href;\n const dependency: ReleaseResult = { releases: [] };\n const { headers, lookupUrl: sanitizedUrl } =\n await this.getAuthHeaders(lookupUrl);\n const response = await this.http.getText(sanitizedUrl, { headers });\n const dep = response?.body;\n if (!dep) {\n logger.trace({ dependency: packageName }, 'pip package not found');\n return null;\n }\n if (response.authorization) {\n dependency.isPrivate = true;\n }\n const root = parse(PypiDatasource.cleanSimpleHtml(dep));\n const links = root.querySelectorAll('a');\n const releases: Releases = {};\n for (const link of Array.from(links)) {\n const version = PypiDatasource.extractVersionFromLinkText(\n link.text?.trim(),\n packageName,\n );\n if (version) {\n const release: PypiRelease = {\n yanked: link.hasAttribute('data-yanked'),\n };\n const requiresPython = link.getAttribute('data-requires-python');\n if (requiresPython) {\n release.requires_python = requiresPython;\n }\n if (!releases[version]) {\n releases[version] = [];\n }\n releases[version].push(release);\n }\n }\n const versions = Object.keys(releases);\n dependency.releases = versions.map((version) => {\n const versionReleases = coerceArray(releases[version]);\n const isDeprecated = versionReleases.some(({ yanked }) => yanked);\n const result: Release = { version };\n if (isDeprecated) {\n result.isDeprecated = isDeprecated;\n }\n // There may be multiple releases with different requires_python, so we return all in an array\n result.constraints = {\n // TODO: string[] isn't allowed here\n python: versionReleases.map(\n ({ requires_python }) => requires_python,\n ) as any,\n };\n return result;\n });\n return dependency;\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":["pep440.id"],"sources":["../../../../lib/modules/datasource/pypi/index.ts"],"sourcesContent":["import { isString } from '@sindresorhus/is';\nimport changelogFilenameRegex from 'changelog-filename-regex';\nimport { logger } from '../../../logger/index.ts';\nimport { coerceArray } from '../../../util/array.ts';\nimport { getEnv } from '../../../util/env.ts';\nimport { parse } from '../../../util/html.ts';\nimport type { OutgoingHttpHeaders } from '../../../util/http/types.ts';\nimport { regEx } from '../../../util/regex.ts';\nimport { asTimestamp } from '../../../util/timestamp.ts';\nimport { ensureTrailingSlash, parseUrl } from '../../../util/url.ts';\nimport * as pep440 from '../../versioning/pep440/index.ts';\nimport { Datasource } from '../datasource.ts';\nimport type { GetReleasesConfig, Release, ReleaseResult } from '../types.ts';\nimport { getGoogleAuthToken } from '../util.ts';\nimport { isGitHubRepo, normalizePythonDepName } from './common.ts';\nimport type { PypiRelease } from './schema.ts';\nimport { PypiResponse } from './schema.ts';\nimport type { Releases } from './types.ts';\n\nexport class PypiDatasource extends Datasource {\n static readonly id = 'pypi';\n\n constructor() {\n super(PypiDatasource.id);\n }\n\n override readonly caching = true;\n\n override readonly customRegistrySupport = true;\n\n static readonly defaultURL =\n getEnv().PIP_INDEX_URL ?? 'https://pypi.org/pypi/';\n override readonly defaultRegistryUrls = [PypiDatasource.defaultURL];\n\n override readonly defaultVersioning = pep440.id;\n\n override readonly registryStrategy = 'merge';\n\n override readonly releaseTimestampSupport = true;\n override readonly releaseTimestampNote =\n 'The relase timestamp is determined from the `upload_time` field in the results. This field is not available when using the simple API.';\n override readonly sourceUrlSupport = 'release';\n override readonly sourceUrlNote =\n 'The source URL is determined from the `homepage` field if it is a github repository, else we use the `project_urls` field.';\n\n async getReleases({\n packageName,\n registryUrl,\n }: GetReleasesConfig): Promise<ReleaseResult | null> {\n let dependency: ReleaseResult | null = null;\n // TODO: null check (#22198)\n const hostUrl = ensureTrailingSlash(\n registryUrl!.replace('https://pypi.org/simple', 'https://pypi.org/pypi'),\n );\n const normalizedLookupName = normalizePythonDepName(packageName);\n\n // not all simple indexes use this identifier, but most do\n if (hostUrl.endsWith('/simple/') || hostUrl.endsWith('/+simple/')) {\n logger.trace(\n { packageName, hostUrl },\n 'Looking up pypi simple dependency',\n );\n dependency = await this.getSimpleDependency(\n normalizedLookupName,\n hostUrl,\n );\n } else {\n logger.trace({ packageName, hostUrl }, 'Looking up pypi api dependency');\n try {\n // we need to resolve early here so we can catch any 404s and fallback to a simple lookup\n dependency = await this.getDependency(normalizedLookupName, hostUrl);\n } catch (err) {\n // error contacting json-style api -- attempt to fallback to a simple-style api\n logger.trace(\n { packageName, hostUrl, err },\n 'Looking up pypi simple dependency via fallback',\n );\n dependency = await this.getSimpleDependency(\n normalizedLookupName,\n hostUrl,\n );\n }\n }\n return dependency;\n }\n\n private sanitizeLookupUrl(lookupUrl: string, parsedUrl: URL): string {\n if (!parsedUrl.username && !parsedUrl.password) {\n return lookupUrl;\n }\n\n parsedUrl.username = '';\n parsedUrl.password = '';\n return parsedUrl.toString();\n }\n\n private async getAuthHeaders(\n lookupUrl: string,\n ): Promise<{ headers: OutgoingHttpHeaders; lookupUrl: string }> {\n const parsedUrl = parseUrl(lookupUrl);\n // v8 ignore if -- TODO: refactor to cover this branch through public behavior again\n if (!parsedUrl) {\n logger.once.debug({ lookupUrl }, 'Failed to parse URL');\n return { headers: {}, lookupUrl };\n }\n if (parsedUrl.hostname.endsWith('.pkg.dev')) {\n const auth = await getGoogleAuthToken();\n if (auth) {\n const sanitizedLookupUrl = this.sanitizeLookupUrl(lookupUrl, parsedUrl);\n return {\n headers: { authorization: `Basic ${auth}` },\n lookupUrl: sanitizedLookupUrl,\n };\n }\n logger.once.debug({ lookupUrl }, 'Could not get Google access token');\n return { headers: {}, lookupUrl };\n }\n return { headers: {}, lookupUrl };\n }\n\n private async getDependency(\n packageName: string,\n hostUrl: string,\n ): Promise<ReleaseResult | null> {\n const lookupUrl = new URL(\n `${normalizePythonDepName(packageName)}/json`,\n hostUrl,\n ).href;\n const dependency: ReleaseResult = { releases: [] };\n logger.trace({ lookupUrl }, 'Pypi api got lookup');\n const { headers, lookupUrl: sanitizedUrl } =\n await this.getAuthHeaders(lookupUrl);\n const rep = await this.http.getJson(\n sanitizedUrl,\n { headers },\n PypiResponse,\n );\n const dep = rep?.body;\n if (rep.authorization) {\n dependency.isPrivate = true;\n }\n logger.trace({ lookupUrl }, 'Got pypi api result');\n\n if (dep.info?.home_page) {\n dependency.homepage = dep.info.home_page;\n if (isGitHubRepo(dep.info.home_page)) {\n dependency.sourceUrl = dep.info.home_page.replace(\n 'http://',\n 'https://',\n );\n }\n }\n\n if (dep.info?.project_urls) {\n for (const [name, projectUrl] of Object.entries(dep.info.project_urls)) {\n const lower = name.toLowerCase();\n\n if (\n projectUrl &&\n !dependency.sourceUrl &&\n (lower.startsWith('repo') ||\n lower === 'code' ||\n lower === 'source' ||\n isGitHubRepo(projectUrl))\n ) {\n dependency.sourceUrl = projectUrl;\n }\n\n if (\n !dependency.changelogUrl &&\n ([\n 'changelog',\n 'change log',\n 'changes',\n 'release notes',\n 'news',\n \"what's new\",\n ].includes(lower) ||\n changelogFilenameRegex.exec(lower))\n ) {\n // from https://github.com/pypa/warehouse/blob/418c7511dc367fb410c71be139545d0134ccb0df/warehouse/templates/packaging/detail.html#L24\n dependency.changelogUrl = projectUrl;\n }\n }\n }\n\n if (dep.releases) {\n const versions = Object.keys(dep.releases);\n dependency.releases = versions.map((version) => {\n const releases = coerceArray(dep.releases?.[version]);\n const { upload_time: releaseTimestamp } = releases[0] || {};\n const isDeprecated = releases.some(({ yanked }) => yanked);\n const result: Release = {\n version,\n releaseTimestamp: asTimestamp(releaseTimestamp),\n };\n if (isDeprecated) {\n result.isDeprecated = isDeprecated;\n }\n // There may be multiple releases with different requires_python, so we return all in an array\n const pythonConstraints = releases\n .map(({ requires_python }) => requires_python)\n .filter(isString);\n result.constraints = {\n python: Array.from(new Set(pythonConstraints)),\n };\n return result;\n });\n }\n return dependency;\n }\n\n private static extractVersionFromLinkText(\n text: string,\n packageName: string,\n ): string | null {\n // source packages\n const lcText = text.toLowerCase();\n const normalizedSrcText = normalizePythonDepName(text);\n const srcPrefix = `${packageName}-`;\n\n // source distribution format: `{name}-{version}.tar.gz` (https://packaging.python.org/en/latest/specifications/source-distribution-format/#source-distribution-file-name)\n // binary distribution: `{distribution}-{version}(-{build tag})?-{python tag}-{abi tag}-{platform tag}.whl` (https://packaging.python.org/en/latest/specifications/binary-distribution-format/#file-name-convention)\n // officially both `name` and `distribution` should be normalized and then the - replaced with _, but in reality this is not the case\n // We therefore normalize the name we have (replacing `_-.` with -) and then check if the text starts with the normalized name\n\n if (!normalizedSrcText.startsWith(srcPrefix)) {\n return null;\n }\n\n // strip off the prefix using the prefix length as we may have normalized the srcPrefix/packageName\n // We assume that neither the version nor the suffix contains multiple `-` like `0.1.2---rc1.tar.gz`\n // and use the difference in length to strip off the prefix in case the name contains double `--` characters\n const normalizedLengthDiff = lcText.length - normalizedSrcText.length;\n const res = lcText.slice(srcPrefix.length + normalizedLengthDiff);\n\n // source distribution\n const srcSuffixes = ['.tar.gz', '.tar.bz2', '.tar.xz', '.zip', '.tgz'];\n const srcSuffix = srcSuffixes.find((suffix) => lcText.endsWith(suffix));\n if (srcSuffix) {\n // strip off the suffix using character length\n return res.slice(0, -srcSuffix.length);\n }\n\n // binary distribution\n // for binary distributions the version is the first part after the removed distribution name\n const wheelSuffix = '.whl';\n if (lcText.endsWith(wheelSuffix) && lcText.split('-').length > 2) {\n return res.split('-')[0];\n }\n return null;\n }\n\n private static cleanSimpleHtml(html: string): string {\n return (\n html\n .replace(regEx(/<\\/?pre>/), '')\n // Certain simple repositories like artifactory don't escape > and <\n .replace(\n regEx(/data-requires-python=\"([^\"]*?)>([^\"]*?)\"/g),\n 'data-requires-python=\"$1>$2\"',\n )\n .replace(\n regEx(/data-requires-python=\"([^\"]*?)<([^\"]*?)\"/g),\n 'data-requires-python=\"$1<$2\"',\n )\n );\n }\n\n private async getSimpleDependency(\n packageName: string,\n hostUrl: string,\n ): Promise<ReleaseResult | null> {\n const lookupUrl = new URL(\n ensureTrailingSlash(normalizePythonDepName(packageName)),\n hostUrl,\n ).href;\n const dependency: ReleaseResult = { releases: [] };\n const { headers, lookupUrl: sanitizedUrl } =\n await this.getAuthHeaders(lookupUrl);\n const response = await this.http.getText(sanitizedUrl, { headers });\n const dep = response?.body;\n if (!dep) {\n logger.trace({ dependency: packageName }, 'pip package not found');\n return null;\n }\n if (response.authorization) {\n dependency.isPrivate = true;\n }\n const root = parse(PypiDatasource.cleanSimpleHtml(dep));\n const links = root.querySelectorAll('a');\n const releases: Releases = {};\n for (const link of Array.from(links)) {\n const version = PypiDatasource.extractVersionFromLinkText(\n link.text?.trim(),\n packageName,\n );\n if (version) {\n const release: PypiRelease = {\n yanked: link.hasAttribute('data-yanked'),\n };\n const requiresPython = link.getAttribute('data-requires-python');\n if (requiresPython) {\n release.requires_python = requiresPython;\n }\n if (!releases[version]) {\n releases[version] = [];\n }\n releases[version].push(release);\n }\n }\n const versions = Object.keys(releases);\n dependency.releases = versions.map((version) => {\n const versionReleases = coerceArray(releases[version]);\n const isDeprecated = versionReleases.some(({ yanked }) => yanked);\n const result: Release = { version };\n if (isDeprecated) {\n result.isDeprecated = isDeprecated;\n }\n // There may be multiple releases with different requires_python, so we return all in an array\n result.constraints = {\n // TODO: string[] isn't allowed here\n python: versionReleases.map(\n ({ requires_python }) => requires_python,\n ) as any,\n };\n return result;\n });\n return dependency;\n }\n}\n"],"mappings":"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"}
|
|
@@ -1,15 +1,16 @@
|
|
|
1
|
+
import { Nullish } from "../../../util/schema-utils/index.js";
|
|
1
2
|
import { z } from "zod/v4";
|
|
2
3
|
//#region lib/modules/datasource/pypi/schema.ts
|
|
3
4
|
const PypiRelease = z.object({
|
|
4
|
-
requires_python: z.string()
|
|
5
|
-
upload_time: z.string()
|
|
6
|
-
yanked: z.boolean().
|
|
5
|
+
requires_python: Nullish(z.string()),
|
|
6
|
+
upload_time: Nullish(z.string()),
|
|
7
|
+
yanked: Nullish(z.boolean()).default(false)
|
|
7
8
|
});
|
|
8
9
|
const PypiResponse = z.object({
|
|
9
10
|
info: z.object({
|
|
10
|
-
name: z.string()
|
|
11
|
-
home_page: z.string()
|
|
12
|
-
project_urls: z.record(z.string(), z.string()).optional()
|
|
11
|
+
name: Nullish(z.string()),
|
|
12
|
+
home_page: Nullish(z.string()),
|
|
13
|
+
project_urls: z.record(z.string(), Nullish(z.string())).optional()
|
|
13
14
|
}).optional(),
|
|
14
15
|
releases: z.record(z.string(), z.array(PypiRelease)).optional()
|
|
15
16
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schema.js","names":[],"sources":["../../../../lib/modules/datasource/pypi/schema.ts"],"sourcesContent":["import { z } from 'zod/v4';\n\nexport const PypiRelease = z.object({\n requires_python: z.string()
|
|
1
|
+
{"version":3,"file":"schema.js","names":[],"sources":["../../../../lib/modules/datasource/pypi/schema.ts"],"sourcesContent":["import { z } from 'zod/v4';\nimport { Nullish } from '../../../util/schema-utils/index.ts';\n\nexport const PypiRelease = z.object({\n requires_python: Nullish(z.string()),\n upload_time: Nullish(z.string()),\n yanked: Nullish(z.boolean()).default(false),\n});\n\nexport type PypiRelease = z.infer<typeof PypiRelease>;\n\nexport const PypiResponse = z.object({\n info: z\n .object({\n name: Nullish(z.string()),\n home_page: Nullish(z.string()),\n project_urls: z.record(z.string(), Nullish(z.string())).optional(),\n })\n .optional(),\n releases: z.record(z.string(), z.array(PypiRelease)).optional(),\n});\n\nexport type PypiResponse = z.infer<typeof PypiResponse>;\n"],"mappings":";;;AAGA,MAAa,cAAc,EAAE,OAAO;CAClC,iBAAiB,QAAQ,EAAE,OAAO,CAAC;CACnC,aAAa,QAAQ,EAAE,OAAO,CAAC;CAC/B,QAAQ,QAAQ,EAAE,QAAQ,CAAC,EAAE,QAAQ,KAAK;AAC5C,CAAC;AAID,MAAa,eAAe,EAAE,OAAO;CACnC,MAAM,EACH,OAAO;EACN,MAAM,QAAQ,EAAE,OAAO,CAAC;EACxB,WAAW,QAAQ,EAAE,OAAO,CAAC;EAC7B,cAAc,EAAE,OAAO,EAAE,OAAO,GAAG,QAAQ,EAAE,OAAO,CAAC,CAAC,EAAE,SAAS;CACnE,CAAC,EACA,SAAS;CACZ,UAAU,EAAE,OAAO,EAAE,OAAO,GAAG,EAAE,MAAM,WAAW,CAAC,EAAE,SAAS;AAChE,CAAC"}
|
|
@@ -103,6 +103,14 @@ function LooseRecord(arg1, arg2, arg3) {
|
|
|
103
103
|
return output;
|
|
104
104
|
});
|
|
105
105
|
}
|
|
106
|
+
/**
|
|
107
|
+
* Accepts `null`, `undefined`, or an absent key and normalizes all to
|
|
108
|
+
* `undefined`. Keeps the output type as `T | undefined` (never `null`), so
|
|
109
|
+
* assignment into non-nullable targets needs no `?? undefined` coalescing.
|
|
110
|
+
*/
|
|
111
|
+
function Nullish(schema) {
|
|
112
|
+
return schema.nullable().transform((value) => value ?? void 0).optional();
|
|
113
|
+
}
|
|
106
114
|
const Json = z.string().transform((str, ctx) => {
|
|
107
115
|
try {
|
|
108
116
|
return JSON.parse(str);
|
|
@@ -244,6 +252,6 @@ function isEmailAdress(value) {
|
|
|
244
252
|
return EmailAddress.safeParse(value).success;
|
|
245
253
|
}
|
|
246
254
|
//#endregion
|
|
247
|
-
export { EmailAddress, Ini, Json, Json5, Jsonc, LooseArray, LooseRecord, NotCircular, Toml, UtcDate, Yaml, isEmailAdress, multidocYaml, withDebugMessage, withDepType };
|
|
255
|
+
export { EmailAddress, Ini, Json, Json5, Jsonc, LooseArray, LooseRecord, NotCircular, Nullish, Toml, UtcDate, Yaml, isEmailAdress, multidocYaml, withDebugMessage, withDepType };
|
|
248
256
|
|
|
249
257
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["parseToml"],"sources":["../../../lib/util/schema-utils/index.ts"],"sourcesContent":["import ini from 'ini';\nimport JSON5 from 'json5';\nimport { DateTime } from 'luxon';\nimport type { JsonArray } from 'type-fest';\nimport { z } from 'zod/v4';\nimport { logger } from '../../logger/index.ts';\nimport type { PackageDependency } from '../../modules/manager/types.ts';\nimport { parseJsonc } from '../common.ts';\nimport { parse as parseToml } from '../toml.ts';\nimport type { YamlOptions } from '../yaml.ts';\nimport { parseSingleYaml, parseYaml } from '../yaml.ts';\n\ninterface ErrorContext<T> {\n error: z.ZodError;\n input: T;\n}\n\ninterface LooseOpts<T> {\n onError?: (err: ErrorContext<T>) => void;\n}\n\n/**\n * Works like `z.array()`, but drops wrong elements instead of invalidating the whole array.\n *\n * **Important**: non-array inputs are still invalid.\n * Use `LooseArray(...).catch([])` to handle it.\n *\n * @param Elem Schema for array elements\n * @param onError Callback for errors\n * @returns Schema for array\n */\nexport function LooseArray<Schema extends z.ZodTypeAny>(\n Elem: Schema,\n { onError }: LooseOpts<unknown[]> = {},\n): z.ZodType<z.TypeOf<Schema>[], any> {\n if (!onError) {\n // Avoid error-related computations inside the loop\n return z.array(z.any()).transform((input) => {\n const output: z.infer<Schema>[] = [];\n for (const x of input) {\n const parsed = Elem.safeParse(x);\n if (parsed.success) {\n output.push(parsed.data);\n }\n }\n return output;\n });\n }\n\n return z.array(z.any()).transform((input) => {\n const output: z.infer<Schema>[] = [];\n const issues: z.ZodIssue[] = [];\n\n for (let idx = 0; idx < input.length; idx += 1) {\n const x = input[idx];\n const parsed = Elem.safeParse(x);\n\n if (parsed.success) {\n output.push(parsed.data);\n continue;\n }\n\n for (const issue of parsed.error.issues) {\n issues.push({ ...issue, path: [idx, ...issue.path] });\n }\n }\n\n if (issues.length) {\n const error = new z.ZodError(issues);\n onError({ error, input });\n }\n\n return output;\n });\n}\n\ntype LooseRecordResult<ValueSchema extends z.ZodTypeAny> = z.ZodType<\n Record<string, z.TypeOf<ValueSchema>>,\n any\n>;\n\ntype LooseRecordOpts = LooseOpts<Record<string, unknown>>;\n\n/**\n * Works like `z.record()`, but drops wrong elements instead of invalidating the whole record.\n *\n * **Important**: non-record inputs other are still invalid.\n * Use `LooseRecord(...).catch({})` to handle it.\n *\n * @param KeyValue Schema for record keys\n * @param ValueValue Schema for record values\n * @param onError Callback for errors\n * @returns Schema for record\n */\nexport function LooseRecord<ValueSchema extends z.ZodTypeAny>(\n Value: ValueSchema,\n): LooseRecordResult<ValueSchema>;\nexport function LooseRecord<\n KeySchema extends z.ZodTypeAny,\n ValueSchema extends z.ZodTypeAny,\n>(Key: KeySchema, Value: ValueSchema): LooseRecordResult<ValueSchema>;\nexport function LooseRecord<ValueSchema extends z.ZodTypeAny>(\n Value: ValueSchema,\n { onError }: LooseRecordOpts,\n): LooseRecordResult<ValueSchema>;\nexport function LooseRecord<\n KeySchema extends z.ZodTypeAny,\n ValueSchema extends z.ZodTypeAny,\n>(\n Key: KeySchema,\n Value: ValueSchema,\n { onError }: LooseRecordOpts,\n): LooseRecordResult<ValueSchema>;\nexport function LooseRecord<\n KeySchema extends z.ZodTypeAny,\n ValueSchema extends z.ZodTypeAny,\n>(\n arg1: ValueSchema | KeySchema,\n arg2?: ValueSchema | LooseOpts<Record<string, unknown>>,\n arg3?: LooseRecordOpts,\n): LooseRecordResult<ValueSchema> {\n let Key: z.ZodType = z.any();\n let Value: ValueSchema;\n let opts: LooseRecordOpts = {};\n if (arg2 && arg3) {\n Key = arg1 as KeySchema;\n Value = arg2 as ValueSchema;\n opts = arg3;\n } else if (arg2) {\n if (arg2 instanceof z.ZodType) {\n Key = arg1 as KeySchema;\n Value = arg2;\n } else {\n Value = arg1 as ValueSchema;\n opts = arg2;\n }\n } else {\n Value = arg1 as ValueSchema;\n }\n\n const { onError } = opts;\n if (!onError) {\n // Avoid error-related computations inside the loop\n return z.record(z.string(), z.any()).transform((input) => {\n const output: Record<string, z.infer<ValueSchema>> = {};\n for (const [inputKey, inputVal] of Object.entries(input)) {\n const parsedKey = Key.safeParse(inputKey);\n const parsedValue = Value.safeParse(inputVal);\n if (parsedKey.success && parsedValue.success) {\n output[parsedKey.data as string] = parsedValue.data;\n }\n }\n return output;\n });\n }\n\n return z.record(z.string(), z.any()).transform((input) => {\n const output: Record<string, z.infer<ValueSchema>> = {};\n const issues: z.ZodIssue[] = [];\n\n for (const [inputKey, inputVal] of Object.entries(input)) {\n const parsedKey = Key.safeParse(inputKey);\n if (!parsedKey.success) {\n for (const issue of parsedKey.error.issues) {\n issues.push({ ...issue, path: [inputKey, ...issue.path] });\n }\n continue;\n }\n\n const parsedValue = Value.safeParse(inputVal);\n if (!parsedValue.success) {\n for (const issue of parsedValue.error.issues) {\n issues.push({ ...issue, path: [inputKey, ...issue.path] });\n }\n continue;\n }\n\n output[parsedKey.data as string] = parsedValue.data;\n }\n\n if (issues.length) {\n const error = new z.ZodError(issues);\n onError({ error, input });\n }\n\n return output;\n });\n}\n\nexport const Json = z.string().transform((str, ctx): unknown => {\n try {\n return JSON.parse(str);\n } catch {\n ctx.addIssue({ code: 'custom', message: 'Invalid JSON' });\n return z.NEVER;\n }\n});\n\nexport const Json5 = z.string().transform((str, ctx): unknown => {\n try {\n return JSON5.parse(str);\n } catch {\n ctx.addIssue({ code: 'custom', message: 'Invalid JSON5' });\n return z.NEVER;\n }\n});\n\nexport const Jsonc = z.string().transform((str, ctx): unknown => {\n try {\n return parseJsonc(str);\n } catch {\n ctx.addIssue({ code: 'custom', message: 'Invalid JSONC' });\n return z.NEVER;\n }\n});\n\nexport const UtcDate = z\n .string()\n .describe('ISO 8601 string')\n .transform((str, ctx): DateTime => {\n const date = DateTime.fromISO(str, { zone: 'utc' });\n if (!date.isValid) {\n ctx.addIssue({ code: 'custom', message: 'Invalid date' });\n return z.NEVER;\n }\n return date;\n });\n\nexport const Yaml = z.string().transform((str, ctx): unknown => {\n try {\n return parseSingleYaml(str);\n } catch {\n ctx.addIssue({ code: 'custom', message: 'Invalid YAML' });\n return z.NEVER;\n }\n});\n\nexport const MultidocYaml = z.string().transform((str, ctx): unknown => {\n try {\n return parseYaml(str);\n } catch {\n ctx.addIssue({ code: 'custom', message: 'Invalid YAML' });\n return z.NEVER;\n }\n});\n\nexport function multidocYaml(\n opts?: Omit<YamlOptions, 'customSchema'>,\n): z.ZodType<JsonArray> {\n return z.string().transform((str, ctx): JsonArray => {\n try {\n return parseYaml(str, opts) as JsonArray;\n } catch {\n ctx.addIssue({ code: 'custom', message: 'Invalid YAML' });\n return z.NEVER;\n }\n });\n}\n\nexport const Toml = z.string().transform((str, ctx) => {\n try {\n return parseToml(str);\n } catch {\n ctx.addIssue({ code: 'custom', message: 'Invalid TOML' });\n return z.NEVER;\n }\n});\n\nexport const Ini = z.string().transform((str, ctx): Record<string, unknown> => {\n try {\n return ini.parse(str);\n } catch /* v8 ignore next -- TODO: add test #40625 */ {\n ctx.addIssue({ code: 'custom', message: 'Invalid INI' });\n return z.NEVER;\n }\n});\n\nexport function withDepType<\n Output extends PackageDependency[],\n Schema extends z.ZodType<Output>,\n>(schema: Schema, depType: string, force = true): z.ZodType<Output> {\n return schema.transform((deps) => {\n for (const dep of deps) {\n if (!dep.depType || force) {\n dep.depType = depType;\n }\n }\n return deps;\n });\n}\n\nexport function withDebugMessage<Output>(\n value: Output,\n msg: string,\n): (ctx: { error: unknown; input: unknown }) => Output {\n return ({ error: err }) => {\n logger.debug({ err }, msg);\n return value;\n };\n}\n\nexport function withTraceMessage<Output>(\n value: Output,\n msg: string,\n): (ctx: { error: unknown; input: unknown }) => Output {\n return ({ error: err }) => {\n logger.trace({ err }, msg);\n return value;\n };\n}\n\nfunction isCircular(value: unknown, visited = new Set<unknown>()): boolean {\n if (value === null || typeof value !== 'object') {\n return false;\n }\n\n if (visited.has(value)) {\n return true;\n }\n\n const downstreamVisited = new Set(visited);\n downstreamVisited.add(value);\n\n if (Array.isArray(value)) {\n for (const childValue of value) {\n if (isCircular(childValue, downstreamVisited)) {\n return true;\n }\n }\n\n return false;\n }\n\n const values = Object.values(value);\n for (const ov of values) {\n if (isCircular(ov, downstreamVisited)) {\n return true;\n }\n }\n\n return false;\n}\n\nexport const NotCircular = z.unknown().superRefine((val, ctx) => {\n if (isCircular(val)) {\n ctx.addIssue({\n code: 'custom',\n message: 'values cannot be circular data structures',\n fatal: true,\n });\n\n return z.NEVER;\n }\n});\n\nexport const EmailAddress = z.email();\nexport type EmailAddress = z.infer<typeof EmailAddress>;\n\nexport function isEmailAdress(value: string): boolean {\n return EmailAddress.safeParse(value).success;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":["parseToml"],"sources":["../../../lib/util/schema-utils/index.ts"],"sourcesContent":["import ini from 'ini';\nimport JSON5 from 'json5';\nimport { DateTime } from 'luxon';\nimport type { JsonArray } from 'type-fest';\nimport { z } from 'zod/v4';\nimport { logger } from '../../logger/index.ts';\nimport type { PackageDependency } from '../../modules/manager/types.ts';\nimport { parseJsonc } from '../common.ts';\nimport { parse as parseToml } from '../toml.ts';\nimport type { YamlOptions } from '../yaml.ts';\nimport { parseSingleYaml, parseYaml } from '../yaml.ts';\n\ninterface ErrorContext<T> {\n error: z.ZodError;\n input: T;\n}\n\ninterface LooseOpts<T> {\n onError?: (err: ErrorContext<T>) => void;\n}\n\n/**\n * Works like `z.array()`, but drops wrong elements instead of invalidating the whole array.\n *\n * **Important**: non-array inputs are still invalid.\n * Use `LooseArray(...).catch([])` to handle it.\n *\n * @param Elem Schema for array elements\n * @param onError Callback for errors\n * @returns Schema for array\n */\nexport function LooseArray<Schema extends z.ZodTypeAny>(\n Elem: Schema,\n { onError }: LooseOpts<unknown[]> = {},\n): z.ZodType<z.TypeOf<Schema>[], any> {\n if (!onError) {\n // Avoid error-related computations inside the loop\n return z.array(z.any()).transform((input) => {\n const output: z.infer<Schema>[] = [];\n for (const x of input) {\n const parsed = Elem.safeParse(x);\n if (parsed.success) {\n output.push(parsed.data);\n }\n }\n return output;\n });\n }\n\n return z.array(z.any()).transform((input) => {\n const output: z.infer<Schema>[] = [];\n const issues: z.ZodIssue[] = [];\n\n for (let idx = 0; idx < input.length; idx += 1) {\n const x = input[idx];\n const parsed = Elem.safeParse(x);\n\n if (parsed.success) {\n output.push(parsed.data);\n continue;\n }\n\n for (const issue of parsed.error.issues) {\n issues.push({ ...issue, path: [idx, ...issue.path] });\n }\n }\n\n if (issues.length) {\n const error = new z.ZodError(issues);\n onError({ error, input });\n }\n\n return output;\n });\n}\n\ntype LooseRecordResult<ValueSchema extends z.ZodTypeAny> = z.ZodType<\n Record<string, z.TypeOf<ValueSchema>>,\n any\n>;\n\ntype LooseRecordOpts = LooseOpts<Record<string, unknown>>;\n\n/**\n * Works like `z.record()`, but drops wrong elements instead of invalidating the whole record.\n *\n * **Important**: non-record inputs other are still invalid.\n * Use `LooseRecord(...).catch({})` to handle it.\n *\n * @param KeyValue Schema for record keys\n * @param ValueValue Schema for record values\n * @param onError Callback for errors\n * @returns Schema for record\n */\nexport function LooseRecord<ValueSchema extends z.ZodTypeAny>(\n Value: ValueSchema,\n): LooseRecordResult<ValueSchema>;\nexport function LooseRecord<\n KeySchema extends z.ZodTypeAny,\n ValueSchema extends z.ZodTypeAny,\n>(Key: KeySchema, Value: ValueSchema): LooseRecordResult<ValueSchema>;\nexport function LooseRecord<ValueSchema extends z.ZodTypeAny>(\n Value: ValueSchema,\n { onError }: LooseRecordOpts,\n): LooseRecordResult<ValueSchema>;\nexport function LooseRecord<\n KeySchema extends z.ZodTypeAny,\n ValueSchema extends z.ZodTypeAny,\n>(\n Key: KeySchema,\n Value: ValueSchema,\n { onError }: LooseRecordOpts,\n): LooseRecordResult<ValueSchema>;\nexport function LooseRecord<\n KeySchema extends z.ZodTypeAny,\n ValueSchema extends z.ZodTypeAny,\n>(\n arg1: ValueSchema | KeySchema,\n arg2?: ValueSchema | LooseOpts<Record<string, unknown>>,\n arg3?: LooseRecordOpts,\n): LooseRecordResult<ValueSchema> {\n let Key: z.ZodType = z.any();\n let Value: ValueSchema;\n let opts: LooseRecordOpts = {};\n if (arg2 && arg3) {\n Key = arg1 as KeySchema;\n Value = arg2 as ValueSchema;\n opts = arg3;\n } else if (arg2) {\n if (arg2 instanceof z.ZodType) {\n Key = arg1 as KeySchema;\n Value = arg2;\n } else {\n Value = arg1 as ValueSchema;\n opts = arg2;\n }\n } else {\n Value = arg1 as ValueSchema;\n }\n\n const { onError } = opts;\n if (!onError) {\n // Avoid error-related computations inside the loop\n return z.record(z.string(), z.any()).transform((input) => {\n const output: Record<string, z.infer<ValueSchema>> = {};\n for (const [inputKey, inputVal] of Object.entries(input)) {\n const parsedKey = Key.safeParse(inputKey);\n const parsedValue = Value.safeParse(inputVal);\n if (parsedKey.success && parsedValue.success) {\n output[parsedKey.data as string] = parsedValue.data;\n }\n }\n return output;\n });\n }\n\n return z.record(z.string(), z.any()).transform((input) => {\n const output: Record<string, z.infer<ValueSchema>> = {};\n const issues: z.ZodIssue[] = [];\n\n for (const [inputKey, inputVal] of Object.entries(input)) {\n const parsedKey = Key.safeParse(inputKey);\n if (!parsedKey.success) {\n for (const issue of parsedKey.error.issues) {\n issues.push({ ...issue, path: [inputKey, ...issue.path] });\n }\n continue;\n }\n\n const parsedValue = Value.safeParse(inputVal);\n if (!parsedValue.success) {\n for (const issue of parsedValue.error.issues) {\n issues.push({ ...issue, path: [inputKey, ...issue.path] });\n }\n continue;\n }\n\n output[parsedKey.data as string] = parsedValue.data;\n }\n\n if (issues.length) {\n const error = new z.ZodError(issues);\n onError({ error, input });\n }\n\n return output;\n });\n}\n\n/**\n * Accepts `null`, `undefined`, or an absent key and normalizes all to\n * `undefined`. Keeps the output type as `T | undefined` (never `null`), so\n * assignment into non-nullable targets needs no `?? undefined` coalescing.\n */\nexport function Nullish<Schema extends z.ZodTypeAny>(\n schema: Schema,\n): z.ZodOptional<z.ZodType<z.output<Schema> | undefined>> {\n return schema\n .nullable()\n .transform((value) => value ?? undefined)\n .optional();\n}\n\nexport const Json = z.string().transform((str, ctx): unknown => {\n try {\n return JSON.parse(str);\n } catch {\n ctx.addIssue({ code: 'custom', message: 'Invalid JSON' });\n return z.NEVER;\n }\n});\n\nexport const Json5 = z.string().transform((str, ctx): unknown => {\n try {\n return JSON5.parse(str);\n } catch {\n ctx.addIssue({ code: 'custom', message: 'Invalid JSON5' });\n return z.NEVER;\n }\n});\n\nexport const Jsonc = z.string().transform((str, ctx): unknown => {\n try {\n return parseJsonc(str);\n } catch {\n ctx.addIssue({ code: 'custom', message: 'Invalid JSONC' });\n return z.NEVER;\n }\n});\n\nexport const UtcDate = z\n .string()\n .describe('ISO 8601 string')\n .transform((str, ctx): DateTime => {\n const date = DateTime.fromISO(str, { zone: 'utc' });\n if (!date.isValid) {\n ctx.addIssue({ code: 'custom', message: 'Invalid date' });\n return z.NEVER;\n }\n return date;\n });\n\nexport const Yaml = z.string().transform((str, ctx): unknown => {\n try {\n return parseSingleYaml(str);\n } catch {\n ctx.addIssue({ code: 'custom', message: 'Invalid YAML' });\n return z.NEVER;\n }\n});\n\nexport const MultidocYaml = z.string().transform((str, ctx): unknown => {\n try {\n return parseYaml(str);\n } catch {\n ctx.addIssue({ code: 'custom', message: 'Invalid YAML' });\n return z.NEVER;\n }\n});\n\nexport function multidocYaml(\n opts?: Omit<YamlOptions, 'customSchema'>,\n): z.ZodType<JsonArray> {\n return z.string().transform((str, ctx): JsonArray => {\n try {\n return parseYaml(str, opts) as JsonArray;\n } catch {\n ctx.addIssue({ code: 'custom', message: 'Invalid YAML' });\n return z.NEVER;\n }\n });\n}\n\nexport const Toml = z.string().transform((str, ctx) => {\n try {\n return parseToml(str);\n } catch {\n ctx.addIssue({ code: 'custom', message: 'Invalid TOML' });\n return z.NEVER;\n }\n});\n\nexport const Ini = z.string().transform((str, ctx): Record<string, unknown> => {\n try {\n return ini.parse(str);\n } catch /* v8 ignore next -- TODO: add test #40625 */ {\n ctx.addIssue({ code: 'custom', message: 'Invalid INI' });\n return z.NEVER;\n }\n});\n\nexport function withDepType<\n Output extends PackageDependency[],\n Schema extends z.ZodType<Output>,\n>(schema: Schema, depType: string, force = true): z.ZodType<Output> {\n return schema.transform((deps) => {\n for (const dep of deps) {\n if (!dep.depType || force) {\n dep.depType = depType;\n }\n }\n return deps;\n });\n}\n\nexport function withDebugMessage<Output>(\n value: Output,\n msg: string,\n): (ctx: { error: unknown; input: unknown }) => Output {\n return ({ error: err }) => {\n logger.debug({ err }, msg);\n return value;\n };\n}\n\nexport function withTraceMessage<Output>(\n value: Output,\n msg: string,\n): (ctx: { error: unknown; input: unknown }) => Output {\n return ({ error: err }) => {\n logger.trace({ err }, msg);\n return value;\n };\n}\n\nfunction isCircular(value: unknown, visited = new Set<unknown>()): boolean {\n if (value === null || typeof value !== 'object') {\n return false;\n }\n\n if (visited.has(value)) {\n return true;\n }\n\n const downstreamVisited = new Set(visited);\n downstreamVisited.add(value);\n\n if (Array.isArray(value)) {\n for (const childValue of value) {\n if (isCircular(childValue, downstreamVisited)) {\n return true;\n }\n }\n\n return false;\n }\n\n const values = Object.values(value);\n for (const ov of values) {\n if (isCircular(ov, downstreamVisited)) {\n return true;\n }\n }\n\n return false;\n}\n\nexport const NotCircular = z.unknown().superRefine((val, ctx) => {\n if (isCircular(val)) {\n ctx.addIssue({\n code: 'custom',\n message: 'values cannot be circular data structures',\n fatal: true,\n });\n\n return z.NEVER;\n }\n});\n\nexport const EmailAddress = z.email();\nexport type EmailAddress = z.infer<typeof EmailAddress>;\n\nexport function isEmailAdress(value: string): boolean {\n return EmailAddress.safeParse(value).success;\n}\n"],"mappings":"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"}
|