import type { RangeStrategy } from '../../../types/versioning.ts'; import { regEx } from '../../../util/regex.ts'; import { api as npm } from '../npm/index.ts'; import type { NewValueConfig, VersioningApi } from '../types.ts'; export const id = 'hex'; export const displayName = 'Hex'; export const urls = [ '[Elixir Version module](https://hexdocs.pm/elixir/Version.html)', ]; export const supportsRanges = true; export const supportedRangeStrategies: RangeStrategy[] = [ 'bump', 'widen', 'replace', 'update-lockfile', ]; function hex2npm(input: string): string { return input .replace(regEx(/~>\s*(?\d+\.\d+)$/), '^$') .replace(regEx(/~>\s*(?\d+\.\d+\.\d+)/), '~$') .replace(regEx(/==|and/), '') .replace('or', '||') .replace( regEx(/!=\s*(?\d+\.\d+(?:\.\d+.*)?)/), '>$ <$', ) .trim(); } function npm2hex(input: string): string { const res = input .split(' ') .map((str) => str.trim()) .filter((str) => str !== ''); let output = ''; const operators = ['^', '=', '>', '<', '<=', '>=', '~>']; for (let i = 0; i < res.length; i += 1) { if (i === res.length - 1) { output += res[i]; break; } if (i < res.length - 1 && res[i + 1].includes('||')) { output += `${res[i]} or `; i += 1; } else if (operators.includes(res[i])) { output += `${res[i]} `; } else { output += `${res[i]} and `; } } return output; } function isLessThanRange(version: string, range: string): boolean { return !!npm.isLessThanRange?.(hex2npm(version), hex2npm(range)); } function isValid(input: string): boolean { return !!npm.isValid(hex2npm(input)); } function isSingleVersion(constraint: string): boolean { return ( npm.isVersion(constraint) || (constraint?.startsWith('==') && npm.isVersion(constraint.substring(2).trim())) ); } function getPinnedValue(newVersion: string): string { return `== ${newVersion}`; } function matches(version: string, range: string): boolean { return npm.matches(hex2npm(version), hex2npm(range)); } function getSatisfyingVersion( versions: string[], range: string, ): string | null { return npm.getSatisfyingVersion(versions.map(hex2npm), hex2npm(range)); } function minSatisfyingVersion( versions: string[], range: string, ): string | null { return npm.minSatisfyingVersion(versions.map(hex2npm), hex2npm(range)); } function getNewValue({ currentValue, rangeStrategy, currentVersion, newVersion, }: NewValueConfig): string | null { let newSemver = npm.getNewValue({ currentValue: hex2npm(currentValue), rangeStrategy, currentVersion, newVersion, }); if (newSemver) { newSemver = npm2hex(newSemver); if (regEx(/~>\s*(?:\d+\.\d+\.\d+)$/).test(currentValue)) { newSemver = newSemver.replace( regEx(/[\^~]\s*(?\d+\.\d+\.\d+)/g), (_str, version: string) => `~> ${version}`, ); } else if (regEx(/~>\s*(?:\d+\.\d+)$/).test(currentValue)) { newSemver = newSemver.replace( regEx(/\^\s*(?\d+\.\d+)(?:\.\d+)?/g), (_str, version: string) => `~> ${version}`, ); } else { newSemver = newSemver.replace( regEx(/~\s*(?\d+\.\d+\.\d)/g), '~> $', ); } if (npm.isVersion(newSemver)) { newSemver = `== ${newSemver}`; } } return newSemver; } export { isValid }; export const api: VersioningApi = { ...npm, isLessThanRange, isSingleVersion, isValid, matches, getSatisfyingVersion, minSatisfyingVersion, getNewValue, getPinnedValue, }; export default api;