diff --git a/internal/cmd/genversionindex/main.go b/internal/cmd/genversionindex/main.go index eb00830819..836294b0e5 100644 --- a/internal/cmd/genversionindex/main.go +++ b/internal/cmd/genversionindex/main.go @@ -22,10 +22,7 @@ func minVersionIndex() ast.VersionIndex { } for _, v := range versions { - var sv semver.Version - if err := sv.Set(v[1:]); err != nil { - panic(err) - } + sv := semver.MustParse(v[1:]) c, err := ast.LoadCapabilitiesVersion(v) if err != nil { diff --git a/internal/report/report.go b/internal/report/report.go index bc71d66a3c..eab948499f 100644 --- a/internal/report/report.go +++ b/internal/report/report.go @@ -81,8 +81,6 @@ type GHResponse struct { // New returns an instance of the Reporter func New(opts Options) (Reporter, error) { - r := GHVersionCollector{} - url := cmp.Or(os.Getenv("OPA_TELEMETRY_SERVICE_URL"), ExternalServiceURL) restConfig := fmt.Appendf(nil, `{ @@ -93,7 +91,7 @@ func New(opts Options) (Reporter, error) { if err != nil { return nil, err } - r.client = client + r := GHVersionCollector{client: client} // heap_usage_bytes is always present, so register it unconditionally r.RegisterGatherer("heap_usage_bytes", readRuntimeMemStats) @@ -135,19 +133,17 @@ func createDataResponse(ghResp GHResponse) (*DataResponse, error) { return nil, errors.New("server response does not contain tag_name") } - v := strings.TrimPrefix(version.Version, "v") - sv, err := semver.NewVersion(v) + sv, err := semver.Parse(version.Version) if err != nil { - return nil, fmt.Errorf("failed to parse current version %q: %w", v, err) + return nil, fmt.Errorf("failed to parse current version %q: %w", version.Version, err) } - latestV := strings.TrimPrefix(ghResp.TagName, "v") - latestSV, err := semver.NewVersion(latestV) + latestSV, err := semver.Parse(ghResp.TagName) if err != nil { - return nil, fmt.Errorf("failed to parse latest version %q: %w", latestV, err) + return nil, fmt.Errorf("failed to parse latest version %q: %w", ghResp.TagName, err) } - isLatest := sv.Compare(*latestSV) >= 0 + isLatest := sv.Compare(latestSV) >= 0 // Note: alternatively, we could look through the assets in the GH API response to find a matching asset, // and use its URL. However, this is not guaranteed to be more robust, and wouldn't use the 'openpolicyagent.org' domain. diff --git a/internal/semver/semver.go b/internal/semver/semver.go index 23c6c186d9..725f86318a 100644 --- a/internal/semver/semver.go +++ b/internal/semver/semver.go @@ -14,237 +14,234 @@ // Semantic Versions http://semver.org -// Package semver has been vendored from: +// This file was originally vendored from: // https://github.com/coreos/go-semver/tree/e214231b295a8ea9479f11b70b35d5acf3556d9b/semver -// A number of the original functions of the package have been removed since -// they are not required for our built-ins. +// There isn't a single line left from the original source today, but being generous about +// attribution won't hurt. package semver import ( - "bytes" "fmt" "regexp" "strconv" "strings" + + "github.com/open-policy-agent/opa/v1/util" ) +// reMetaIdentifier matches pre-release and metadata identifiers against the spec requirements +var reMetaIdentifier = regexp.MustCompile(`^[0-9A-Za-z-]+(\.[0-9A-Za-z-]+)*$`) + // Version represents a parsed SemVer type Version struct { Major int64 Minor int64 Patch int64 - PreRelease PreRelease - Metadata string + PreRelease string `json:"PreRelease,omitempty"` + Metadata string `json:"Metadata,omitempty"` } -// PreRelease represents a pre-release suffix string -type PreRelease string +// Parse constructs new semver Version from version string. +func Parse(version string) (v Version, err error) { + version = strings.TrimPrefix(version, "v") -func splitOff(input *string, delim string) (val string) { - parts := strings.SplitN(*input, delim, 2) - - if len(parts) == 2 { - *input = parts[0] - val = parts[1] + version, v.Metadata = cut(version, '+') + if v.Metadata != "" && !reMetaIdentifier.MatchString(v.Metadata) { + return v, fmt.Errorf("invalid metadata identifier: %s", v.Metadata) } - return val + version, v.PreRelease = cut(version, '-') + if v.PreRelease != "" && !reMetaIdentifier.MatchString(v.PreRelease) { + return v, fmt.Errorf("invalid pre-release identifier: %s", v.PreRelease) + } + + if strings.Count(version, ".") != 2 { + return v, fmt.Errorf("%s should contain major, minor, and patch versions", version) + } + + major, after := cut(version, '.') + if v.Major, err = strconv.ParseInt(major, 10, 64); err != nil { + return v, err + } + + minor, after := cut(after, '.') + if v.Minor, err = strconv.ParseInt(minor, 10, 64); err != nil { + return v, err + } + + if v.Patch, err = strconv.ParseInt(after, 10, 64); err != nil { + return v, err + } + + return v, nil } -// NewVersion constructs new SemVers from strings -func NewVersion(version string) (*Version, error) { - v := Version{} - - if err := v.Set(version); err != nil { - return nil, err +// MustParse is like Parse but panics if the version string is invalid instead of returning an error. +func MustParse(version string) Version { + v, err := Parse(version) + if err != nil { + panic(err) } - return &v, nil + return v } -// Set parses and updates v from the given version string. Implements flag.Value -func (v *Version) Set(version string) error { - metadata := splitOff(&version, "+") - preRelease := PreRelease(splitOff(&version, "-")) - dotParts := strings.SplitN(version, ".", 3) - - if len(dotParts) != 3 { - return fmt.Errorf("%s is not in dotted-tri format", version) - } - - if err := validateIdentifier(string(preRelease)); err != nil { - return fmt.Errorf("failed to validate pre-release: %v", err) - } - - if err := validateIdentifier(metadata); err != nil { - return fmt.Errorf("failed to validate metadata: %v", err) - } - - parsed := make([]int64, 3) - - for i, v := range dotParts[:3] { - val, err := strconv.ParseInt(v, 10, 64) - parsed[i] = val - if err != nil { - return err - } - } - - v.Metadata = metadata - v.PreRelease = preRelease - v.Major = parsed[0] - v.Minor = parsed[1] - v.Patch = parsed[2] - return nil -} - -func (v Version) String() string { - var buffer bytes.Buffer - - fmt.Fprintf(&buffer, "%d.%d.%d", v.Major, v.Minor, v.Patch) - - if v.PreRelease != "" { - fmt.Fprintf(&buffer, "-%s", v.PreRelease) - } - - if v.Metadata != "" { - fmt.Fprintf(&buffer, "+%s", v.Metadata) - } - - return buffer.String() -} - -// Compare tests if v is less than, equal to, or greater than versionB, -// returning -1, 0, or +1 respectively. -func (v Version) Compare(versionB Version) int { - if cmp := recursiveCompare(v.Slice(), versionB.Slice()); cmp != 0 { - return cmp - } - return preReleaseCompare(v, versionB) -} - -// Slice converts the comparable parts of the semver into a slice of integers. -func (v Version) Slice() []int64 { - return []int64{v.Major, v.Minor, v.Patch} -} - -// Slice splits the pre-release suffix string -func (p PreRelease) Slice() []string { - preRelease := string(p) - return strings.Split(preRelease, ".") -} - -func preReleaseCompare(versionA Version, versionB Version) int { - a := versionA.PreRelease - b := versionB.PreRelease - - /* Handle the case where if two versions are otherwise equal it is the - * one without a PreRelease that is greater */ - if len(a) == 0 && (len(b) > 0) { - return 1 - } else if len(b) == 0 && (len(a) > 0) { - return -1 - } - - // If there is a prerelease, check and compare each part. - return recursivePreReleaseCompare(a.Slice(), b.Slice()) -} - -func recursiveCompare(versionA []int64, versionB []int64) int { - if len(versionA) == 0 { - return 0 - } - - a := versionA[0] - b := versionB[0] - - if a > b { - return 1 - } else if a < b { - return -1 - } - - return recursiveCompare(versionA[1:], versionB[1:]) -} - -func recursivePreReleaseCompare(versionA []string, versionB []string) int { - // A larger set of pre-release fields has a higher precedence than a smaller set, - // if all of the preceding identifiers are equal. - if len(versionA) == 0 { - if len(versionB) > 0 { - return -1 - } - return 0 - } else if len(versionB) == 0 { - // We're longer than versionB so return 1. - return 1 - } - - a := versionA[0] - b := versionB[0] - - aInt := false - bInt := false - - aI, err := strconv.Atoi(versionA[0]) - if err == nil { - aInt = true - } - - bI, err := strconv.Atoi(versionB[0]) - if err == nil { - bInt = true - } - - // Numeric identifiers always have lower precedence than non-numeric identifiers. - if aInt && !bInt { - return -1 - } else if !aInt && bInt { - return 1 - } - - // Handle Integer Comparison - if aInt && bInt { - if aI > bI { - return 1 - } else if aI < bI { - return -1 - } - } - - // Handle String Comparison - if a > b { - return 1 - } else if a < b { - return -1 - } - - return recursivePreReleaseCompare(versionA[1:], versionB[1:]) -} - -// validateIdentifier makes sure the provided identifier satisfies semver spec -func validateIdentifier(id string) error { - if id != "" && !reIdentifier.MatchString(id) { - return fmt.Errorf("%s is not a valid semver identifier", id) - } - return nil -} - -// reIdentifier is a regular expression used to check that pre-release and metadata -// identifiers satisfy the spec requirements -var reIdentifier = regexp.MustCompile(`^[0-9A-Za-z-]+(\.[0-9A-Za-z-]+)*$`) - // Compare compares two semver strings. func Compare(a, b string) int { - aV, err := NewVersion(strings.TrimPrefix(a, "v")) + aV, err := Parse(a) if err != nil { return -1 } - bV, err := NewVersion(strings.TrimPrefix(b, "v")) + bV, err := Parse(b) if err != nil { return 1 } - return aV.Compare(*bV) + return aV.Compare(bV) +} + +// AppendText appends the textual representation of the version to b and returns the extended buffer. +// This method conforms to the encoding.TextAppender interface, and is useful for serializing the Version +// without allocating, provided the caller has pre-allocated sufficient space in b. +func (v Version) AppendText(b []byte) ([]byte, error) { + if b == nil { + b = make([]byte, 0, length(v)) + } + + b = append(strconv.AppendInt(b, v.Major, 10), '.') + b = append(strconv.AppendInt(b, v.Minor, 10), '.') + b = strconv.AppendInt(b, v.Patch, 10) + + if v.PreRelease != "" { + b = append(append(b, '-'), v.PreRelease...) + } + if v.Metadata != "" { + b = append(append(b, '+'), v.Metadata...) + } + + return b, nil +} + +// String returns the string representation of the version. +func (v Version) String() string { + bs := make([]byte, 0, length(v)) + bs, _ = v.AppendText(bs) + + return string(bs) +} + +// Compare tests if v is less than, equal to, or greater than other, returning -1, 0, or +1 respectively. +// Comparison is based on the SemVer specification (https://semver.org/#spec-item-11). +func (v Version) Compare(other Version) int { + if v.Major > other.Major { + return 1 + } else if v.Major < other.Major { + return -1 + } + + if v.Minor > other.Minor { + return 1 + } else if v.Minor < other.Minor { + return -1 + } + + if v.Patch > other.Patch { + return 1 + } else if v.Patch < other.Patch { + return -1 + } + + if v.PreRelease == other.PreRelease { + return 0 + } + + // if two versions are otherwise equal it is the one without a pre-release that is greater + if v.PreRelease == "" && other.PreRelease != "" { + return 1 + } + if other.PreRelease == "" && v.PreRelease != "" { + return -1 + } + + a, afterA := cut(v.PreRelease, '.') + b, afterB := cut(other.PreRelease, '.') + + for { + if a == "" && b != "" { + return -1 + } + if a != "" && b == "" { + return 1 + } + + aIsInt := isAllDecimals(a) + bIsInt := isAllDecimals(b) + + // numeric identifiers have lower precedence than non-numeric + if aIsInt && !bIsInt { + return -1 + } else if !aIsInt && bIsInt { + return 1 + } + + if aIsInt && bIsInt { + aInt, _ := strconv.Atoi(a) + bInt, _ := strconv.Atoi(b) + + if aInt > bInt { + return 1 + } else if aInt < bInt { + return -1 + } + } else { + // string comparison + if a > b { + return 1 + } else if a < b { + return -1 + } + } + + // a larger set of pre-release fields has a higher precedence than a + // smaller set, if all of the preceding identifiers are equal. + if afterA != "" && afterB == "" { + return 1 + } else if afterA == "" && afterB != "" { + return -1 + } + + a, afterA = cut(afterA, '.') + b, afterB = cut(afterB, '.') + } +} + +func isAllDecimals(s string) bool { + for _, r := range s { + if r < '0' || r > '9' { + return false + } + } + return s != "" +} + +// length allows calculating the length of the version for pre-allocation. +func length(v Version) int { + n := util.NumDigitsInt64(v.Major) + util.NumDigitsInt64(v.Minor) + util.NumDigitsInt64(v.Patch) + 2 + if v.PreRelease != "" { + n += len(v.PreRelease) + 1 + } + if v.Metadata != "" { + n += len(v.Metadata) + 1 + } + return n +} + +// cut is a *slightly* faster version of strings.Cut only accepting +// single byte separators, and skipping the boolean return value. +func cut(s string, sep byte) (before, after string) { + if i := strings.IndexByte(s, sep); i >= 0 { + return s[:i], s[i+1:] + } + return s, "" } diff --git a/internal/semver/semver_test.go b/internal/semver/semver_test.go index d4b7780e0d..b49b2c6339 100644 --- a/internal/semver/semver_test.go +++ b/internal/semver/semver_test.go @@ -12,76 +12,98 @@ // See the License for the specific language governing permissions and // limitations under the License. -// vendored from: https://github.com/coreos/go-semver/tree/e214231b295a8ea9479f11b70b35d5acf3556d9b/semver +// originally vendored from: https://github.com/coreos/go-semver/tree/e214231b295a8ea9479f11b70b35d5acf3556d9b/semver package semver import ( "testing" ) -type fixture struct { - GreaterVersion string - LesserVersion string -} +type ( + fixture struct { + greater string + lesser string + } -var fixtures = []fixture{ - {"0.0.0", "0.0.0-foo"}, - {"0.0.1", "0.0.0"}, - {"1.0.0", "0.9.9"}, - {"0.10.0", "0.9.0"}, - {"0.99.0", "0.10.0"}, - {"2.0.0", "1.2.3"}, - {"0.0.0", "0.0.0-foo"}, - {"0.0.1", "0.0.0"}, - {"1.0.0", "0.9.9"}, - {"0.10.0", "0.9.0"}, - {"0.99.0", "0.10.0"}, - {"2.0.0", "1.2.3"}, - {"0.0.0", "0.0.0-foo"}, - {"0.0.1", "0.0.0"}, - {"1.0.0", "0.9.9"}, - {"0.10.0", "0.9.0"}, - {"0.99.0", "0.10.0"}, - {"2.0.0", "1.2.3"}, - {"1.2.3", "1.2.3-asdf"}, - {"1.2.3", "1.2.3-4"}, - {"1.2.3", "1.2.3-4-foo"}, - {"1.2.3-5-foo", "1.2.3-5"}, - {"1.2.3-5", "1.2.3-4"}, - {"1.2.3-5-foo", "1.2.3-5-Foo"}, - {"3.0.0", "2.7.2+asdf"}, - {"3.0.0+foobar", "2.7.2"}, - {"1.2.3-a.10", "1.2.3-a.5"}, - {"1.2.3-a.b", "1.2.3-a.5"}, - {"1.2.3-a.b", "1.2.3-a"}, - {"1.2.3-a.b.c.10.d.5", "1.2.3-a.b.c.5.d.100"}, - {"1.0.0", "1.0.0-rc.1"}, - {"1.0.0-rc.2", "1.0.0-rc.1"}, - {"1.0.0-rc.1", "1.0.0-beta.11"}, - {"1.0.0-beta.11", "1.0.0-beta.2"}, - {"1.0.0-beta.2", "1.0.0-beta"}, - {"1.0.0-beta", "1.0.0-alpha.beta"}, - {"1.0.0-alpha.beta", "1.0.0-alpha.1"}, - {"1.0.0-alpha.1", "1.0.0-alpha"}, - {"1.2.3-rc.1-1-1hash", "1.2.3-rc.2"}, + compareFixture struct { + greater Version + lesser Version + } +) + +var ( + fixtures = []fixture{ + {"0.0.0", "0.0.0-foo"}, + {"0.0.1", "0.0.0"}, + {"1.0.0", "0.9.9"}, + {"0.10.0", "0.9.0"}, + {"0.99.0", "0.10.0"}, + {"2.0.0", "1.2.3"}, + {"0.0.0", "0.0.0-foo"}, + {"0.0.1", "0.0.0"}, + {"1.0.0", "0.9.9"}, + {"0.10.0", "0.9.0"}, + {"0.99.0", "0.10.0"}, + {"2.0.0", "1.2.3"}, + {"0.0.0", "0.0.0-foo"}, + {"0.0.1", "0.0.0"}, + {"1.0.0", "0.9.9"}, + {"0.10.0", "0.9.0"}, + {"0.99.0", "0.10.0"}, + {"2.0.0", "1.2.3"}, + {"1.2.3", "1.2.3-asdf"}, + {"1.2.3", "1.2.3-4"}, + {"1.2.3", "1.2.3-4-foo"}, + {"1.2.3-5-foo", "1.2.3-5"}, + {"1.2.3-5", "1.2.3-4"}, + {"1.2.3-5-foo", "1.2.3-5-Foo"}, + {"3.0.0", "2.7.2+asdf"}, + {"3.0.0+foobar", "2.7.2"}, + {"1.2.3-a.10", "1.2.3-a.5"}, + {"1.2.3-a.b", "1.2.3-a.5"}, + {"1.2.3-a.b", "1.2.3-a"}, + {"1.2.3-a.b.c.10.d.5", "1.2.3-a.b.c.5.d.100"}, + {"1.0.0", "1.0.0-rc.1"}, + {"1.0.0-rc.2", "1.0.0-rc.1"}, + {"1.0.0-rc.1", "1.0.0-beta.11"}, + {"1.0.0-beta.11", "1.0.0-beta.2"}, + {"1.0.0-beta.2", "1.0.0-beta"}, + {"1.0.0-beta", "1.0.0-alpha.beta"}, + {"1.0.0-alpha.beta", "1.0.0-alpha.1"}, + {"1.0.0-alpha.1", "1.0.0-alpha"}, + {"1.2.3-rc.1-1-1hash", "1.2.3-rc.2"}, + } + + equalFixtures = []string{ + "0.0.0", + "1.2.3", + "1.2.3-rc.1", + "1.2.3+build.123", + "1.2.3-rc.1+build.123", + "1.2.3-rc.1+build.123.444", + } +) + +func TestCompareEqual(t *testing.T) { + for _, v := range equalFixtures { + a := MustParse(v) + o := a + + if a.Compare(o) != 0 { + t.Errorf("Expected %s to be equal to %s", a, o) + } + } } func TestCompare(t *testing.T) { for _, v := range fixtures { - gt, err := NewVersion(v.GreaterVersion) - if err != nil { - t.Error(err) - } + gt := MustParse(v.greater) + lt := MustParse(v.lesser) - lt, err := NewVersion(v.LesserVersion) - if err != nil { - t.Error(err) - } - - if gt.Compare(*lt) <= 0 { + if gt.Compare(lt) <= 0 { t.Errorf("%s should be greater than %s", gt, lt) } - if lt.Compare(*gt) > 0 { + if lt.Compare(gt) > 0 { t.Errorf("%s should not be greater than %s", lt, gt) } } @@ -98,8 +120,97 @@ func TestBadInput(t *testing.T) { "0.88.0+11_e4e5dcabb", } for _, b := range bad { - if _, err := NewVersion(b); err == nil { + if _, err := Parse(b); err == nil { t.Error("Improperly accepted value: ", b) } } } + +func BenchmarkCompare(b *testing.B) { + versionFixtures := make([]compareFixture, 0, len(fixtures)) + for _, v := range fixtures { + versionFixtures = append(versionFixtures, compareFixture{ + greater: MustParse(v.greater), + lesser: MustParse(v.lesser), + }) + } + + for b.Loop() { + for _, v := range versionFixtures { + if v.greater.Compare(v.lesser) <= 0 { + b.Fatalf("%s should be greater than %s", v.greater, v.lesser) + } + if v.lesser.Compare(v.greater) > 0 { + b.Fatalf("%s should not be greater than %s", v.lesser, v.greater) + } + } + } +} + +func BenchmarkCompareEqual(b *testing.B) { + versionFixtures := make([]Version, 0, len(equalFixtures)) + for _, v := range equalFixtures { + versionFixtures = append(versionFixtures, MustParse(v)) + } + + for b.Loop() { + for _, v := range versionFixtures { + o := v + if v.Compare(o) != 0 { + b.Fatalf("Expected %s to be equal to %s", v, o) + } + } + } +} + +func BenchmarkString(b *testing.B) { + v := MustParse("1.2.3-alpha.1+build.123") + + for b.Loop() { + if s := v.String(); s != "1.2.3-alpha.1+build.123" { + b.Fatalf("unexpected version string: %s", s) + } + } +} + +func BenchmarkAppendText(b *testing.B) { + v := MustParse("1.2.3-alpha.1+build.123") + + for b.Loop() { + _, err := v.AppendText(nil) + if err != nil { + b.Fatal(err) + } + } +} + +func BenchmarkAppendTextPreAllocated(b *testing.B) { + v, err := Parse("1.2.3-alpha.1+build.123") + if err != nil { + b.Fatal(err) + } + + buf := make([]byte, 0, 32) + + for b.Loop() { + if buf, err = v.AppendText(buf); err != nil { + b.Fatal(err) + } + if string(buf) != "1.2.3-alpha.1+build.123" { + b.Fatal("unexpected version string") + } + buf = buf[:0] + } +} + +func BenchmarkParseSimple(b *testing.B) { + for b.Loop() { + MustParse("1.2.3") + } +} + +func BenchmarkParsePrereleaseAndMetadata(b *testing.B) { + for b.Loop() { + MustParse("1.2.3-alpha.1+build.123") + } +} diff --git a/v1/ast/capabilities.go b/v1/ast/capabilities.go index 844cb66f0b..0461aab8bc 100644 --- a/v1/ast/capabilities.go +++ b/v1/ast/capabilities.go @@ -228,13 +228,8 @@ func LoadCapabilitiesVersions() ([]string, error) { // MinimumCompatibleVersion returns the minimum compatible OPA version based on // the built-ins, features, and keywords in c. func (c *Capabilities) MinimumCompatibleVersion() (string, bool) { - var maxVersion semver.Version - // this is the oldest OPA release that includes capabilities - if err := maxVersion.Set("0.17.0"); err != nil { - panic("unreachable") - } - + maxVersion := semver.MustParse("0.17.0") minVersionIndex := minVersionIndexOnce() for _, bi := range c.Builtins { diff --git a/v1/ast/version_index.json b/v1/ast/version_index.json index b02f785299..32cf2e50f6 100644 --- a/v1/ast/version_index.json +++ b/v1/ast/version_index.json @@ -3,1476 +3,1062 @@ "abs": { "Major": 0, "Minor": 17, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "all": { "Major": 0, "Minor": 17, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "and": { "Major": 0, "Minor": 17, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "any": { "Major": 0, "Minor": 17, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "array.concat": { "Major": 0, "Minor": 17, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "array.reverse": { "Major": 0, "Minor": 36, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "array.slice": { "Major": 0, "Minor": 17, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "assign": { "Major": 0, "Minor": 17, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "base64.decode": { "Major": 0, "Minor": 17, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "base64.encode": { "Major": 0, "Minor": 17, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "base64.is_valid": { "Major": 0, "Minor": 24, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "base64url.decode": { "Major": 0, "Minor": 17, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "base64url.encode": { "Major": 0, "Minor": 17, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "base64url.encode_no_pad": { "Major": 0, "Minor": 25, "Patch": 0, - "PreRelease": "rc2", - "Metadata": "" + "PreRelease": "rc2" }, "bits.and": { "Major": 0, "Minor": 18, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "bits.lsh": { "Major": 0, "Minor": 18, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "bits.negate": { "Major": 0, "Minor": 18, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "bits.or": { "Major": 0, "Minor": 18, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "bits.rsh": { "Major": 0, "Minor": 18, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "bits.xor": { "Major": 0, "Minor": 18, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "cast_array": { "Major": 0, "Minor": 17, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "cast_boolean": { "Major": 0, "Minor": 17, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "cast_null": { "Major": 0, "Minor": 17, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "cast_object": { "Major": 0, "Minor": 17, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "cast_set": { "Major": 0, "Minor": 17, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "cast_string": { "Major": 0, "Minor": 17, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "ceil": { "Major": 0, "Minor": 26, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "concat": { "Major": 0, "Minor": 17, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "contains": { "Major": 0, "Minor": 17, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "count": { "Major": 0, "Minor": 17, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "crypto.hmac.equal": { "Major": 0, "Minor": 52, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "crypto.hmac.md5": { "Major": 0, "Minor": 36, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "crypto.hmac.sha1": { "Major": 0, "Minor": 36, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "crypto.hmac.sha256": { "Major": 0, "Minor": 36, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "crypto.hmac.sha512": { "Major": 0, "Minor": 36, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "crypto.md5": { "Major": 0, "Minor": 17, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "crypto.parse_private_keys": { "Major": 0, "Minor": 55, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "crypto.sha1": { "Major": 0, "Minor": 17, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "crypto.sha256": { "Major": 0, "Minor": 17, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "crypto.x509.parse_and_verify_certificates": { "Major": 0, "Minor": 31, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "crypto.x509.parse_and_verify_certificates_with_options": { "Major": 0, "Minor": 63, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "crypto.x509.parse_certificate_request": { "Major": 0, "Minor": 21, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "crypto.x509.parse_certificates": { "Major": 0, "Minor": 17, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "crypto.x509.parse_keypair": { "Major": 0, "Minor": 53, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "crypto.x509.parse_rsa_private_key": { "Major": 0, "Minor": 33, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "div": { "Major": 0, "Minor": 17, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "endswith": { "Major": 0, "Minor": 17, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "eq": { "Major": 0, "Minor": 17, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "equal": { "Major": 0, "Minor": 17, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "floor": { "Major": 0, "Minor": 26, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "format_int": { "Major": 0, "Minor": 17, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "glob.match": { "Major": 0, "Minor": 17, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "glob.quote_meta": { "Major": 0, "Minor": 17, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "graph.reachable": { "Major": 0, "Minor": 20, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "graph.reachable_paths": { "Major": 0, "Minor": 37, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "graphql.is_valid": { "Major": 0, "Minor": 41, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "graphql.parse": { "Major": 0, "Minor": 41, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "graphql.parse_and_verify": { "Major": 0, "Minor": 41, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "graphql.parse_query": { "Major": 0, "Minor": 41, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "graphql.parse_schema": { "Major": 0, "Minor": 41, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "graphql.schema_is_valid": { "Major": 0, "Minor": 46, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "gt": { "Major": 0, "Minor": 17, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "gte": { "Major": 0, "Minor": 17, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "hex.decode": { "Major": 0, "Minor": 25, "Patch": 0, - "PreRelease": "rc2", - "Metadata": "" + "PreRelease": "rc2" }, "hex.encode": { "Major": 0, "Minor": 25, "Patch": 0, - "PreRelease": "rc2", - "Metadata": "" + "PreRelease": "rc2" }, "http.send": { "Major": 0, "Minor": 17, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "indexof": { "Major": 0, "Minor": 17, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "indexof_n": { "Major": 0, "Minor": 37, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "internal.member_2": { "Major": 0, "Minor": 34, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "internal.member_3": { "Major": 0, "Minor": 34, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "internal.print": { "Major": 0, "Minor": 34, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "internal.test_case": { "Major": 1, "Minor": 2, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "intersection": { "Major": 0, "Minor": 17, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "io.jwt.decode": { "Major": 0, "Minor": 17, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "io.jwt.decode_verify": { "Major": 0, "Minor": 17, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "io.jwt.encode_sign": { "Major": 0, "Minor": 17, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "io.jwt.encode_sign_raw": { "Major": 0, "Minor": 17, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "io.jwt.verify_eddsa": { "Major": 1, "Minor": 8, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "io.jwt.verify_es256": { "Major": 0, "Minor": 17, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "io.jwt.verify_es384": { "Major": 0, "Minor": 20, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "io.jwt.verify_es512": { "Major": 0, "Minor": 20, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "io.jwt.verify_hs256": { "Major": 0, "Minor": 17, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "io.jwt.verify_hs384": { "Major": 0, "Minor": 20, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "io.jwt.verify_hs512": { "Major": 0, "Minor": 20, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "io.jwt.verify_ps256": { "Major": 0, "Minor": 17, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "io.jwt.verify_ps384": { "Major": 0, "Minor": 20, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "io.jwt.verify_ps512": { "Major": 0, "Minor": 20, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "io.jwt.verify_rs256": { "Major": 0, "Minor": 17, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "io.jwt.verify_rs384": { "Major": 0, "Minor": 20, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "io.jwt.verify_rs512": { "Major": 0, "Minor": 20, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "is_array": { "Major": 0, "Minor": 17, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "is_boolean": { "Major": 0, "Minor": 17, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "is_null": { "Major": 0, "Minor": 17, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "is_number": { "Major": 0, "Minor": 17, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "is_object": { "Major": 0, "Minor": 17, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "is_set": { "Major": 0, "Minor": 17, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "is_string": { "Major": 0, "Minor": 17, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "json.filter": { "Major": 0, "Minor": 17, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "json.is_valid": { "Major": 0, "Minor": 25, "Patch": 0, - "PreRelease": "rc1", - "Metadata": "" + "PreRelease": "rc1" }, "json.marshal": { "Major": 0, "Minor": 17, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "json.marshal_with_options": { "Major": 0, "Minor": 64, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "json.match_schema": { "Major": 0, "Minor": 50, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "json.patch": { "Major": 0, "Minor": 25, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "json.remove": { "Major": 0, "Minor": 18, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "json.unmarshal": { "Major": 0, "Minor": 17, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "json.verify_schema": { "Major": 0, "Minor": 50, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "lower": { "Major": 0, "Minor": 17, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "lt": { "Major": 0, "Minor": 17, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "lte": { "Major": 0, "Minor": 17, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "max": { "Major": 0, "Minor": 17, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "min": { "Major": 0, "Minor": 17, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "minus": { "Major": 0, "Minor": 17, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "mul": { "Major": 0, "Minor": 17, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "neq": { "Major": 0, "Minor": 17, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "net.cidr_contains": { "Major": 0, "Minor": 17, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "net.cidr_contains_matches": { "Major": 0, "Minor": 19, "Patch": 0, - "PreRelease": "rc1", - "Metadata": "" + "PreRelease": "rc1" }, "net.cidr_expand": { "Major": 0, "Minor": 17, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "net.cidr_intersects": { "Major": 0, "Minor": 17, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "net.cidr_is_valid": { "Major": 0, "Minor": 46, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "net.cidr_merge": { "Major": 0, "Minor": 24, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "net.cidr_overlap": { "Major": 0, "Minor": 17, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "net.lookup_ip_addr": { "Major": 0, "Minor": 35, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "numbers.range": { "Major": 0, "Minor": 22, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "numbers.range_step": { "Major": 0, "Minor": 56, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "object.filter": { "Major": 0, "Minor": 17, - "Patch": 2, - "PreRelease": "", - "Metadata": "" + "Patch": 2 }, "object.get": { "Major": 0, "Minor": 17, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "object.keys": { "Major": 0, "Minor": 47, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "object.remove": { "Major": 0, "Minor": 17, - "Patch": 2, - "PreRelease": "", - "Metadata": "" + "Patch": 2 }, "object.subset": { "Major": 0, "Minor": 42, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "object.union": { "Major": 0, "Minor": 17, - "Patch": 2, - "PreRelease": "", - "Metadata": "" + "Patch": 2 }, "object.union_n": { "Major": 0, "Minor": 37, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "opa.runtime": { "Major": 0, "Minor": 17, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "or": { "Major": 0, "Minor": 17, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "plus": { "Major": 0, "Minor": 17, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "print": { "Major": 0, "Minor": 34, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "product": { "Major": 0, "Minor": 17, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "providers.aws.sign_req": { "Major": 0, "Minor": 47, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "rand.intn": { "Major": 0, "Minor": 31, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "re_match": { "Major": 0, "Minor": 17, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "regex.find_all_string_submatch_n": { "Major": 0, "Minor": 17, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "regex.find_n": { "Major": 0, "Minor": 17, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "regex.globs_match": { "Major": 0, "Minor": 17, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "regex.is_valid": { "Major": 0, "Minor": 23, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "regex.match": { "Major": 0, "Minor": 23, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "regex.replace": { "Major": 0, "Minor": 45, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "regex.split": { "Major": 0, "Minor": 17, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "regex.template_match": { "Major": 0, "Minor": 17, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "rego.metadata.chain": { "Major": 0, "Minor": 40, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "rego.metadata.rule": { "Major": 0, "Minor": 40, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "rego.parse_module": { "Major": 0, "Minor": 17, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "rem": { "Major": 0, "Minor": 17, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "replace": { "Major": 0, "Minor": 17, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "round": { "Major": 0, "Minor": 17, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "semver.compare": { "Major": 0, "Minor": 22, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "semver.is_valid": { "Major": 0, "Minor": 22, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "set_diff": { "Major": 0, "Minor": 17, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "sort": { "Major": 0, "Minor": 17, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "split": { "Major": 0, "Minor": 17, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "sprintf": { "Major": 0, "Minor": 17, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "startswith": { "Major": 0, "Minor": 17, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "strings.any_prefix_match": { "Major": 0, "Minor": 44, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "strings.any_suffix_match": { "Major": 0, "Minor": 44, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "strings.count": { "Major": 0, "Minor": 67, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "strings.render_template": { "Major": 0, "Minor": 59, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "strings.replace_n": { "Major": 0, "Minor": 17, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "strings.reverse": { "Major": 0, "Minor": 36, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "substring": { "Major": 0, "Minor": 17, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "sum": { "Major": 0, "Minor": 17, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "time.add_date": { "Major": 0, "Minor": 19, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "time.clock": { "Major": 0, "Minor": 17, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "time.date": { "Major": 0, "Minor": 17, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "time.diff": { "Major": 0, "Minor": 28, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "time.format": { "Major": 0, "Minor": 48, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "time.now_ns": { "Major": 0, "Minor": 17, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "time.parse_duration_ns": { "Major": 0, "Minor": 17, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "time.parse_ns": { "Major": 0, "Minor": 17, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "time.parse_rfc3339_ns": { "Major": 0, "Minor": 17, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "time.weekday": { "Major": 0, "Minor": 17, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "to_number": { "Major": 0, "Minor": 17, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "trace": { "Major": 0, "Minor": 17, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "trim": { "Major": 0, "Minor": 17, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "trim_left": { "Major": 0, "Minor": 17, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "trim_prefix": { "Major": 0, "Minor": 17, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "trim_right": { "Major": 0, "Minor": 17, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "trim_space": { "Major": 0, "Minor": 17, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "trim_suffix": { "Major": 0, "Minor": 17, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "type_name": { "Major": 0, "Minor": 17, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "union": { "Major": 0, "Minor": 17, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "units.parse": { "Major": 0, "Minor": 41, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "units.parse_bytes": { "Major": 0, "Minor": 17, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "upper": { "Major": 0, "Minor": 17, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "urlquery.decode": { "Major": 0, "Minor": 17, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "urlquery.decode_object": { "Major": 0, "Minor": 24, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "urlquery.encode": { "Major": 0, "Minor": 17, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "urlquery.encode_object": { "Major": 0, "Minor": 17, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "uuid.parse": { "Major": 0, "Minor": 57, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "uuid.rfc4122": { "Major": 0, "Minor": 20, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "walk": { "Major": 0, "Minor": 17, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "yaml.is_valid": { "Major": 0, "Minor": 25, "Patch": 0, - "PreRelease": "rc1", - "Metadata": "" + "PreRelease": "rc1" }, "yaml.marshal": { "Major": 0, "Minor": 17, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "yaml.unmarshal": { "Major": 0, "Minor": 17, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 } }, "features": { "keywords_in_refs": { "Major": 1, "Minor": 6, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "rego_v1": { "Major": 1, "Minor": 0, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "rego_v1_import": { "Major": 0, "Minor": 59, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "rule_head_ref_string_prefixes": { "Major": 0, "Minor": 46, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "rule_head_refs": { "Major": 0, "Minor": 59, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 } }, "keywords": { "contains": { "Major": 0, "Minor": 42, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "every": { "Major": 0, "Minor": 38, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "if": { "Major": 0, "Minor": 42, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 }, "in": { "Major": 0, "Minor": 34, - "Patch": 0, - "PreRelease": "", - "Metadata": "" + "Patch": 0 } } } diff --git a/v1/compile/compile.go b/v1/compile/compile.go index 2c832253d2..7922c378d6 100644 --- a/v1/compile/compile.go +++ b/v1/compile/compile.go @@ -1268,11 +1268,12 @@ func compile(c *ast.Capabilities, b *bundle.Bundle, dbg debug.Debug, enablePrint return nil, compiler.Errors } - minVersion, ok := compiler.Required.MinimumCompatibleVersion() - if !ok { - dbg.Printf("could not determine minimum compatible version!") - } else { - dbg.Printf("minimum compatible version: %v", minVersion) + if dbg.Writer() != io.Discard { + if minVersion, ok := compiler.Required.MinimumCompatibleVersion(); !ok { + dbg.Printf("could not determine minimum compatible version!") + } else { + dbg.Printf("minimum compatible version: %v", minVersion) + } } return compiler, nil diff --git a/v1/topdown/semver.go b/v1/topdown/semver.go index 3b79ebd586..1b2ac79038 100644 --- a/v1/topdown/semver.go +++ b/v1/topdown/semver.go @@ -23,34 +23,25 @@ func builtinSemVerCompare(_ BuiltinContext, operands []*ast.Term, iter func(*ast return err } - versionA, err := semver.NewVersion(string(versionStringA)) + versionA, err := semver.Parse(string(versionStringA)) if err != nil { return fmt.Errorf("operand 1: string %s is not a valid SemVer", versionStringA) } - versionB, err := semver.NewVersion(string(versionStringB)) + versionB, err := semver.Parse(string(versionStringB)) if err != nil { return fmt.Errorf("operand 2: string %s is not a valid SemVer", versionStringB) } - result := versionA.Compare(*versionB) - - return iter(ast.InternedTerm(result)) + return iter(ast.InternedTerm(versionA.Compare(versionB))) } func builtinSemVerIsValid(_ BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error { versionString, err := builtins.StringOperand(operands[0].Value, 1) - if err != nil { - return iter(ast.InternedTerm(false)) + if err == nil { + _, err = semver.Parse(string(versionString)) } - result := true - - _, err = semver.NewVersion(string(versionString)) - if err != nil { - result = false - } - - return iter(ast.InternedTerm(result)) + return iter(ast.InternedTerm(err == nil)) } func init() { diff --git a/v1/util/performance.go b/v1/util/performance.go index 09a8e74011..01d1390663 100644 --- a/v1/util/performance.go +++ b/v1/util/performance.go @@ -44,6 +44,12 @@ func StringToByteSlice[T ~string](s T) []byte { // NumDigitsInt returns the number of digits in n. // This is useful for pre-allocating buffers for string conversion. func NumDigitsInt(n int) int { + return NumDigitsInt64(int64(n)) +} + +// NumDigitsInt64 returns the number of digits in n. +// This is useful for pre-allocating buffers for string conversion. +func NumDigitsInt64(n int64) int { if n == 0 { return 1 }