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

Handle '', '*', '1.x.', 'URL#semver:...', etc. #1

Closed
wants to merge 7 commits into from

Conversation

jacobq
Copy link

@jacobq jacobq commented Mar 12, 2018

This PR makes the following changes:

  • Correctly detect ranges specified with ".x" notation, e.g. 1.0.x
  • Correctly detect ranges specified with *, '', or a.b.c - d.e.f notation
  • Improve test coverage, e.g. commitish URLs with exact (e.g. #hash) and range (e.g. #semver:~1.0.0)

(see https://docs.npmjs.com/files/package.json#dependencies)

@jacobq jacobq changed the title Handle commitish strings & ".x" Handle '', '*', '1.x.', 'URL#semver:...', etc. Mar 12, 2018
@bendrucker
Copy link
Owner

Hi, I just updated standard. Tape did not need updating, your change was a noop and just forced a newer version that was previously allowed. Please don't make any changes to the package.

Updating necessary deps is ok but bumping the version or making other changes is poor PR etiquette.

I will try to clean this up and merge later this afternoon.

@jacobq
Copy link
Author

jacobq commented Mar 12, 2018

@bendrucker Thanks for your reply. Per your request I've reverted the package.json changes except for bumping standard from ^4.0.0 to ^11.0.0. I wasn't trying to have bad PR etiquette; I've just found that often the authors/maintainers of projects that are this old/inactive do not want to invest any effort in them, so I was trying to make things easy. I appreciate you being willing to merge & publish an updated version.

@bendrucker
Copy link
Owner

That's ok, I appreciate the contribution. Trying to make things effort-free is nice but part of that is minimizing the change set.

The changes to the source are more substantial than expected so I'll leave some comments and we'll work on this a bit more.

@jacobq
Copy link
Author

jacobq commented Mar 12, 2018

I'll rebase this PR w/ your new commits on master in a moment. Feel free to edit anything however you like. All I really care about is that the test suite passes.

@jacobq jacobq force-pushed the feat/support-commitish branch from 50d11b4 to e270f67 Compare March 12, 2018 22:31
Copy link
Owner

@bendrucker bendrucker left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Left a lot of comments. I care most about getting the tests to a more readable place, then focusing on the source.

.travis.yml Outdated
language: node_js
node_js:
- iojs
- "4"
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please remove travis changes. I updated the node versions to 4/6/8. The npm test script is the default. And I don't want caching, that's for big projects.

.travis.yml Outdated
@@ -4,3 +4,11 @@ node_js:
- 4
- 6
- 8

cache:
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove this, caching is for projects with huge dep graphs

.travis.yml Outdated
- $HOME/.npm
- node_modules

script:
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the default, remove it please. And generally don't change the CI config for a PR unless it's related (e.g. removing or adding node version support).

// - Any of the symbols ^*~<>|
// - A digit followed by .x
// - A hyphenated range like "a.b.c - d.e.f"
const rangeRegEx = /^$|[\^*~<>|]|(\d+\.x)|(\d+(\.\d)*\s*-\s*\d+(\.\d)*)/
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This regex is a lot hairier than the original and I'm not sure if I'm ok with munging all this logic into a single line. I'll come back to this.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You may want to consider eliminating the use of regex altogether. I think there are some standard functions in the semver package that might help.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah that's what I meant

index.js Outdated
module.exports = function exactVersion (version) {
return !regex.test(version)
function extractSemVer (s) {
let result = null
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Return early, don't declare "result" and conditionally assign to it

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you think that

function extractSemVer (s) {
  const match = s.match(nestedSemVerRegEx)
  return match && match[1]
}

is more readable then so be it :trollface:

test.js Outdated
})

test('range versions -> false', function (t) {
t.notOk(exact(''), 'Blank/empty is the same as *')
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Empty string

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done. However, I think there is some merit to the idea of expressing why something is the way it is. There are quite a few "grey areas" regarding what an "exact" version is so there is potential for confusion. The test suite can serve to resolve any ambiguity.

test.js Outdated

test('range versions -> false', function (t) {
t.notOk(exact(''), 'Blank/empty is the same as *')
t.notOk(exact('*'), '* means anything')
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

*

Same goes for all the other assertions. Don't write them like comments.

test.js Outdated
test('range versions -> false', function (t) {
t.notOk(exact(''), 'Blank/empty is the same as *')
t.notOk(exact('*'), '* means anything')
t.notOk(exact('~4.0.0'), '~ specifies as range')
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test section is called range, keep the messages as concise as possible

test.js Outdated
'#semver:1.0.0'
]

test('exact commitish strings -> true', function (t) {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Move these to the main exact suite. There should be two test calls, one for exact, one for ranges.

Don't construct test assertions in a complex loop when you can avoid it. You can generate all your test "version" identifiers ahead of time using your URLs and refs.

test.js Outdated

const exactRefs = [
'#master',
'#jj-abrams',
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull this out, it's not distinct from #master

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It contains a - which could be mistakenly identified as a range operator

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we wanted to make our lives harder we could test #1.0.0-1.2.0, which could be a valid (though misleading) exact tag but looks very similar to #semver:1.0.0-1.2.0 which would be a range.

'#semver:1.0.0'
]

const generateUrls = (baseURLs, refs) => {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use a function declaration and put it at the end of the file. Don't use arrow functions except as one-liners or to bind this.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can also do urls = in each test callback for the respective case. The idea is just that the test cases not be generated in a loop for easier debugging. If you call your helper twice that's still accomplished.


const generateUrls = (baseURLs, refs) => {
return baseURLs.reduce((urls, baseURL) => {
return urls.concat(refs.map(ref => `${baseURL}${ref}`))
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Avoid template strings when concatenation is clearer: baseURL + ref

}

module.exports = function exactVersion (versionString) {
if (typeof versionString !== 'string') {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't think we need to handle non-strings

// - Any of the symbols ^*~<>|
// - A digit followed by .x
// - A hyphenated range like "a.b.c - d.e.f"
const rangeRegEx = /^$|[\^*~<>|]|(\d+\.x)|(\d+(\.\d)*\s*-\s*\d+(\.\d)*)/
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah that's what I meant

@jacobq
Copy link
Author

jacobq commented Nov 2, 2018

@jacobq jacobq closed this Nov 2, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants