TypeScript Version Resolver
The challenge is to implement a robust version resolver for software packages in TypeScript. This involves understanding and applying common versioning schemes like Semantic Versioning (SemVer) and handling different version resolution strategies such as exact, caret, and tilde ranges. This is crucial for dependency management in large projects, ensuring compatibility and preventing unintended breaking changes.
Problem Description
You need to create a TypeScript function that takes a list of installed package versions and a dependency version range, and determines if any of the installed versions satisfy the given range.
Key Requirements:
- Semantic Versioning (SemVer) Parsing: Implement or utilize a mechanism to parse SemVer strings (e.g., "1.2.3", "2.0.0-beta.1"). This includes handling major, minor, patch, and pre-release identifiers.
- Version Range Resolution: Support the following common version range specifiers:
- Exact Match: e.g.,
"1.2.3"- Only the exact version is acceptable. - Caret Range (
^): e.g.,"^1.2.3"- Allows updates that do not change the most significant digit. For "1.2.3", this means>=1.2.3 <2.0.0. For "0.2.3", this means>=0.2.3 <0.3.0. For "0.0.3", this means>=0.0.3 <0.0.4. - Tilde Range (
~): e.g.,"~1.2.3"- Allows patch-level changes. For "1.2.3", this means>=1.2.3 <1.3.0. For "1.0", this means>=1.0.0 <1.1.0.
- Exact Match: e.g.,
- Pre-release Handling: By default, pre-release versions (e.g., "1.0.0-alpha.1") should not satisfy a non-pre-release range. However, if the range itself is a pre-release version, then pre-release versions are allowed if they satisfy the range.
- Input and Output:
- Input:
- An array of strings, where each string is an installed package version (e.g.,
["1.0.0", "1.0.1", "1.1.0-beta.1"]). - A string representing the dependency version range (e.g.,
"^1.0.0").
- An array of strings, where each string is an installed package version (e.g.,
- Output:
- A single string representing the highest installed version that satisfies the given range.
- If no installed version satisfies the range, return
null.
- Input:
Edge Cases to Consider:
- Invalid version strings (e.g., "abc", "1.2").
- Invalid range strings.
- Versions with build metadata (e.g., "1.2.3+build.456") - this metadata should be ignored for comparison.
- Zero versions (e.g., "0.1.0", "0.0.1").
Examples
Example 1:
Input:
installedVersions = ["1.0.0", "1.0.1", "1.1.0", "2.0.0-beta.1"]
versionRange = "^1.0.0"
Output: "1.1.0"
Explanation:
- "1.0.0" satisfies "^1.0.0" (>=1.0.0 <2.0.0)
- "1.0.1" satisfies "^1.0.0" (>=1.0.0 <2.0.0)
- "1.1.0" satisfies "^1.0.0" (>=1.0.0 <2.0.0)
- "2.0.0-beta.1" does not satisfy "^1.0.0" because it's a pre-release and the range is not a pre-release.
Among the satisfying versions ("1.0.0", "1.0.1", "1.1.0"), "1.1.0" is the highest.
Example 2:
Input:
installedVersions = ["0.1.2", "0.2.0", "0.2.1-alpha.1", "1.0.0"]
versionRange = "~0.2.0"
Output: "0.2.0"
Explanation:
- "0.1.2" does not satisfy "~0.2.0" (>=0.2.0 <0.3.0)
- "0.2.0" satisfies "~0.2.0" (>=0.2.0 <0.3.0)
- "0.2.1-alpha.1" does not satisfy "~0.2.0" because it's a pre-release and the range is not.
- "1.0.0" does not satisfy "~0.2.0".
The only satisfying version is "0.2.0".
Example 3:
Input:
installedVersions = ["1.0.0-alpha.1", "1.0.0-alpha.2", "1.0.0"]
versionRange = "1.0.0-alpha.1"
Output: "1.0.0-alpha.2"
Explanation:
The range is a pre-release.
- "1.0.0-alpha.1" satisfies the exact range "1.0.0-alpha.1".
- "1.0.0-alpha.2" satisfies the exact range "1.0.0-alpha.1" (as alpha.2 > alpha.1).
- "1.0.0" does not satisfy the exact range "1.0.0-alpha.1".
The highest satisfying version is "1.0.0-alpha.2".
Example 4:
Input:
installedVersions = ["1.2.3", "1.2.4"]
versionRange = "2.0.0"
Output: null
Explanation:
Neither "1.2.3" nor "1.2.4" matches the exact version "2.0.0".
Constraints
- Version strings will follow the SemVer 2.0.0 specification, including optional pre-release tags.
- Range strings will be either an exact version, a caret range (
^), or a tilde range (~). - Assume input arrays will not be excessively large (e.g., less than 1000 versions).
- Parsing and comparison operations should be reasonably efficient.
Notes
- You might find it helpful to create helper functions for parsing versions and comparing them.
- Consider how to handle version comparisons correctly, especially with pre-release tags. SemVer specifies a strict ordering.
- The definition of "highest" implies the version that is lexicographically largest according to SemVer rules.
- You'll need to implement a robust version comparison function that adheres to SemVer.