Skip to content

Commit db4ead6

Browse files
authored
Fix Npm version range #79 (#82)
* Fix Npm version range #79 Reference: #79 Signed-off-by: Tushar Goel <tushar.goel.dav@gmail.com> * Support - in npm version ranges #83 Reference: #83 Signed-off-by: Tushar Goel <tushar.goel.dav@gmail.com> * Address review comments Signed-off-by: Tushar Goel <tushar.goel.dav@gmail.com> * Use named arguments Signed-off-by: Tushar Goel <tushar.goel.dav@gmail.com> * Remove space from split Signed-off-by: Tushar Goel <tushar.goel.dav@gmail.com> Signed-off-by: Tushar Goel <tushar.goel.dav@gmail.com>
1 parent 2282b61 commit db4ead6

3 files changed

Lines changed: 5426 additions & 28 deletions

File tree

src/univers/version_range.py

Lines changed: 97 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,40 @@ def from_osv_v1(data, scheme):
223223
"""
224224

225225

226+
def get_allof_constraints(cls, clause):
227+
"""
228+
Return a list of VersionConstraint given an AllOf ``clause``.
229+
"""
230+
if not isinstance(clause, AllOf):
231+
raise ValueError(f"Unknown clause type: {clause!r}")
232+
allof_constraints = []
233+
for constraint in clause.clauses:
234+
comparator = cls.vers_by_native_comparators[constraint.operator]
235+
version = cls.version_class(str(constraint.target))
236+
constraint = VersionConstraint(comparator=comparator, version=version)
237+
allof_constraints.append(constraint)
238+
return allof_constraints
239+
240+
241+
def get_npm_version_constraints_from_semver_npm_spec(string, cls):
242+
"""
243+
Return a VersionConstraint for the provided ``string``.
244+
"""
245+
spec = semantic_version.NpmSpec(string)
246+
clause = spec.clause.simplify()
247+
if isinstance(clause, (AnyOf, AllOf)):
248+
anyof_constraints = []
249+
if isinstance(clause, AnyOf):
250+
for allof_clause in clause.clauses:
251+
anyof_constraints.extend(get_allof_constraints(cls, allof_clause))
252+
elif isinstance(clause, AllOf):
253+
alloc = get_allof_constraints(cls, clause)
254+
anyof_constraints.extend(alloc)
255+
else:
256+
raise ValueError(f"Unknown clause type: {spec!r}")
257+
return anyof_constraints
258+
259+
226260
class NpmVersionRange(VersionRange):
227261
scheme = "npm"
228262
version_class = versions.SemverVersion
@@ -245,35 +279,71 @@ def from_native(cls, string):
245279

246280
# an NpmSpec handles parsing of both the semver versions and node-semver
247281
# ranges at once
248-
spec = semantic_version.NpmSpec(string)
249-
250-
clause = spec.clause.simplify()
251-
assert isinstance(clause, (AnyOf, AllOf))
252-
anyof_constraints = []
253-
if isinstance(clause, AnyOf):
254-
for allof_clause in clause.clauses:
255-
anyof_constraints.extend(get_allof_constraints(cls, allof_clause))
256-
elif isinstance(clause, AllOf):
257-
alloc = get_allof_constraints(cls, clause)
258-
anyof_constraints.extend(alloc)
259-
else:
260-
raise ValueError(f"Unknown clause type: {spec!r}")
261-
262-
return cls(constraints=anyof_constraints)
263282

283+
if string == "*":
284+
return cls(
285+
constraints=[
286+
VersionConstraint.from_string(string="*", version_class=cls.version_class)
287+
]
288+
)
264289

265-
def get_allof_constraints(cls, clause):
266-
"""
267-
Return a list of VersionConstraint given an AllOf ``clause``.
268-
"""
269-
assert isinstance(clause, AllOf)
270-
allof_constraints = []
271-
for constraint in clause.clauses:
272-
comparator = cls.vers_by_native_comparators[constraint.operator]
273-
version = cls.version_class(str(constraint.target))
274-
constraint = VersionConstraint(comparator=comparator, version=version)
275-
allof_constraints.append(constraint)
276-
return allof_constraints
290+
constraints = []
291+
vrc = cls.version_class
292+
# A constraint item can be a comparator or a version or a version with comparator
293+
# If it's empty continue
294+
# If it's in `vers_by_native_comparators`, append it with the comparator and continue
295+
# If it's a version, make version constraint from the version and use the comparator from the previous item and make comparator empty
296+
# If it's a version with comparator, use split_req to get version and comparator to form constraint and make comparator empty
297+
298+
for range in string.split("||"):
299+
if " - " in range:
300+
constraints.extend(
301+
get_npm_version_constraints_from_semver_npm_spec(string=range, cls=cls)
302+
)
303+
continue
304+
comparator = ""
305+
for constraint in range.split():
306+
cmp = "".join([comparator, constraint])
307+
if cmp in cls.vers_by_native_comparators:
308+
comparator = cls.vers_by_native_comparators[cmp]
309+
continue
310+
if comparator:
311+
if constraint.endswith(".x"):
312+
constraints.extend(
313+
get_npm_version_constraints_from_semver_npm_spec(
314+
string=constraint, cls=cls
315+
)
316+
)
317+
else:
318+
constraint = constraint.lstrip("vV")
319+
constraints.append(
320+
VersionConstraint(comparator=comparator, version=vrc(constraint))
321+
)
322+
else:
323+
if (
324+
constraint.endswith(".x")
325+
or constraint.startswith("~")
326+
or constraint.startswith("^")
327+
):
328+
constraints.extend(
329+
get_npm_version_constraints_from_semver_npm_spec(
330+
string=constraint, cls=cls
331+
)
332+
)
333+
else:
334+
comparator, version_constraint = split_req(
335+
string=constraint,
336+
comparators=cls.vers_by_native_comparators,
337+
default="=",
338+
)
339+
version_constraint = version_constraint.lstrip("vV")
340+
constraints.append(
341+
VersionConstraint(
342+
comparator=comparator, version=vrc(version_constraint)
343+
)
344+
)
345+
comparator = ""
346+
return cls(constraints=constraints)
277347

278348

279349
class GemVersionRange(VersionRange):

0 commit comments

Comments
 (0)