Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Invalid NPM block #99

Closed
gjedeer opened this issue May 29, 2020 · 3 comments
Closed

Invalid NPM block #99

gjedeer opened this issue May 29, 2020 · 3 comments
Labels
Topic:NPM Implementing NPM-style version specifiers Type:Q&A

Comments

@gjedeer
Copy link

gjedeer commented May 29, 2020

I'm getting an error when parsing an expression from npmjs.com:

>>> import semantic_version
>>> semantic_version.__version__
'2.8.5'
>>> semantic_version.NpmSpec('>= 2.1.2 < 3')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/gdr/venv3/lib/python3.6/site-packages/semantic_version/base.py", line 618, in __init__
    self.clause = self._parse_to_clause(expression)
  File "/home/gdr/venv3/lib/python3.6/site-packages/semantic_version/base.py", line 1225, in _parse_to_clause
    return cls.Parser.parse(expression)
  File "/home/gdr/venv3/lib/python3.6/site-packages/semantic_version/base.py", line 1265, in parse
    raise ValueError("Invalid NPM block in %r: %r" % (expression, block))
ValueError: Invalid NPM block in '>= 2.1.2 < 3': '>='

The full version spec was:

>= 2.1.2 < 3

I did not make up this spec string - it was found when parsing package.json found on npm.

@rbarrois
Copy link
Owner

rbarrois commented Jun 2, 2020

Reading the NPM grammar, the version is invalid:

range      ::= hyphen | simple ( ' ' simple ) * | ''
simple     ::= primitive | partial | tilde | caret

A range can be empty, an hyphen (a.b.c-d.e.f), or a set of simple blocks separated by a single space.

A simple block is defined as:

primitive  ::= ( '<' | '>' | '>=' | '<=' | '=' ) partial

So: a comparator, immediately attached to a partial.

A partial is:

partial    ::= xr ( '.' xr ( '.' xr qualifier ? )? )?
xr         ::= 'x' | 'X' | '*' | nr
nr         ::= '0' | ['1'-'9'] ( ['0'-'9'] ) *
qualifier  ::= ( '-' pre )? ( '+' build )?

I suggest raising the issue with the developer of that package ;)

@rbarrois rbarrois added Topic:NPM Implementing NPM-style version specifiers Type:Q&A labels Jun 2, 2020
@rbarrois rbarrois closed this as completed Jun 2, 2020
@gjedeer
Copy link
Author

gjedeer commented Jun 2, 2020

It seems what they implement is different from their specification, then: https://github.com/npm/node-semver/blob/master/classes/range.js#L91 - but it looks like I can pre-process the range with the same regex node-semver uses internally.

@gjedeer
Copy link
Author

gjedeer commented Jun 3, 2020

So, just in case this comes useful for someone in the future, the npm logic translated to Python is as following:

comparator_trim_re = re.compile(r'(\s*)((?:<|>)?=?)\s*([v=\s]*([0-9]+)\.([0-9]+)\.([0-9]+)(?:-?((?:[0-9]+|\d*[a-zA-Z-][a-zA-Z0-9-]*)(?:\.(?:[0-9]+|\d*[a-zA-Z-][a-zA-Z0-9-]*))*))?(?:\+([0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*))?|[v=\s]*(0|[1-9]\d*|x|X|\*)(?:\.(0|[1-9]\d*|x|X|\*)(?:\.(0|[1-9]\d*|x|X|\*)(?:(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][a-zA-Z0-9-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][a-zA-Z0-9-]*))*)))?(?:\+([0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*))?)?)?)')

def clean_up_npm_range(range):
    return comparator_trim_re.sub(r'\1\2\3', range)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Topic:NPM Implementing NPM-style version specifiers Type:Q&A
Projects
None yet
Development

No branches or pull requests

2 participants