import type { RangeStrategy } from '../../../types/versioning.ts'; import { regEx } from '../../../util/regex.ts'; import mavenVersion from '../maven/index.ts'; import type { NewValueConfig, VersioningApi } from '../types.ts'; import { TokenType, compare, isValid, isVersion, parse, parseMavenBasedRange, parsePrefixRange, parseSingleVersionRange, } from './compare.ts'; export const id = 'gradle'; export const displayName = 'Gradle'; export const urls = [ '[Gradle version ordering](https://docs.gradle.org/current/userguide/single_versions.html#version_ordering)', ]; export const supportsRanges = true; export const supportedRangeStrategies: RangeStrategy[] = ['bump']; function equals(a: string, b: string): boolean { return compare(a, b) === 0; } function getMajor(version: string): number | null { const tokens = parse(version?.replace(regEx(/^v/i), '')); if (tokens) { const majorToken = tokens?.[0]; if (majorToken?.type === TokenType.Number) { return majorToken.val as number; } } return null; } function getMinor(version: string): number | null { const tokens = parse(version?.replace(regEx(/^v/i), '')); if (tokens) { const majorToken = tokens[0]; const minorToken = tokens[1]; if ( majorToken?.type === TokenType.Number && minorToken?.type === TokenType.Number ) { return minorToken.val as number; } return 0; } return null; } function getPatch(version: string): number | null { const tokens = parse(version?.replace(regEx(/^v/i), '')); if (tokens) { const majorToken = tokens[0]; const minorToken = tokens[1]; const patchToken = tokens[2]; if ( majorToken?.type === TokenType.Number && minorToken?.type === TokenType.Number && patchToken?.type === TokenType.Number ) { return patchToken.val as number; } return 0; } return null; } function isGreaterThan(a: string, b: string): boolean { return compare(a, b) === 1; } const unstable = new Set([ 'dev', 'a', 'alpha', 'b', 'beta', 'm', 'mt', 'milestone', 'rc', 'cr', 'preview', 'snapshot', ]); function isStable(version: string): boolean { const tokens = parse(version); if (tokens) { for (const token of tokens) { if (token.type === TokenType.String) { const val = token.val.toString().toLowerCase(); if (unstable.has(val)) { return false; } } } return true; } return false; } function matches(a: string, b: string): boolean { const versionTokens = parse(a); if (!a || !versionTokens || !b) { return false; } if (isVersion(b)) { return equals(a, b); } const singleVersionRange = parseSingleVersionRange(b); if (singleVersionRange) { const { val } = singleVersionRange; return equals(a, val); } const prefixRange = parsePrefixRange(b); if (prefixRange) { const tokens = prefixRange.tokens; if (tokens.length === 0) { return true; } const x = versionTokens .slice(0, tokens.length) .map(({ val }) => val) .join('.'); const y = tokens.map(({ val }) => val).join('.'); return equals(x, y); } const mavenBasedRange = parseMavenBasedRange(b); if (!mavenBasedRange) { return false; } const { leftBound, leftVal, rightBound, rightVal } = mavenBasedRange; let leftResult = true; let rightResult = true; if (leftVal) { leftResult = leftBound === 'exclusive' ? compare(leftVal, a) === -1 : compare(leftVal, a) !== 1; } if (rightVal) { rightResult = rightBound === 'exclusive' ? compare(a, rightVal) === -1 : compare(a, rightVal) !== 1; } return leftResult && rightResult; } function getSatisfyingVersion( versions: string[], range: string, ): string | null { return versions.reduce((result: string | null, version) => { if (matches(version, range)) { if (!result) { return version; } if (isGreaterThan(version, result)) { return version; } } return result; }, null); } function minSatisfyingVersion( versions: string[], range: string, ): string | null { return versions.reduce((result: string | null, version) => { if (matches(version, range)) { if (!result) { return version; } if (compare(version, result) === -1) { return version; } } return result; }, null); } function getNewValue({ currentValue, rangeStrategy, newVersion, }: NewValueConfig): string | null { if (isVersion(currentValue)) { return newVersion; } // Check if our version is of the form "1.2.+" const prefixRange = parsePrefixRange(currentValue); const parsedNewVersion = parse(newVersion); if (prefixRange && parsedNewVersion) { if (prefixRange.tokens.length > 0) { if (prefixRange.tokens.length <= parsedNewVersion.length) { const newPrefixed = prefixRange.tokens .map((_, i) => parsedNewVersion[i].val) .join('.'); return `${newPrefixed}.+`; } // our new version is shorter than our prefix range so drop our prefix range return newVersion; } // our version is already "+" which includes ever version return null; } const mavenRange = parseMavenBasedRange(currentValue); if (mavenRange?.preferredVal) { const { leftVal, rightVal, preferredVal } = mavenRange; const baseRange = currentValue.slice( 0, currentValue.lastIndexOf(`!!${preferredVal}`), ); const newBaseRange = mavenVersion.getNewValue({ currentValue: baseRange, rangeStrategy, newVersion, }); // v8 ignore if: the implementation has a non-null return type if (newBaseRange === null) { return null; } const preferredIsBoundary = preferredVal === leftVal || preferredVal === rightVal; const newParsed = parseMavenBasedRange(newBaseRange); const preferredStillPresent = newParsed?.leftVal === preferredVal || newParsed?.rightVal === preferredVal; const newPreferredVal = preferredIsBoundary && !preferredStillPresent ? newVersion : preferredVal; return `${newBaseRange}!!${newPreferredVal}`; } return mavenVersion.getNewValue({ currentValue, rangeStrategy, newVersion }); } export const api: VersioningApi = { equals, getMajor, getMinor, getPatch, isCompatible: isVersion, isGreaterThan, isSingleVersion: isVersion, isStable, isValid, isVersion, matches, getSatisfyingVersion, minSatisfyingVersion, getNewValue, sortVersions: compare, }; export default api;