import fs from "node:fs"; import * as toml from "smol-toml"; export function getUvVersionFromRequirementsFile( filePath: string, ): string | undefined { const fileContent = fs.readFileSync(filePath, "utf-8"); if (filePath.endsWith(".txt")) { return getUvVersionFromRequirementsText(fileContent); } return getUvVersionFromPyprojectContent(fileContent); } export function getUvVersionFromRequirementsText( fileContent: string, ): string | undefined { return getUvVersionFromAllDependencies(fileContent.split("\n")); } export function getUvVersionFromParsedPyproject( pyproject: Pyproject, ): string | undefined { const dependencies: string[] = pyproject?.project?.dependencies || []; const optionalDependencies: string[] = Object.values( pyproject?.project?.["optional-dependencies"] || {}, ).flat(); const devDependencies: string[] = Object.values( pyproject?.["dependency-groups"] || {}, ) .flat() .filter((item: string | object) => typeof item === "string"); return getUvVersionFromAllDependencies( dependencies.concat(optionalDependencies, devDependencies), ); } export function getUvVersionFromPyprojectContent( pyprojectContent: string, ): string | undefined { const pyproject = parsePyprojectContent(pyprojectContent); return getUvVersionFromParsedPyproject(pyproject); } export interface Pyproject { project?: { dependencies?: string[]; "optional-dependencies"?: Record; }; "dependency-groups"?: Record>; tool?: { uv?: Record; }; } export function parsePyprojectContent(pyprojectContent: string): Pyproject { return toml.parse(pyprojectContent) as Pyproject; } function getUvVersionFromAllDependencies( allDependencies: string[], ): string | undefined { return allDependencies .find((dep: string) => dep.match(/^uv[=<>~!]/)) ?.match(/^uv([=<>~!]+\S*)/)?.[1] .trim(); }