UNPKG

renovate

Version:

Automated dependency updates. Flexible so you don't need to be.

179 lines (178 loc) 5.77 kB
import { regEx } from "../../../util/regex.js"; import { isString } from "@sindresorhus/is"; //#region lib/modules/versioning/gradle/compare.ts const TokenType = { Number: 1, String: 2 }; function iterateChars(str, cb) { let prev = null; let next = null; for (let i = 0; i < str.length; i += 1) { next = str.charAt(i); cb(prev, next); prev = next; } cb(prev, null); } function isSeparator(char) { return regEx(/^[-._+]$/i).test(char); } function isDigit(char) { return regEx(/^\d$/).test(char); } function isLetter(char) { return !isSeparator(char) && !isDigit(char); } function isTransition(prevChar, nextChar) { return isDigit(prevChar) && isLetter(nextChar) || isLetter(prevChar) && isDigit(nextChar); } function tokenize(versionStr) { let result = []; let currentVal = ""; function yieldToken() { if (result) { const val = currentVal; if (regEx(/^\d+$/).test(val)) result.push({ type: TokenType.Number, val: parseInt(val, 10) }); else result.push({ type: TokenType.String, val }); } } iterateChars(versionStr, (prevChar, nextChar) => { if (nextChar === null) yieldToken(); else if (isSeparator(nextChar)) if (prevChar && !isSeparator(prevChar)) { yieldToken(); currentVal = ""; } else result = null; else if (prevChar !== null && isTransition(prevChar, nextChar)) { yieldToken(); currentVal = nextChar; } else currentVal = currentVal.concat(nextChar); }); return result; } const QualifierRank = { Dev: -1, Default: 0, RC: 1, Snapshot: 2, Final: 3, GA: 4, Release: 5, SP: 6 }; function qualifierRank(input) { const val = input.toLowerCase(); if (val === "dev") return QualifierRank.Dev; if (val === "rc" || val === "cr") return QualifierRank.RC; if (val === "snapshot") return QualifierRank.Snapshot; if (val === "ga") return QualifierRank.GA; if (val === "final") return QualifierRank.Final; if (val === "release" || val === "latest" || val === "sr") return QualifierRank.Release; if (val === "sp") return QualifierRank.SP; return QualifierRank.Default; } function stringTokenCmp(left, right) { const leftRank = qualifierRank(left); const rightRank = qualifierRank(right); if (leftRank === 0 && rightRank === 0) { if (left < right) return -1; if (left > right) return 1; } else { if (leftRank < rightRank) return -1; if (leftRank > rightRank) return 1; } return 0; } function tokenCmp(left, right) { if (left === null) { if (right?.type === TokenType.String) return 1; return -1; } if (right === null) { if (left.type === TokenType.String) return -1; return 1; } if (left.type === TokenType.Number && right.type === TokenType.Number) { if (left.val < right.val) return -1; if (left.val > right.val) return 1; } else if (typeof left.val === "string" && typeof right.val === "string") return stringTokenCmp(left.val, right.val); else if (right.type === TokenType.Number) return -1; else if (left.type === TokenType.Number) return 1; return 0; } function compare(left, right) { const leftTokens = tokenize(left) ?? []; const rightTokens = tokenize(right) ?? []; const length = Math.max(leftTokens.length, rightTokens.length); for (let idx = 0; idx < length; idx += 1) { const cmpResult = tokenCmp(leftTokens[idx] || null, rightTokens[idx] || null); if (cmpResult !== 0) return cmpResult; } return 0; } function parse(input) { if (!input) return null; if (!regEx(/^[-._+a-zA-Z0-9]+$/i).test(input)) return null; if (regEx(/^latest\.?/i).test(input)) return null; const tokens = tokenize(input); // istanbul ignore if: should not happen if (!tokens?.length) return null; return tokens; } function isVersion(input) { return !!parse(input); } function parsePrefixRange(input) { if (!input) return null; if (input.trim() === "+") return { tokens: [] }; if (regEx(/[^-._+][-._]\+$/).test(input)) { const tokens = tokenize(input.replace(regEx(/[-._]\+$/), "")); if (tokens) return { tokens }; } return null; } const mavenBasedRangeRegex = regEx(/^(?<leftBoundStr>[[\](]\s*)(?<leftVal>[-._+a-zA-Z0-9]*?)(?<separator>\s*,\s*)(?<rightVal>[-._+a-zA-Z0-9]*?)(?<rightBoundStr>\s*[[\])])(?:!!(?<preferredVal>[-._+a-zA-Z0-9]+))?$/); function parseMavenBasedRange(input) { if (!input) return null; const matchGroups = mavenBasedRangeRegex.exec(input)?.groups; if (!matchGroups) return null; const { leftBoundStr, separator, rightBoundStr } = matchGroups; const leftVal = matchGroups.leftVal || null; const rightVal = matchGroups.rightVal || null; const preferredVal = matchGroups.preferredVal || null; const isVersionLeft = isString(leftVal) && isVersion(leftVal); const isVersionRight = isString(rightVal) && isVersion(rightVal); if (leftVal !== null && !isVersionLeft || rightVal !== null && !isVersionRight) return null; if (isVersionLeft && isVersionRight && leftVal && rightVal && compare(leftVal, rightVal) === 1) return null; return { leftBound: leftBoundStr.trim() === "[" ? "inclusive" : "exclusive", leftBoundStr, leftVal, separator, rightBound: rightBoundStr.trim() === "]" ? "inclusive" : "exclusive", rightBoundStr, rightVal, preferredVal }; } const singleVersionRangeRegex = regEx(/^\[\s*(?<val>[-._+a-zA-Z0-9]*?)\s*\]$/); function parseSingleVersionRange(input) { const matchGroups = singleVersionRangeRegex.exec(input)?.groups; if (!matchGroups) return null; const { val } = matchGroups; if (!isVersion(val)) return null; return { val }; } function isValid(str) { if (!str) return false; return isVersion(str) || !!parsePrefixRange(str) || !!parseMavenBasedRange(str) || !!parseSingleVersionRange(str); } //#endregion export { TokenType, compare, isValid, isVersion, parse, parseMavenBasedRange, parsePrefixRange, parseSingleVersionRange }; //# sourceMappingURL=compare.js.map