Repository navigation
Expand file tree
/
Copy pathreleases.dang
More file actions
87 lines (83 loc) · 2.55 KB
/
Copy pathreleases.dang
File metadata and controls
87 lines (83 loc) · 2.55 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
"""
Engine releases as this SDK orders them: `v?MAJOR.MINOR.PATCH`, prerelease
identifiers after a "-" and a build after a "+", in semver precedence with
the build ignored.
"""
type Releases {
pub isRelease(v: String!): Boolean! {
v.match(Regexp(pattern)) != null
}
"""
A release as this SDK writes it, `v`-prefixed and without its build, or
`v` itself when it is no release.
"""
pub canonical(v: String!): String! {
let m = v.match(Regexp(pattern))
if (m == null) {
v
} else {
let c = m.captures
let pre = c[3] ?? ""
let suffix = if (pre == "") { "" } else { "-" + pre }
"v" + (c[0] ?? "") + "." + (c[1] ?? "") + "." + (c[2] ?? "") + suffix
}
}
"""
Whether release `a` comes before release `b`. False when either is no
release, so a version this cannot read never fails a check.
"""
pub precedes(a: String!, b: String!): Boolean! {
let ma = a.match(Regexp(pattern))
let mb = b.match(Regexp(pattern))
if (ma == null) {
false
} else if (mb == null) {
false
} else {
let ca = ma.captures
let cb = mb.captures
let coreA = [ca[0] ?? "", ca[1] ?? "", ca[2] ?? ""]
let coreB = [cb[0] ?? "", cb[1] ?? "", cb[2] ?? ""]
let preA = ca[3] ?? ""
let preB = cb[3] ?? ""
if (identifiersPrecede(coreA, coreB, 0)) {
true
} else if (identifiersPrecede(coreB, coreA, 0)) {
false
} else if (preA == "") {
false
} else if (preB == "") {
true
} else {
identifiersPrecede(preA.split("."), preB.split("."), 0)
}
}
}
"""
Semver precedence of dot-separated identifiers from index `i`: numbers by
value and before words, words by ASCII, and a shorter list first when one
is a prefix of the other.
"""
let identifiersPrecede(a: [String!]!, b: [String!]!, i: Int!): Boolean! {
if (i >= a.length) {
i < b.length
} else if (i >= b.length) {
false
} else {
let x = a[i] ?? ""
let y = b[i] ?? ""
let xNumber = x.containsMatch("^[0-9]+$")
let yNumber = y.containsMatch("^[0-9]+$")
if (x == y) {
identifiersPrecede(a, b, i + 1)
} else if (xNumber and yNumber) {
let xDigits = x.split("").length
let yDigits = y.split("").length
xDigits < yDigits or (xDigits == yDigits and x < y)
} else {
xNumber or (yNumber == false and x < y)
}
}
}
let pattern: String! = "^v?([0-9]+)\\.([0-9]+)\\.([0-9]+)(?:-([0-9A-Za-z-]+(?:\\.[0-9A-Za-z-]+)*))?(?:\\+[0-9A-Za-z-]+(?:\\.[0-9A-Za-z-]+)*)?$"
}