server-version.ts 2.0 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061
  1. /**
  2. * Minimal server-version checks for `config.min_server_version` /
  3. * `config.stable_server_version` (replaces the `semver` package, ~300 KB in
  4. * the client bundle for two comparisons).
  5. *
  6. * Supports what the settings actually use: plain versions (`15.0.0`) and
  7. * `x` wildcards (`15.x.x`, `15.2.x`). Prerelease tags are ignored, like
  8. * `semver.coerce` did.
  9. */
  10. /** "v15.1.0-beta.2" → [15, 1, 0]; null when there is no number at all. */
  11. export function coerceVersion(input: string) {
  12. const m = String(input ?? '').match(/(\d+)(?:\.(\d+))?(?:\.(\d+))?/)
  13. if (!m) return null
  14. return [Number(m[1]), Number(m[2] ?? 0), Number(m[3] ?? 0)]
  15. }
  16. function compare(a: any, b: any) {
  17. for (let i = 0; i < 3; i++) {
  18. if (a[i] !== b[i]) return a[i] < b[i] ? -1 : 1
  19. }
  20. return 0
  21. }
  22. /** Parse a range like `15.x.x` into its lowest and highest concrete versions. */
  23. function rangeBounds(range: any) {
  24. const parts = String(range ?? '').split('.')
  25. const low = [0, 0, 0]
  26. const high = [0, 0, 0]
  27. let wildcard = false
  28. for (let i = 0; i < 3; i++) {
  29. const p = parts[i]
  30. if (wildcard || p === undefined || /^[xX*]$/.test(p)) {
  31. wildcard = true
  32. low[i] = 0
  33. high[i] = Number.MAX_SAFE_INTEGER
  34. } else {
  35. const n = Number(p)
  36. if (Number.isNaN(n)) return null
  37. low[i] = n
  38. high[i] = n
  39. }
  40. }
  41. return { low, high }
  42. }
  43. /** `semver.ltr(version, range)`: version is lower than every version the range allows. */
  44. export function isBelowRange(version: string, range: any) {
  45. const v = coerceVersion(version)
  46. const bounds = rangeBounds(range)
  47. if (!v || !bounds) return false
  48. return compare(v, bounds.low) < 0
  49. }
  50. /** `semver.gtr(version, range)`: version is higher than every version the range allows. */
  51. export function isAboveRange(version: string, range: any) {
  52. const v = coerceVersion(version)
  53. const bounds = rangeBounds(range)
  54. if (!v || !bounds) return false
  55. return compare(v, bounds.high) > 0
  56. }