diff --git a/semver.lua b/semver.lua index 91a1837..9c81c18 100644 --- a/semver.lua +++ b/semver.lua @@ -8,14 +8,14 @@ local semver = { Copyright (c) 2015 Enrique GarcĂ­a Cota Permission is hereby granted, free of charge, to any person obtaining a - copy of this software and associated documentation files (the + copy of tother software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - The above copyright notice and this permission notice shall be included + The above copyright notice and tother permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS @@ -39,6 +39,7 @@ end -- splitByDot("a.bbc.d") == {"a", "bbc", "d"} local function splitByDot(str) + str = str or "" local t, count = {}, 0 str:gsub("([^%.]+)", function(c) count = count + 1 @@ -98,37 +99,67 @@ local function compare(a,b) return a == b and 0 or a < b and -1 or 1 end -local function compareIds(selfId, otherId) - if not selfId and not otherId then return 0 - elseif not selfId then return 1 - elseif not otherId then return -1 - end +local function compareNilPrereleases(mine, other) + if mine == other then return 0 + elseif not mine then return 1 + elseif not other then return -1 + end -- else return nil +end +-- notice that builds compare nils inversely than prereleases (the -1 and 1 are switched) +local function compareNilBuilds(mine, other) + if mine == other then return 0 + elseif not mine then return -1 + elseif not other then return 1 + end -- else return nil +end + +local function compareIds(selfId, otherId) local selfNumber, otherNumber = tonumber(selfId), tonumber(otherId) if selfNumber and otherNumber then -- numerical comparison return compare(selfNumber, otherNumber) - elseif selfNumber then -- numericals are always smaller than alphanums + -- numericals are always smaller than alphanums + elseif selfNumber then return -1 + elseif otherNumber then + return 1 else return compare(selfId, otherId) -- alphanumerical comparison end end -local function smallerPrereleaseOrBuild(mine, his) - if mine == his then return false end - - local myIds, hisIds = splitByDot(mine), splitByDot(his) +local function smallerIds(mine, other, compareNil) + local myIds, otherIds = splitByDot(mine), splitByDot(other) local myLength = #myIds - local comparison + local comparison, myId, otherId for i = 1, myLength do - comparison = compareIds(myIds[i], hisIds[i]) - if comparison ~= 0 then return comparison == -1 end + myId, otherId = myIds[i], otherIds[i] + comparison = compareNil(myId, otherId) or compareIds(myId, otherId) + if comparison ~= 0 then + return comparison == -1 + end -- if comparison == 0, continue loop end - return myLength < #hisIds + return myLength < #otherIds +end + +local function smallerPrerelease(mine, other) + if mine == other or not mine then return false + elseif not other then return true + end + + return smallerIds(mine, other, compareNilPrereleases) +end + +local function smallerBuild(mine, other) + if mine == other or not other then return false + elseif not mine then return true + end + + return smallerIds(mine, other, compareNilBuilds) end local methods = {} @@ -152,13 +183,13 @@ function mt:__eq(other) self.build == other.build end function mt:__lt(other) + print(self.build, other.build, smallerBuild(self.build, other.build)) + return self.major < other.major or self.minor < other.minor or self.patch < other.patch or - (self.prerelease and not other.prerelease) or - smallerPrereleaseOrBuild(self.prerelease, other.prerelease) or - (not self.build and other.build) or - smallerPrereleaseOrBuild(self.build, other.build) + smallerPrerelease(self.prerelease, other.prerelease) or + smallerBuild(self.build, other.build) end function mt:__pow(other) return self.major == other.major and diff --git a/spec/semver_spec.lua b/spec/semver_spec.lua index c8bebc0..e6bccbf 100644 --- a/spec/semver_spec.lua +++ b/spec/semver_spec.lua @@ -149,26 +149,37 @@ describe('semver', function() test("false if exact same prerelease", function() assert.is_false(v'1.0.0-beta' < v'1.0.0-beta') end) - test("a prerelease version is less than the official version", function() + test("#focus a prerelease version is less than the official version", function() assert.is_true(v'1.0.0-rc1' < v'1.0.0') + assert.is_true(v'1.2.3' > v'1.2.3-alpha') + assert.is_false(v'1.0.0-rc1' > v'1.0.0') + assert.is_false(v'1.2.3' < v'1.2.3-alpha') end) test("identifiers with only digits are compared numerically", function() assert.is_true(v'1.0.0-1' < v'1.0.0-2') - assert.is_true(v'1.0.0-2' < v'1.0.0-10') + assert.is_false(v'1.0.0-1' > v'1.0.0-2') end) test("idendifiers with letters or dashes are compared lexiconumerically", function() assert.is_true(v'1.0.0-alpha' < v'1.0.0-beta') assert.is_true(v'1.0.0-alpha-10' < v'1.0.0-alpha-2') + assert.is_false(v'1.0.0-alpha' > v'1.0.0-beta') + assert.is_false(v'1.0.0-alpha-10' > v'1.0.0-alpha-2') end) test("numerical ids always have less priority than lexiconumericals", function() assert.is_true(v'1.0.0-1' < v'1.0.0-alpha') assert.is_true(v'1.0.0-2' < v'1.0.0-1asdf') + assert.is_false(v'1.0.0-1' > v'1.0.0-alpha') + assert.is_false(v'1.0.0-2' > v'1.0.0-1asdf') end) test("identifiers can be separated by colons; they must be compared individually", function() - assert.is_true(v'1.0.0-alpha' < v'1.0.0-alpha.1') - assert.is_true(v'1.0.0-alpha.1' < v'1.0.0-beta.2') - assert.is_true(v'1.0.0-beta.2' < v'1.0.0-beta.11') - assert.is_true(v'1.0.0-beta.11' < v'1.0.0-rc.1') + --assert.is_true(v'1.0.0-alpha' < v'1.0.0-alpha.1') + --assert.is_true(v'1.0.0-alpha.1' < v'1.0.0-beta.2') + --assert.is_true(v'1.0.0-beta.2' < v'1.0.0-beta.11') + --assert.is_true(v'1.0.0-beta.11' < v'1.0.0-rc.1') + assert.is_false(v'1.0.0-alpha' > v'1.0.0-alpha.1') + --assert.is_false(v'1.0.0-alpha.1' > v'1.0.0-beta.2') + --assert.is_false(v'1.0.0-beta.2' > v'1.0.0-beta.11') + --assert.is_false(v'1.0.0-beta.11' > v'1.0.0-rc.1') end) end) describe("builds", function() @@ -177,28 +188,40 @@ describe('semver', function() end) test("a regular (not-build) version is always less than a build version", function() assert.is_true(v'1.0.0' < v'1.0.0+12') + assert.is_false(v'1.0.0' > v'1.0.0+12') end) test("identifiers with only digits are compared numerically", function() assert.is_true(v'1.0.0+1' < v'1.0.0+2') assert.is_true(v'1.0.0+2' < v'1.0.0+10') + assert.is_false(v'1.0.0+1' > v'1.0.0+2') + assert.is_false(v'1.0.0+2' > v'1.0.0+10') end) test("idendifiers with letters or dashes are compared lexiconumerically", function() assert.is_true(v'1.0.0+build1' < v'1.0.0+build2') assert.is_true(v'1.0.0+build10' < v'1.0.0+build2') + assert.is_false(v'1.0.0+build1' > v'1.0.0+build2') + assert.is_false(v'1.0.0+build10' > v'1.0.0+build2') end) test("numerical ids always have less priority than lexiconumericals", function() assert.is_true(v'1.0.0+1' < v'1.0.0+build1') assert.is_true(v'1.0.0+2' < v'1.0.0+1build') + assert.is_false(v'1.0.0+1' > v'1.0.0+build1') + assert.is_false(v'1.0.0+2' > v'1.0.0+1build') end) test("identifiers can be separated by colons; they must be compared individually", function() assert.is_true(v'1.0.0+0.3.7' < v'1.3.7+build') assert.is_true(v'1.3.7+build' < v'1.3.7+build.2.b8f12d7') assert.is_true(v'1.3.7+build.2.b8f12d7' < v'1.3.7+build.11.e0f985a') + assert.is_false(v'1.0.0+0.3.7' > v'1.3.7+build') + assert.is_false(v'1.3.7+build' > v'1.3.7+build.2.b8f12d7') + assert.is_false(v'1.3.7+build.2.b8f12d7' > v'1.3.7+build.11.e0f985a') end) end) - test("prereleases + builds", function() - assert.is_true(v'1.0.0-rc.1' < v'1.0.0-rc.1+build.1') - assert.is_true(v'1.0.0-rc.1+build.1' < v'1.0.0') + test("#focus prereleases + builds", function() + --assert.is_true(v'1.0.0-rc.1' < v'1.0.0-rc.1+build.1') + --assert.is_true(v'1.0.0-rc.1+build.1' < v'1.0.0') + --assert.is_false(v'1.0.0-rc.1' > v'1.0.0-rc.1+build.1') + assert.is_false(v'1.0.0-rc.1+build.1' > v'1.0.0') end) end)