build(deps): bump github.com/open-policy-agent/opa from 1.6.0 to 1.8.0
Bumps [github.com/open-policy-agent/opa](https://github.com/open-policy-agent/opa) from 1.6.0 to 1.8.0. - [Release notes](https://github.com/open-policy-agent/opa/releases) - [Changelog](https://github.com/open-policy-agent/opa/blob/main/CHANGELOG.md) - [Commits](https://github.com/open-policy-agent/opa/compare/v1.6.0...v1.8.0) --- updated-dependencies: - dependency-name: github.com/open-policy-agent/opa dependency-version: 1.8.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com>
This commit is contained in:
committed by
Ralf Haferkamp
parent
98d773bb9b
commit
76ac20e9e8
+24
@@ -0,0 +1,24 @@
|
||||
package core
|
||||
|
||||
import (
|
||||
"github.com/vektah/gqlparser/v2/gqlerror"
|
||||
)
|
||||
|
||||
type AddErrFunc func(options ...ErrorOption)
|
||||
|
||||
type RuleFunc func(observers *Events, addError AddErrFunc)
|
||||
|
||||
type Rule struct {
|
||||
Name string
|
||||
RuleFunc RuleFunc
|
||||
}
|
||||
|
||||
// NameSorter sorts Rules by name.
|
||||
// usage: sort.Sort(core.NameSorter(specifiedRules))
|
||||
type NameSorter []Rule
|
||||
|
||||
func (a NameSorter) Len() int { return len(a) }
|
||||
func (a NameSorter) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
|
||||
func (a NameSorter) Less(i, j int) bool { return a[i].Name < a[j].Name }
|
||||
|
||||
type ErrorOption func(err *gqlerror.Error)
|
||||
+154
@@ -0,0 +1,154 @@
|
||||
package core
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"math"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/agnivade/levenshtein"
|
||||
"github.com/vektah/gqlparser/v2/ast"
|
||||
"github.com/vektah/gqlparser/v2/gqlerror"
|
||||
)
|
||||
|
||||
func Message(msg string, args ...interface{}) ErrorOption {
|
||||
return func(err *gqlerror.Error) {
|
||||
err.Message += fmt.Sprintf(msg, args...)
|
||||
}
|
||||
}
|
||||
|
||||
func At(position *ast.Position) ErrorOption {
|
||||
return func(err *gqlerror.Error) {
|
||||
if position == nil {
|
||||
return
|
||||
}
|
||||
err.Locations = append(err.Locations, gqlerror.Location{
|
||||
Line: position.Line,
|
||||
Column: position.Column,
|
||||
})
|
||||
if position.Src.Name != "" {
|
||||
err.SetFile(position.Src.Name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func SuggestListQuoted(prefix string, typed string, suggestions []string) ErrorOption {
|
||||
suggested := SuggestionList(typed, suggestions)
|
||||
return func(err *gqlerror.Error) {
|
||||
if len(suggested) > 0 {
|
||||
err.Message += " " + prefix + " " + QuotedOrList(suggested...) + "?"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func SuggestListUnquoted(prefix string, typed string, suggestions []string) ErrorOption {
|
||||
suggested := SuggestionList(typed, suggestions)
|
||||
return func(err *gqlerror.Error) {
|
||||
if len(suggested) > 0 {
|
||||
err.Message += " " + prefix + " " + OrList(suggested...) + "?"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func Suggestf(suggestion string, args ...interface{}) ErrorOption {
|
||||
return func(err *gqlerror.Error) {
|
||||
err.Message += " Did you mean " + fmt.Sprintf(suggestion, args...) + "?"
|
||||
}
|
||||
}
|
||||
|
||||
// Given [ A, B, C ] return '"A", "B", or "C"'.
|
||||
func QuotedOrList(items ...string) string {
|
||||
itemsQuoted := make([]string, len(items))
|
||||
for i, item := range items {
|
||||
itemsQuoted[i] = `"` + item + `"`
|
||||
}
|
||||
return OrList(itemsQuoted...)
|
||||
}
|
||||
|
||||
// Given [ A, B, C ] return 'A, B, or C'.
|
||||
func OrList(items ...string) string {
|
||||
var buf bytes.Buffer
|
||||
|
||||
if len(items) > 5 {
|
||||
items = items[:5]
|
||||
}
|
||||
if len(items) == 2 {
|
||||
buf.WriteString(items[0])
|
||||
buf.WriteString(" or ")
|
||||
buf.WriteString(items[1])
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
for i, item := range items {
|
||||
if i != 0 {
|
||||
if i == len(items)-1 {
|
||||
buf.WriteString(", or ")
|
||||
} else {
|
||||
buf.WriteString(", ")
|
||||
}
|
||||
}
|
||||
buf.WriteString(item)
|
||||
}
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
// Given an invalid input string and a list of valid options, returns a filtered
|
||||
// list of valid options sorted based on their similarity with the input.
|
||||
func SuggestionList(input string, options []string) []string {
|
||||
var results []string
|
||||
optionsByDistance := map[string]int{}
|
||||
|
||||
for _, option := range options {
|
||||
distance := lexicalDistance(input, option)
|
||||
threshold := calcThreshold(input)
|
||||
if distance <= threshold {
|
||||
results = append(results, option)
|
||||
optionsByDistance[option] = distance
|
||||
}
|
||||
}
|
||||
|
||||
sort.Slice(results, func(i, j int) bool {
|
||||
return optionsByDistance[results[i]] < optionsByDistance[results[j]]
|
||||
})
|
||||
return results
|
||||
}
|
||||
|
||||
func calcThreshold(a string) (threshold int) {
|
||||
// the logic is copied from here
|
||||
// https://github.com/graphql/graphql-js/blob/47bd8c8897c72d3efc17ecb1599a95cee6bac5e8/src/jsutils/suggestionList.ts#L14
|
||||
threshold = int(math.Floor(float64(len(a))*0.4) + 1)
|
||||
|
||||
if threshold < 1 {
|
||||
threshold = 1
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Computes the lexical distance between strings A and B.
|
||||
//
|
||||
// The "distance" between two strings is given by counting the minimum number
|
||||
// of edits needed to transform string A into string B. An edit can be an
|
||||
// insertion, deletion, or substitution of a single character, or a swap of two
|
||||
// adjacent characters.
|
||||
//
|
||||
// Includes a custom alteration from Damerau-Levenshtein to treat case changes
|
||||
// as a single edit which helps identify mis-cased values with an edit distance
|
||||
// of 1.
|
||||
//
|
||||
// This distance can be useful for detecting typos in input or sorting
|
||||
func lexicalDistance(a, b string) int {
|
||||
if a == b {
|
||||
return 0
|
||||
}
|
||||
|
||||
a = strings.ToLower(a)
|
||||
b = strings.ToLower(b)
|
||||
|
||||
// Any case change counts as a single edit
|
||||
if a == b {
|
||||
return 1
|
||||
}
|
||||
|
||||
return levenshtein.ComputeDistance(a, b)
|
||||
}
|
||||
Generated
Vendored
+1
-1
@@ -1,4 +1,4 @@
|
||||
package validator
|
||||
package core
|
||||
|
||||
import (
|
||||
"context"
|
||||
-55
@@ -1,55 +0,0 @@
|
||||
package validator
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/vektah/gqlparser/v2/ast"
|
||||
"github.com/vektah/gqlparser/v2/gqlerror"
|
||||
)
|
||||
|
||||
type ErrorOption func(err *gqlerror.Error)
|
||||
|
||||
func Message(msg string, args ...interface{}) ErrorOption {
|
||||
return func(err *gqlerror.Error) {
|
||||
err.Message += fmt.Sprintf(msg, args...)
|
||||
}
|
||||
}
|
||||
|
||||
func At(position *ast.Position) ErrorOption {
|
||||
return func(err *gqlerror.Error) {
|
||||
if position == nil {
|
||||
return
|
||||
}
|
||||
err.Locations = append(err.Locations, gqlerror.Location{
|
||||
Line: position.Line,
|
||||
Column: position.Column,
|
||||
})
|
||||
if position.Src.Name != "" {
|
||||
err.SetFile(position.Src.Name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func SuggestListQuoted(prefix string, typed string, suggestions []string) ErrorOption {
|
||||
suggested := SuggestionList(typed, suggestions)
|
||||
return func(err *gqlerror.Error) {
|
||||
if len(suggested) > 0 {
|
||||
err.Message += " " + prefix + " " + QuotedOrList(suggested...) + "?"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func SuggestListUnquoted(prefix string, typed string, suggestions []string) ErrorOption {
|
||||
suggested := SuggestionList(typed, suggestions)
|
||||
return func(err *gqlerror.Error) {
|
||||
if len(suggested) > 0 {
|
||||
err.Message += " " + prefix + " " + OrList(suggested...) + "?"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func Suggestf(suggestion string, args ...interface{}) ErrorOption {
|
||||
return func(err *gqlerror.Error) {
|
||||
err.Message += " Did you mean " + fmt.Sprintf(suggestion, args...) + "?"
|
||||
}
|
||||
}
|
||||
-39
@@ -1,39 +0,0 @@
|
||||
package validator
|
||||
|
||||
import "bytes"
|
||||
|
||||
// Given [ A, B, C ] return '"A", "B", or "C"'.
|
||||
func QuotedOrList(items ...string) string {
|
||||
itemsQuoted := make([]string, len(items))
|
||||
for i, item := range items {
|
||||
itemsQuoted[i] = `"` + item + `"`
|
||||
}
|
||||
return OrList(itemsQuoted...)
|
||||
}
|
||||
|
||||
// Given [ A, B, C ] return 'A, B, or C'.
|
||||
func OrList(items ...string) string {
|
||||
var buf bytes.Buffer
|
||||
|
||||
if len(items) > 5 {
|
||||
items = items[:5]
|
||||
}
|
||||
if len(items) == 2 {
|
||||
buf.WriteString(items[0])
|
||||
buf.WriteString(" or ")
|
||||
buf.WriteString(items[1])
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
for i, item := range items {
|
||||
if i != 0 {
|
||||
if i == len(items)-1 {
|
||||
buf.WriteString(", or ")
|
||||
} else {
|
||||
buf.WriteString(", ")
|
||||
}
|
||||
}
|
||||
buf.WriteString(item)
|
||||
}
|
||||
return buf.String()
|
||||
}
|
||||
+1
-5
@@ -8,7 +8,7 @@ import (
|
||||
"github.com/vektah/gqlparser/v2/ast"
|
||||
|
||||
//nolint:staticcheck // Validator rules each use dot imports for convenience.
|
||||
. "github.com/vektah/gqlparser/v2/validator"
|
||||
. "github.com/vektah/gqlparser/v2/validator/core"
|
||||
)
|
||||
|
||||
func ruleFuncFieldsOnCorrectType(observers *Events, addError AddErrFunc, disableSuggestion bool) {
|
||||
@@ -48,10 +48,6 @@ var FieldsOnCorrectTypeRuleWithoutSuggestions = Rule{
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
AddRule(FieldsOnCorrectTypeRule.Name, FieldsOnCorrectTypeRule.RuleFunc)
|
||||
}
|
||||
|
||||
// Go through all the implementations of type, as well as the interfaces
|
||||
// that they implement. If any of those types include the provided field,
|
||||
// suggest them, sorted by how often the type is referenced, starting
|
||||
|
||||
Generated
Vendored
+1
-5
@@ -6,7 +6,7 @@ import (
|
||||
"github.com/vektah/gqlparser/v2/ast"
|
||||
|
||||
//nolint:staticcheck // Validator rules each use dot imports for convenience.
|
||||
. "github.com/vektah/gqlparser/v2/validator"
|
||||
. "github.com/vektah/gqlparser/v2/validator/core"
|
||||
)
|
||||
|
||||
var FragmentsOnCompositeTypesRule = Rule{
|
||||
@@ -40,7 +40,3 @@ var FragmentsOnCompositeTypesRule = Rule{
|
||||
})
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
AddRule(FragmentsOnCompositeTypesRule.Name, FragmentsOnCompositeTypesRule.RuleFunc)
|
||||
}
|
||||
|
||||
+1
-5
@@ -4,7 +4,7 @@ import (
|
||||
"github.com/vektah/gqlparser/v2/ast"
|
||||
|
||||
//nolint:staticcheck // Validator rules each use dot imports for convenience.
|
||||
. "github.com/vektah/gqlparser/v2/validator"
|
||||
. "github.com/vektah/gqlparser/v2/validator/core"
|
||||
)
|
||||
|
||||
func ruleFuncKnownArgumentNames(observers *Events, addError AddErrFunc, disableSuggestion bool) {
|
||||
@@ -82,7 +82,3 @@ var KnownArgumentNamesRuleWithoutSuggestions = Rule{
|
||||
ruleFuncKnownArgumentNames(observers, addError, true)
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
AddRule(KnownArgumentNamesRule.Name, KnownArgumentNamesRule.RuleFunc)
|
||||
}
|
||||
|
||||
+1
-5
@@ -4,7 +4,7 @@ import (
|
||||
"github.com/vektah/gqlparser/v2/ast"
|
||||
|
||||
//nolint:staticcheck // Validator rules each use dot imports for convenience.
|
||||
. "github.com/vektah/gqlparser/v2/validator"
|
||||
. "github.com/vektah/gqlparser/v2/validator/core"
|
||||
)
|
||||
|
||||
var KnownDirectivesRule = Rule{
|
||||
@@ -48,7 +48,3 @@ var KnownDirectivesRule = Rule{
|
||||
})
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
AddRule(KnownDirectivesRule.Name, KnownDirectivesRule.RuleFunc)
|
||||
}
|
||||
|
||||
+1
-5
@@ -4,7 +4,7 @@ import (
|
||||
"github.com/vektah/gqlparser/v2/ast"
|
||||
|
||||
//nolint:staticcheck // Validator rules each use dot imports for convenience.
|
||||
. "github.com/vektah/gqlparser/v2/validator"
|
||||
. "github.com/vektah/gqlparser/v2/validator/core"
|
||||
)
|
||||
|
||||
var KnownFragmentNamesRule = Rule{
|
||||
@@ -20,7 +20,3 @@ var KnownFragmentNamesRule = Rule{
|
||||
})
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
AddRule(KnownFragmentNamesRule.Name, KnownFragmentNamesRule.RuleFunc)
|
||||
}
|
||||
|
||||
+1
-5
@@ -6,7 +6,7 @@ import (
|
||||
"github.com/vektah/gqlparser/v2/ast"
|
||||
|
||||
//nolint:staticcheck // Validator rules each use dot imports for convenience.
|
||||
. "github.com/vektah/gqlparser/v2/validator"
|
||||
. "github.com/vektah/gqlparser/v2/validator/core"
|
||||
)
|
||||
|
||||
var KnownRootTypeRule = Rule{
|
||||
@@ -36,7 +36,3 @@ var KnownRootTypeRule = Rule{
|
||||
})
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
AddRule(KnownRootTypeRule.Name, KnownRootTypeRule.RuleFunc)
|
||||
}
|
||||
|
||||
+1
-5
@@ -4,7 +4,7 @@ import (
|
||||
"github.com/vektah/gqlparser/v2/ast"
|
||||
|
||||
//nolint:staticcheck // Validator rules each use dot imports for convenience.
|
||||
. "github.com/vektah/gqlparser/v2/validator"
|
||||
. "github.com/vektah/gqlparser/v2/validator/core"
|
||||
)
|
||||
|
||||
func ruleFuncKnownTypeNames(observers *Events, addError AddErrFunc, disableSuggestion bool) {
|
||||
@@ -78,7 +78,3 @@ var KnownTypeNamesRuleWithoutSuggestions = Rule{
|
||||
ruleFuncKnownTypeNames(observers, addError, true)
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
AddRule(KnownTypeNamesRule.Name, KnownTypeNamesRule.RuleFunc)
|
||||
}
|
||||
|
||||
Generated
Vendored
+1
-5
@@ -4,7 +4,7 @@ import (
|
||||
"github.com/vektah/gqlparser/v2/ast"
|
||||
|
||||
//nolint:staticcheck // Validator rules each use dot imports for convenience.
|
||||
. "github.com/vektah/gqlparser/v2/validator"
|
||||
. "github.com/vektah/gqlparser/v2/validator/core"
|
||||
)
|
||||
|
||||
var LoneAnonymousOperationRule = Rule{
|
||||
@@ -20,7 +20,3 @@ var LoneAnonymousOperationRule = Rule{
|
||||
})
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
AddRule(LoneAnonymousOperationRule.Name, LoneAnonymousOperationRule.RuleFunc)
|
||||
}
|
||||
|
||||
+1
-5
@@ -4,7 +4,7 @@ import (
|
||||
"github.com/vektah/gqlparser/v2/ast"
|
||||
|
||||
//nolint:staticcheck // Validator rules each use dot imports for convenience.
|
||||
. "github.com/vektah/gqlparser/v2/validator"
|
||||
. "github.com/vektah/gqlparser/v2/validator/core"
|
||||
)
|
||||
|
||||
const maxListsDepth = 3
|
||||
@@ -84,7 +84,3 @@ func checkDepthFragmentSpread(fragmentSpread *ast.FragmentSpread, visitedFragmen
|
||||
defer delete(visitedFragments, fragmentName)
|
||||
return checkDepthSelectionSet(fragment.SelectionSet, visitedFragments, depth)
|
||||
}
|
||||
|
||||
func init() {
|
||||
AddRule(MaxIntrospectionDepth.Name, MaxIntrospectionDepth.RuleFunc)
|
||||
}
|
||||
|
||||
+1
-5
@@ -7,7 +7,7 @@ import (
|
||||
"github.com/vektah/gqlparser/v2/ast"
|
||||
|
||||
//nolint:staticcheck // Validator rules each use dot imports for convenience.
|
||||
. "github.com/vektah/gqlparser/v2/validator"
|
||||
. "github.com/vektah/gqlparser/v2/validator/core"
|
||||
)
|
||||
|
||||
var NoFragmentCyclesRule = Rule{
|
||||
@@ -71,10 +71,6 @@ var NoFragmentCyclesRule = Rule{
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
AddRule(NoFragmentCyclesRule.Name, NoFragmentCyclesRule.RuleFunc)
|
||||
}
|
||||
|
||||
func getFragmentSpreads(node ast.SelectionSet) []*ast.FragmentSpread {
|
||||
var spreads []*ast.FragmentSpread
|
||||
|
||||
|
||||
+1
-5
@@ -4,7 +4,7 @@ import (
|
||||
"github.com/vektah/gqlparser/v2/ast"
|
||||
|
||||
//nolint:staticcheck // Validator rules each use dot imports for convenience.
|
||||
. "github.com/vektah/gqlparser/v2/validator"
|
||||
. "github.com/vektah/gqlparser/v2/validator/core"
|
||||
)
|
||||
|
||||
var NoUndefinedVariablesRule = Rule{
|
||||
@@ -29,7 +29,3 @@ var NoUndefinedVariablesRule = Rule{
|
||||
})
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
AddRule(NoUndefinedVariablesRule.Name, NoUndefinedVariablesRule.RuleFunc)
|
||||
}
|
||||
|
||||
+1
-5
@@ -4,7 +4,7 @@ import (
|
||||
"github.com/vektah/gqlparser/v2/ast"
|
||||
|
||||
//nolint:staticcheck // Validator rules each use dot imports for convenience.
|
||||
. "github.com/vektah/gqlparser/v2/validator"
|
||||
. "github.com/vektah/gqlparser/v2/validator/core"
|
||||
)
|
||||
|
||||
var NoUnusedFragmentsRule = Rule{
|
||||
@@ -30,7 +30,3 @@ var NoUnusedFragmentsRule = Rule{
|
||||
})
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
AddRule(NoUnusedFragmentsRule.Name, NoUnusedFragmentsRule.RuleFunc)
|
||||
}
|
||||
|
||||
+1
-5
@@ -4,7 +4,7 @@ import (
|
||||
"github.com/vektah/gqlparser/v2/ast"
|
||||
|
||||
//nolint:staticcheck // Validator rules each use dot imports for convenience.
|
||||
. "github.com/vektah/gqlparser/v2/validator"
|
||||
. "github.com/vektah/gqlparser/v2/validator/core"
|
||||
)
|
||||
|
||||
var NoUnusedVariablesRule = Rule{
|
||||
@@ -31,7 +31,3 @@ var NoUnusedVariablesRule = Rule{
|
||||
})
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
AddRule(NoUnusedVariablesRule.Name, NoUnusedVariablesRule.RuleFunc)
|
||||
}
|
||||
|
||||
Generated
Vendored
+1
-5
@@ -8,7 +8,7 @@ import (
|
||||
"github.com/vektah/gqlparser/v2/ast"
|
||||
|
||||
//nolint:staticcheck // Validator rules each use dot imports for convenience.
|
||||
. "github.com/vektah/gqlparser/v2/validator"
|
||||
. "github.com/vektah/gqlparser/v2/validator/core"
|
||||
)
|
||||
|
||||
var OverlappingFieldsCanBeMergedRule = Rule{
|
||||
@@ -108,10 +108,6 @@ var OverlappingFieldsCanBeMergedRule = Rule{
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
AddRule(OverlappingFieldsCanBeMergedRule.Name, OverlappingFieldsCanBeMergedRule.RuleFunc)
|
||||
}
|
||||
|
||||
type pairSet struct {
|
||||
data map[string]map[string]bool
|
||||
}
|
||||
|
||||
Generated
Vendored
+1
-5
@@ -4,7 +4,7 @@ import (
|
||||
"github.com/vektah/gqlparser/v2/ast"
|
||||
|
||||
//nolint:staticcheck // Validator rules each use dot imports for convenience.
|
||||
. "github.com/vektah/gqlparser/v2/validator"
|
||||
. "github.com/vektah/gqlparser/v2/validator/core"
|
||||
)
|
||||
|
||||
var PossibleFragmentSpreadsRule = Rule{
|
||||
@@ -68,7 +68,3 @@ var PossibleFragmentSpreadsRule = Rule{
|
||||
})
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
AddRule(PossibleFragmentSpreadsRule.Name, PossibleFragmentSpreadsRule.RuleFunc)
|
||||
}
|
||||
|
||||
Generated
Vendored
+1
-5
@@ -3,7 +3,7 @@ package rules
|
||||
import (
|
||||
"github.com/vektah/gqlparser/v2/ast"
|
||||
//nolint:staticcheck // Validator rules each use dot imports for convenience.
|
||||
. "github.com/vektah/gqlparser/v2/validator"
|
||||
. "github.com/vektah/gqlparser/v2/validator/core"
|
||||
)
|
||||
|
||||
var ProvidedRequiredArgumentsRule = Rule{
|
||||
@@ -62,7 +62,3 @@ var ProvidedRequiredArgumentsRule = Rule{
|
||||
})
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
AddRule(ProvidedRequiredArgumentsRule.Name, ProvidedRequiredArgumentsRule.RuleFunc)
|
||||
}
|
||||
|
||||
+119
@@ -0,0 +1,119 @@
|
||||
package rules
|
||||
|
||||
import (
|
||||
"slices"
|
||||
|
||||
"github.com/vektah/gqlparser/v2/validator/core"
|
||||
)
|
||||
|
||||
// Rules manages GraphQL validation rules.
|
||||
type Rules struct {
|
||||
rules map[string]core.RuleFunc
|
||||
ruleNameKeys []string // for deterministic order
|
||||
}
|
||||
|
||||
// NewRules creates a Rules instance with the specified rules.
|
||||
func NewRules(rs ...core.Rule) *Rules {
|
||||
r := &Rules{
|
||||
rules: make(map[string]core.RuleFunc),
|
||||
}
|
||||
|
||||
for _, rule := range rs {
|
||||
r.AddRule(rule.Name, rule.RuleFunc)
|
||||
}
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
// NewDefaultRules creates a Rules instance containing the default GraphQL validation rule set.
|
||||
func NewDefaultRules() *Rules {
|
||||
rules := []core.Rule{
|
||||
FieldsOnCorrectTypeRule,
|
||||
FragmentsOnCompositeTypesRule,
|
||||
KnownArgumentNamesRule,
|
||||
KnownDirectivesRule,
|
||||
KnownFragmentNamesRule,
|
||||
KnownRootTypeRule,
|
||||
KnownTypeNamesRule,
|
||||
LoneAnonymousOperationRule,
|
||||
MaxIntrospectionDepth,
|
||||
NoFragmentCyclesRule,
|
||||
NoUndefinedVariablesRule,
|
||||
NoUnusedFragmentsRule,
|
||||
NoUnusedVariablesRule,
|
||||
OverlappingFieldsCanBeMergedRule,
|
||||
PossibleFragmentSpreadsRule,
|
||||
ProvidedRequiredArgumentsRule,
|
||||
ScalarLeafsRule,
|
||||
SingleFieldSubscriptionsRule,
|
||||
UniqueArgumentNamesRule,
|
||||
UniqueDirectivesPerLocationRule,
|
||||
UniqueFragmentNamesRule,
|
||||
UniqueInputFieldNamesRule,
|
||||
UniqueOperationNamesRule,
|
||||
UniqueVariableNamesRule,
|
||||
ValuesOfCorrectTypeRule,
|
||||
VariablesAreInputTypesRule,
|
||||
VariablesInAllowedPositionRule,
|
||||
}
|
||||
|
||||
r := NewRules(rules...)
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
// AddRule adds a rule with the specified name and rule function to the rule set.
|
||||
// If a rule with the same name already exists, it will not be added.
|
||||
func (r *Rules) AddRule(name string, ruleFunc core.RuleFunc) {
|
||||
if r.rules == nil {
|
||||
r.rules = make(map[string]core.RuleFunc)
|
||||
}
|
||||
|
||||
if _, exists := r.rules[name]; !exists {
|
||||
r.rules[name] = ruleFunc
|
||||
r.ruleNameKeys = append(r.ruleNameKeys, name)
|
||||
}
|
||||
}
|
||||
|
||||
// GetInner returns the internal rule map.
|
||||
// If the map is not initialized, it returns an empty map.
|
||||
func (r *Rules) GetInner() map[string]core.RuleFunc {
|
||||
if r == nil {
|
||||
return nil // impossible nonsense, hopefully
|
||||
}
|
||||
if r.rules == nil {
|
||||
return make(map[string]core.RuleFunc)
|
||||
}
|
||||
return r.rules
|
||||
}
|
||||
|
||||
// RemoveRule removes a rule with the specified name from the rule set.
|
||||
// If no rule with the specified name exists, it does nothing.
|
||||
func (r *Rules) RemoveRule(name string) {
|
||||
if r == nil {
|
||||
return // impossible nonsense, hopefully
|
||||
}
|
||||
if r.rules != nil {
|
||||
delete(r.rules, name)
|
||||
}
|
||||
|
||||
if len(r.ruleNameKeys) > 0 {
|
||||
r.ruleNameKeys = slices.DeleteFunc(r.ruleNameKeys, func(s string) bool {
|
||||
return s == name // delete the name rule key
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// ReplaceRule replaces a rule with the specified name with a new rule function.
|
||||
// If no rule with the specified name exists, it does nothing.
|
||||
func (r *Rules) ReplaceRule(name string, ruleFunc core.RuleFunc) {
|
||||
if r == nil {
|
||||
return // impossible nonsense, hopefully
|
||||
}
|
||||
if r.rules == nil {
|
||||
r.rules = make(map[string]core.RuleFunc)
|
||||
}
|
||||
if _, exists := r.rules[name]; exists {
|
||||
r.rules[name] = ruleFunc
|
||||
}
|
||||
}
|
||||
+1
-5
@@ -4,7 +4,7 @@ import (
|
||||
"github.com/vektah/gqlparser/v2/ast"
|
||||
|
||||
//nolint:staticcheck // Validator rules each use dot imports for convenience.
|
||||
. "github.com/vektah/gqlparser/v2/validator"
|
||||
. "github.com/vektah/gqlparser/v2/validator/core"
|
||||
)
|
||||
|
||||
var ScalarLeafsRule = Rule{
|
||||
@@ -37,7 +37,3 @@ var ScalarLeafsRule = Rule{
|
||||
})
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
AddRule(ScalarLeafsRule.Name, ScalarLeafsRule.RuleFunc)
|
||||
}
|
||||
|
||||
Generated
Vendored
+1
-5
@@ -7,7 +7,7 @@ import (
|
||||
"github.com/vektah/gqlparser/v2/ast"
|
||||
|
||||
//nolint:staticcheck // Validator rules each use dot imports for convenience.
|
||||
. "github.com/vektah/gqlparser/v2/validator"
|
||||
. "github.com/vektah/gqlparser/v2/validator/core"
|
||||
)
|
||||
|
||||
var SingleFieldSubscriptionsRule = Rule{
|
||||
@@ -44,10 +44,6 @@ var SingleFieldSubscriptionsRule = Rule{
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
AddRule(SingleFieldSubscriptionsRule.Name, SingleFieldSubscriptionsRule.RuleFunc)
|
||||
}
|
||||
|
||||
type topField struct {
|
||||
name string
|
||||
position *ast.Position
|
||||
|
||||
+1
-5
@@ -4,7 +4,7 @@ import (
|
||||
"github.com/vektah/gqlparser/v2/ast"
|
||||
|
||||
//nolint:staticcheck // Validator rules each use dot imports for convenience.
|
||||
. "github.com/vektah/gqlparser/v2/validator"
|
||||
. "github.com/vektah/gqlparser/v2/validator/core"
|
||||
)
|
||||
|
||||
var UniqueArgumentNamesRule = Rule{
|
||||
@@ -20,10 +20,6 @@ var UniqueArgumentNamesRule = Rule{
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
AddRule(UniqueArgumentNamesRule.Name, UniqueArgumentNamesRule.RuleFunc)
|
||||
}
|
||||
|
||||
func checkUniqueArgs(args ast.ArgumentList, addError AddErrFunc) {
|
||||
knownArgNames := map[string]int{}
|
||||
|
||||
|
||||
Generated
Vendored
+1
-5
@@ -4,7 +4,7 @@ import (
|
||||
"github.com/vektah/gqlparser/v2/ast"
|
||||
|
||||
//nolint:staticcheck // Validator rules each use dot imports for convenience.
|
||||
. "github.com/vektah/gqlparser/v2/validator"
|
||||
. "github.com/vektah/gqlparser/v2/validator/core"
|
||||
)
|
||||
|
||||
var UniqueDirectivesPerLocationRule = Rule{
|
||||
@@ -25,7 +25,3 @@ var UniqueDirectivesPerLocationRule = Rule{
|
||||
})
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
AddRule(UniqueDirectivesPerLocationRule.Name, UniqueDirectivesPerLocationRule.RuleFunc)
|
||||
}
|
||||
|
||||
+1
-5
@@ -4,7 +4,7 @@ import (
|
||||
"github.com/vektah/gqlparser/v2/ast"
|
||||
|
||||
//nolint:staticcheck // Validator rules each use dot imports for convenience.
|
||||
. "github.com/vektah/gqlparser/v2/validator"
|
||||
. "github.com/vektah/gqlparser/v2/validator/core"
|
||||
)
|
||||
|
||||
var UniqueFragmentNamesRule = Rule{
|
||||
@@ -23,7 +23,3 @@ var UniqueFragmentNamesRule = Rule{
|
||||
})
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
AddRule(UniqueFragmentNamesRule.Name, UniqueFragmentNamesRule.RuleFunc)
|
||||
}
|
||||
|
||||
Generated
Vendored
+1
-5
@@ -4,7 +4,7 @@ import (
|
||||
"github.com/vektah/gqlparser/v2/ast"
|
||||
|
||||
//nolint:staticcheck // Validator rules each use dot imports for convenience.
|
||||
. "github.com/vektah/gqlparser/v2/validator"
|
||||
. "github.com/vektah/gqlparser/v2/validator/core"
|
||||
)
|
||||
|
||||
var UniqueInputFieldNamesRule = Rule{
|
||||
@@ -28,7 +28,3 @@ var UniqueInputFieldNamesRule = Rule{
|
||||
})
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
AddRule(UniqueInputFieldNamesRule.Name, UniqueInputFieldNamesRule.RuleFunc)
|
||||
}
|
||||
|
||||
+1
-5
@@ -4,7 +4,7 @@ import (
|
||||
"github.com/vektah/gqlparser/v2/ast"
|
||||
|
||||
//nolint:staticcheck // Validator rules each use dot imports for convenience.
|
||||
. "github.com/vektah/gqlparser/v2/validator"
|
||||
. "github.com/vektah/gqlparser/v2/validator/core"
|
||||
)
|
||||
|
||||
var UniqueOperationNamesRule = Rule{
|
||||
@@ -23,7 +23,3 @@ var UniqueOperationNamesRule = Rule{
|
||||
})
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
AddRule(UniqueOperationNamesRule.Name, UniqueOperationNamesRule.RuleFunc)
|
||||
}
|
||||
|
||||
+1
-5
@@ -4,7 +4,7 @@ import (
|
||||
"github.com/vektah/gqlparser/v2/ast"
|
||||
|
||||
//nolint:staticcheck // Validator rules each use dot imports for convenience.
|
||||
. "github.com/vektah/gqlparser/v2/validator"
|
||||
. "github.com/vektah/gqlparser/v2/validator/core"
|
||||
)
|
||||
|
||||
var UniqueVariableNamesRule = Rule{
|
||||
@@ -25,7 +25,3 @@ var UniqueVariableNamesRule = Rule{
|
||||
})
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
AddRule(UniqueVariableNamesRule.Name, UniqueVariableNamesRule.RuleFunc)
|
||||
}
|
||||
|
||||
+1
-5
@@ -8,7 +8,7 @@ import (
|
||||
"github.com/vektah/gqlparser/v2/ast"
|
||||
|
||||
//nolint:staticcheck // Validator rules each use dot imports for convenience.
|
||||
. "github.com/vektah/gqlparser/v2/validator"
|
||||
. "github.com/vektah/gqlparser/v2/validator/core"
|
||||
)
|
||||
|
||||
func ruleFuncValuesOfCorrectType(observers *Events, addError AddErrFunc, disableSuggestion bool) {
|
||||
@@ -213,10 +213,6 @@ var ValuesOfCorrectTypeRuleWithoutSuggestions = Rule{
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
AddRule(ValuesOfCorrectTypeRule.Name, ValuesOfCorrectTypeRule.RuleFunc)
|
||||
}
|
||||
|
||||
func unexpectedTypeMessage(addError AddErrFunc, v *ast.Value) {
|
||||
addError(
|
||||
unexpectedTypeMessageOnly(v),
|
||||
|
||||
Generated
Vendored
+1
-5
@@ -4,7 +4,7 @@ import (
|
||||
"github.com/vektah/gqlparser/v2/ast"
|
||||
|
||||
//nolint:staticcheck // Validator rules each use dot imports for convenience.
|
||||
. "github.com/vektah/gqlparser/v2/validator"
|
||||
. "github.com/vektah/gqlparser/v2/validator/core"
|
||||
)
|
||||
|
||||
var VariablesAreInputTypesRule = Rule{
|
||||
@@ -29,7 +29,3 @@ var VariablesAreInputTypesRule = Rule{
|
||||
})
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
AddRule(VariablesAreInputTypesRule.Name, VariablesAreInputTypesRule.RuleFunc)
|
||||
}
|
||||
|
||||
Generated
Vendored
+1
-5
@@ -4,7 +4,7 @@ import (
|
||||
"github.com/vektah/gqlparser/v2/ast"
|
||||
|
||||
//nolint:staticcheck // Validator rules each use dot imports for convenience.
|
||||
. "github.com/vektah/gqlparser/v2/validator"
|
||||
. "github.com/vektah/gqlparser/v2/validator/core"
|
||||
)
|
||||
|
||||
var VariablesInAllowedPositionRule = Rule{
|
||||
@@ -39,7 +39,3 @@ var VariablesInAllowedPositionRule = Rule{
|
||||
})
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
AddRule(VariablesInAllowedPositionRule.Name, VariablesInAllowedPositionRule.RuleFunc)
|
||||
}
|
||||
|
||||
-69
@@ -1,69 +0,0 @@
|
||||
package validator
|
||||
|
||||
import (
|
||||
"math"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/agnivade/levenshtein"
|
||||
)
|
||||
|
||||
// Given an invalid input string and a list of valid options, returns a filtered
|
||||
// list of valid options sorted based on their similarity with the input.
|
||||
func SuggestionList(input string, options []string) []string {
|
||||
var results []string
|
||||
optionsByDistance := map[string]int{}
|
||||
|
||||
for _, option := range options {
|
||||
distance := lexicalDistance(input, option)
|
||||
threshold := calcThreshold(input)
|
||||
if distance <= threshold {
|
||||
results = append(results, option)
|
||||
optionsByDistance[option] = distance
|
||||
}
|
||||
}
|
||||
|
||||
sort.Slice(results, func(i, j int) bool {
|
||||
return optionsByDistance[results[i]] < optionsByDistance[results[j]]
|
||||
})
|
||||
return results
|
||||
}
|
||||
|
||||
func calcThreshold(a string) (threshold int) {
|
||||
// the logic is copied from here
|
||||
// https://github.com/graphql/graphql-js/blob/47bd8c8897c72d3efc17ecb1599a95cee6bac5e8/src/jsutils/suggestionList.ts#L14
|
||||
threshold = int(math.Floor(float64(len(a))*0.4) + 1)
|
||||
|
||||
if threshold < 1 {
|
||||
threshold = 1
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Computes the lexical distance between strings A and B.
|
||||
//
|
||||
// The "distance" between two strings is given by counting the minimum number
|
||||
// of edits needed to transform string A into string B. An edit can be an
|
||||
// insertion, deletion, or substitution of a single character, or a swap of two
|
||||
// adjacent characters.
|
||||
//
|
||||
// Includes a custom alteration from Damerau-Levenshtein to treat case changes
|
||||
// as a single edit which helps identify mis-cased values with an edit distance
|
||||
// of 1.
|
||||
//
|
||||
// This distance can be useful for detecting typos in input or sorting
|
||||
func lexicalDistance(a, b string) int {
|
||||
if a == b {
|
||||
return 0
|
||||
}
|
||||
|
||||
a = strings.ToLower(a)
|
||||
b = strings.ToLower(b)
|
||||
|
||||
// Any case change counts as a single edit
|
||||
if a == b {
|
||||
return 1
|
||||
}
|
||||
|
||||
return levenshtein.ComputeDistance(a, b)
|
||||
}
|
||||
+71
-6
@@ -1,22 +1,46 @@
|
||||
package validator
|
||||
|
||||
import (
|
||||
"sort"
|
||||
//nolint:staticcheck // bad, yeah
|
||||
. "github.com/vektah/gqlparser/v2/ast"
|
||||
"github.com/vektah/gqlparser/v2/gqlerror"
|
||||
"github.com/vektah/gqlparser/v2/validator/core"
|
||||
validatorrules "github.com/vektah/gqlparser/v2/validator/rules"
|
||||
)
|
||||
|
||||
type AddErrFunc func(options ...ErrorOption)
|
||||
type (
|
||||
AddErrFunc = core.AddErrFunc
|
||||
RuleFunc = core.RuleFunc
|
||||
Rule = core.Rule
|
||||
Events = core.Events
|
||||
ErrorOption = core.ErrorOption
|
||||
Walker = core.Walker
|
||||
)
|
||||
|
||||
type RuleFunc func(observers *Events, addError AddErrFunc)
|
||||
var (
|
||||
Message = core.Message
|
||||
QuotedOrList = core.QuotedOrList
|
||||
OrList = core.OrList
|
||||
)
|
||||
|
||||
type Rule struct {
|
||||
Name string
|
||||
RuleFunc RuleFunc
|
||||
// Walk is an alias for core.Walk
|
||||
func Walk(schema *Schema, document *QueryDocument, observers *Events) {
|
||||
core.Walk(schema, document, observers)
|
||||
}
|
||||
|
||||
var specifiedRules []Rule
|
||||
|
||||
func init() {
|
||||
// Initialize specifiedRules with default rules
|
||||
defaultRules := validatorrules.NewDefaultRules()
|
||||
for name, ruleFunc := range defaultRules.GetInner() {
|
||||
specifiedRules = append(specifiedRules, Rule{Name: name, RuleFunc: ruleFunc})
|
||||
// ensure initial default is in deterministic order
|
||||
sort.Sort(core.NameSorter(specifiedRules))
|
||||
}
|
||||
}
|
||||
|
||||
// AddRule adds a rule to the rule set.
|
||||
// ruleFunc is called once each time `Validate` is executed.
|
||||
func AddRule(name string, ruleFunc RuleFunc) {
|
||||
@@ -59,6 +83,7 @@ func ReplaceRule(name string, ruleFunc RuleFunc) {
|
||||
specifiedRules = result
|
||||
}
|
||||
|
||||
// Deprecated: use ValidateWithRules instead.
|
||||
func Validate(schema *Schema, doc *QueryDocument, rules ...Rule) gqlerror.List {
|
||||
if rules == nil {
|
||||
rules = specifiedRules
|
||||
@@ -74,7 +99,7 @@ func Validate(schema *Schema, doc *QueryDocument, rules ...Rule) gqlerror.List {
|
||||
if len(errs) > 0 {
|
||||
return errs
|
||||
}
|
||||
observers := &Events{}
|
||||
observers := &core.Events{}
|
||||
for i := range rules {
|
||||
rule := rules[i]
|
||||
rule.RuleFunc(observers, func(options ...ErrorOption) {
|
||||
@@ -91,3 +116,43 @@ func Validate(schema *Schema, doc *QueryDocument, rules ...Rule) gqlerror.List {
|
||||
Walk(schema, doc, observers)
|
||||
return errs
|
||||
}
|
||||
|
||||
func ValidateWithRules(schema *Schema, doc *QueryDocument, rules *validatorrules.Rules) gqlerror.List {
|
||||
if rules == nil {
|
||||
rules = validatorrules.NewDefaultRules()
|
||||
}
|
||||
|
||||
var errs gqlerror.List
|
||||
if schema == nil {
|
||||
errs = append(errs, gqlerror.Errorf("cannot validate as Schema is nil"))
|
||||
}
|
||||
if doc == nil {
|
||||
errs = append(errs, gqlerror.Errorf("cannot validate as QueryDocument is nil"))
|
||||
}
|
||||
if len(errs) > 0 {
|
||||
return errs
|
||||
}
|
||||
observers := &core.Events{}
|
||||
|
||||
var currentRules []Rule // nolint:prealloc // would require extra local refs for len
|
||||
for name, ruleFunc := range rules.GetInner() {
|
||||
currentRules = append(currentRules, Rule{Name: name, RuleFunc: ruleFunc})
|
||||
// ensure deterministic order evaluation
|
||||
sort.Sort(core.NameSorter(currentRules))
|
||||
}
|
||||
|
||||
for _, currentRule := range currentRules {
|
||||
currentRule.RuleFunc(observers, func(options ...ErrorOption) {
|
||||
err := &gqlerror.Error{
|
||||
Rule: currentRule.Name,
|
||||
}
|
||||
for _, o := range options {
|
||||
o(err)
|
||||
}
|
||||
errs = append(errs, err)
|
||||
})
|
||||
}
|
||||
|
||||
Walk(schema, doc, observers)
|
||||
return errs
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user