import { isTruthy } from '@sindresorhus/is'; import { z } from 'zod/v4'; import { DeepNullish, LooseArray } from '../../../util/schema-utils/index.ts'; export const PypiRelease = DeepNullish( z.object({ requires_python: z.string().optional(), upload_time: z.string().optional(), yanked: z.boolean().optional().default(false), }), ); export type PypiRelease = z.infer; export const PypiResponse = DeepNullish( z.object({ info: z .object({ name: z.string().optional(), home_page: z.string().optional(), project_urls: z.record(z.string(), z.string().optional()).optional(), }) .optional(), releases: z.record(z.string(), z.array(PypiRelease)).optional(), }), ); export type PypiResponse = z.infer; // JSON-based Simple API (PEP 691) schemas // https://peps.python.org/pep-0691/ export const PypiSimpleFile = DeepNullish( z.object({ filename: z.string(), 'requires-python': z.string().optional(), yanked: z.union([z.boolean(), z.string()]).optional().default(false), // `upload-time` is specified by PEP 700, which mandates an ISO 8601 string and lets a server omit the key even at `api-version` 1.1. // A string which `asTimestamp` cannot parse downstream degrades to a missing timestamp; a value of any other type fails validation, and `LooseArray` then drops the file entry. 'upload-time': z.string().optional(), }), ).transform( ({ filename, 'requires-python': requires_python, yanked, 'upload-time': upload_time, }) => ({ filename, requires_python, // Per the Simple API spec, `yanked` is yanked when truthy // https://packaging.python.org/en/latest/specifications/simple-repository-api/#json-based-simple-api-for-python-package-indexes yanked: isTruthy(yanked), upload_time, }), ); export type PypiSimpleFile = z.infer; export const PypiSimpleResponse = z.object({ files: LooseArray(PypiSimpleFile), }); export type PypiSimpleResponse = z.infer;