semver.ts 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. /**
  2. * Semantic versioning utility for comparing version strings.
  3. * Accepts 1-3 parts (e.g., "1", "1.5", "1.5.0"). Missing parts default to 0.
  4. */
  5. export interface SemverVersion {
  6. major: number
  7. minor: number
  8. patch: number
  9. }
  10. /**
  11. * Parses a semver string into its components.
  12. * Accepts 1-3 parts (e.g., "1", "1.5", "1.5.0"). Missing parts default to 0.
  13. * @param version - The version string to parse (e.g., "1.2.3")
  14. * @returns The parsed version components or null if invalid
  15. */
  16. export function parseSemver(version: string): SemverVersion | null {
  17. if (!version || typeof version !== 'string') {
  18. return null
  19. }
  20. const parts = version.trim().split('.')
  21. if (parts.length === 0 || parts.length > 3) {
  22. return null
  23. }
  24. const numbers = parts.map((p) => parseInt(p, 10))
  25. if (numbers.some(isNaN)) {
  26. return null
  27. }
  28. if (numbers.some((n) => n < 0)) {
  29. return null
  30. }
  31. return {
  32. major: numbers[0],
  33. minor: numbers[1] ?? 0,
  34. patch: numbers[2] ?? 0,
  35. }
  36. }
  37. /**
  38. * Compares two semver version strings.
  39. * Missing parts are treated as 0 (e.g., "1.5" equals "1.5.0").
  40. * @param a - First version string
  41. * @param b - Second version string
  42. * @returns -1 if a < b, 0 if a === b, 1 if a > b, or null if either version is invalid
  43. */
  44. export function compareSemver(a: string, b: string): -1 | 0 | 1 | null {
  45. const versionA = parseSemver(a)
  46. const versionB = parseSemver(b)
  47. if (!versionA || !versionB) {
  48. return null
  49. }
  50. if (versionA.major !== versionB.major) {
  51. return versionA.major > versionB.major ? 1 : -1
  52. }
  53. if (versionA.minor !== versionB.minor) {
  54. return versionA.minor > versionB.minor ? 1 : -1
  55. }
  56. if (versionA.patch !== versionB.patch) {
  57. return versionA.patch > versionB.patch ? 1 : -1
  58. }
  59. return 0
  60. }
  61. /**
  62. * Checks if version a is greater than version b
  63. * @param a - First version string
  64. * @param b - Second version string
  65. * @returns true if a > b, false otherwise
  66. */
  67. export function isGreaterThan(a: string, b: string): boolean {
  68. return compareSemver(a, b) === 1
  69. }
  70. /**
  71. * Checks if version a is less than version b
  72. * @param a - First version string
  73. * @param b - Second version string
  74. * @returns true if a < b, false otherwise
  75. */
  76. export function isLessThan(a: string, b: string): boolean {
  77. return compareSemver(a, b) === -1
  78. }
  79. /**
  80. * Checks if version a is equal to version b
  81. * @param a - First version string
  82. * @param b - Second version string
  83. * @returns true if a === b, false otherwise
  84. */
  85. export function isEqual(a: string, b: string): boolean {
  86. return compareSemver(a, b) === 0
  87. }
  88. /**
  89. * Checks if version a is greater than or equal to version b
  90. * @param a - First version string
  91. * @param b - Second version string
  92. * @returns true if a >= b, false otherwise
  93. */
  94. export function isGreaterThanOrEqual(a: string, b: string): boolean {
  95. const result = compareSemver(a, b)
  96. return result === 1 || result === 0
  97. }
  98. /**
  99. * Checks if version a is less than or equal to version b
  100. * @param a - First version string
  101. * @param b - Second version string
  102. * @returns true if a <= b, false otherwise
  103. */
  104. export function isLessThanOrEqual(a: string, b: string): boolean {
  105. const result = compareSemver(a, b)
  106. return result === -1 || result === 0
  107. }
  108. /**
  109. * Checks if a version string is valid
  110. * @param version - The version string to validate
  111. * @returns true if the version is valid, false otherwise
  112. */
  113. export function isValidSemver(version: string): boolean {
  114. return parseSemver(version) !== null
  115. }