Class: Vers::Parser
- Inherits:
-
Object
- Object
- Vers::Parser
- Defined in:
- lib/vers/parser.rb
Overview
Parses vers URI strings and package manager specific version ranges
This class handles parsing of vers URI format (e.g., "vers:npm/>=1.2.3|<2.0.0") and provides extensible support for different package ecosystem syntaxes.
Examples
parser = Vers::Parser.new
range = parser.parse("vers:npm/>=1.2.3|<2.0.0")
range.contains?("1.5.0") # => true
Constant Summary collapse
- VERS_URI_REGEX =
Regex for parsing vers URI format
/\Avers:([^\/]+)\/(.+)\z/- NPM_CARET_REGEX =
Pre-compiled regex patterns for common npm patterns
/\A\^(.+)\z/- NPM_TILDE_REGEX =
/\A~(.+)\z/- NPM_HYPHEN_REGEX =
/\A(.+?)\s+-\s+(.+)\z/- NPM_X_RANGE_MAJOR_REGEX =
/\A(\d+)\.x\z/- NPM_X_RANGE_MINOR_REGEX =
/\A(\d+)\.(\d+)\.x\z/- OPERATOR_PREFIX_REGEX =
/\A[><=!]+/- MAX_INPUT_LENGTH =
Maximum accepted length for a range string at parse/parse_native entry points. Range strings concatenate multiple constraints so this is set higher than Version::MAX_LENGTH while still bounding split/regex work to a few KB.
2048- MAX_CONSTRAINTS =
Maximum number of |-separated or ||-separated constraints in a single range. The exclusion loop in parse_constraints does O(n^2 log n) work as each != splits an interval and reconstructs the range; capping n keeps the worst case under a few thousand interval operations.
64- @@parser_cache =
Cache for parsed ranges to improve performance
{}
- @@cache_size_limit =
500
Instance Method Summary collapse
-
#parse(vers_string) ⇒ VersionRange
Parses a vers URI string into a VersionRange.
-
#parse_native(range_string, scheme) ⇒ VersionRange
Parses a native package manager version range into a VersionRange.
-
#to_vers_string(version_range, scheme) ⇒ String
Converts a VersionRange back to a vers URI string.
Instance Method Details
#parse(vers_string) ⇒ VersionRange
62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 |
# File 'lib/vers/parser.rb', line 62 def parse(vers_string) validate_input_length!(vers_string) if vers_string == "*" return VersionRange.unbounded end match = vers_string.match(VERS_URI_REGEX) raise ArgumentError, "Invalid vers URI format: #{vers_string}" unless match scheme = match[1] constraints_string = match[2] parse_constraints(constraints_string, scheme) end |
#parse_native(range_string, scheme) ⇒ VersionRange
92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 |
# File 'lib/vers/parser.rb', line 92 def parse_native(range_string, scheme) validate_input_length!(range_string) case scheme when "npm" parse_npm_range(range_string) when "gem", "rubygems" parse_gem_range(range_string) when "pypi" parse_pypi_range(range_string) when "maven" parse_maven_range(range_string) when "cargo" parse_npm_range(range_string) when "nuget" parse_nuget_range(range_string) when "hex", "elixir" parse_hex_range(range_string) when "go", "golang" parse_go_range(range_string) when "deb", "debian" parse_debian_range(range_string) when "rpm" parse_rpm_range(range_string) else # Fall back to generic constraint parsing parse_constraints(range_string, scheme) end end |
#to_vers_string(version_range, scheme) ⇒ String
Converts a VersionRange back to a vers URI string
129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 |
# File 'lib/vers/parser.rb', line 129 def to_vers_string(version_range, scheme) return "vers:#{scheme}/*" if version_range.unbounded? return "vers:#{scheme}/" if version_range.empty? intervals = version_range.raw_constraints || version_range.intervals constraints = [] # Detect != pattern: two intervals (-∞,V) ∪ (V,+∞) if intervals.length == 2 a, b = intervals if a.min.nil? && !a.max_inclusive && b.max.nil? && !b.min_inclusive && a.max == b.min constraints << "!=#{a.max}" constraints.sort_by! { |c| sort_key_for_constraint(c) } return "vers:#{scheme}/#{constraints.join('|')}" end end intervals.each do |interval| if interval.min == interval.max && interval.min_inclusive && interval.max_inclusive # Exact version constraints << interval.min.to_s else # Range constraints if interval.min operator = interval.min_inclusive ? ">=" : ">" constraints << "#{operator}#{interval.min}" end if interval.max operator = interval.max_inclusive ? "<=" : "<" constraints << "#{operator}#{interval.max}" end end end constraints.sort_by! { |c| sort_key_for_constraint(c) } "vers:#{scheme}/#{constraints.join('|')}" end |