diff --git a/examples/engine/go.mod b/examples/engine/go.mod new file mode 100644 index 0000000000..722b64f4fb --- /dev/null +++ b/examples/engine/go.mod @@ -0,0 +1,28 @@ +module github.com/wundergraph/graphql-go-tools/examples/engine + +go 1.25 + +require ( + github.com/cespare/xxhash/v2 v2.3.0 + github.com/wundergraph/graphql-go-tools/v2 v2.1.0 +) + +require ( + github.com/buger/jsonparser v1.1.1 // indirect + github.com/jensneuse/abstractlogger v0.0.4 // indirect + github.com/jensneuse/byte-template v0.0.0-20231025215717-69252eb3ed56 // indirect + github.com/kingledion/go-tools v0.6.0 // indirect + github.com/phf/go-queue v0.0.0-20170504031614-9abe38d0371d // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/sirupsen/logrus v1.9.3 // indirect + github.com/tidwall/gjson v1.18.0 // indirect + github.com/tidwall/match v1.1.1 // indirect + github.com/tidwall/pretty v1.2.1 // indirect + github.com/tidwall/sjson v1.2.5 // indirect + github.com/wundergraph/astjson v1.1.0 // indirect + github.com/wundergraph/go-arena v1.1.0 // indirect + go.uber.org/multierr v1.11.0 // indirect + go.uber.org/zap v1.27.0 // indirect + golang.org/x/sync v0.17.0 // indirect + golang.org/x/sys v0.37.0 // indirect +) diff --git a/examples/engine/go.sum b/examples/engine/go.sum new file mode 100644 index 0000000000..6028c5ca70 --- /dev/null +++ b/examples/engine/go.sum @@ -0,0 +1,107 @@ +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/buger/jsonparser v1.1.1 h1:2PnMjfWD7wBILjqQbt530v576A/cAbQvEW9gGIpYMUs= +github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0= +github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= +github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc= +github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= +github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/jensneuse/abstractlogger v0.0.4 h1:sa4EH8fhWk3zlTDbSncaWKfwxYM8tYSlQ054ETLyyQY= +github.com/jensneuse/abstractlogger v0.0.4/go.mod h1:6WuamOHuykJk8zED/R0LNiLhWR6C7FIAo43ocUEB3mo= +github.com/jensneuse/byte-template v0.0.0-20231025215717-69252eb3ed56 h1:wo26fh6a6Za0cOMZIopD2sfH/kq83SJ89ixUWl7pCWc= +github.com/jensneuse/byte-template v0.0.0-20231025215717-69252eb3ed56/go.mod h1:0D5r/VSW6D/o65rKLL9xk7sZxL2+oku2HvFPYeIMFr4= +github.com/jensneuse/diffview v1.0.0 h1:4b6FQJ7y3295JUHU3tRko6euyEboL825ZsXeZZM47Z4= +github.com/jensneuse/diffview v1.0.0/go.mod h1:i6IacuD8LnEaPuiyzMHA+Wfz5mAuycMOf3R/orUY9y4= +github.com/kingledion/go-tools v0.6.0 h1:y8C/4mWoHgLkO45dB+Y/j0o4Y4WUB5lDTAcMPMtFpTg= +github.com/kingledion/go-tools v0.6.0/go.mod h1:qcDJQxBui/H/hterGb90GMlLs9Yi7QrwaJL8OGdbsms= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= +github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= +github.com/phf/go-queue v0.0.0-20170504031614-9abe38d0371d h1:U+PMnTlV2tu7RuMK5etusZG3Cf+rpow5hqQByeCzJ2g= +github.com/phf/go-queue v0.0.0-20170504031614-9abe38d0371d/go.mod h1:lXfE4PvvTW5xOjO6Mba8zDPyw8M93B6AQ7frTGnMlA8= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/sebdah/goldie/v2 v2.7.1 h1:PkBHymaYdtvEkZV7TmyqKxdmn5/Vcj+8TpATWZjnG5E= +github.com/sebdah/goldie/v2 v2.7.1/go.mod h1:oZ9fp0+se1eapSRjfYbsV/0Hqhbuu3bJVvKI/NNtssI= +github.com/sergi/go-diff v1.3.1 h1:xkr+Oxo4BOQKmkn/B9eMK0g5Kg/983T9DqqPHwYqD+8= +github.com/sergi/go-diff v1.3.1/go.mod h1:aMJSSKb2lpPvRNec0+w3fl7LP9IOFzdc9Pa4NFbPK1I= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= +github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= +github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= +github.com/tidwall/gjson v1.14.2/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= +github.com/tidwall/gjson v1.18.0 h1:FIDeeyB800efLX89e5a8Y0BNH+LOngJyGrIWxG2FKQY= +github.com/tidwall/gjson v1.18.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= +github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= +github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= +github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= +github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4= +github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= +github.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY= +github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28= +github.com/wundergraph/astjson v1.1.0 h1:xORDosrZ87zQFJwNGe/HIHXqzpdHOFmqWgykCLVL040= +github.com/wundergraph/astjson v1.1.0/go.mod h1:h12D/dxxnedtLzsKyBLK7/Oe4TAoGpRVC9nDpDrZSWw= +github.com/wundergraph/go-arena v1.1.0 h1:9+wSRkJAkA2vbYHp6s8tEGhPViRGQNGXqPHT0QzhdIc= +github.com/wundergraph/go-arena v1.1.0/go.mod h1:ROOysEHWJjLQ8FSfNxZCziagb7Qw2nXY3/vgKRh7eWw= +github.com/wundergraph/graphql-go-tools/v2 v2.1.0 h1:V1MU/uo+oc5b+aIh3SpCr0rJgLHuhonWg2fhN1sfMdY= +github.com/wundergraph/graphql-go-tools/v2 v2.1.0/go.mod h1:UG/grnPEHumtD82H8FC+3dokiCGK8GF0b5IJc00lSbM= +go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= +go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= +go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= +go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= +go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= +go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= +go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= +go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= +go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= +go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.17.0 h1:l60nONMj9l5drqw6jlhIELNv9I0A4OFgRsG9k2oT9Ug= +golang.org/x/sync v0.17.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.37.0 h1:fdNQudmxPjkdUTPnLn5mdQv7Zwvbvpaxqs831goi9kQ= +golang.org/x/sys v0.37.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +gonum.org/v1/gonum v0.14.0 h1:2NiG67LD1tEH0D7kM+ps2V+fXmsAnpUeec7n8tcr4S0= +gonum.org/v1/gonum v0.14.0/go.mod h1:AoWeoz0becf9QMWtE8iWXNXc27fK4fNeHNf/oMejGfU= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= diff --git a/examples/engine/main.go b/examples/engine/main.go new file mode 100644 index 0000000000..b755a3c469 --- /dev/null +++ b/examples/engine/main.go @@ -0,0 +1,666 @@ +package main + +import ( + "bytes" + "context" + "fmt" + + "github.com/cespare/xxhash/v2" + + "github.com/wundergraph/graphql-go-tools/v2/pkg/ast" + "github.com/wundergraph/graphql-go-tools/v2/pkg/astnormalization" + "github.com/wundergraph/graphql-go-tools/v2/pkg/astparser" + "github.com/wundergraph/graphql-go-tools/v2/pkg/astprinter" + "github.com/wundergraph/graphql-go-tools/v2/pkg/asttransform" + "github.com/wundergraph/graphql-go-tools/v2/pkg/astvalidation" + "github.com/wundergraph/graphql-go-tools/v2/pkg/astvisitor" + "github.com/wundergraph/graphql-go-tools/v2/pkg/engine/datasource/staticdatasource" + "github.com/wundergraph/graphql-go-tools/v2/pkg/engine/plan" + "github.com/wundergraph/graphql-go-tools/v2/pkg/engine/resolve" + "github.com/wundergraph/graphql-go-tools/v2/pkg/operationreport" +) + +func main() { + ExampleParsePrintDocument() + ExampleParseComplexDocument() + ExamplePrintWithIndentation() + ExampleParseOperationNameAndType() + ExampleNormalizeDocument() + ExampleValidateDocument() + ExampleGenerateCacheKey() + ExampleGenerateCacheKeyWithStaticOperationName() + ExamplePlanOperation() + ExampleExecuteOperation() + ExampleWalkAST() +} + +/* +ExampleParsePrintDocument shows you the most basic usage of the library. +It parses a GraphQL document and prints it back to a writer. +*/ +func ExampleParsePrintDocument() { + input := []byte(`query Hello { world }`) + + report := &operationreport.Report{} + document := ast.NewSmallDocument() + parser := astparser.NewParser() + printer := &astprinter.Printer{} + + document.Input.ResetInputBytes(input) + parser.Parse(document, report) + + if report.HasErrors() { + panic(report.Error()) + } + + out := &bytes.Buffer{} + err := printer.Print(document, out) + if err != nil { + panic(err) + } + fmt.Println(out.String()) // Output: query Hello {world} +} + +/* +Okay, that was easy, but also not very useful. +Let's try to parse a more complex document and print it back to a writer. +*/ + +// ExampleParseComplexDocument shows a special feature of the printer +func ExampleParseComplexDocument() { + input := []byte(` + query { + hello + foo { + bar + } + } + `) + + report := &operationreport.Report{} + document := ast.NewSmallDocument() + parser := astparser.NewParser() + printer := &astprinter.Printer{} + + document.Input.ResetInputBytes(input) + parser.Parse(document, report) + + if report.HasErrors() { + panic(report.Error()) + } + + out := &bytes.Buffer{} + err := printer.Print(document, out) + if err != nil { + panic(err) + } + fmt.Println(out.String()) // Output: { hello foo { bar } } +} + +/* +You'll notice that the printer removes all whitespace and newlines. +But what if we wanted to print the document with indentation? +*/ + +func ExamplePrintWithIndentation() { + input := []byte(` + { + hello + foo { + bar + } + } + `) + + report := &operationreport.Report{} + document := ast.NewSmallDocument() + parser := astparser.NewParser() + + document.Input.ResetInputBytes(input) + parser.Parse(document, report) + + if report.HasErrors() { + panic(report.Error()) + } + + out, err := astprinter.PrintStringIndent(document, " ") + if err != nil { + panic(err) + } + fmt.Println(out) + // Output: { + // hello + // foo { + // bar + // } + // } +} + +/* +Okay, fantastic. We can parse and print GraphQL documents. +As a next step, we could analyze the document and extract some information from it. +What if we wanted to know the name of the operation in the document, if any? +And what if we wanted to know about the Operation type? +*/ + +func ExampleParseOperationNameAndType() { + input := []byte(` + query MyQuery { + hello + foo { + bar + } + } + `) + + report := &operationreport.Report{} + document := ast.NewSmallDocument() + parser := astparser.NewParser() + + document.Input.ResetInputBytes(input) + parser.Parse(document, report) + + if report.HasErrors() { + panic(report.Error()) + } + + operationCount := 0 + var ( + operationNames []string + operationTypes []ast.OperationType + ) + + for _, node := range document.RootNodes { + if node.Kind != ast.NodeKindOperationDefinition { + continue + } + operationCount++ + name := document.OperationDefinitionNameString(node.Ref) + operationNames = append(operationNames, name) + operationType := document.OperationDefinitions[node.Ref].OperationType + operationTypes = append(operationTypes, operationType) + } + + fmt.Println(operationCount) // Output: 1 + fmt.Println(operationNames) // Output: [MyQuery] +} + +/* +We've now seen how to analyze the document and learn a bit about it. +We could now add some validation to our application, +e.g. we could check for the number of operations in the document, +and return an error if there are multiple anonymous operations. + +We could also validate the Operation content against a schema. +But before we do this, we need to normalize the document. +This is important because validation relies on the document being normalized. +It was much easier to build the validation and many other features on top of a normalized document. + +Normalization is the process of transforming the document into a canonical form. +This means that the document is transformed in a way that makes it easier to reason about it. +We inline fragments, we remove unused fragments, +we remove duplicate fields, we remove unused variables, +we remove unused operations etc... + +So, let's normalize the document! +*/ + +func ExampleNormalizeDocument() { + input := []byte(` + query MyQuery { + hello + hello + foo { + bar + bar + } + ...MyFragment + } + + fragment MyFragment on Query { + hello + foo { + bar + } + } + `) + + schema := []byte(` + type Query { + hello: String + foo: Foo + } + + type Foo { + bar: String + } + `) + + report := &operationreport.Report{} + document := ast.NewSmallDocument() + parser := astparser.NewParser() + + document.Input.ResetInputBytes(input) + parser.Parse(document, report) + + if report.HasErrors() { + panic(report.Error()) + } + + schemaDocument := ast.NewSmallDocument() + schemaParser := astparser.NewParser() + schemaDocument.Input.ResetInputBytes(schema) + schemaParser.Parse(schemaDocument, report) + + if report.HasErrors() { + panic(report.Error()) + } + + // graphql-go-tools is very strict about the schema + // the above GraphQL Schema is not fully valid, e.g. the `schema { query: Query }` part is missing + // we can fix this automatically by merging the schema with a base schema + err := asttransform.MergeDefinitionWithBaseSchema(schemaDocument) + if err != nil { + panic(err) + } + + // you can customize what rules the normalizer should apply + normalizer := astnormalization.NewWithOpts( + astnormalization.WithExtractVariables(), + astnormalization.WithInlineFragmentSpreads(), + astnormalization.WithRemoveFragmentDefinitions(), + astnormalization.WithRemoveNotMatchingOperationDefinitions(), + ) + + // It's generally recommended to always give your operation a name + // If it doesn't have a name, just add one to the AST before normalizing it + // This is not strictly necessary, but ensures that all normalization rules work as expected + normalizer.NormalizeNamedOperation(document, schemaDocument, []byte("MyQuery"), report) + + if report.HasErrors() { + panic(report.Error()) + } + + out, err := astprinter.PrintStringIndent(document, " ") + if err != nil { + panic(err) + } + + fmt.Println(out) + // Output: query MyQuery { + // hello + // foo { + // bar + // } + // } +} + +/* +Okay, that was a lot of work, but now we have a normalized document. +As you can see, all the duplicate fields have been removed and the fragment has been inlined. + +What can we do with it? +Well, the possibilities are endless, +but why don't we start with validating the document against a schema? +Alright. Let's do it! +*/ + +func ExampleValidateDocument() { + input := []byte(` + query MyQuery { + helo + } + `) + schema := []byte(` + type Query { + hello: String + } + `) + + report := &operationreport.Report{} + + operationDocumentParser := astparser.NewParser() + operationDocument := ast.NewSmallDocument() + operationDocument.Input.ResetInputBytes(input) + operationDocumentParser.Parse(operationDocument, report) + if report.HasErrors() { + panic(report.Error()) + } + + schemaParser := astparser.NewParser() + schemaDocument := ast.NewSmallDocument() + schemaDocument.Input.ResetInputBytes(schema) + schemaParser.Parse(schemaDocument, report) + if report.HasErrors() { + panic(report.Error()) + } + + err := asttransform.MergeDefinitionWithBaseSchema(schemaDocument) + if err != nil { + panic(err) + } + + validator := astvalidation.DefaultOperationValidator() + validator.Validate(operationDocument, schemaDocument, report) + if report.HasErrors() { + println(report.Error()) + } +} + +/* +Fantastic, we've now got a GraphQL document that is valid against a schema. + +As a next step, we could generate a cache key for the document. +This is very useful if we want to start doing expensive operations afterward that could be de-duplicated or cached. +At the same time, generating a cache key from a normalized document is not as trivial as it sounds. +Let's take a look! +*/ + +func ExampleGenerateCacheKey() { + operationDocument := ast.NewSmallDocument() + schemaDocument := ast.NewSmallDocument() + report := &operationreport.Report{} + + normalizer := astnormalization.NewWithOpts( + astnormalization.WithExtractVariables(), + astnormalization.WithInlineFragmentSpreads(), + astnormalization.WithRemoveFragmentDefinitions(), + astnormalization.WithRemoveNotMatchingOperationDefinitions(), + ) + + normalizer.NormalizeNamedOperation( + operationDocument, schemaDocument, []byte("MyQuery"), report) + printer := &astprinter.Printer{} + keyGen := xxhash.New() + err := printer.Print(operationDocument, keyGen) + if err != nil { + panic(err) + } + + // you might be thinking that we're done now, but we're not + // we've extracted the variables, so we need to add them to the cache key + + _, err = keyGen.Write(operationDocument.Input.Variables) + if err != nil { + panic(err) + } + + key := keyGen.Sum64() + fmt.Printf("%x\n", key) // Output: {cache key} +} + +/* +Good job! We now have a correct cache key for the document. +We're using this ourselves in production to de-duplicate e.g. planning the execution of a GraphQL Operation. + +There's just one problem with the above code. +An attacker could easily send the same document with a different Operation name and get a different cache key. +This could quite easily fill up our cache with duplicate entries. +To prevent this, we can make the operation name static. +Let's change out code to account for this. +*/ + +func ExampleGenerateCacheKeyWithStaticOperationName() { + staticOperationName := []byte("O") + + operationDocument := ast.NewSmallDocument() + schemaDocument := ast.NewSmallDocument() + report := &operationreport.Report{} + + normalizer := astnormalization.NewWithOpts( + astnormalization.WithExtractVariables(), + astnormalization.WithInlineFragmentSpreads(), + astnormalization.WithRemoveFragmentDefinitions(), + astnormalization.WithRemoveNotMatchingOperationDefinitions(), + ) + + // First, we add the static operation name to the document and get an "address" to the byte slice (string) in the document + // We cannot just add a string to an AST because the AST only stores references to byte slices + // Storing strings in AST nodes would be very inefficient and would require a lot of allocations + nameRef := operationDocument.Input.AppendInputBytes(staticOperationName) + + for _, node := range operationDocument.RootNodes { + if node.Kind != ast.NodeKindOperationDefinition { + continue + } + name := operationDocument.OperationDefinitionNameString(node.Ref) + if name != "MyQuery" { + continue + } + // Then we set the name of the operation to the address of the static operation name + // Now we have renamed MyQuery to O + operationDocument.OperationDefinitions[node.Ref].Name = nameRef + } + + // Now we can normalize the modified document + // All Operations that don't have the name O will be removed + normalizer.NormalizeNamedOperation(operationDocument, schemaDocument, staticOperationName, report) + + printer := &astprinter.Printer{} + keyGen := xxhash.New() + err := printer.Print(operationDocument, keyGen) + if err != nil { + panic(err) + } + + _, err = keyGen.Write(operationDocument.Input.Variables) + if err != nil { + panic(err) + } + + key := keyGen.Sum64() + fmt.Printf("%x\n", key) // Output: {cache key} +} + +/* +With these changes, the name of the operation doesn't matter anymore. +Independent of the name, the cache key will always be the same. + +As a next step, we could start planning the execution of the operation. +This is a very complex topic, so we'll just show you how to plan the operation. +Going into detail would be beyond the scope of this example. +It took us years to get this right, so we won't be able to explain it in a few lines of code. + +graphql-go-tools is not a GraphQL server by itself. +It's a library that you can use to build Routers, Gateways, or even GraphQL Server frameworks on top of it. +What this means is that there's no built-in support to define "resolvers". +Instead, you have to define DataSources that are used to resolve fields. + +A DataSource can be anything, e.g. a static value, a HTTP JSON API, a GraphQL API, a WASM Lambda, a Database etc. +It's up to you to implement the DataSource interface. + +The simplest DataSource is the StaticDataSource. +It's a DataSource that returns a static value for a field. +Let's see how to use it! + +You have to attach the DataSource to one or more fields in the schema, +and you have to provide a config and a factory for the DataSource, +so that the planner knows how to create an execution plan for the DataSource and an "instance" of the DataSource. +*/ + +func ExamplePlanOperation() { + staticDataSource, err := plan.NewDataSourceConfiguration[staticdatasource.Configuration]( + "StaticDataSource", + &staticdatasource.Factory[staticdatasource.Configuration]{}, + &plan.DataSourceMetadata{ + RootNodes: []plan.TypeField{ + { + TypeName: "Query", + FieldNames: []string{"hello"}, + }, + }, + }, + staticdatasource.Configuration{ + Data: `{"hello":"world"}`, + }, + ) + if err != nil { + panic(err) + } + + config := plan.Configuration{ + DataSources: []plan.DataSource{ + staticDataSource, + }, + Fields: []plan.FieldConfiguration{ + { + TypeName: "Query", // attach this config to the Query type and the field hello + FieldName: "hello", + DisableDefaultMapping: true, // disable the default mapping for this field which only applies to GraphQL APIs + Path: []string{"hello"}, // returns the value of the field "hello" from the JSON data + }, + }, + } + + input := []byte(`query O { hello }`) + schema := []byte(`type Query { hello: String }`) + + report := &operationreport.Report{} + operationDocument := ast.NewSmallDocument() + operationDocumentParser := astparser.NewParser() + operationDocument.Input.ResetInputBytes(input) + operationDocumentParser.Parse(operationDocument, report) + if report.HasErrors() { + panic(report.Error()) + } + + schemaDocument := ast.NewSmallDocument() + schemaParser := astparser.NewParser() + schemaDocument.Input.ResetInputBytes(schema) + schemaParser.Parse(schemaDocument, report) + if report.HasErrors() { + panic(report.Error()) + } + + operationName := "O" + + err = asttransform.MergeDefinitionWithBaseSchema(schemaDocument) + if err != nil { + panic(err) + } + + planner, err := plan.NewPlanner(config) + if err != nil { + panic(err) + } + executionPlan := planner.Plan(operationDocument, schemaDocument, operationName, report) + if report.HasErrors() { + panic(report.Error()) + } + fmt.Printf("%+v\n", executionPlan) // Output: Plan... +} + +/* +As you can see, the planner has created a plan for us. +This plan can now be executed by using the Resolver. +*/ + +func ExampleExecuteOperation() { + var preparedPlan plan.Plan + resolver := resolve.New(context.Background(), resolve.ResolverOptions{}) + + ctx := resolve.NewContext(context.Background()) + + switch p := preparedPlan.(type) { + case *plan.SynchronousResponsePlan: + out := &bytes.Buffer{} + err, _ := resolver.ResolveGraphQLResponse(ctx, p.Response, nil, out) + if err != nil { + panic(err) + } + fmt.Println(out.String()) // Output: {"data":{"hello":"world"}} + case *plan.SubscriptionResponsePlan: + // this is a Query, so we ignore Subscriptions for now, but they are supported + } +} + +/* +Well done! You've now seen how to parse, print, validate, normalize, plan and execute a GraphQL document. +You've built a complete GraphQL API Gateway from scratch. +That said, this was really just the tip of the iceberg. + +When you look under the hood of graphql-go-tools, you'll notice that a lot of its functionality is built on top of the AST, +more specifically on top of the "astvisitor" package. +It comes with a lot of useful bells and whistles that help you to solve complex problems. + +You'll notice that almost everything, from normalization to printing, planning, validation, etc. +is built on top of the AST and the astvisitor package. + +Let's take a look at a basic example of how to use the astvisitor package to build higher level functionality. +Here's a simple use case: + +Let's walk through the AST of a GraphQL document and extract all tuples of (TypeName, FieldName). +This is useful, e.g. when you want to extract information about the fields that are used in a document. +*/ + +type visitor struct { + walker *astvisitor.Walker + operation, definition *ast.Document + typeFields [][]string +} + +func (v *visitor) EnterField(ref int) { + // get the name of the enclosing type (Query) + enclosingTypeName := v.walker.EnclosingTypeDefinition.NameString(v.definition) + // get the name of the field (hello) + fieldName := v.operation.FieldNameString(ref) + // get the type definition of the field (String) + definitionRef, exists := v.walker.FieldDefinition(ref) + if !exists { + return + } + // get the name of the field type (String) + fieldTypeName := v.definition.FieldDefinitionTypeNameString(definitionRef) + v.typeFields = append(v.typeFields, []string{enclosingTypeName, fieldName, fieldTypeName}) +} + +func ExampleWalkAST() { + report := &operationreport.Report{} + + operationInput := []byte(`query O { hello }`) + operationParser := astparser.NewParser() + operationDocument := ast.NewSmallDocument() + operationDocument.Input.ResetInputBytes(operationInput) + operationParser.Parse(operationDocument, report) + if report.HasErrors() { + panic(report.Error()) + } + + schemaInput := []byte(`type Query { hello: String }`) + schemaParser := astparser.NewParser() + schemaDocument := ast.NewSmallDocument() + schemaDocument.Input.ResetInputBytes(schemaInput) + schemaParser.Parse(schemaDocument, report) + if report.HasErrors() { + panic(report.Error()) + } + + err := asttransform.MergeDefinitionWithBaseSchema(schemaDocument) + if err != nil { + panic(err) + } + + walker := astvisitor.NewWalker(24) + + vis := &visitor{ + walker: &walker, + operation: operationDocument, + definition: schemaDocument, + } + + walker.RegisterEnterFieldVisitor(vis) + walker.Walk(operationDocument, schemaDocument, report) + if report.HasErrors() { + panic(report.Error()) + } + fmt.Printf("%+v\n", vis.typeFields) // Output: [[Query hello String]] +} + +/* +This is just a very basic example of what you can do with the astvisitor package, +but you can see that it's very powerful and flexible. + +You can register callbacks for every AST node and do whatever you want with it. +In addition, the walker helps you to keep track of the current position in the AST, +and it can help you to figure out the enclosing type of a field,or the ancestors or a node. +*/ diff --git a/examples/federation/README.md b/examples/federation/README.md index d9261697cb..58ae3d6309 100644 --- a/examples/federation/README.md +++ b/examples/federation/README.md @@ -1,4 +1,17 @@ -# Federation Demo +# Federation example + +This is a very basic example of the federation. +It is not meant to be used in production. + +If you're looking for a complete ready-to-use Open Source Router for Federation, +have a look at the [Cosmo Router](https://github.com/wundergraph/cosmo) which is based on this engine library. + +This example includes three services: +- `accounts` +- `products` +- `reviews` + +Services defines a few queries and subscriptions. ## Getting started 1. Install go modules @@ -9,4 +22,8 @@ go mod download ``` chmod +x start.sh ./start.sh -``` \ No newline at end of file +``` +3. To change subgraphs +- edit corresponding `/graph/schema.graphqls` file +- run `go generate ./...` +- compose a new config via `compose.sh` \ No newline at end of file diff --git a/examples/federation/compose.sh b/examples/federation/compose.sh new file mode 100755 index 0000000000..d20d9811f0 --- /dev/null +++ b/examples/federation/compose.sh @@ -0,0 +1,10 @@ +#!/usr/bin/env bash +set -euo pipefail + +echo "Composing subgraphs" + +npx -y wgc@latest router compose -i graph.yaml -o config.json + +echo "Formatting config" +jq . config.json > config.json.tmp +mv config.json.tmp config.json diff --git a/examples/federation/config.json b/examples/federation/config.json new file mode 100644 index 0000000000..9bb65775a6 --- /dev/null +++ b/examples/federation/config.json @@ -0,0 +1,248 @@ +{ + "engineConfig": { + "defaultFlushInterval": "500", + "datasourceConfigurations": [ + { + "kind": "GRAPHQL", + "rootNodes": [ + { + "typeName": "Query", + "fieldNames": [ + "me" + ] + }, + { + "typeName": "User", + "fieldNames": [ + "id", + "username" + ] + } + ], + "overrideFieldPathFromAlias": true, + "customGraphql": { + "fetch": { + "url": { + "staticVariableContent": "http://localhost:4001/query" + }, + "method": "POST", + "body": {}, + "baseUrl": {}, + "path": {} + }, + "subscription": { + "enabled": true, + "url": { + "staticVariableContent": "http://localhost:4001/query" + }, + "protocol": "GRAPHQL_SUBSCRIPTION_PROTOCOL_WS", + "websocketSubprotocol": "GRAPHQL_WEBSOCKET_SUBPROTOCOL_AUTO" + }, + "federation": { + "enabled": true, + "serviceSdl": "extend type Query {\n me: User\n}\n\ntype User @key(fields: \"id\") {\n id: ID!\n username: String!\n}\n" + }, + "upstreamSchema": { + "key": "fd8732851b74811c8ef4ec60923cbad1c5fab185" + } + }, + "requestTimeoutSeconds": "10", + "id": "0", + "keys": [ + { + "typeName": "User", + "selectionSet": "id" + } + ] + }, + { + "kind": "GRAPHQL", + "rootNodes": [ + { + "typeName": "Query", + "fieldNames": [ + "topProducts" + ] + }, + { + "typeName": "Subscription", + "fieldNames": [ + "updatedPrice", + "updateProductPrice", + "stock" + ] + }, + { + "typeName": "Product", + "fieldNames": [ + "upc", + "name", + "price", + "inStock" + ] + } + ], + "overrideFieldPathFromAlias": true, + "customGraphql": { + "fetch": { + "url": { + "staticVariableContent": "http://localhost:4002/query" + }, + "method": "POST", + "body": {}, + "baseUrl": {}, + "path": {} + }, + "subscription": { + "enabled": true, + "url": { + "staticVariableContent": "http://localhost:4002/query" + }, + "protocol": "GRAPHQL_SUBSCRIPTION_PROTOCOL_WS", + "websocketSubprotocol": "GRAPHQL_WEBSOCKET_SUBPROTOCOL_AUTO" + }, + "federation": { + "enabled": true, + "serviceSdl": "extend type Query {\n topProducts(first: Int = 5): [Product]\n}\n\nextend type Subscription {\n updatedPrice: Product!\n updateProductPrice(upc: String!): Product!\n stock: [Product!]\n}\n\ntype Product @key(fields: \"upc\") {\n upc: String!\n name: String!\n price: Int!\n inStock: Int!\n}" + }, + "upstreamSchema": { + "key": "9604371bfa5d636011500a2b8b94a97c2309c222" + } + }, + "requestTimeoutSeconds": "10", + "id": "1", + "keys": [ + { + "typeName": "Product", + "selectionSet": "upc" + } + ] + }, + { + "kind": "GRAPHQL", + "rootNodes": [ + { + "typeName": "User", + "fieldNames": [ + "id", + "reviews" + ], + "externalFieldNames": [ + "username" + ] + }, + { + "typeName": "Product", + "fieldNames": [ + "upc", + "reviews" + ] + } + ], + "childNodes": [ + { + "typeName": "Review", + "fieldNames": [ + "body", + "author", + "product" + ] + } + ], + "overrideFieldPathFromAlias": true, + "customGraphql": { + "fetch": { + "url": { + "staticVariableContent": "http://localhost:4003/query" + }, + "method": "POST", + "body": {}, + "baseUrl": {}, + "path": {} + }, + "subscription": { + "enabled": true, + "url": { + "staticVariableContent": "http://localhost:4003/query" + }, + "protocol": "GRAPHQL_SUBSCRIPTION_PROTOCOL_WS", + "websocketSubprotocol": "GRAPHQL_WEBSOCKET_SUBPROTOCOL_AUTO" + }, + "federation": { + "enabled": true, + "serviceSdl": "type Review {\n body: String!\n author: User! @provides(fields: \"username\")\n product: Product!\n}\n\nextend type User @key(fields: \"id\") {\n id: ID! @external\n username: String! @external\n reviews: [Review]\n}\n\nextend type Product @key(fields: \"upc\") {\n upc: String! @external\n reviews: [Review]\n}\n" + }, + "upstreamSchema": { + "key": "3b6908f2120ecc5615dd1e62d4b96c285a67b387" + } + }, + "requestTimeoutSeconds": "10", + "id": "2", + "keys": [ + { + "typeName": "User", + "selectionSet": "id" + }, + { + "typeName": "Product", + "selectionSet": "upc" + } + ], + "provides": [ + { + "typeName": "Review", + "fieldName": "author", + "selectionSet": "username" + } + ] + } + ], + "fieldConfigurations": [ + { + "typeName": "Query", + "fieldName": "topProducts", + "argumentsConfiguration": [ + { + "name": "first", + "sourceType": "FIELD_ARGUMENT" + } + ] + }, + { + "typeName": "Subscription", + "fieldName": "updateProductPrice", + "argumentsConfiguration": [ + { + "name": "upc", + "sourceType": "FIELD_ARGUMENT" + } + ] + } + ], + "graphqlSchema": "schema {\n query: Query\n subscription: Subscription\n}\n\ntype Query {\n me: User\n topProducts(first: Int = 5): [Product]\n}\n\ntype User {\n id: ID!\n username: String!\n reviews: [Review]\n}\n\ntype Subscription {\n updatedPrice: Product!\n updateProductPrice(upc: String!): Product!\n stock: [Product!]\n}\n\ntype Product {\n upc: String!\n name: String!\n price: Int!\n inStock: Int!\n reviews: [Review]\n}\n\ntype Review {\n body: String!\n author: User!\n product: Product!\n}", + "stringStorage": { + "fd8732851b74811c8ef4ec60923cbad1c5fab185": "schema {\n query: Query\n}\n\ndirective @key(fields: openfed__FieldSet!, resolvable: Boolean = true) repeatable on INTERFACE | OBJECT\n\ntype Query {\n me: User\n}\n\ntype User @key(fields: \"id\") {\n id: ID!\n username: String!\n}\n\nscalar openfed__FieldSet", + "9604371bfa5d636011500a2b8b94a97c2309c222": "schema {\n query: Query\n subscription: Subscription\n}\n\ndirective @key(fields: openfed__FieldSet!, resolvable: Boolean = true) repeatable on INTERFACE | OBJECT\n\ntype Product @key(fields: \"upc\") {\n inStock: Int!\n name: String!\n price: Int!\n upc: String!\n}\n\ntype Query {\n topProducts(first: Int = 5): [Product]\n}\n\ntype Subscription {\n stock: [Product!]\n updateProductPrice(upc: String!): Product!\n updatedPrice: Product!\n}\n\nscalar openfed__FieldSet", + "3b6908f2120ecc5615dd1e62d4b96c285a67b387": "directive @external on FIELD_DEFINITION | OBJECT\n\ndirective @key(fields: openfed__FieldSet!, resolvable: Boolean = true) repeatable on INTERFACE | OBJECT\n\ndirective @provides(fields: openfed__FieldSet!) on FIELD_DEFINITION\n\ntype Product @key(fields: \"upc\") {\n reviews: [Review]\n upc: String! @external\n}\n\ntype Review {\n author: User! @provides(fields: \"username\")\n body: String!\n product: Product!\n}\n\ntype User @key(fields: \"id\") {\n id: ID! @external\n reviews: [Review]\n username: String! @external\n}\n\nscalar openfed__FieldSet" + } + }, + "version": "00000000-0000-0000-0000-000000000000", + "subgraphs": [ + { + "id": "0", + "name": "accounts", + "routingUrl": "http://localhost:4001/query" + }, + { + "id": "1", + "name": "products", + "routingUrl": "http://localhost:4002/query" + }, + { + "id": "2", + "name": "reviews", + "routingUrl": "http://localhost:4003/query" + } + ], + "compatibilityVersion": "1:0.58.2" +} diff --git a/examples/federation/gateway/datasource_poller.go b/examples/federation/gateway/datasource_poller.go deleted file mode 100644 index 332ae77b54..0000000000 --- a/examples/federation/gateway/datasource_poller.go +++ /dev/null @@ -1,216 +0,0 @@ -package main - -import ( - "bytes" - "context" - "encoding/json" - "fmt" - "io" - "log" - "net/http" - "strings" - "sync" - "time" - - "github.com/wundergraph/graphql-go-tools/execution/engine" -) - -type ServiceConfig struct { - Name string - URL string - WS string - Fallback func(*ServiceConfig) (string, error) -} - -type DatasourcePollerConfig struct { - Services []ServiceConfig - PollingInterval time.Duration -} - -const ServiceDefinitionQuery = ` - { - "query": "query __ApolloGetServiceDefinition__ { _service { sdl } }", - "operationName": "__ApolloGetServiceDefinition__", - "variables": {} - }` - -type GQLErr []struct { - Message string `json:"message"` -} - -func (g GQLErr) Error() string { - var builder strings.Builder - for _, m := range g { - _ = builder.WriteByte('\t') - _, _ = builder.WriteString(m.Message) - } - - return builder.String() -} - -func NewDatasourcePoller( - httpClient *http.Client, - config DatasourcePollerConfig, -) *DatasourcePollerPoller { - return &DatasourcePollerPoller{ - httpClient: httpClient, - config: config, - sdlMap: make(map[string]string), - } -} - -type DatasourcePollerPoller struct { - httpClient *http.Client - - config DatasourcePollerConfig - sdlMap map[string]string - - updateDatasourceObservers []DataSourceObserver -} - -func (d *DatasourcePollerPoller) Register(updateDatasourceObserver DataSourceObserver) { - d.updateDatasourceObservers = append(d.updateDatasourceObservers, updateDatasourceObserver) -} - -func (d *DatasourcePollerPoller) Run(ctx context.Context) { - d.updateSDLs(ctx) - - if d.config.PollingInterval == 0 { - <-ctx.Done() - return - } - - ticker := time.NewTicker(d.config.PollingInterval) - defer ticker.Stop() - - for { - select { - case <-ctx.Done(): - return - case <-ticker.C: - d.updateSDLs(ctx) - } - } -} - -func (d *DatasourcePollerPoller) updateSDLs(ctx context.Context) { - d.sdlMap = make(map[string]string) - - var wg sync.WaitGroup - resultCh := make(chan struct { - name string - sdl string - }) - - for _, serviceConf := range d.config.Services { - serviceConf := serviceConf // Create new instance of serviceConf for the goroutine. - wg.Add(1) - go func() { - defer wg.Done() - - sdl, err := d.fetchServiceSDL(ctx, serviceConf.URL) - if err != nil { - log.Println("Failed to get sdl.", err) - - if serviceConf.Fallback == nil { - return - } else { - sdl, err = serviceConf.Fallback(&serviceConf) - if err != nil { - log.Println("Failed to get sdl with fallback.", err) - return - } - } - } - - select { - case <-ctx.Done(): - case resultCh <- struct { - name string - sdl string - }{name: serviceConf.Name, sdl: sdl}: - } - }() - } - - go func() { - wg.Wait() - close(resultCh) - }() - - for result := range resultCh { - d.sdlMap[result.name] = result.sdl - } - - d.updateObservers() -} - -func (d *DatasourcePollerPoller) updateObservers() { - subgraphsConfig := d.createSubgraphsConfig() - - for i := range d.updateDatasourceObservers { - d.updateDatasourceObservers[i].UpdateDataSources(subgraphsConfig) - } -} - -func (d *DatasourcePollerPoller) createSubgraphsConfig() []engine.SubgraphConfiguration { - subgraphConfigs := make([]engine.SubgraphConfiguration, 0, len(d.config.Services)) - - for _, serviceConfig := range d.config.Services { - sdl, exists := d.sdlMap[serviceConfig.Name] - if !exists { - continue - } - - subgraphConfig := engine.SubgraphConfiguration{ - Name: serviceConfig.Name, - URL: serviceConfig.URL, - SubscriptionUrl: serviceConfig.WS, - SDL: sdl, - } - - subgraphConfigs = append(subgraphConfigs, subgraphConfig) - } - - return subgraphConfigs -} - -func (d *DatasourcePollerPoller) fetchServiceSDL(ctx context.Context, serviceURL string) (string, error) { - req, err := http.NewRequestWithContext(ctx, http.MethodPost, serviceURL, bytes.NewReader([]byte(ServiceDefinitionQuery))) - req.Header.Add("Content-Type", "application/json") - - if err != nil { - return "", fmt.Errorf("create request: %v", err) - } - - resp, err := d.httpClient.Do(req) - if err != nil { - return "", fmt.Errorf("do request: %v", err) - } - - defer resp.Body.Close() - - var result struct { - Data struct { - Service struct { - SDL string `json:"sdl"` - } `json:"_service"` - } `json:"data"` - Errors GQLErr `json:"errors,omitempty"` - } - - bs, err := io.ReadAll(resp.Body) - if err != nil { - return "", fmt.Errorf("read bytes: %v", err) - } - - if err = json.NewDecoder(bytes.NewReader(bs)).Decode(&result); err != nil { - return "", fmt.Errorf("decode response: %v", err) - } - - if result.Errors != nil { - return "", fmt.Errorf("response error:%v", result.Errors) - } - - return result.Data.Service.SDL, nil -} diff --git a/examples/federation/gateway/gateway.go b/examples/federation/gateway/gateway.go index 906a78741b..a9b69c8985 100644 --- a/examples/federation/gateway/gateway.go +++ b/examples/federation/gateway/gateway.go @@ -1,98 +1,56 @@ -package main +package gateway import ( "context" + "fmt" "net/http" - "sync" + "github.com/gobwas/ws" log "github.com/jensneuse/abstractlogger" + "google.golang.org/protobuf/encoding/protojson" + nodev1 "github.com/wundergraph/cosmo/router/gen/proto/wg/cosmo/node/v1" + + "github.com/wundergraph/graphql-go-tools/examples/federation/gateway/httphandler" "github.com/wundergraph/graphql-go-tools/execution/engine" - "github.com/wundergraph/graphql-go-tools/execution/graphql" "github.com/wundergraph/graphql-go-tools/v2/pkg/engine/resolve" ) -type DataSourceObserver interface { - UpdateDataSources(subgraphsConfigs []engine.SubgraphConfiguration) -} - -type DataSourceSubject interface { - Register(observer DataSourceObserver) -} - -type HandlerFactory interface { - Make(schema *graphql.Schema, engine *engine.ExecutionEngine) http.Handler -} - -type HandlerFactoryFn func(schema *graphql.Schema, engine *engine.ExecutionEngine) http.Handler - -func (h HandlerFactoryFn) Make(schema *graphql.Schema, engine *engine.ExecutionEngine) http.Handler { - return h(schema, engine) -} - func NewGateway( ctx context.Context, - gqlHandlerFactory HandlerFactory, + configFileContent []byte, httpClient *http.Client, logger log.Logger, -) *Gateway { - return &Gateway{ - engineCtx: ctx, - gqlHandlerFactory: gqlHandlerFactory, - httpClient: httpClient, - logger: logger, - - mu: &sync.Mutex{}, - readyCh: make(chan struct{}), - readyOnce: &sync.Once{}, + enableART bool, +) (*Gateway, error) { + var rc nodev1.RouterConfig + if err := protojson.Unmarshal(configFileContent, &rc); err != nil { + return nil, fmt.Errorf("can't unmarshal composed config: %w", err) } -} - -type Gateway struct { - gqlHandlerFactory HandlerFactory - httpClient *http.Client - logger log.Logger - - gqlHandler http.Handler - mu *sync.Mutex - - readyCh chan struct{} - readyOnce *sync.Once - engineCtx context.Context -} -func (g *Gateway) ServeHTTP(w http.ResponseWriter, r *http.Request) { - g.mu.Lock() - handler := g.gqlHandler - g.mu.Unlock() + engineConfigFactory := engine.NewFederationEngineConfigFactory(ctx, engine.WithFederationHttpClient(httpClient)) - handler.ServeHTTP(w, r) -} - -func (g *Gateway) Ready() { - <-g.readyCh -} - -func (g *Gateway) UpdateDataSources(subgraphsConfigs []engine.SubgraphConfiguration) { - engineConfigFactory := engine.NewFederationEngineConfigFactory(g.engineCtx, subgraphsConfigs, engine.WithFederationHttpClient(g.httpClient)) - - engineConfig, err := engineConfigFactory.BuildEngineConfiguration() + engineConfig, err := engineConfigFactory.BuildEngineConfiguration(&rc) if err != nil { - g.logger.Error("get engine config: %v", log.Error(err)) - return + return nil, fmt.Errorf("can't build engine configuration: %w", err) } - executionEngine, err := engine.NewExecutionEngine(g.engineCtx, g.logger, engineConfig, resolve.ResolverOptions{ + executionEngine, err := engine.NewExecutionEngine(ctx, logger, engineConfig, resolve.ResolverOptions{ MaxConcurrency: 1024, }) if err != nil { - g.logger.Error("create engine: %v", log.Error(err)) - return + return nil, fmt.Errorf("can't create an engine: %w", err) } - g.mu.Lock() - g.gqlHandler = g.gqlHandlerFactory.Make(engineConfig.Schema(), executionEngine) - g.mu.Unlock() + upgrader := &ws.DefaultHTTPUpgrader + upgrader.Header = http.Header{} + upgrader.Header.Add("Sec-Websocket-Protocol", "graphql-ws") + + handler := httphandler.NewGraphqlHTTPHandler(engineConfig.Schema(), executionEngine, upgrader, logger, enableART) - g.readyOnce.Do(func() { close(g.readyCh) }) + return &Gateway{handler}, nil +} + +type Gateway struct { + http.Handler } diff --git a/examples/federation/gateway/http/handler.go b/examples/federation/gateway/httphandler/handler.go similarity index 98% rename from examples/federation/gateway/http/handler.go rename to examples/federation/gateway/httphandler/handler.go index e6d575cd7a..8b6e537c22 100644 --- a/examples/federation/gateway/http/handler.go +++ b/examples/federation/gateway/httphandler/handler.go @@ -1,4 +1,4 @@ -package http +package httphandler import ( "net/http" diff --git a/examples/federation/gateway/http/http.go b/examples/federation/gateway/httphandler/http.go similarity index 98% rename from examples/federation/gateway/http/http.go rename to examples/federation/gateway/httphandler/http.go index a4ca04ad8c..05624e57d2 100644 --- a/examples/federation/gateway/http/http.go +++ b/examples/federation/gateway/httphandler/http.go @@ -1,5 +1,5 @@ // Package http handles GraphQL HTTP Requests including WebSocket Upgrades. -package http +package httphandler import ( "bytes" diff --git a/examples/federation/gateway/http/ws.go b/examples/federation/gateway/httphandler/ws.go similarity index 99% rename from examples/federation/gateway/http/ws.go rename to examples/federation/gateway/httphandler/ws.go index 48943da4fb..24fec4a079 100644 --- a/examples/federation/gateway/http/ws.go +++ b/examples/federation/gateway/httphandler/ws.go @@ -1,4 +1,4 @@ -package http +package httphandler import ( "context" diff --git a/examples/federation/go.mod b/examples/federation/go.mod index 2c6235bf58..d56b38b7ff 100644 --- a/examples/federation/go.mod +++ b/examples/federation/go.mod @@ -8,10 +8,12 @@ require ( github.com/gorilla/websocket v1.5.1 github.com/jensneuse/abstractlogger v0.0.4 github.com/vektah/gqlparser/v2 v2.5.30 + github.com/wundergraph/cosmo/router v0.0.0-20251013094319-c611abf26b17 github.com/wundergraph/graphql-go-tools/execution v1.0.1 - github.com/wundergraph/graphql-go-tools/v2 v2.0.0-rc.231 + github.com/wundergraph/graphql-go-tools/v2 v2.1.0 go.uber.org/atomic v1.11.0 go.uber.org/zap v1.27.0 + google.golang.org/protobuf v1.36.9 ) require ( @@ -22,13 +24,9 @@ require ( github.com/coder/websocket v1.8.14 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.7 // indirect github.com/davecgh/go-spew v1.1.1 // indirect - github.com/dlclark/regexp2 v1.11.0 // indirect - github.com/dop251/goja v0.0.0-20230906160731-9410bcaa81d2 // indirect - github.com/go-sourcemap/sourcemap v2.1.3+incompatible // indirect github.com/go-viper/mapstructure/v2 v2.4.0 // indirect github.com/gobwas/httphead v0.1.0 // indirect github.com/gobwas/pool v0.2.1 // indirect - github.com/google/pprof v0.0.0-20230207041349-798e818bf904 // indirect github.com/google/uuid v1.6.0 // indirect github.com/hashicorp/golang-lru v0.5.4 // indirect github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect @@ -51,9 +49,7 @@ require ( github.com/tidwall/pretty v1.2.1 // indirect github.com/tidwall/sjson v1.2.5 // indirect github.com/urfave/cli/v2 v2.27.7 // indirect - github.com/wundergraph/astjson v1.0.0 // indirect - github.com/wundergraph/cosmo/composition-go v0.0.0-20241020204711-78f240a77c99 // indirect - github.com/wundergraph/cosmo/router v0.0.0-20251013094319-c611abf26b17 // indirect + github.com/wundergraph/astjson v1.1.0 // indirect github.com/wundergraph/go-arena v1.1.0 // indirect github.com/xrash/smetrics v0.0.0-20250705151800-55b8f293f342 // indirect go.uber.org/multierr v1.11.0 // indirect @@ -65,10 +61,8 @@ require ( golang.org/x/tools v0.38.0 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20250115164207-1a7da9e5054f // indirect google.golang.org/grpc v1.71.0 // indirect - google.golang.org/protobuf v1.36.9 // indirect gopkg.in/cenkalti/backoff.v1 v1.1.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect - rogchap.com/v8go v0.9.0 // indirect ) replace github.com/wundergraph/graphql-go-tools/v2 => ../../v2 diff --git a/examples/federation/go.sum b/examples/federation/go.sum index b7957488be..cbfb7a7a12 100644 --- a/examples/federation/go.sum +++ b/examples/federation/go.sum @@ -17,36 +17,21 @@ github.com/buger/jsonparser v1.1.1 h1:2PnMjfWD7wBILjqQbt530v576A/cAbQvEW9gGIpYMU github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/chzyer/logex v1.2.0/go.mod h1:9+9sk7u7pGNWYMkh0hdiL++6OeibzJccyQU4p4MedaY= -github.com/chzyer/readline v1.5.0/go.mod h1:x22KAscuvRqlLoK9CsoYsmxoXZMMFVyOl86cAH8qUic= -github.com/chzyer/test v0.0.0-20210722231415-061457976a23/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/coder/websocket v1.8.14 h1:9L0p0iKiNOibykf283eHkKUHHrpG7f65OE3BhhO7v9g= github.com/coder/websocket v1.8.14/go.mod h1:NX3SzP+inril6yawo5CQXx8+fk145lPDC6pumgx0mVg= github.com/cpuguy83/go-md2man/v2 v2.0.7 h1:zbFlGlXEAKlwXpmvle3d8Oe3YnkKIK4xSRTd3sHPnBo= github.com/cpuguy83/go-md2man/v2 v2.0.7/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= -github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dgryski/trifles v0.0.0-20230903005119-f50d829f2e54 h1:SG7nF6SRlWhcT7cNTs5R6Hk4V2lcmLz2NsG2VnInyNo= github.com/dgryski/trifles v0.0.0-20230903005119-f50d829f2e54/go.mod h1:if7Fbed8SFyPtHLHbg49SI7NAdJiC5WIA09pe59rfAA= -github.com/dlclark/regexp2 v1.4.1-0.20201116162257-a2a8dda75c91/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc= -github.com/dlclark/regexp2 v1.7.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= -github.com/dlclark/regexp2 v1.11.0 h1:G/nrcoOa7ZXlpoa/91N3X7mM3r8eIlMBBJZvsz/mxKI= -github.com/dlclark/regexp2 v1.11.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= -github.com/dop251/goja v0.0.0-20211022113120-dc8c55024d06/go.mod h1:R9ET47fwRVRPZnOGvHxxhuZcbrMCuiqOz3Rlrh4KSnk= -github.com/dop251/goja v0.0.0-20230906160731-9410bcaa81d2 h1:3J+RqSTu+JuyCYjoe82vvUUljEfgp8i6+nyhUsaYAbg= -github.com/dop251/goja v0.0.0-20230906160731-9410bcaa81d2/go.mod h1:QMWlm50DNe14hD7t24KEqZuUdC9sOTy8W6XbCU1mlw4= -github.com/dop251/goja_nodejs v0.0.0-20210225215109-d91c329300e7/go.mod h1:hn7BA7c8pLvoGndExHudxTDKZ84Pyvv+90pbBjbTz0Y= -github.com/dop251/goja_nodejs v0.0.0-20211022123610-8dd9abb0616d/go.mod h1:DngW8aVqWbuLRMHItjPUyqdj+HWPvnQe8V8y1nDpIbM= github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM= github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU= github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= -github.com/go-sourcemap/sourcemap v2.1.3+incompatible h1:W1iEw64niKVGogNgBN3ePyLFfuisuzeidWPMPWmECqU= -github.com/go-sourcemap/sourcemap v2.1.3+incompatible/go.mod h1:F8jJfvm2KbVjc5NqelyYJmf/v5J0dwNLS2mL4sNA1Jg= github.com/go-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs= github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= github.com/gobwas/httphead v0.1.0 h1:exrUm0f4YX0L7EBwZHuCF4GDp8aJfVeBrlLQrs6NqWU= @@ -60,8 +45,7 @@ github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+Licev github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= -github.com/google/pprof v0.0.0-20230207041349-798e818bf904 h1:4/hN5RUoecvl+RmJRE2YxKWtnnQls6rQjjW5oV7qg2U= -github.com/google/pprof v0.0.0-20230207041349-798e818bf904/go.mod h1:uglQLonpP8qtYCYyzA+8c/9qtqgA3qsXGYqCPKARAFg= +github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= @@ -77,7 +61,6 @@ github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= github.com/hashicorp/yamux v0.1.1 h1:yrQxtgseBDrq9Y652vSRDvsKCJKOUD+GzTS4Y0Y8pvE= github.com/hashicorp/yamux v0.1.1/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= -github.com/ianlancetaylor/demangle v0.0.0-20220319035150-800ac71e25c2/go.mod h1:aYm2/VgdVmcIU8iMfdMvDMsRAQjcfZSKFby6HOFvi/w= github.com/jensneuse/abstractlogger v0.0.4 h1:sa4EH8fhWk3zlTDbSncaWKfwxYM8tYSlQ054ETLyyQY= github.com/jensneuse/abstractlogger v0.0.4/go.mod h1:6WuamOHuykJk8zED/R0LNiLhWR6C7FIAo43ocUEB3mo= github.com/jensneuse/byte-template v0.0.0-20231025215717-69252eb3ed56 h1:wo26fh6a6Za0cOMZIopD2sfH/kq83SJ89ixUWl7pCWc= @@ -89,8 +72,6 @@ github.com/kingledion/go-tools v0.6.0/go.mod h1:qcDJQxBui/H/hterGb90GMlLs9Yi7Qrw github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= -github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= @@ -117,7 +98,6 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN github.com/r3labs/sse/v2 v2.8.1 h1:lZH+W4XOLIq88U5MIHOsLec7+R62uhz3bIi2yn0Sg8o= github.com/r3labs/sse/v2 v2.8.1/go.mod h1:Igau6Whc+F17QUgML1fYe1VPZzTV6EMCnYktEmkNJ7I= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= github.com/rs/xid v1.6.0 h1:fV591PaemRlL6JfRxGDEPl69wICngIQ3shQtzfy2gxU= @@ -155,17 +135,14 @@ github.com/urfave/cli/v2 v2.27.7 h1:bH59vdhbjLv3LAvIu6gd0usJHgoTTPhCFib8qqOwXYU= github.com/urfave/cli/v2 v2.27.7/go.mod h1:CyNAG/xg+iAOg0N4MPGZqVmv2rCoP267496AOXUZjA4= github.com/vektah/gqlparser/v2 v2.5.30 h1:EqLwGAFLIzt1wpx1IPpY67DwUujF1OfzgEyDsLrN6kE= github.com/vektah/gqlparser/v2 v2.5.30/go.mod h1:D1/VCZtV3LPnQrcPBeR/q5jkSQIPti0uYCP/RI0gIeo= -github.com/wundergraph/astjson v1.0.0 h1:rETLJuQkMWWW03HCF6WBttEBOu8gi5vznj5KEUPVV2Q= -github.com/wundergraph/astjson v1.0.0/go.mod h1:h12D/dxxnedtLzsKyBLK7/Oe4TAoGpRVC9nDpDrZSWw= -github.com/wundergraph/cosmo/composition-go v0.0.0-20241020204711-78f240a77c99 h1:TGXDYfDhwFLFTuNuCwkuqXT5aXGz47zcurXLfTBS9w4= -github.com/wundergraph/cosmo/composition-go v0.0.0-20241020204711-78f240a77c99/go.mod h1:fUuOAUAXUFB/mlSkAaImGeE4A841AKR5dTMWhV4ibxI= +github.com/wundergraph/astjson v1.1.0 h1:xORDosrZ87zQFJwNGe/HIHXqzpdHOFmqWgykCLVL040= +github.com/wundergraph/astjson v1.1.0/go.mod h1:h12D/dxxnedtLzsKyBLK7/Oe4TAoGpRVC9nDpDrZSWw= github.com/wundergraph/cosmo/router v0.0.0-20251013094319-c611abf26b17 h1:GjO2E8LTf3U5JiQJCY4MmlRcAjVt7IvAbWFSgEjQdl8= github.com/wundergraph/cosmo/router v0.0.0-20251013094319-c611abf26b17/go.mod h1:7kt64e0LOLMBqOzrfu9PuLRn9cVT9YN1Bb3EennVtws= github.com/wundergraph/go-arena v1.1.0 h1:9+wSRkJAkA2vbYHp6s8tEGhPViRGQNGXqPHT0QzhdIc= github.com/wundergraph/go-arena v1.1.0/go.mod h1:ROOysEHWJjLQ8FSfNxZCziagb7Qw2nXY3/vgKRh7eWw= github.com/xrash/smetrics v0.0.0-20250705151800-55b8f293f342 h1:FnBeRrxr7OU4VvAzt5X7s6266i6cSVkkFPS0TuXWbIg= github.com/xrash/smetrics v0.0.0-20250705151800-55b8f293f342/go.mod h1:Ohn+xnUBiLI6FVj/9LpzZWtj1/D6lUovWYBkxHVV3aM= -github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= go.opentelemetry.io/otel v1.36.0 h1:UumtzIklRBY6cI/lllNZlALOF5nNIzJVb16APdvgTXg= @@ -192,52 +169,33 @@ go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= -golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.29.0 h1:HV8lRxZC4l2cr3Zq1LvtOsi/ThTgWnUk/y64QSs8GwA= golang.org/x/mod v0.29.0/go.mod h1:NyhrlYXJ2H4eJiRy/WDBO6HMqZQ6q9nk4JzS3NuCK+w= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191116160921-f9c825593386/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.46.0 h1:giFlY12I07fugqwPuWJi68oOnpfqFnJIJzaIIm2JVV4= golang.org/x/net v0.46.0/go.mod h1:Q9BGdFy1y4nkUwiLvT5qtyhAnEHgnQ/zd8PfU6nc210= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.17.0 h1:l60nONMj9l5drqw6jlhIELNv9I0A4OFgRsG9k2oT9Ug= golang.org/x/sync v0.17.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.37.0 h1:fdNQudmxPjkdUTPnLn5mdQv7Zwvbvpaxqs831goi9kQ= golang.org/x/sys v0.37.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= -golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= golang.org/x/text v0.30.0 h1:yznKA/E9zq54KzlzBEAWn1NXSQ8DIp/NYMy88xJjl4k= golang.org/x/text v0.30.0/go.mod h1:yDdHFIX9t+tORqspjENWgzaCVXgk0yYnYuSZ8UzzBVM= -golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.38.0 h1:Hx2Xv8hISq8Lm16jvBZ2VQf+RLmbd7wVUsALibYI/IQ= golang.org/x/tools v0.38.0/go.mod h1:yEsQ/d/YK8cjh0L6rZlY8tgtlKiBNTL14pGDJPJpYQs= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -257,11 +215,7 @@ gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntN gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= -gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= -rogchap.com/v8go v0.9.0 h1:wYbUCO4h6fjTamziHrzyrPnpFNuzPpjZY+nfmZjNaew= -rogchap.com/v8go v0.9.0/go.mod h1:MxgP3pL2MW4dpme/72QRs8sgNMmM0pRc8DPhcuLWPAs= diff --git a/examples/federation/graph.yaml b/examples/federation/graph.yaml new file mode 100644 index 0000000000..269f35b76d --- /dev/null +++ b/examples/federation/graph.yaml @@ -0,0 +1,14 @@ +version: 1 +subgraphs: + - name: accounts + routing_url: http://localhost:4001/query + schema: + file: accounts/graph/schema.graphqls + - name: products + routing_url: http://localhost:4002/query + schema: + file: products/graph/schema.graphqls + - name: reviews + routing_url: http://localhost:4003/query + schema: + file: reviews/graph/schema.graphqls diff --git a/examples/federation/gateway/main.go b/examples/federation/main.go similarity index 51% rename from examples/federation/gateway/main.go rename to examples/federation/main.go index 013b652b8c..54669fcfb1 100644 --- a/examples/federation/gateway/main.go +++ b/examples/federation/main.go @@ -6,16 +6,12 @@ import ( "net/http" "os" "strings" - "time" - "github.com/gobwas/ws" log "github.com/jensneuse/abstractlogger" "go.uber.org/zap" - gatewayHttp "github.com/wundergraph/graphql-go-tools/examples/federation/gateway/http" - "github.com/wundergraph/graphql-go-tools/execution/engine" - "github.com/wundergraph/graphql-go-tools/execution/graphql" - "github.com/wundergraph/graphql-go-tools/v2/pkg/playground" + "github.com/wundergraph/graphql-go-tools/examples/federation/gateway" + "github.com/wundergraph/graphql-go-tools/execution/playground" ) // It's just a simple example of graphql federation gateway server, it's NOT a production ready code. @@ -28,26 +24,13 @@ func logger() log.Logger { return log.NewZapLogger(logger, log.DebugLevel) } -func fallback(sc *ServiceConfig) (string, error) { - dat, err := os.ReadFile(sc.Name + "/graph/schema.graphqls") - if err != nil { - return "", err - } - - return string(dat), nil -} - -func startServer() { +func main() { logger := logger() logger.Info("logger initialized") ctx, cancel := context.WithCancel(context.Background()) defer cancel() - upgrader := &ws.DefaultHTTPUpgrader - upgrader.Header = http.Header{} - upgrader.Header.Add("Sec-Websocket-Protocol", "graphql-ws") - graphqlEndpoint := "/query" playgroundURLPrefix := "/playground" playgroundURL := "" @@ -56,15 +39,6 @@ func startServer() { mux := http.NewServeMux() - datasourceWatcher := NewDatasourcePoller(httpClient, DatasourcePollerConfig{ - Services: []ServiceConfig{ - {Name: "accounts", URL: "http://localhost:4001/query", Fallback: fallback}, - {Name: "products", URL: "http://localhost:4002/query", WS: "ws://localhost:4002/query"}, - {Name: "reviews", URL: "http://localhost:4003/query"}, - }, - PollingInterval: 30 * time.Second, - }) - p := playground.New(playground.Config{ PathPrefix: "", PlaygroundPath: playgroundURLPrefix, @@ -82,20 +56,19 @@ func startServer() { mux.Handle(handlers[i].Path, handlers[i].Handler) } - enableART := true - - var gqlHandlerFactory HandlerFactoryFn = func(schema *graphql.Schema, engine *engine.ExecutionEngine) http.Handler { - return gatewayHttp.NewGraphqlHTTPHandler(schema, engine, upgrader, logger, enableART) + configFileContent, err := os.ReadFile("config.json") + if err != nil { + logger.Fatal("read config", log.Error(err)) + return } - gateway := NewGateway(ctx, gqlHandlerFactory, httpClient, logger) - - datasourceWatcher.Register(gateway) - go datasourceWatcher.Run(ctx) - - gateway.Ready() + gw, err := gateway.NewGateway(ctx, configFileContent, httpClient, logger, true) + if err != nil { + logger.Fatal("create gateway", log.Error(err)) + return + } - mux.Handle("/query", gateway) + mux.Handle("/query", gw) addr := "0.0.0.0:4000" logger.Info("Listening", @@ -110,7 +83,3 @@ func startServer() { func prettyAddr(addr string) string { return strings.Replace(addr, "0.0.0.0", "localhost", -1) } - -func main() { - startServer() -} diff --git a/examples/federation/start.sh b/examples/federation/start.sh index 0cd1a11b52..da028c42af 100755 --- a/examples/federation/start.sh +++ b/examples/federation/start.sh @@ -10,7 +10,7 @@ trap cleanup EXIT go build -o /tmp/srv-accounts ./accounts go build -o /tmp/srv-products ./products go build -o /tmp/srv-reviews ./reviews -go build -o /tmp/srv-gateway ./gateway +go build -o /tmp/srv-gateway . /tmp/srv-accounts & ACCOUNTS_PID=$! diff --git a/execution/engine/config_factory_federation.go b/execution/engine/config_factory_federation.go index dab9c708a0..1bdbc83ae9 100644 --- a/execution/engine/config_factory_federation.go +++ b/execution/engine/config_factory_federation.go @@ -8,9 +8,7 @@ import ( "time" "google.golang.org/grpc" - "google.golang.org/protobuf/encoding/protojson" - "github.com/wundergraph/cosmo/composition-go" "github.com/wundergraph/cosmo/router/gen/proto/wg/cosmo/common" nodev1 "github.com/wundergraph/cosmo/router/gen/proto/wg/cosmo/node/v1" @@ -79,7 +77,7 @@ func WithFederationSubscriptionType(subscriptionType SubscriptionType) Federatio } } -func NewFederationEngineConfigFactory(engineCtx context.Context, subgraphsConfigs []SubgraphConfiguration, opts ...FederationEngineConfigFactoryOption) *FederationEngineConfigFactory { +func NewFederationEngineConfigFactory(engineCtx context.Context, opts ...FederationEngineConfigFactoryOption) *FederationEngineConfigFactory { options := federationEngineConfigFactoryOptions{ httpClient: &http.Client{ Timeout: time.Second * 10, @@ -109,7 +107,6 @@ func NewFederationEngineConfigFactory(engineCtx context.Context, subgraphsConfig subscriptionClientFactory: options.subscriptionClientFactory, subscriptionType: options.subscriptionType, customResolveMap: options.customResolveMap, - subgraphsConfigs: subgraphsConfigs, } } @@ -127,19 +124,7 @@ type FederationEngineConfigFactory struct { grpcClient grpc.ClientConnInterface } -func (f *FederationEngineConfigFactory) BuildEngineConfiguration() (Configuration, error) { - rc, err := f.Compose() - if err != nil { - return Configuration{}, err - } - return f.buildEngineConfiguration(rc) -} - -func (f *FederationEngineConfigFactory) BuildEngineConfigurationWithRouterConfig(c *nodev1.RouterConfig) (Configuration, error) { - return f.buildEngineConfiguration(c) -} - -func (f *FederationEngineConfigFactory) buildEngineConfiguration(routerConfig *nodev1.RouterConfig) (Configuration, error) { +func (f *FederationEngineConfigFactory) BuildEngineConfiguration(routerConfig *nodev1.RouterConfig) (Configuration, error) { plannerConfiguration, err := f.createPlannerConfiguration(routerConfig) if err != nil { return Configuration{}, err @@ -164,41 +149,6 @@ func (f *FederationEngineConfigFactory) buildEngineConfiguration(routerConfig *n return conf, nil } -// Compose produces a federated router configuration. -func (f *FederationEngineConfigFactory) Compose() (*nodev1.RouterConfig, error) { - subgraphs := make([]*composition.Subgraph, len(f.subgraphsConfigs)) - - for i, subgraphConfig := range f.subgraphsConfigs { - subgraphs[i] = &composition.Subgraph{ - Name: subgraphConfig.Name, - URL: subgraphConfig.URL, - Schema: subgraphConfig.SDL, - } - - if subgraphConfig.SubscriptionUrl != "" { - subgraphs[i].SubscriptionURL = subgraphConfig.SubscriptionUrl - } - - if subgraphConfig.SubscriptionProtocol == "" { - subgraphs[i].SubscriptionProtocol = string(SubscriptionProtocolWS) - } else { - subgraphs[i].SubscriptionProtocol = string(subgraphConfig.SubscriptionProtocol) - } - } - - resultJSON, err := composition.BuildRouterConfiguration(subgraphs...) - if err != nil { - return nil, err - } - - var routerConfig nodev1.RouterConfig - if err := protojson.Unmarshal([]byte(resultJSON), &routerConfig); err != nil { - return nil, err - } - - return &routerConfig, nil -} - func (f *FederationEngineConfigFactory) createPlannerConfiguration(routerConfig *nodev1.RouterConfig) (*plan.Configuration, error) { var ( outConfig plan.Configuration diff --git a/execution/engine/config_factory_federation_test.go b/execution/engine/config_factory_federation_test.go index e445fafdcb..98f1c1ad7a 100644 --- a/execution/engine/config_factory_federation_test.go +++ b/execution/engine/config_factory_federation_test.go @@ -3,6 +3,7 @@ package engine import ( "context" "net/http" + "os" "testing" "github.com/stretchr/testify/assert" @@ -20,54 +21,27 @@ func TestEngineConfigFactory_EngineConfiguration(t *testing.T) { engineCtx, cancel := context.WithCancel(context.Background()) defer cancel() - runWithoutError := func( - t *testing.T, - httpClient *http.Client, - streamingClient *http.Client, - subgraphs []SubgraphConfiguration, - baseSchema string, - expectedConfigFactory func(t *testing.T, baseSchema string) Configuration, - ) { - engineConfigFactory := NewFederationEngineConfigFactory( - engineCtx, - subgraphs, - WithFederationHttpClient(httpClient), - WithFederationStreamingClient(streamingClient), - WithFederationSubscriptionClientFactory(&MockSubscriptionClientFactory{}), - ) - config, err := engineConfigFactory.BuildEngineConfiguration() - assert.NoError(t, err) - - expectedConfig := expectedConfigFactory(t, baseSchema) - assert.Equal(t, expectedConfig, config) - } - runWithoutErrorUsingRouteConfig := func( t *testing.T, httpClient *http.Client, streamingClient *http.Client, - subgraphs []SubgraphConfiguration, baseSchema string, expectedConfigFactory func(t *testing.T, baseSchema string) Configuration, ) { engineConfigFactory := NewFederationEngineConfigFactory( engineCtx, - subgraphs, WithFederationHttpClient(httpClient), WithFederationStreamingClient(streamingClient), WithFederationSubscriptionClientFactory(&MockSubscriptionClientFactory{}), ) - // Compose and serialize the router config - rc0, err := engineConfigFactory.Compose() - require.NoError(t, err) - b, err := protojson.Marshal(rc0) + data, err := os.ReadFile("testdata/config_factory_federation/config.json") require.NoError(t, err) // Build the engine configuration using the router config var rc1 nodev1.RouterConfig - assert.NoError(t, protojson.Unmarshal(b, &rc1)) - config, err := engineConfigFactory.BuildEngineConfigurationWithRouterConfig(&rc1) + assert.NoError(t, protojson.Unmarshal(data, &rc1)) + config, err := engineConfigFactory.BuildEngineConfiguration(&rc1) assert.NoError(t, err) expectedConfig := expectedConfigFactory(t, baseSchema) @@ -77,246 +51,203 @@ func TestEngineConfigFactory_EngineConfiguration(t *testing.T) { httpClient := &http.Client{} streamingClient := &http.Client{} - tests := []struct { - name string - run func(t *testing.T, - httpClient *http.Client, - streamingClient *http.Client, - subgraphs []SubgraphConfiguration, - baseSchema string, - expectedConfigFactory func(t *testing.T, baseSchema string) Configuration, - ) - }{ - {name: "should create engine configuration", run: runWithoutError}, - {name: "should create engine configuration using route config", run: runWithoutErrorUsingRouteConfig}, - } + t.Run("should create engine configuration using router config", func(t *testing.T) { + runWithoutErrorUsingRouteConfig(t, httpClient, streamingClient, baseFederationSchema, func(t *testing.T, baseSchema string) Configuration { + schema, err := graphql.NewSchemaFromString(baseSchema) + require.NoError(t, err) - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - tt.run(t, httpClient, streamingClient, []SubgraphConfiguration{ - { - Name: "users", - URL: "http://user.service", - SDL: accountSchema, - }, - { - Name: "products", - URL: "http://product.service", - SDL: productSchema, - }, + conf := NewConfiguration(schema) + conf.SetFieldConfigurations(plan.FieldConfigurations{ { - Name: "reviews", - URL: "http://review.service", - SDL: reviewSchema, - }, - }, baseFederationSchema, func(t *testing.T, baseSchema string) Configuration { - schema, err := graphql.NewSchemaFromString(baseSchema) - require.NoError(t, err) - - conf := NewConfiguration(schema) - conf.SetFieldConfigurations(plan.FieldConfigurations{ - { - TypeName: "Query", - FieldName: "topProducts", - Arguments: []plan.ArgumentConfiguration{ - { - Name: "first", - SourceType: plan.FieldArgumentSource, - }, + TypeName: "Query", + FieldName: "topProducts", + Arguments: []plan.ArgumentConfiguration{ + { + Name: "first", + SourceType: plan.FieldArgumentSource, }, }, - }) + }, + }) - gqlFactory, err := graphqlDataSource.NewFactory(engineCtx, httpClient, mockSubscriptionClient) - require.NoError(t, err) + gqlFactory, err := graphqlDataSource.NewFactory(engineCtx, httpClient, mockSubscriptionClient) + require.NoError(t, err) - conf.SetDataSources([]plan.DataSource{ - mustGraphqlDataSourceConfiguration(t, - "0", - gqlFactory, - &plan.DataSourceMetadata{ - RootNodes: []plan.TypeField{ - { - TypeName: "Query", - FieldNames: []string{"me"}, - }, - { - TypeName: "User", - FieldNames: []string{"id", "username"}, - }, + conf.SetDataSources([]plan.DataSource{ + mustGraphqlDataSourceConfiguration(t, + "0", + gqlFactory, + &plan.DataSourceMetadata{ + RootNodes: []plan.TypeField{ + { + TypeName: "Query", + FieldNames: []string{"me"}, + }, + { + TypeName: "User", + FieldNames: []string{"id", "username"}, }, - ChildNodes: []plan.TypeField{}, - FederationMetaData: plan.FederationMetaData{ - Keys: []plan.FederationFieldConfiguration{ - { - TypeName: "User", - SelectionSet: "id", - }, + }, + ChildNodes: []plan.TypeField{}, + FederationMetaData: plan.FederationMetaData{ + Keys: []plan.FederationFieldConfiguration{ + { + TypeName: "User", + SelectionSet: "id", }, - Requires: []plan.FederationFieldConfiguration{}, - Provides: []plan.FederationFieldConfiguration{}, }, - Directives: plan.NewDirectiveConfigurations([]plan.DirectiveConfiguration{}), + Requires: []plan.FederationFieldConfiguration{}, + Provides: []plan.FederationFieldConfiguration{}, + }, + Directives: plan.NewDirectiveConfigurations([]plan.DirectiveConfiguration{}), + }, + mustConfiguration(t, graphqlDataSource.ConfigurationInput{ + Fetch: &graphqlDataSource.FetchConfiguration{ + URL: "http://user.service", + Header: make(http.Header), + }, + Subscription: &graphqlDataSource.SubscriptionConfiguration{ + URL: "http://user.service", }, - mustConfiguration(t, graphqlDataSource.ConfigurationInput{ - Fetch: &graphqlDataSource.FetchConfiguration{ - URL: "http://user.service", - Header: make(http.Header), + SchemaConfiguration: mustSchemaConfig( + t, + &graphqlDataSource.FederationConfiguration{ + Enabled: true, + ServiceSDL: accountSchema, }, - Subscription: &graphqlDataSource.SubscriptionConfiguration{ - URL: "http://user.service", + accountUpstreamSchema, + ), + CustomScalarTypeFields: []graphqlDataSource.SingleTypeField{}, + }), + ), + mustGraphqlDataSourceConfiguration(t, + "1", + gqlFactory, + &plan.DataSourceMetadata{ + RootNodes: []plan.TypeField{ + { + TypeName: "Query", + FieldNames: []string{"topProducts"}, }, - SchemaConfiguration: mustSchemaConfig( - t, - &graphqlDataSource.FederationConfiguration{ - Enabled: true, - ServiceSDL: accountSchema, - }, - accountUpstreamSchema, - ), - CustomScalarTypeFields: []graphqlDataSource.SingleTypeField{}, - }), - ), - mustGraphqlDataSourceConfiguration(t, - "1", - gqlFactory, - &plan.DataSourceMetadata{ - RootNodes: []plan.TypeField{ - { - TypeName: "Query", - FieldNames: []string{"topProducts"}, - }, - { - TypeName: "Product", - FieldNames: []string{"upc", "name", "price"}, - }, + { + TypeName: "Product", + FieldNames: []string{"upc", "name", "price"}, }, - ChildNodes: []plan.TypeField{}, - FederationMetaData: plan.FederationMetaData{ - Keys: []plan.FederationFieldConfiguration{ - { - TypeName: "Product", - SelectionSet: "upc", - }, + }, + ChildNodes: []plan.TypeField{}, + FederationMetaData: plan.FederationMetaData{ + Keys: []plan.FederationFieldConfiguration{ + { + TypeName: "Product", + SelectionSet: "upc", }, - Requires: []plan.FederationFieldConfiguration{}, - Provides: []plan.FederationFieldConfiguration{}, }, - Directives: plan.NewDirectiveConfigurations([]plan.DirectiveConfiguration{}), + Requires: []plan.FederationFieldConfiguration{}, + Provides: []plan.FederationFieldConfiguration{}, + }, + Directives: plan.NewDirectiveConfigurations([]plan.DirectiveConfiguration{}), + }, + mustConfiguration(t, graphqlDataSource.ConfigurationInput{ + Fetch: &graphqlDataSource.FetchConfiguration{ + URL: "http://product.service", + Header: make(http.Header), + }, + Subscription: &graphqlDataSource.SubscriptionConfiguration{ + URL: "http://product.service", }, - mustConfiguration(t, graphqlDataSource.ConfigurationInput{ - Fetch: &graphqlDataSource.FetchConfiguration{ - URL: "http://product.service", - Header: make(http.Header), + SchemaConfiguration: mustSchemaConfig( + t, + &graphqlDataSource.FederationConfiguration{ + Enabled: true, + ServiceSDL: productSchema, + }, + productUpstreamSchema, + ), + CustomScalarTypeFields: []graphqlDataSource.SingleTypeField{}, + }), + ), + mustGraphqlDataSourceConfiguration(t, + "2", + gqlFactory, + &plan.DataSourceMetadata{ + RootNodes: []plan.TypeField{ + { + TypeName: "User", + FieldNames: []string{"id", "reviews"}, }, - Subscription: &graphqlDataSource.SubscriptionConfiguration{ - URL: "http://product.service", + { + TypeName: "Product", + FieldNames: []string{"upc", "reviews"}, }, - SchemaConfiguration: mustSchemaConfig( - t, - &graphqlDataSource.FederationConfiguration{ - Enabled: true, - ServiceSDL: productSchema, - }, - productUpstreamSchema, - ), - CustomScalarTypeFields: []graphqlDataSource.SingleTypeField{}, - }), - ), - mustGraphqlDataSourceConfiguration(t, - "2", - gqlFactory, - &plan.DataSourceMetadata{ - RootNodes: []plan.TypeField{ + }, + ChildNodes: []plan.TypeField{ + { + TypeName: "Review", + FieldNames: []string{"body", "author", "product"}, + }, + }, + FederationMetaData: plan.FederationMetaData{ + Keys: []plan.FederationFieldConfiguration{ { - TypeName: "User", - FieldNames: []string{"reviews", "id"}, + TypeName: "User", + SelectionSet: "id", }, { - TypeName: "Product", - FieldNames: []string{"reviews", "upc"}, + TypeName: "Product", + SelectionSet: "upc", }, }, - ChildNodes: []plan.TypeField{ + Requires: []plan.FederationFieldConfiguration{}, + Provides: []plan.FederationFieldConfiguration{ { - TypeName: "Review", - FieldNames: []string{"body", "author", "product"}, - }, - }, - FederationMetaData: plan.FederationMetaData{ - Keys: []plan.FederationFieldConfiguration{ - { - TypeName: "User", - SelectionSet: "id", - }, - { - TypeName: "Product", - SelectionSet: "upc", - }, - }, - Requires: []plan.FederationFieldConfiguration{}, - Provides: []plan.FederationFieldConfiguration{ - { - TypeName: "Review", - FieldName: "author", - SelectionSet: "username", - }, + TypeName: "Review", + FieldName: "author", + SelectionSet: "username", }, }, - Directives: plan.NewDirectiveConfigurations([]plan.DirectiveConfiguration{}), }, - mustConfiguration(t, graphqlDataSource.ConfigurationInput{ - Fetch: &graphqlDataSource.FetchConfiguration{ - URL: "http://review.service", - Header: make(http.Header), - }, - Subscription: &graphqlDataSource.SubscriptionConfiguration{ - URL: "http://review.service", + Directives: plan.NewDirectiveConfigurations([]plan.DirectiveConfiguration{}), + }, + mustConfiguration(t, graphqlDataSource.ConfigurationInput{ + Fetch: &graphqlDataSource.FetchConfiguration{ + URL: "http://review.service", + Header: make(http.Header), + }, + Subscription: &graphqlDataSource.SubscriptionConfiguration{ + URL: "http://review.service", + }, + SchemaConfiguration: mustSchemaConfig( + t, + &graphqlDataSource.FederationConfiguration{ + Enabled: true, + ServiceSDL: reviewSchema, }, - SchemaConfiguration: mustSchemaConfig( - t, - &graphqlDataSource.FederationConfiguration{ - Enabled: true, - ServiceSDL: reviewSchema, - }, - reviewUpstreamSchema, - ), - CustomScalarTypeFields: []graphqlDataSource.SingleTypeField{}, - }), - ), - }) - - return conf + reviewUpstreamSchema, + ), + CustomScalarTypeFields: []graphqlDataSource.SingleTypeField{}, + }), + ), }) + + return conf }) - } + }) } const ( - accountSchema = ` - extend type Query { - me: User - } - type User @key(fields: "id"){ - id: ID! - username: String! - }` + accountSchema = `extend type Query { + me: User +} +type User @key(fields: "id"){ + id: ID! + username: String! +}` accountUpstreamSchema = `schema { query: Query } -directive @extends on INTERFACE | OBJECT - -directive @external on FIELD_DEFINITION | OBJECT - directive @key(fields: openfed__FieldSet!, resolvable: Boolean = true) repeatable on INTERFACE | OBJECT -directive @provides(fields: openfed__FieldSet!) on FIELD_DEFINITION - -directive @requires(fields: openfed__FieldSet!) on FIELD_DEFINITION - -directive @tag(name: String!) repeatable on ARGUMENT_DEFINITION | ENUM | ENUM_VALUE | FIELD_DEFINITION | INPUT_FIELD_DEFINITION | INPUT_OBJECT | INTERFACE | OBJECT | SCALAR | UNION - type Query { me: User } @@ -328,31 +259,20 @@ type User @key(fields: "id") { scalar openfed__FieldSet` - productSchema = ` - extend type Query { - topProducts(first: Int = 5): [Product] - } - type Product @key(fields: "upc") { - upc: String! - name: String! - price: Int! - }` + productSchema = `extend type Query { + topProducts(first: Int = 5): [Product] +} +type Product @key(fields: "upc") { + upc: String! + name: String! + price: Int! +}` productUpstreamSchema = `schema { query: Query } -directive @extends on INTERFACE | OBJECT - -directive @external on FIELD_DEFINITION | OBJECT - directive @key(fields: openfed__FieldSet!, resolvable: Boolean = true) repeatable on INTERFACE | OBJECT -directive @provides(fields: openfed__FieldSet!) on FIELD_DEFINITION - -directive @requires(fields: openfed__FieldSet!) on FIELD_DEFINITION - -directive @tag(name: String!) repeatable on ARGUMENT_DEFINITION | ENUM | ENUM_VALUE | FIELD_DEFINITION | INPUT_FIELD_DEFINITION | INPUT_OBJECT | INTERFACE | OBJECT | SCALAR | UNION - type Product @key(fields: "upc") { name: String! price: Int! @@ -365,34 +285,27 @@ type Query { scalar openfed__FieldSet` - reviewSchema = ` - type Review { - body: String! - author: User! @provides(fields: "username") - product: Product! - } - extend type User @key(fields: "id") { - id: ID! @external - username: String! @external - reviews: [Review] - } - extend type Product @key(fields: "upc") { - upc: String!@external - reviews: [Review] - }` - - reviewUpstreamSchema = `directive @extends on INTERFACE | OBJECT - -directive @external on FIELD_DEFINITION | OBJECT + reviewSchema = `type Review { + body: String! + author: User! @provides(fields: "username") + product: Product! +} +extend type User @key(fields: "id") { + id: ID! @external + username: String! @external + reviews: [Review] +} +extend type Product @key(fields: "upc") { + upc: String!@external + reviews: [Review] +}` + + reviewUpstreamSchema = `directive @external on FIELD_DEFINITION | OBJECT directive @key(fields: openfed__FieldSet!, resolvable: Boolean = true) repeatable on INTERFACE | OBJECT directive @provides(fields: openfed__FieldSet!) on FIELD_DEFINITION -directive @requires(fields: openfed__FieldSet!) on FIELD_DEFINITION - -directive @tag(name: String!) repeatable on ARGUMENT_DEFINITION | ENUM | ENUM_VALUE | FIELD_DEFINITION | INPUT_FIELD_DEFINITION | INPUT_OBJECT | INTERFACE | OBJECT | SCALAR | UNION - type Product @key(fields: "upc") { reviews: [Review] upc: String! @external @@ -412,7 +325,9 @@ type User @key(fields: "id") { scalar openfed__FieldSet` - baseFederationSchema = `directive @tag(name: String!) repeatable on ARGUMENT_DEFINITION | ENUM | ENUM_VALUE | FIELD_DEFINITION | INPUT_FIELD_DEFINITION | INPUT_OBJECT | INTERFACE | OBJECT | SCALAR | UNION + baseFederationSchema = `schema { + query: Query +} type Query { me: User diff --git a/execution/engine/execution_engine_test.go b/execution/engine/execution_engine_test.go index 26e8f7af6a..760c6d84db 100644 --- a/execution/engine/execution_engine_test.go +++ b/execution/engine/execution_engine_test.go @@ -6065,20 +6065,9 @@ func BenchmarkExecutionEngine(b *testing.B) { } func newFederationEngineStaticConfig(ctx context.Context, setup *federationtesting.FederationSetup) (engine *ExecutionEngine, schema *graphql.Schema, err error) { - accountsSDL, err := federationtesting.LoadTestingSubgraphSDL(federationtesting.UpstreamAccounts) - if err != nil { - return - } - - productsSDL, err := federationtesting.LoadTestingSubgraphSDL(federationtesting.UpstreamProducts) - if err != nil { - return - } - - reviewsSDL, err := federationtesting.LoadTestingSubgraphSDL(federationtesting.UpstreamReviews) - if err != nil { - return - } + accountsSDL := federationtesting.AccountSDL + productsSDL := federationtesting.ProductsSDL + reviewsSDL := federationtesting.ReviewsSDL subscriptionClient := graphql_datasource.NewGraphQLSubscriptionClient(ctx, graphql_datasource.WithUpgradeClient(httpclient.DefaultNetHttpClient), diff --git a/execution/engine/federation_integration_static_test.go b/execution/engine/federation_integration_static_test.go index 65574463fd..cd325f473c 100644 --- a/execution/engine/federation_integration_static_test.go +++ b/execution/engine/federation_integration_static_test.go @@ -24,7 +24,8 @@ func TestExecutionEngine_FederationAndSubscription_IntegrationTest(t *testing.T) t.Run("operation", func(t *testing.T) { t.Parallel() ctx, cancelFn := context.WithCancel(context.Background()) - setup := federationtesting.NewFederationSetup() + setup, err := federationtesting.NewFederationSetup() + require.NoError(t, err) t.Cleanup(func() { cancelFn() setup.Close() @@ -61,7 +62,8 @@ func TestExecutionEngine_FederationAndSubscription_IntegrationTest(t *testing.T) t.Run("subscription", func(t *testing.T) { t.Parallel() ctx, cancelFn := context.WithCancel(context.Background()) - setup := federationtesting.NewFederationSetup() + setup, err := federationtesting.NewFederationSetup() + require.NoError(t, err) t.Cleanup(func() { cancelFn() setup.Close() diff --git a/execution/engine/federation_integration_test.go b/execution/engine/federation_integration_test.go index 9b749cda2b..32bbc95c5c 100644 --- a/execution/engine/federation_integration_test.go +++ b/execution/engine/federation_integration_test.go @@ -10,7 +10,6 @@ import ( "regexp" "strings" "testing" - "time" "github.com/jensneuse/abstractlogger" "github.com/sebdah/goldie/v2" @@ -21,23 +20,22 @@ import ( "github.com/wundergraph/graphql-go-tools/execution/federationtesting/gateway" ) -func addGateway(enableART bool) func(setup *federationtesting.FederationSetup) *httptest.Server { - return func(setup *federationtesting.FederationSetup) *httptest.Server { +func addGateway(enableART bool) func(setup *federationtesting.FederationSetup) (*httptest.Server, error) { + return func(setup *federationtesting.FederationSetup) (*httptest.Server, error) { httpClient := http.DefaultClient - poller := gateway.NewDatasource([]gateway.ServiceConfig{ - {Name: "accounts", URL: setup.AccountsUpstreamServer.URL}, - {Name: "products", URL: setup.ProductsUpstreamServer.URL, WS: strings.ReplaceAll(setup.ProductsUpstreamServer.URL, "http:", "ws:")}, - {Name: "reviews", URL: setup.ReviewsUpstreamServer.URL}, - }, httpClient) + cfg := bytes.Clone(federationtesting.RouterConfigJson) - gtw := gateway.Handler(abstractlogger.NoopLogger, poller, httpClient, enableART) + cfg = bytes.ReplaceAll(cfg, []byte("http://accounts-url-placeholder"), []byte(setup.AccountsUpstreamServer.URL)) + cfg = bytes.ReplaceAll(cfg, []byte("http://products-url-placeholder"), []byte(setup.ProductsUpstreamServer.URL)) + cfg = bytes.ReplaceAll(cfg, []byte("http://reviews-url-placeholder"), []byte(setup.ReviewsUpstreamServer.URL)) - ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second) - defer cancel() + gtw, err := gateway.NewGateway(cfg, httpClient, abstractlogger.NoopLogger, enableART) + if err != nil { + return nil, err + } - poller.Run(ctx) - return httptest.NewServer(gtw) + return httptest.NewServer(gtw), nil } } @@ -49,7 +47,8 @@ func TestFederationIntegrationTestWithArt(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() - setup := federationtesting.NewFederationSetup(addGateway(true)) + setup, err := federationtesting.NewFederationSetup(addGateway(true)) + require.NoError(t, err) defer setup.Close() gqlClient := NewGraphqlClient(http.DefaultClient) @@ -78,7 +77,8 @@ func TestFederationIntegrationTest(t *testing.T) { t.Parallel() // Shared setup for all read-only tests (minimizes open ports) - setup := federationtesting.NewFederationSetup(addGateway(false)) + setup, err := federationtesting.NewFederationSetup(addGateway(false)) + require.NoError(t, err) t.Cleanup(setup.Close) gqlClient := NewGraphqlClient(http.DefaultClient) @@ -101,7 +101,8 @@ func TestFederationIntegrationTest(t *testing.T) { // Mutation test needs its own setup because AddReview modifies the reviews resolver state t.Run("mutation operation with variables", func(t *testing.T) { t.Parallel() - mutSetup := federationtesting.NewFederationSetup(addGateway(false)) + mutSetup, err := federationtesting.NewFederationSetup(addGateway(false)) + require.NoError(t, err) t.Cleanup(mutSetup.Close) mutClient := NewGraphqlClient(http.DefaultClient) ctx, cancel := context.WithCancel(context.Background()) diff --git a/execution/federationtesting/skipped_fetch_test.go b/execution/engine/skipped_fetch_test.go similarity index 63% rename from execution/federationtesting/skipped_fetch_test.go rename to execution/engine/skipped_fetch_test.go index ed3ea8c467..f267cff5db 100644 --- a/execution/federationtesting/skipped_fetch_test.go +++ b/execution/engine/skipped_fetch_test.go @@ -1,17 +1,21 @@ -package federationtesting +package engine import ( + "bytes" "io" "net/http" "net/http/httptest" + "os" "sync/atomic" "testing" "github.com/jensneuse/abstractlogger" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "google.golang.org/protobuf/encoding/protojson" + + nodev1 "github.com/wundergraph/cosmo/router/gen/proto/wg/cosmo/node/v1" - "github.com/wundergraph/graphql-go-tools/execution/engine" "github.com/wundergraph/graphql-go-tools/execution/graphql" "github.com/wundergraph/graphql-go-tools/v2/pkg/engine/resolve" ) @@ -21,7 +25,7 @@ func TestSkippedFetchOnNullParent(t *testing.T) { usersServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json") _, _ = io.ReadAll(r.Body) - _, _ = w.Write([]byte(`{"data":{"user":null}}`)) + _, _ = w.Write([]byte(`{"data":{"me":null}}`)) })) t.Cleanup(usersServer.Close) @@ -36,25 +40,28 @@ func TestSkippedFetchOnNullParent(t *testing.T) { })) t.Cleanup(reviewsServer.Close) - const usersSDL = `type Query { user(id: ID!): User } type User @key(fields: "id") { id: ID! name: String! }` - const reviewsSDL = `type User @key(fields: "id") { id: ID! @external reviews: [Review] } type Review { body: String! }` - ctx := t.Context() - factory := engine.NewFederationEngineConfigFactory(ctx, []engine.SubgraphConfiguration{ - {Name: "users", URL: usersServer.URL, SDL: usersSDL}, - {Name: "reviews", URL: reviewsServer.URL, SDL: reviewsSDL}, - }) + factory := NewFederationEngineConfigFactory(ctx) + + cfgData, err := os.ReadFile("testdata/config_factory_federation/config.json") + require.NoError(t, err) + + cfgData = bytes.ReplaceAll(cfgData, []byte("http://user.service"), []byte(usersServer.URL)) + cfgData = bytes.ReplaceAll(cfgData, []byte("http://review.service"), []byte(reviewsServer.URL)) - engineConfig, err := factory.BuildEngineConfiguration() + // Build the engine configuration using the router config + var rc1 nodev1.RouterConfig + assert.NoError(t, protojson.Unmarshal(cfgData, &rc1)) + engineConfig, err := factory.BuildEngineConfiguration(&rc1) require.NoError(t, err) - eng, err := engine.NewExecutionEngine(ctx, abstractlogger.NoopLogger, engineConfig, resolve.ResolverOptions{ + eng, err := NewExecutionEngine(ctx, abstractlogger.NoopLogger, engineConfig, resolve.ResolverOptions{ MaxConcurrency: 1024, }) require.NoError(t, err) gqlRequest := &graphql.Request{ - Query: `{ user(id: "1") { id name reviews { body } } }`, + Query: `{ me { id username reviews { body } } }`, } resultWriter := graphql.NewEngineResultWriter() @@ -62,7 +69,7 @@ func TestSkippedFetchOnNullParent(t *testing.T) { require.NoError(t, err) // The user is null, so the response should reflect that without panic. - assert.Equal(t, `{"data":{"user":null}}`, resultWriter.String()) + assert.Equal(t, `{"data":{"me":null}}`, resultWriter.String()) // The reviews subgraph must NOT have been called — the entity fetch was skipped // because the parent user is null. diff --git a/execution/engine/testdata/complex_nesting_query_with_art.json b/execution/engine/testdata/complex_nesting_query_with_art.json index ec85c1e5c1..d0b79acab3 100644 --- a/execution/engine/testdata/complex_nesting_query_with_art.json +++ b/execution/engine/testdata/complex_nesting_query_with_art.json @@ -201,14 +201,14 @@ "duration_since_start_pretty": "" }, "connect_start": { - "duration_since_start_nanoseconds": 0, - "duration_since_start_pretty": "", + "duration_since_start_nanoseconds": 1, + "duration_since_start_pretty": "1ns", "network": "", "addr": "" }, "connect_done": { - "duration_since_start_nanoseconds": 0, - "duration_since_start_pretty": "", + "duration_since_start_nanoseconds": 1, + "duration_since_start_pretty": "1ns", "network": "", "addr": "" }, @@ -341,14 +341,14 @@ "duration_since_start_pretty": "" }, "connect_start": { - "duration_since_start_nanoseconds": 0, - "duration_since_start_pretty": "", + "duration_since_start_nanoseconds": 1, + "duration_since_start_pretty": "1ns", "network": "", "addr": "" }, "connect_done": { - "duration_since_start_nanoseconds": 0, - "duration_since_start_pretty": "", + "duration_since_start_nanoseconds": 1, + "duration_since_start_pretty": "1ns", "network": "", "addr": "" }, @@ -527,14 +527,14 @@ "duration_since_start_pretty": "" }, "connect_start": { - "duration_since_start_nanoseconds": 0, - "duration_since_start_pretty": "", + "duration_since_start_nanoseconds": 1, + "duration_since_start_pretty": "1ns", "network": "", "addr": "" }, "connect_done": { - "duration_since_start_nanoseconds": 0, - "duration_since_start_pretty": "", + "duration_since_start_nanoseconds": 1, + "duration_since_start_pretty": "1ns", "network": "", "addr": "" }, diff --git a/execution/engine/testdata/config_factory_federation/account_sdl.graphql b/execution/engine/testdata/config_factory_federation/account_sdl.graphql new file mode 100644 index 0000000000..a978199bfb --- /dev/null +++ b/execution/engine/testdata/config_factory_federation/account_sdl.graphql @@ -0,0 +1,7 @@ +extend type Query { + me: User +} +type User @key(fields: "id"){ + id: ID! + username: String! +} \ No newline at end of file diff --git a/execution/engine/testdata/config_factory_federation/compose.sh b/execution/engine/testdata/config_factory_federation/compose.sh new file mode 100755 index 0000000000..d20d9811f0 --- /dev/null +++ b/execution/engine/testdata/config_factory_federation/compose.sh @@ -0,0 +1,10 @@ +#!/usr/bin/env bash +set -euo pipefail + +echo "Composing subgraphs" + +npx -y wgc@latest router compose -i graph.yaml -o config.json + +echo "Formatting config" +jq . config.json > config.json.tmp +mv config.json.tmp config.json diff --git a/execution/engine/testdata/config_factory_federation/config.json b/execution/engine/testdata/config_factory_federation/config.json new file mode 100644 index 0000000000..6744d2c926 --- /dev/null +++ b/execution/engine/testdata/config_factory_federation/config.json @@ -0,0 +1,229 @@ +{ + "engineConfig": { + "defaultFlushInterval": "500", + "datasourceConfigurations": [ + { + "kind": "GRAPHQL", + "rootNodes": [ + { + "typeName": "Query", + "fieldNames": [ + "me" + ] + }, + { + "typeName": "User", + "fieldNames": [ + "id", + "username" + ] + } + ], + "overrideFieldPathFromAlias": true, + "customGraphql": { + "fetch": { + "url": { + "staticVariableContent": "http://user.service" + }, + "method": "POST", + "body": {}, + "baseUrl": {}, + "path": {} + }, + "subscription": { + "enabled": true, + "url": { + "staticVariableContent": "http://user.service" + }, + "protocol": "GRAPHQL_SUBSCRIPTION_PROTOCOL_WS", + "websocketSubprotocol": "GRAPHQL_WEBSOCKET_SUBPROTOCOL_AUTO" + }, + "federation": { + "enabled": true, + "serviceSdl": "extend type Query {\n me: User\n}\ntype User @key(fields: \"id\"){\n id: ID!\n username: String!\n}" + }, + "upstreamSchema": { + "key": "fd8732851b74811c8ef4ec60923cbad1c5fab185" + } + }, + "requestTimeoutSeconds": "10", + "id": "0", + "keys": [ + { + "typeName": "User", + "selectionSet": "id" + } + ] + }, + { + "kind": "GRAPHQL", + "rootNodes": [ + { + "typeName": "Query", + "fieldNames": [ + "topProducts" + ] + }, + { + "typeName": "Product", + "fieldNames": [ + "upc", + "name", + "price" + ] + } + ], + "overrideFieldPathFromAlias": true, + "customGraphql": { + "fetch": { + "url": { + "staticVariableContent": "http://product.service" + }, + "method": "POST", + "body": {}, + "baseUrl": {}, + "path": {} + }, + "subscription": { + "enabled": true, + "url": { + "staticVariableContent": "http://product.service" + }, + "protocol": "GRAPHQL_SUBSCRIPTION_PROTOCOL_WS", + "websocketSubprotocol": "GRAPHQL_WEBSOCKET_SUBPROTOCOL_AUTO" + }, + "federation": { + "enabled": true, + "serviceSdl": "extend type Query {\n topProducts(first: Int = 5): [Product]\n}\ntype Product @key(fields: \"upc\") {\n upc: String!\n name: String!\n price: Int!\n}" + }, + "upstreamSchema": { + "key": "bf9df95abb66a2141de3b0a64f0db4d5c31bd235" + } + }, + "requestTimeoutSeconds": "10", + "id": "1", + "keys": [ + { + "typeName": "Product", + "selectionSet": "upc" + } + ] + }, + { + "kind": "GRAPHQL", + "rootNodes": [ + { + "typeName": "User", + "fieldNames": [ + "id", + "reviews" + ], + "externalFieldNames": [ + "username" + ] + }, + { + "typeName": "Product", + "fieldNames": [ + "upc", + "reviews" + ] + } + ], + "childNodes": [ + { + "typeName": "Review", + "fieldNames": [ + "body", + "author", + "product" + ] + } + ], + "overrideFieldPathFromAlias": true, + "customGraphql": { + "fetch": { + "url": { + "staticVariableContent": "http://review.service" + }, + "method": "POST", + "body": {}, + "baseUrl": {}, + "path": {} + }, + "subscription": { + "enabled": true, + "url": { + "staticVariableContent": "http://review.service" + }, + "protocol": "GRAPHQL_SUBSCRIPTION_PROTOCOL_WS", + "websocketSubprotocol": "GRAPHQL_WEBSOCKET_SUBPROTOCOL_AUTO" + }, + "federation": { + "enabled": true, + "serviceSdl": "type Review {\n body: String!\n author: User! @provides(fields: \"username\")\n product: Product!\n}\nextend type User @key(fields: \"id\") {\n id: ID! @external\n username: String! @external\n reviews: [Review]\n}\nextend type Product @key(fields: \"upc\") {\n upc: String!@external\n reviews: [Review]\n}" + }, + "upstreamSchema": { + "key": "3b6908f2120ecc5615dd1e62d4b96c285a67b387" + } + }, + "requestTimeoutSeconds": "10", + "id": "2", + "keys": [ + { + "typeName": "User", + "selectionSet": "id" + }, + { + "typeName": "Product", + "selectionSet": "upc" + } + ], + "provides": [ + { + "typeName": "Review", + "fieldName": "author", + "selectionSet": "username" + } + ] + } + ], + "fieldConfigurations": [ + { + "typeName": "Query", + "fieldName": "topProducts", + "argumentsConfiguration": [ + { + "name": "first", + "sourceType": "FIELD_ARGUMENT" + } + ] + } + ], + "graphqlSchema": "schema {\n query: Query\n}\n\ntype Query {\n me: User\n topProducts(first: Int = 5): [Product]\n}\n\ntype User {\n id: ID!\n username: String!\n reviews: [Review]\n}\n\ntype Product {\n upc: String!\n name: String!\n price: Int!\n reviews: [Review]\n}\n\ntype Review {\n body: String!\n author: User!\n product: Product!\n}", + "stringStorage": { + "fd8732851b74811c8ef4ec60923cbad1c5fab185": "schema {\n query: Query\n}\n\ndirective @key(fields: openfed__FieldSet!, resolvable: Boolean = true) repeatable on INTERFACE | OBJECT\n\ntype Query {\n me: User\n}\n\ntype User @key(fields: \"id\") {\n id: ID!\n username: String!\n}\n\nscalar openfed__FieldSet", + "bf9df95abb66a2141de3b0a64f0db4d5c31bd235": "schema {\n query: Query\n}\n\ndirective @key(fields: openfed__FieldSet!, resolvable: Boolean = true) repeatable on INTERFACE | OBJECT\n\ntype Product @key(fields: \"upc\") {\n name: String!\n price: Int!\n upc: String!\n}\n\ntype Query {\n topProducts(first: Int = 5): [Product]\n}\n\nscalar openfed__FieldSet", + "3b6908f2120ecc5615dd1e62d4b96c285a67b387": "directive @external on FIELD_DEFINITION | OBJECT\n\ndirective @key(fields: openfed__FieldSet!, resolvable: Boolean = true) repeatable on INTERFACE | OBJECT\n\ndirective @provides(fields: openfed__FieldSet!) on FIELD_DEFINITION\n\ntype Product @key(fields: \"upc\") {\n reviews: [Review]\n upc: String! @external\n}\n\ntype Review {\n author: User! @provides(fields: \"username\")\n body: String!\n product: Product!\n}\n\ntype User @key(fields: \"id\") {\n id: ID! @external\n reviews: [Review]\n username: String! @external\n}\n\nscalar openfed__FieldSet" + } + }, + "version": "00000000-0000-0000-0000-000000000000", + "subgraphs": [ + { + "id": "0", + "name": "account", + "routingUrl": "http://user.service" + }, + { + "id": "1", + "name": "products", + "routingUrl": "http://product.service" + }, + { + "id": "2", + "name": "reviews", + "routingUrl": "http://review.service" + } + ], + "compatibilityVersion": "1:0.58.2" +} diff --git a/execution/engine/testdata/config_factory_federation/graph.yaml b/execution/engine/testdata/config_factory_federation/graph.yaml new file mode 100644 index 0000000000..b85c27985d --- /dev/null +++ b/execution/engine/testdata/config_factory_federation/graph.yaml @@ -0,0 +1,14 @@ +version: 1 +subgraphs: + - name: account + routing_url: http://user.service + schema: + file: account_sdl.graphql + - name: products + routing_url: http://product.service + schema: + file: product_sdl.graphql + - name: reviews + routing_url: http://review.service + schema: + file: review_sdl.graphql diff --git a/execution/engine/testdata/config_factory_federation/product_sdl.graphql b/execution/engine/testdata/config_factory_federation/product_sdl.graphql new file mode 100644 index 0000000000..e19170d930 --- /dev/null +++ b/execution/engine/testdata/config_factory_federation/product_sdl.graphql @@ -0,0 +1,8 @@ +extend type Query { + topProducts(first: Int = 5): [Product] +} +type Product @key(fields: "upc") { + upc: String! + name: String! + price: Int! +} \ No newline at end of file diff --git a/execution/engine/testdata/config_factory_federation/review_sdl.graphql b/execution/engine/testdata/config_factory_federation/review_sdl.graphql new file mode 100644 index 0000000000..bd49aa7c59 --- /dev/null +++ b/execution/engine/testdata/config_factory_federation/review_sdl.graphql @@ -0,0 +1,14 @@ +type Review { + body: String! + author: User! @provides(fields: "username") + product: Product! +} +extend type User @key(fields: "id") { + id: ID! @external + username: String! @external + reviews: [Review] +} +extend type Product @key(fields: "upc") { + upc: String!@external + reviews: [Review] +} \ No newline at end of file diff --git a/execution/federationtesting/accounts/graph/schema.graphqls b/execution/federationtesting/accounts/graph/schema.graphqls index 1f8806c71a..e1f8328118 100644 --- a/execution/federationtesting/accounts/graph/schema.graphqls +++ b/execution/federationtesting/accounts/graph/schema.graphqls @@ -28,8 +28,8 @@ type User implements Identifiable @key(fields: "id") { realName: String! } -type Product @key(fields: "upc") { - upc: String! @external +type Product @key(fields: "upc", resolvable: false) { + upc: String! } union History = Purchase | Sale diff --git a/execution/federationtesting/compose.sh b/execution/federationtesting/compose.sh new file mode 100755 index 0000000000..d20d9811f0 --- /dev/null +++ b/execution/federationtesting/compose.sh @@ -0,0 +1,10 @@ +#!/usr/bin/env bash +set -euo pipefail + +echo "Composing subgraphs" + +npx -y wgc@latest router compose -i graph.yaml -o config.json + +echo "Formatting config" +jq . config.json > config.json.tmp +mv config.json.tmp config.json diff --git a/execution/federationtesting/config.json b/execution/federationtesting/config.json new file mode 100644 index 0000000000..d3fac07e2d --- /dev/null +++ b/execution/federationtesting/config.json @@ -0,0 +1,602 @@ +{ + "engineConfig": { + "defaultFlushInterval": "500", + "datasourceConfigurations": [ + { + "kind": "GRAPHQL", + "rootNodes": [ + { + "typeName": "Query", + "fieldNames": [ + "me", + "identifiable", + "histories", + "cat", + "interfaceUnion", + "abstractList", + "titleName", + "cds", + "otherInterfaces", + "someNestedInterfaces" + ] + }, + { + "typeName": "User", + "fieldNames": [ + "id", + "username", + "history", + "realName" + ] + }, + { + "typeName": "Product", + "fieldNames": [ + "upc" + ] + } + ], + "childNodes": [ + { + "typeName": "Cat", + "fieldNames": [ + "name" + ] + }, + { + "typeName": "Identifiable", + "fieldNames": [ + "id" + ] + }, + { + "typeName": "Info", + "fieldNames": [ + "quantity" + ] + }, + { + "typeName": "Purchase", + "fieldNames": [ + "product", + "wallet", + "quantity" + ] + }, + { + "typeName": "Store", + "fieldNames": [ + "location" + ] + }, + { + "typeName": "Sale", + "fieldNames": [ + "product", + "rating", + "location" + ] + }, + { + "typeName": "Wallet", + "fieldNames": [ + "currency", + "amount" + ] + }, + { + "typeName": "WalletType1", + "fieldNames": [ + "currency", + "amount", + "specialField1" + ] + }, + { + "typeName": "WalletType2", + "fieldNames": [ + "currency", + "amount", + "specialField2" + ] + }, + { + "typeName": "A", + "fieldNames": [ + "name" + ] + }, + { + "typeName": "B", + "fieldNames": [ + "name" + ] + }, + { + "typeName": "Namer", + "fieldNames": [ + "name" + ] + }, + { + "typeName": "AbstractListItem", + "fieldNames": [ + "obj" + ] + }, + { + "typeName": "ConcreteListItem1", + "fieldNames": [ + "obj" + ] + }, + { + "typeName": "ConcreteListItem2", + "fieldNames": [ + "obj" + ] + }, + { + "typeName": "OtherInterface", + "fieldNames": [ + "name", + "names" + ] + }, + { + "typeName": "SomeNestedInterface", + "fieldNames": [ + "otherInterfaces" + ] + }, + { + "typeName": "SomeNestedType1", + "fieldNames": [ + "otherInterfaces" + ] + }, + { + "typeName": "SomeNestedType2", + "fieldNames": [ + "otherInterfaces" + ] + }, + { + "typeName": "SomeInterface", + "fieldNames": [ + "someObject" + ] + }, + { + "typeName": "SomeType1", + "fieldNames": [ + "name", + "age", + "names", + "someObject" + ] + }, + { + "typeName": "SomeType2", + "fieldNames": [ + "name", + "height", + "names", + "someObject" + ] + }, + { + "typeName": "SomeType3", + "fieldNames": [ + "someObject" + ] + }, + { + "typeName": "SomeObject", + "fieldNames": [ + "a", + "b", + "c" + ] + }, + { + "typeName": "TitleName", + "fieldNames": [ + "a", + "b", + "c", + "title", + "name" + ] + }, + { + "typeName": "Title", + "fieldNames": [ + "title" + ] + }, + { + "typeName": "Name", + "fieldNames": [ + "name" + ] + }, + { + "typeName": "C", + "fieldNames": [ + "name" + ] + }, + { + "typeName": "D", + "fieldNames": [ + "name" + ] + }, + { + "typeName": "CDer", + "fieldNames": [ + "name" + ] + }, + { + "typeName": "CDerObj", + "fieldNames": [ + "first", + "middle", + "last" + ] + } + ], + "overrideFieldPathFromAlias": true, + "customGraphql": { + "fetch": { + "url": { + "staticVariableContent": "http://accounts-url-placeholder" + }, + "method": "POST", + "body": {}, + "baseUrl": {}, + "path": {} + }, + "subscription": { + "enabled": true, + "url": { + "staticVariableContent": "http://accounts-url-placeholder" + }, + "protocol": "GRAPHQL_SUBSCRIPTION_PROTOCOL_WS", + "websocketSubprotocol": "GRAPHQL_WEBSOCKET_SUBPROTOCOL_AUTO" + }, + "federation": { + "enabled": true, + "serviceSdl": "type Query {\n me: User\n identifiable: Identifiable\n histories: [History]\n cat: Cat\n\n # merge data test cases\n interfaceUnion(which: Which! = A): AB\n abstractList: [AbstractListItem]\n titleName: TitleName\n cds: [CD]\n otherInterfaces: [SomeInterface]\n someNestedInterfaces: [SomeNestedInterface]\n}\n\ntype Cat {\n name: String!\n}\n\ninterface Identifiable {\n id: ID!\n}\n\ntype User implements Identifiable @key(fields: \"id\") {\n id: ID!\n username: String!\n history: [History!]!\n realName: String!\n}\n\ntype Product @key(fields: \"upc\", resolvable: false) {\n upc: String!\n}\n\nunion History = Purchase | Sale\n\ninterface Info {\n quantity: Int!\n}\n\ntype Purchase implements Info {\n product: Product!\n wallet: Wallet\n quantity: Int!\n}\n\ninterface Store {\n location: String!\n}\n\ntype Sale implements Store {\n product: Product!\n rating: Int!\n location: String!\n}\n\ninterface Wallet {\n currency: String!\n amount: Float!\n}\n\ntype WalletType1 implements Wallet {\n currency: String!\n amount: Float!\n specialField1: String!\n}\n\ntype WalletType2 implements Wallet {\n currency: String!\n amount: Float!\n specialField2: String!\n}\n\nenum Which {\n A\n B\n}\n\nunion AB = A | B\n\ntype A implements Namer {\n name: String!\n}\n\ntype B implements Namer {\n name: String!\n}\n\ninterface Namer {\n name: String!\n}\n\ninterface AbstractListItem {\n obj: OtherInterface!\n}\n\ntype ConcreteListItem1 implements AbstractListItem {\n obj: OtherInterface!\n}\n\ntype ConcreteListItem2 implements AbstractListItem {\n obj: OtherInterface!\n}\n\ninterface OtherInterface {\n name: String!\n names: [String!]!\n}\n\ninterface SomeNestedInterface {\n otherInterfaces: [SomeInterface]\n}\n\ntype SomeNestedType1 implements SomeNestedInterface {\n otherInterfaces: [SomeInterface]\n}\n\ntype SomeNestedType2 implements SomeNestedInterface {\n otherInterfaces: [SomeInterface]\n}\n\ninterface SomeInterface {\n someObject: SomeObject!\n}\n\ntype SomeType1 implements OtherInterface & SomeInterface {\n name: String!\n age: Int!\n names: [String!]!\n someObject: SomeObject!\n}\n\ntype SomeType2 implements OtherInterface & SomeInterface {\n name: String!\n height: Float!\n names: [String!]!\n someObject: SomeObject!\n}\n\ntype SomeType3 implements SomeInterface {\n someObject: SomeObject!\n}\n\ntype SomeObject {\n a: String!\n b: String!\n c: String!\n}\n\ntype TitleName implements Title & Name {\n a: String!\n b: String!\n c: String!\n title: String!\n name: String!\n}\n\ninterface Title {\n title: String!\n}\n\ninterface Name {\n name: String!\n}\n\nunion CD = C | D\n\ntype C implements CDer {\n name: CDerObj\n}\n\ntype D implements CDer {\n name: CDerObj\n}\n\ninterface CDer {\n name: CDerObj\n}\n\ntype CDerObj {\n first: String!\n middle: String!\n last: String!\n}" + }, + "upstreamSchema": { + "key": "6f520b55de37e18b3a1354cb4ca7af798ca2b05f" + } + }, + "requestTimeoutSeconds": "10", + "id": "0", + "keys": [ + { + "typeName": "User", + "selectionSet": "id" + }, + { + "typeName": "Product", + "selectionSet": "upc", + "disableEntityResolver": true + } + ] + }, + { + "kind": "GRAPHQL", + "rootNodes": [ + { + "typeName": "Query", + "fieldNames": [ + "topProducts" + ] + }, + { + "typeName": "Mutation", + "fieldNames": [ + "setPrice" + ] + }, + { + "typeName": "Subscription", + "fieldNames": [ + "updatedPrice", + "updateProductPrice" + ] + }, + { + "typeName": "Product", + "fieldNames": [ + "upc", + "name", + "price", + "inStock" + ] + } + ], + "overrideFieldPathFromAlias": true, + "customGraphql": { + "fetch": { + "url": { + "staticVariableContent": "http://products-url-placeholder" + }, + "method": "POST", + "body": {}, + "baseUrl": {}, + "path": {} + }, + "subscription": { + "enabled": true, + "url": { + "staticVariableContent": "http://products-url-placeholder" + }, + "protocol": "GRAPHQL_SUBSCRIPTION_PROTOCOL_WS", + "websocketSubprotocol": "GRAPHQL_WEBSOCKET_SUBPROTOCOL_AUTO" + }, + "federation": { + "enabled": true, + "serviceSdl": "type Query {\n topProducts(first: Int = 5): [Product]\n}\n\ntype Mutation {\n setPrice(upc: String!, price: Int!): Product\n}\n\ntype Subscription {\n updatedPrice: Product!\n updateProductPrice(upc: String!): Product!\n}\n\ntype Product @key(fields: \"upc\") {\n upc: String!\n name: String!\n price: Int!\n inStock: Int!\n}\n" + }, + "upstreamSchema": { + "key": "5632255cc1750ef3bb9a7ca53e8a75f83331ebfa" + } + }, + "requestTimeoutSeconds": "10", + "id": "1", + "keys": [ + { + "typeName": "Product", + "selectionSet": "upc" + } + ] + }, + { + "kind": "GRAPHQL", + "rootNodes": [ + { + "typeName": "Query", + "fieldNames": [ + "me", + "cat" + ] + }, + { + "typeName": "User", + "fieldNames": [ + "id", + "reviews", + "realName" + ], + "externalFieldNames": [ + "username" + ] + }, + { + "typeName": "Product", + "fieldNames": [ + "upc", + "reviews" + ] + }, + { + "typeName": "Mutation", + "fieldNames": [ + "addReview" + ] + } + ], + "childNodes": [ + { + "typeName": "Cat", + "fieldNames": [ + "name" + ] + }, + { + "typeName": "Comment", + "fieldNames": [ + "upc", + "body" + ] + }, + { + "typeName": "Review", + "fieldNames": [ + "body", + "author", + "product", + "attachments", + "comment" + ] + }, + { + "typeName": "Iface", + "fieldNames": [ + "subject" + ] + }, + { + "typeName": "Question", + "fieldNames": [ + "upc", + "body", + "subject" + ] + }, + { + "typeName": "OtherQuestion", + "fieldNames": [ + "upc", + "body" + ] + }, + { + "typeName": "DetatchedQuestion", + "fieldNames": [ + "upc", + "body" + ] + }, + { + "typeName": "Rating", + "fieldNames": [ + "upc", + "body", + "score" + ] + }, + { + "typeName": "Video", + "fieldNames": [ + "upc", + "size", + "subject" + ] + } + ], + "overrideFieldPathFromAlias": true, + "customGraphql": { + "fetch": { + "url": { + "staticVariableContent": "http://reviews-url-placeholder" + }, + "method": "POST", + "body": {}, + "baseUrl": {}, + "path": {} + }, + "subscription": { + "enabled": true, + "url": { + "staticVariableContent": "http://reviews-url-placeholder" + }, + "protocol": "GRAPHQL_SUBSCRIPTION_PROTOCOL_WS", + "websocketSubprotocol": "GRAPHQL_WEBSOCKET_SUBPROTOCOL_AUTO" + }, + "federation": { + "enabled": true, + "serviceSdl": "type Query {\n me: User\n cat: Cat\n}\n\ntype Cat {\n name: String!\n}\n\ninterface Comment {\n upc: String!\n body: String!\n}\n\ntype Review {\n body: String!\n author: User! @provides(fields: \"username\")\n product: Product!\n attachments: [Attachment]\n comment: Comment\n}\n\ninterface Iface {\n subject: String!\n}\n\ntype Question implements Comment & Iface {\n upc: String!\n body: String!\n subject: String!\n}\n\ntype OtherQuestion implements Comment {\n upc: String!\n body: String!\n}\n\ntype DetatchedQuestion implements Comment {\n upc: String!\n body: String!\n}\n\ntype Rating implements Comment {\n upc: String!\n body: String!\n score: Int!\n}\n\ntype Video implements Iface {\n upc: String!\n size: Float!\n subject: String!\n}\n\nunion Attachment = Question | Rating | Video\n\ntype User @key(fields: \"id\") {\n id: ID!\n username: String! @external\n reviews: [Review]\n realName: String!\n}\n\ntype Product @key(fields: \"upc\") {\n upc: String!\n reviews: [Review]\n}\n\ntype Mutation {\n addReview(authorID: String! upc: String!, review: String!): Review!\n}\n" + }, + "upstreamSchema": { + "key": "3d7329613bdf1a3de2d2d26d61f2cb11370894f6" + } + }, + "requestTimeoutSeconds": "10", + "id": "2", + "keys": [ + { + "typeName": "User", + "selectionSet": "id" + }, + { + "typeName": "Product", + "selectionSet": "upc" + } + ], + "provides": [ + { + "typeName": "Review", + "fieldName": "author", + "selectionSet": "username" + } + ] + } + ], + "fieldConfigurations": [ + { + "typeName": "Query", + "fieldName": "interfaceUnion", + "argumentsConfiguration": [ + { + "name": "which", + "sourceType": "FIELD_ARGUMENT" + } + ] + }, + { + "typeName": "Query", + "fieldName": "topProducts", + "argumentsConfiguration": [ + { + "name": "first", + "sourceType": "FIELD_ARGUMENT" + } + ] + }, + { + "typeName": "Mutation", + "fieldName": "setPrice", + "argumentsConfiguration": [ + { + "name": "upc", + "sourceType": "FIELD_ARGUMENT" + }, + { + "name": "price", + "sourceType": "FIELD_ARGUMENT" + } + ] + }, + { + "typeName": "Mutation", + "fieldName": "addReview", + "argumentsConfiguration": [ + { + "name": "authorID", + "sourceType": "FIELD_ARGUMENT" + }, + { + "name": "upc", + "sourceType": "FIELD_ARGUMENT" + }, + { + "name": "review", + "sourceType": "FIELD_ARGUMENT" + } + ] + }, + { + "typeName": "Subscription", + "fieldName": "updateProductPrice", + "argumentsConfiguration": [ + { + "name": "upc", + "sourceType": "FIELD_ARGUMENT" + } + ] + } + ], + "graphqlSchema": "schema {\n query: Query\n mutation: Mutation\n subscription: Subscription\n}\n\ntype Query {\n me: User\n identifiable: Identifiable\n histories: [History]\n cat: Cat\n interfaceUnion(which: Which! = A): AB\n abstractList: [AbstractListItem]\n titleName: TitleName\n cds: [CD]\n otherInterfaces: [SomeInterface]\n someNestedInterfaces: [SomeNestedInterface]\n topProducts(first: Int = 5): [Product]\n}\n\ntype Cat {\n name: String!\n}\n\ninterface Identifiable {\n id: ID!\n}\n\ntype Product {\n upc: String!\n name: String!\n price: Int!\n inStock: Int!\n reviews: [Review]\n}\n\nunion History = Purchase | Sale\n\ninterface Info {\n quantity: Int!\n}\n\ninterface Store {\n location: String!\n}\n\ninterface Wallet {\n currency: String!\n amount: Float!\n}\n\nenum Which {\n A\n B\n}\n\nunion AB = A | B\n\ninterface Namer {\n name: String!\n}\n\ninterface AbstractListItem {\n obj: OtherInterface!\n}\n\ninterface OtherInterface {\n name: String!\n names: [String!]!\n}\n\ninterface SomeNestedInterface {\n otherInterfaces: [SomeInterface]\n}\n\ninterface SomeInterface {\n someObject: SomeObject!\n}\n\ntype SomeObject {\n a: String!\n b: String!\n c: String!\n}\n\ninterface Title {\n title: String!\n}\n\ninterface Name {\n name: String!\n}\n\nunion CD = C | D\n\ninterface CDer {\n name: CDerObj\n}\n\ntype CDerObj {\n first: String!\n middle: String!\n last: String!\n}\n\ntype Mutation {\n setPrice(upc: String!, price: Int!): Product\n addReview(authorID: String!, upc: String!, review: String!): Review!\n}\n\ntype Subscription {\n updatedPrice: Product!\n updateProductPrice(upc: String!): Product!\n}\n\ninterface Comment {\n upc: String!\n body: String!\n}\n\ntype Review {\n body: String!\n author: User!\n product: Product!\n attachments: [Attachment]\n comment: Comment\n}\n\ninterface Iface {\n subject: String!\n}\n\nunion Attachment = Question | Rating | Video\n\ntype User implements Identifiable {\n id: ID!\n username: String!\n history: [History!]!\n realName: String!\n reviews: [Review]\n}\n\ntype Purchase implements Info {\n product: Product!\n wallet: Wallet\n quantity: Int!\n}\n\ntype Sale implements Store {\n product: Product!\n rating: Int!\n location: String!\n}\n\ntype WalletType1 implements Wallet {\n currency: String!\n amount: Float!\n specialField1: String!\n}\n\ntype WalletType2 implements Wallet {\n currency: String!\n amount: Float!\n specialField2: String!\n}\n\ntype A implements Namer {\n name: String!\n}\n\ntype B implements Namer {\n name: String!\n}\n\ntype ConcreteListItem1 implements AbstractListItem {\n obj: OtherInterface!\n}\n\ntype ConcreteListItem2 implements AbstractListItem {\n obj: OtherInterface!\n}\n\ntype SomeNestedType1 implements SomeNestedInterface {\n otherInterfaces: [SomeInterface]\n}\n\ntype SomeNestedType2 implements SomeNestedInterface {\n otherInterfaces: [SomeInterface]\n}\n\ntype SomeType1 implements OtherInterface & SomeInterface {\n name: String!\n age: Int!\n names: [String!]!\n someObject: SomeObject!\n}\n\ntype SomeType2 implements OtherInterface & SomeInterface {\n name: String!\n height: Float!\n names: [String!]!\n someObject: SomeObject!\n}\n\ntype SomeType3 implements SomeInterface {\n someObject: SomeObject!\n}\n\ntype TitleName implements Title & Name {\n a: String!\n b: String!\n c: String!\n title: String!\n name: String!\n}\n\ntype C implements CDer {\n name: CDerObj\n}\n\ntype D implements CDer {\n name: CDerObj\n}\n\ntype Question implements Comment & Iface {\n upc: String!\n body: String!\n subject: String!\n}\n\ntype OtherQuestion implements Comment {\n upc: String!\n body: String!\n}\n\ntype DetatchedQuestion implements Comment {\n upc: String!\n body: String!\n}\n\ntype Rating implements Comment {\n upc: String!\n body: String!\n score: Int!\n}\n\ntype Video implements Iface {\n upc: String!\n size: Float!\n subject: String!\n}", + "stringStorage": { + "6f520b55de37e18b3a1354cb4ca7af798ca2b05f": "schema {\n query: Query\n}\n\ndirective @key(fields: openfed__FieldSet!, resolvable: Boolean = true) repeatable on INTERFACE | OBJECT\n\ntype A implements Namer {\n name: String!\n}\n\nunion AB = A | B\n\ninterface AbstractListItem {\n obj: OtherInterface!\n}\n\ntype B implements Namer {\n name: String!\n}\n\ntype C implements CDer {\n name: CDerObj\n}\n\nunion CD = C | D\n\ninterface CDer {\n name: CDerObj\n}\n\ntype CDerObj {\n first: String!\n last: String!\n middle: String!\n}\n\ntype Cat {\n name: String!\n}\n\ntype ConcreteListItem1 implements AbstractListItem {\n obj: OtherInterface!\n}\n\ntype ConcreteListItem2 implements AbstractListItem {\n obj: OtherInterface!\n}\n\ntype D implements CDer {\n name: CDerObj\n}\n\nunion History = Purchase | Sale\n\ninterface Identifiable {\n id: ID!\n}\n\ninterface Info {\n quantity: Int!\n}\n\ninterface Name {\n name: String!\n}\n\ninterface Namer {\n name: String!\n}\n\ninterface OtherInterface {\n name: String!\n names: [String!]!\n}\n\ntype Product @key(fields: \"upc\", resolvable: false) {\n upc: String!\n}\n\ntype Purchase implements Info {\n product: Product!\n quantity: Int!\n wallet: Wallet\n}\n\ntype Query {\n abstractList: [AbstractListItem]\n cat: Cat\n cds: [CD]\n histories: [History]\n identifiable: Identifiable\n interfaceUnion(which: Which! = A): AB\n me: User\n otherInterfaces: [SomeInterface]\n someNestedInterfaces: [SomeNestedInterface]\n titleName: TitleName\n}\n\ntype Sale implements Store {\n location: String!\n product: Product!\n rating: Int!\n}\n\ninterface SomeInterface {\n someObject: SomeObject!\n}\n\ninterface SomeNestedInterface {\n otherInterfaces: [SomeInterface]\n}\n\ntype SomeNestedType1 implements SomeNestedInterface {\n otherInterfaces: [SomeInterface]\n}\n\ntype SomeNestedType2 implements SomeNestedInterface {\n otherInterfaces: [SomeInterface]\n}\n\ntype SomeObject {\n a: String!\n b: String!\n c: String!\n}\n\ntype SomeType1 implements OtherInterface & SomeInterface {\n age: Int!\n name: String!\n names: [String!]!\n someObject: SomeObject!\n}\n\ntype SomeType2 implements OtherInterface & SomeInterface {\n height: Float!\n name: String!\n names: [String!]!\n someObject: SomeObject!\n}\n\ntype SomeType3 implements SomeInterface {\n someObject: SomeObject!\n}\n\ninterface Store {\n location: String!\n}\n\ninterface Title {\n title: String!\n}\n\ntype TitleName implements Name & Title {\n a: String!\n b: String!\n c: String!\n name: String!\n title: String!\n}\n\ntype User implements Identifiable @key(fields: \"id\") {\n history: [History!]!\n id: ID!\n realName: String!\n username: String!\n}\n\ninterface Wallet {\n amount: Float!\n currency: String!\n}\n\ntype WalletType1 implements Wallet {\n amount: Float!\n currency: String!\n specialField1: String!\n}\n\ntype WalletType2 implements Wallet {\n amount: Float!\n currency: String!\n specialField2: String!\n}\n\nenum Which {\n A\n B\n}\n\nscalar openfed__FieldSet", + "5632255cc1750ef3bb9a7ca53e8a75f83331ebfa": "schema {\n query: Query\n mutation: Mutation\n subscription: Subscription\n}\n\ndirective @key(fields: openfed__FieldSet!, resolvable: Boolean = true) repeatable on INTERFACE | OBJECT\n\ntype Mutation {\n setPrice(price: Int!, upc: String!): Product\n}\n\ntype Product @key(fields: \"upc\") {\n inStock: Int!\n name: String!\n price: Int!\n upc: String!\n}\n\ntype Query {\n topProducts(first: Int = 5): [Product]\n}\n\ntype Subscription {\n updateProductPrice(upc: String!): Product!\n updatedPrice: Product!\n}\n\nscalar openfed__FieldSet", + "3d7329613bdf1a3de2d2d26d61f2cb11370894f6": "schema {\n query: Query\n mutation: Mutation\n}\n\ndirective @external on FIELD_DEFINITION | OBJECT\n\ndirective @key(fields: openfed__FieldSet!, resolvable: Boolean = true) repeatable on INTERFACE | OBJECT\n\ndirective @provides(fields: openfed__FieldSet!) on FIELD_DEFINITION\n\nunion Attachment = Question | Rating | Video\n\ntype Cat {\n name: String!\n}\n\ninterface Comment {\n body: String!\n upc: String!\n}\n\ntype DetatchedQuestion implements Comment {\n body: String!\n upc: String!\n}\n\ninterface Iface {\n subject: String!\n}\n\ntype Mutation {\n addReview(authorID: String!, review: String!, upc: String!): Review!\n}\n\ntype OtherQuestion implements Comment {\n body: String!\n upc: String!\n}\n\ntype Product @key(fields: \"upc\") {\n reviews: [Review]\n upc: String!\n}\n\ntype Query {\n cat: Cat\n me: User\n}\n\ntype Question implements Comment & Iface {\n body: String!\n subject: String!\n upc: String!\n}\n\ntype Rating implements Comment {\n body: String!\n score: Int!\n upc: String!\n}\n\ntype Review {\n attachments: [Attachment]\n author: User! @provides(fields: \"username\")\n body: String!\n comment: Comment\n product: Product!\n}\n\ntype User @key(fields: \"id\") {\n id: ID!\n realName: String!\n reviews: [Review]\n username: String! @external\n}\n\ntype Video implements Iface {\n size: Float!\n subject: String!\n upc: String!\n}\n\nscalar openfed__FieldSet" + } + }, + "version": "00000000-0000-0000-0000-000000000000", + "subgraphs": [ + { + "id": "0", + "name": "accounts", + "routingUrl": "http://accounts-url-placeholder" + }, + { + "id": "1", + "name": "products", + "routingUrl": "http://products-url-placeholder" + }, + { + "id": "2", + "name": "reviews", + "routingUrl": "http://reviews-url-placeholder" + } + ], + "compatibilityVersion": "1:0.58.2" +} diff --git a/execution/federationtesting/gateway/datasource_poller.go b/execution/federationtesting/gateway/datasource_poller.go deleted file mode 100644 index 06ac67cae9..0000000000 --- a/execution/federationtesting/gateway/datasource_poller.go +++ /dev/null @@ -1,207 +0,0 @@ -package gateway - -import ( - "bytes" - "context" - "encoding/json" - "fmt" - "io" - "log" - "net/http" - "strings" - "sync" - "time" - - "github.com/wundergraph/graphql-go-tools/execution/engine" -) - -type ServiceConfig struct { - Name string - URL string - WS string -} - -type DatasourcePollerConfig struct { - Services []ServiceConfig - PollingInterval time.Duration -} - -const ServiceDefinitionQuery = ` - { - "query": "query __ApolloGetServiceDefinition__ { _service { sdl } }", - "operationName": "__ApolloGetServiceDefinition__", - "variables": {} - }` - -type GQLErr []struct { - Message string `json:"message"` -} - -func (g GQLErr) Error() string { - var builder strings.Builder - for _, m := range g { - _ = builder.WriteByte('\t') - _, _ = builder.WriteString(m.Message) - } - - return builder.String() -} - -func NewDatasourcePoller( - httpClient *http.Client, - config DatasourcePollerConfig, -) *DatasourcePollerPoller { - return &DatasourcePollerPoller{ - httpClient: httpClient, - config: config, - sdlMap: make(map[string]string), - } -} - -type DatasourcePollerPoller struct { - httpClient *http.Client - - config DatasourcePollerConfig - sdlMap map[string]string - - updateDatasourceObservers []DataSourceObserver -} - -func (d *DatasourcePollerPoller) Register(updateDatasourceObserver DataSourceObserver) { - d.updateDatasourceObservers = append(d.updateDatasourceObservers, updateDatasourceObserver) -} - -func (d *DatasourcePollerPoller) Run(ctx context.Context) { - d.updateSDLs(ctx) - - if d.config.PollingInterval == 0 { - <-ctx.Done() - return - } - - ticker := time.NewTicker(d.config.PollingInterval) - defer ticker.Stop() - - for { - select { - case <-ctx.Done(): - return - case <-ticker.C: - d.updateSDLs(ctx) - } - } -} - -func (d *DatasourcePollerPoller) updateSDLs(ctx context.Context) { - d.sdlMap = make(map[string]string) - - var wg sync.WaitGroup - resultCh := make(chan struct { - name string - sdl string - }) - - for _, serviceConf := range d.config.Services { - serviceConf := serviceConf // Create new instance of serviceConf for the goroutine. - wg.Add(1) - go func() { - defer wg.Done() - - sdl, err := d.fetchServiceSDL(ctx, serviceConf.URL) - if err != nil { - log.Printf("Failed to get sdl for service: %s, err: %s\n", serviceConf.Name, err) - return - } - - select { - case <-ctx.Done(): - case resultCh <- struct { - name string - sdl string - }{name: serviceConf.Name, sdl: sdl}: - } - }() - } - - go func() { - wg.Wait() - close(resultCh) - }() - - for result := range resultCh { - d.sdlMap[result.name] = result.sdl - } - - d.updateObservers() -} - -func (d *DatasourcePollerPoller) updateObservers() { - subgraphsConfig := d.createSubgraphsConfig() - - for i := range d.updateDatasourceObservers { - d.updateDatasourceObservers[i].UpdateDataSources(subgraphsConfig) - } -} - -func (d *DatasourcePollerPoller) createSubgraphsConfig() []engine.SubgraphConfiguration { - subgraphConfigs := make([]engine.SubgraphConfiguration, 0, len(d.config.Services)) - - for _, serviceConfig := range d.config.Services { - sdl, exists := d.sdlMap[serviceConfig.Name] - if !exists { - continue - } - - subgraphConfig := engine.SubgraphConfiguration{ - Name: serviceConfig.Name, - URL: serviceConfig.URL, - SDL: sdl, - SubscriptionUrl: serviceConfig.WS, - SubscriptionProtocol: engine.SubscriptionProtocolWS, - } - - subgraphConfigs = append(subgraphConfigs, subgraphConfig) - } - - return subgraphConfigs -} - -func (d *DatasourcePollerPoller) fetchServiceSDL(ctx context.Context, serviceURL string) (string, error) { - req, err := http.NewRequestWithContext(ctx, http.MethodPost, serviceURL, bytes.NewReader([]byte(ServiceDefinitionQuery))) - req.Header.Add("Content-Type", "application/json") - - if err != nil { - return "", fmt.Errorf("create request: %v", err) - } - - resp, err := d.httpClient.Do(req) - if err != nil { - return "", fmt.Errorf("do request: %v", err) - } - - defer resp.Body.Close() - - var result struct { - Data struct { - Service struct { - SDL string `json:"sdl"` - } `json:"_service"` - } `json:"data"` - Errors GQLErr `json:"errors,omitempty"` - } - - bs, err := io.ReadAll(resp.Body) - if err != nil { - return "", fmt.Errorf("read bytes: %v", err) - } - - if err = json.NewDecoder(bytes.NewReader(bs)).Decode(&result); err != nil { - return "", fmt.Errorf("decode response: %v", err) - } - - if result.Errors != nil { - return "", fmt.Errorf("response error:%v", result.Errors) - } - - return result.Data.Service.SDL, nil -} diff --git a/execution/federationtesting/gateway/gateway.go b/execution/federationtesting/gateway/gateway.go index ffc62eb7d9..f856eaa866 100644 --- a/execution/federationtesting/gateway/gateway.go +++ b/execution/federationtesting/gateway/gateway.go @@ -2,95 +2,55 @@ package gateway import ( "context" + "fmt" "net/http" - "sync" + "github.com/gobwas/ws" log "github.com/jensneuse/abstractlogger" + "google.golang.org/protobuf/encoding/protojson" + + nodev1 "github.com/wundergraph/cosmo/router/gen/proto/wg/cosmo/node/v1" "github.com/wundergraph/graphql-go-tools/execution/engine" - "github.com/wundergraph/graphql-go-tools/execution/graphql" + "github.com/wundergraph/graphql-go-tools/execution/federationtesting/gateway/httphandler" "github.com/wundergraph/graphql-go-tools/v2/pkg/engine/resolve" ) -type DataSourceObserver interface { - UpdateDataSources(subgraphsConfigs []engine.SubgraphConfiguration) -} - -type DataSourceSubject interface { - Register(observer DataSourceObserver) -} - -type HandlerFactory interface { - Make(schema *graphql.Schema, engine *engine.ExecutionEngine) http.Handler -} - -type HandlerFactoryFn func(schema *graphql.Schema, engine *engine.ExecutionEngine) http.Handler - -func (h HandlerFactoryFn) Make(schema *graphql.Schema, engine *engine.ExecutionEngine) http.Handler { - return h(schema, engine) -} - func NewGateway( - gqlHandlerFactory HandlerFactory, + configFileContent []byte, httpClient *http.Client, logger log.Logger, -) *Gateway { - return &Gateway{ - gqlHandlerFactory: gqlHandlerFactory, - httpClient: httpClient, - logger: logger, - - mu: &sync.Mutex{}, - readyCh: make(chan struct{}), - readyOnce: &sync.Once{}, + enableART bool, +) (*Gateway, error) { + var rc nodev1.RouterConfig + if err := protojson.Unmarshal(configFileContent, &rc); err != nil { + return nil, fmt.Errorf("can't unmarshal composed config: %w", err) } -} - -type Gateway struct { - gqlHandlerFactory HandlerFactory - httpClient *http.Client - logger log.Logger - gqlHandler http.Handler - mu *sync.Mutex - - readyCh chan struct{} - readyOnce *sync.Once -} - -func (g *Gateway) ServeHTTP(w http.ResponseWriter, r *http.Request) { - g.mu.Lock() - handler := g.gqlHandler - g.mu.Unlock() - - handler.ServeHTTP(w, r) -} - -func (g *Gateway) Ready() { - <-g.readyCh -} - -func (g *Gateway) UpdateDataSources(subgraphsConfigs []engine.SubgraphConfiguration) { ctx := context.Background() - engineConfigFactory := engine.NewFederationEngineConfigFactory(ctx, subgraphsConfigs, engine.WithFederationHttpClient(g.httpClient)) + engineConfigFactory := engine.NewFederationEngineConfigFactory(ctx, engine.WithFederationHttpClient(httpClient)) - engineConfig, err := engineConfigFactory.BuildEngineConfiguration() + engineConfig, err := engineConfigFactory.BuildEngineConfiguration(&rc) if err != nil { - g.logger.Error("get engine config: %v", log.Error(err)) - return + return nil, fmt.Errorf("can't build engine configuration: %w", err) } - executionEngine, err := engine.NewExecutionEngine(ctx, g.logger, engineConfig, resolve.ResolverOptions{ + executionEngine, err := engine.NewExecutionEngine(ctx, logger, engineConfig, resolve.ResolverOptions{ MaxConcurrency: 1024, }) if err != nil { - g.logger.Error("create engine: %v", log.Error(err)) - return + return nil, fmt.Errorf("can't create an engine: %w", err) + } + + upgrader := &ws.HTTPUpgrader{ + Header: http.Header{}, } - g.mu.Lock() - g.gqlHandler = g.gqlHandlerFactory.Make(engineConfig.Schema(), executionEngine) - g.mu.Unlock() + handler := httphandler.NewGraphqlHTTPHandler(engineConfig.Schema(), executionEngine, upgrader, logger, enableART) - g.readyOnce.Do(func() { close(g.readyCh) }) + return &Gateway{handler}, nil +} + +type Gateway struct { + http.Handler } diff --git a/execution/federationtesting/gateway/http/handler.go b/execution/federationtesting/gateway/httphandler/handler.go similarity index 98% rename from execution/federationtesting/gateway/http/handler.go rename to execution/federationtesting/gateway/httphandler/handler.go index e6d575cd7a..8b6e537c22 100644 --- a/execution/federationtesting/gateway/http/handler.go +++ b/execution/federationtesting/gateway/httphandler/handler.go @@ -1,4 +1,4 @@ -package http +package httphandler import ( "net/http" diff --git a/execution/federationtesting/gateway/http/http.go b/execution/federationtesting/gateway/httphandler/http.go similarity index 94% rename from execution/federationtesting/gateway/http/http.go rename to execution/federationtesting/gateway/httphandler/http.go index 5a255e01c9..9483e322b0 100644 --- a/execution/federationtesting/gateway/http/http.go +++ b/execution/federationtesting/gateway/httphandler/http.go @@ -1,5 +1,5 @@ -// Package http handles GraphQL HTTP Requests including WebSocket Upgrades. -package http +// Package httphandler handles GraphQL HTTP Requests including WebSocket Upgrades. +package httphandler import ( "bytes" diff --git a/execution/federationtesting/gateway/http/ws.go b/execution/federationtesting/gateway/httphandler/ws.go similarity index 99% rename from execution/federationtesting/gateway/http/ws.go rename to execution/federationtesting/gateway/httphandler/ws.go index ecd7994c15..4daa10fb5a 100644 --- a/execution/federationtesting/gateway/http/ws.go +++ b/execution/federationtesting/gateway/httphandler/ws.go @@ -1,4 +1,4 @@ -package http +package httphandler import ( "context" diff --git a/execution/federationtesting/gateway/main.go b/execution/federationtesting/gateway/main.go deleted file mode 100644 index 69f6e5023e..0000000000 --- a/execution/federationtesting/gateway/main.go +++ /dev/null @@ -1,43 +0,0 @@ -package gateway - -import ( - "net/http" - "time" - - "github.com/gobwas/ws" - log "github.com/jensneuse/abstractlogger" - - "github.com/wundergraph/graphql-go-tools/execution/engine" - http2 "github.com/wundergraph/graphql-go-tools/execution/federationtesting/gateway/http" - "github.com/wundergraph/graphql-go-tools/execution/graphql" -) - -func NewDatasource(serviceConfig []ServiceConfig, httpClient *http.Client) *DatasourcePollerPoller { - return NewDatasourcePoller(httpClient, DatasourcePollerConfig{ - Services: serviceConfig, - PollingInterval: 30 * time.Second, - }) -} - -func Handler( - logger log.Logger, - datasourcePoller *DatasourcePollerPoller, - httpClient *http.Client, - enableART bool, -) *Gateway { - upgrader := &ws.HTTPUpgrader{ - Header: http.Header{}, - } - - datasourceWatcher := datasourcePoller - - var gqlHandlerFactory HandlerFactoryFn = func(schema *graphql.Schema, engine *engine.ExecutionEngine) http.Handler { - return http2.NewGraphqlHTTPHandler(schema, engine, upgrader, logger, enableART) - } - - gateway := NewGateway(gqlHandlerFactory, httpClient, logger) - - datasourceWatcher.Register(gateway) - - return gateway -} diff --git a/execution/federationtesting/graph.yaml b/execution/federationtesting/graph.yaml new file mode 100644 index 0000000000..a14acb26ea --- /dev/null +++ b/execution/federationtesting/graph.yaml @@ -0,0 +1,14 @@ +version: 1 +subgraphs: + - name: accounts + routing_url: http://accounts-url-placeholder + schema: + file: accounts/graph/schema.graphqls + - name: products + routing_url: http://products-url-placeholder + schema: + file: products/graph/schema.graphqls + - name: reviews + routing_url: http://reviews-url-placeholder + schema: + file: reviews/graph/schema.graphqls diff --git a/execution/federationtesting/reviews/graph/schema.graphqls b/execution/federationtesting/reviews/graph/schema.graphqls index 9df5262ed0..bbd9916aee 100644 --- a/execution/federationtesting/reviews/graph/schema.graphqls +++ b/execution/federationtesting/reviews/graph/schema.graphqls @@ -55,14 +55,14 @@ type Video implements Iface { union Attachment = Question | Rating | Video type User @key(fields: "id") { - id: ID! @external + id: ID! username: String! @external reviews: [Review] realName: String! } type Product @key(fields: "upc") { - upc: String! @external + upc: String! reviews: [Review] } diff --git a/execution/federationtesting/util.go b/execution/federationtesting/util.go index 6fe81b5b75..2bf7214de0 100644 --- a/execution/federationtesting/util.go +++ b/execution/federationtesting/util.go @@ -1,10 +1,8 @@ package federationtesting import ( + _ "embed" "net/http/httptest" - "os" - "path/filepath" - "strings" accounts "github.com/wundergraph/graphql-go-tools/execution/federationtesting/accounts/graph" products "github.com/wundergraph/graphql-go-tools/execution/federationtesting/products/graph" @@ -12,8 +10,6 @@ import ( ) const ( - federationTestingDirectoryRelativePath = "../federationtesting" - QueryReviewsOfMe = `query ReviewsOfMe { me { reviews { @@ -28,25 +24,18 @@ const ( }` ) -type Upstream string - -const ( - UpstreamAccounts Upstream = "accounts" - UpstreamProducts Upstream = "products" - UpstreamReviews Upstream = "reviews" +var ( + //go:embed config.json + RouterConfigJson []byte + //go:embed accounts/graph/schema.graphqls + AccountSDL []byte + //go:embed products/graph/schema.graphqls + ProductsSDL []byte + //go:embed reviews/graph/schema.graphqls + ReviewsSDL []byte ) -func LoadTestingSubgraphSDL(upstream Upstream) ([]byte, error) { - wd, err := os.Getwd() - if err != nil { - return nil, err - } - - absolutePath := filepath.Join(strings.Split(wd, "pkg")[0], federationTestingDirectoryRelativePath, string(upstream), "graph", "schema.graphqls") - return os.ReadFile(absolutePath) -} - -func NewFederationSetup(addGateway ...func(s *FederationSetup) *httptest.Server) *FederationSetup { +func NewFederationSetup(addGateway ...func(s *FederationSetup) (*httptest.Server, error)) (*FederationSetup, error) { accountUpstreamServer := httptest.NewServer(accounts.GraphQLEndpointHandler(accounts.TestOptions)) productsUpstreamServer := httptest.NewServer(products.GraphQLEndpointHandler(products.TestOptions)) reviewsUpstreamServer := httptest.NewServer(reviews.GraphQLEndpointHandler(reviews.TestOptions)) @@ -58,10 +47,15 @@ func NewFederationSetup(addGateway ...func(s *FederationSetup) *httptest.Server) } if len(addGateway) > 0 { - setup.GatewayServer = addGateway[0](setup) + gw, err := addGateway[0](setup) + if err != nil { + return nil, err + } + + setup.GatewayServer = gw } - return setup + return setup, nil } type FederationSetup struct { diff --git a/execution/go.mod b/execution/go.mod index 31ccb51c24..4651da3bc6 100644 --- a/execution/go.mod +++ b/execution/go.mod @@ -14,10 +14,9 @@ require ( github.com/sebdah/goldie/v2 v2.7.1 github.com/stretchr/testify v1.11.1 github.com/vektah/gqlparser/v2 v2.5.30 - github.com/wundergraph/astjson v1.0.0 - github.com/wundergraph/cosmo/composition-go v0.0.0-20241020204711-78f240a77c99 + github.com/wundergraph/astjson v1.1.0 github.com/wundergraph/cosmo/router v0.0.0-20251013094319-c611abf26b17 - github.com/wundergraph/graphql-go-tools/v2 v2.0.0-rc.231 + github.com/wundergraph/graphql-go-tools/v2 v2.1.0 go.uber.org/atomic v1.11.0 google.golang.org/grpc v1.71.0 google.golang.org/protobuf v1.36.9 @@ -32,17 +31,13 @@ require ( github.com/coder/websocket v1.8.14 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.7 // indirect github.com/davecgh/go-spew v1.1.1 // indirect - github.com/dlclark/regexp2 v1.11.0 // indirect github.com/dnephin/pflag v1.0.7 // indirect - github.com/dop251/goja v0.0.0-20230906160731-9410bcaa81d2 // indirect github.com/fatih/color v1.18.0 // indirect github.com/fsnotify/fsnotify v1.9.0 // indirect - github.com/go-sourcemap/sourcemap v2.1.3+incompatible // indirect github.com/go-viper/mapstructure/v2 v2.4.0 // indirect github.com/gobwas/httphead v0.1.0 // indirect github.com/gobwas/pool v0.2.1 // indirect github.com/golang/protobuf v1.5.4 // indirect - github.com/google/pprof v0.0.0-20230207041349-798e818bf904 // indirect github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect github.com/hashicorp/go-hclog v1.6.3 // indirect github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect @@ -57,6 +52,7 @@ require ( github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/r3labs/sse/v2 v2.8.1 // indirect + github.com/rs/xid v1.6.0 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/sergi/go-diff v1.3.1 // indirect github.com/sirupsen/logrus v1.9.3 // indirect @@ -81,7 +77,6 @@ require ( gopkg.in/cenkalti/backoff.v1 v1.1.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect gotest.tools/gotestsum v1.13.0 // indirect - rogchap.com/v8go v0.9.0 // indirect ) tool github.com/99designs/gqlgen diff --git a/execution/go.sum b/execution/go.sum index 5d29f427f1..d4562f812d 100644 --- a/execution/go.sum +++ b/execution/go.sum @@ -15,30 +15,17 @@ github.com/buger/jsonparser v1.1.1 h1:2PnMjfWD7wBILjqQbt530v576A/cAbQvEW9gGIpYMU github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/chzyer/logex v1.2.0/go.mod h1:9+9sk7u7pGNWYMkh0hdiL++6OeibzJccyQU4p4MedaY= -github.com/chzyer/readline v1.5.0/go.mod h1:x22KAscuvRqlLoK9CsoYsmxoXZMMFVyOl86cAH8qUic= -github.com/chzyer/test v0.0.0-20210722231415-061457976a23/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/coder/websocket v1.8.14 h1:9L0p0iKiNOibykf283eHkKUHHrpG7f65OE3BhhO7v9g= github.com/coder/websocket v1.8.14/go.mod h1:NX3SzP+inril6yawo5CQXx8+fk145lPDC6pumgx0mVg= github.com/cpuguy83/go-md2man/v2 v2.0.7 h1:zbFlGlXEAKlwXpmvle3d8Oe3YnkKIK4xSRTd3sHPnBo= github.com/cpuguy83/go-md2man/v2 v2.0.7/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= -github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dgryski/trifles v0.0.0-20230903005119-f50d829f2e54 h1:SG7nF6SRlWhcT7cNTs5R6Hk4V2lcmLz2NsG2VnInyNo= github.com/dgryski/trifles v0.0.0-20230903005119-f50d829f2e54/go.mod h1:if7Fbed8SFyPtHLHbg49SI7NAdJiC5WIA09pe59rfAA= -github.com/dlclark/regexp2 v1.4.1-0.20201116162257-a2a8dda75c91/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc= -github.com/dlclark/regexp2 v1.7.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= -github.com/dlclark/regexp2 v1.11.0 h1:G/nrcoOa7ZXlpoa/91N3X7mM3r8eIlMBBJZvsz/mxKI= -github.com/dlclark/regexp2 v1.11.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= github.com/dnephin/pflag v1.0.7 h1:oxONGlWxhmUct0YzKTgrpQv9AUA1wtPBn7zuSjJqptk= github.com/dnephin/pflag v1.0.7/go.mod h1:uxE91IoWURlOiTUIA8Mq5ZZkAv3dPUfZNaT80Zm7OQE= -github.com/dop251/goja v0.0.0-20211022113120-dc8c55024d06/go.mod h1:R9ET47fwRVRPZnOGvHxxhuZcbrMCuiqOz3Rlrh4KSnk= -github.com/dop251/goja v0.0.0-20230906160731-9410bcaa81d2 h1:3J+RqSTu+JuyCYjoe82vvUUljEfgp8i6+nyhUsaYAbg= -github.com/dop251/goja v0.0.0-20230906160731-9410bcaa81d2/go.mod h1:QMWlm50DNe14hD7t24KEqZuUdC9sOTy8W6XbCU1mlw4= -github.com/dop251/goja_nodejs v0.0.0-20210225215109-d91c329300e7/go.mod h1:hn7BA7c8pLvoGndExHudxTDKZ84Pyvv+90pbBjbTz0Y= -github.com/dop251/goja_nodejs v0.0.0-20211022123610-8dd9abb0616d/go.mod h1:DngW8aVqWbuLRMHItjPUyqdj+HWPvnQe8V8y1nDpIbM= github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM= github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU= @@ -48,8 +35,6 @@ github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= -github.com/go-sourcemap/sourcemap v2.1.3+incompatible h1:W1iEw64niKVGogNgBN3ePyLFfuisuzeidWPMPWmECqU= -github.com/go-sourcemap/sourcemap v2.1.3+incompatible/go.mod h1:F8jJfvm2KbVjc5NqelyYJmf/v5J0dwNLS2mL4sNA1Jg= github.com/go-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs= github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= github.com/gobwas/httphead v0.1.0 h1:exrUm0f4YX0L7EBwZHuCF4GDp8aJfVeBrlLQrs6NqWU= @@ -64,8 +49,6 @@ github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= -github.com/google/pprof v0.0.0-20230207041349-798e818bf904 h1:4/hN5RUoecvl+RmJRE2YxKWtnnQls6rQjjW5oV7qg2U= -github.com/google/pprof v0.0.0-20230207041349-798e818bf904/go.mod h1:uglQLonpP8qtYCYyzA+8c/9qtqgA3qsXGYqCPKARAFg= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= @@ -83,7 +66,6 @@ github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= github.com/hashicorp/yamux v0.1.1 h1:yrQxtgseBDrq9Y652vSRDvsKCJKOUD+GzTS4Y0Y8pvE= github.com/hashicorp/yamux v0.1.1/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= -github.com/ianlancetaylor/demangle v0.0.0-20220319035150-800ac71e25c2/go.mod h1:aYm2/VgdVmcIU8iMfdMvDMsRAQjcfZSKFby6HOFvi/w= github.com/jensneuse/abstractlogger v0.0.4 h1:sa4EH8fhWk3zlTDbSncaWKfwxYM8tYSlQ054ETLyyQY= github.com/jensneuse/abstractlogger v0.0.4/go.mod h1:6WuamOHuykJk8zED/R0LNiLhWR6C7FIAo43ocUEB3mo= github.com/jensneuse/byte-template v0.0.0-20231025215717-69252eb3ed56 h1:wo26fh6a6Za0cOMZIopD2sfH/kq83SJ89ixUWl7pCWc= @@ -97,8 +79,6 @@ github.com/kingledion/go-tools v0.6.0/go.mod h1:qcDJQxBui/H/hterGb90GMlLs9Yi7Qrw github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= -github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= @@ -129,9 +109,10 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN github.com/r3labs/sse/v2 v2.8.1 h1:lZH+W4XOLIq88U5MIHOsLec7+R62uhz3bIi2yn0Sg8o= github.com/r3labs/sse/v2 v2.8.1/go.mod h1:Igau6Whc+F17QUgML1fYe1VPZzTV6EMCnYktEmkNJ7I= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= +github.com/rs/xid v1.6.0 h1:fV591PaemRlL6JfRxGDEPl69wICngIQ3shQtzfy2gxU= +github.com/rs/xid v1.6.0/go.mod h1:7XoLgs4eV+QndskICGsho+ADou8ySMSjJKDIan90Nz0= github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/sebdah/goldie/v2 v2.7.1 h1:PkBHymaYdtvEkZV7TmyqKxdmn5/Vcj+8TpATWZjnG5E= @@ -167,20 +148,17 @@ github.com/urfave/cli/v2 v2.27.7 h1:bH59vdhbjLv3LAvIu6gd0usJHgoTTPhCFib8qqOwXYU= github.com/urfave/cli/v2 v2.27.7/go.mod h1:CyNAG/xg+iAOg0N4MPGZqVmv2rCoP267496AOXUZjA4= github.com/vektah/gqlparser/v2 v2.5.30 h1:EqLwGAFLIzt1wpx1IPpY67DwUujF1OfzgEyDsLrN6kE= github.com/vektah/gqlparser/v2 v2.5.30/go.mod h1:D1/VCZtV3LPnQrcPBeR/q5jkSQIPti0uYCP/RI0gIeo= -github.com/wundergraph/astjson v1.0.0 h1:rETLJuQkMWWW03HCF6WBttEBOu8gi5vznj5KEUPVV2Q= -github.com/wundergraph/astjson v1.0.0/go.mod h1:h12D/dxxnedtLzsKyBLK7/Oe4TAoGpRVC9nDpDrZSWw= -github.com/wundergraph/cosmo/composition-go v0.0.0-20241020204711-78f240a77c99 h1:TGXDYfDhwFLFTuNuCwkuqXT5aXGz47zcurXLfTBS9w4= -github.com/wundergraph/cosmo/composition-go v0.0.0-20241020204711-78f240a77c99/go.mod h1:fUuOAUAXUFB/mlSkAaImGeE4A841AKR5dTMWhV4ibxI= +github.com/wundergraph/astjson v1.1.0 h1:xORDosrZ87zQFJwNGe/HIHXqzpdHOFmqWgykCLVL040= +github.com/wundergraph/astjson v1.1.0/go.mod h1:h12D/dxxnedtLzsKyBLK7/Oe4TAoGpRVC9nDpDrZSWw= github.com/wundergraph/cosmo/router v0.0.0-20251013094319-c611abf26b17 h1:GjO2E8LTf3U5JiQJCY4MmlRcAjVt7IvAbWFSgEjQdl8= github.com/wundergraph/cosmo/router v0.0.0-20251013094319-c611abf26b17/go.mod h1:7kt64e0LOLMBqOzrfu9PuLRn9cVT9YN1Bb3EennVtws= github.com/wundergraph/go-arena v1.1.0 h1:9+wSRkJAkA2vbYHp6s8tEGhPViRGQNGXqPHT0QzhdIc= github.com/wundergraph/go-arena v1.1.0/go.mod h1:ROOysEHWJjLQ8FSfNxZCziagb7Qw2nXY3/vgKRh7eWw= -github.com/wundergraph/graphql-go-tools/v2 v2.0.0-rc.231 h1:2C8LNFGs8MtI2yPy2/a2WRf9/X2FoMqXlEJkpTjvsTg= -github.com/wundergraph/graphql-go-tools/v2 v2.0.0-rc.231/go.mod h1:ErOQH1ki2+SZB8JjpTyGVnoBpg5picIyjvuWQJP4abg= +github.com/wundergraph/graphql-go-tools/v2 v2.1.0 h1:V1MU/uo+oc5b+aIh3SpCr0rJgLHuhonWg2fhN1sfMdY= +github.com/wundergraph/graphql-go-tools/v2 v2.1.0/go.mod h1:UG/grnPEHumtD82H8FC+3dokiCGK8GF0b5IJc00lSbM= github.com/xrash/smetrics v0.0.0-20250705151800-55b8f293f342 h1:FnBeRrxr7OU4VvAzt5X7s6266i6cSVkkFPS0TuXWbIg= github.com/xrash/smetrics v0.0.0-20250705151800-55b8f293f342/go.mod h1:Ohn+xnUBiLI6FVj/9LpzZWtj1/D6lUovWYBkxHVV3aM= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= go.opentelemetry.io/otel v1.36.0 h1:UumtzIklRBY6cI/lllNZlALOF5nNIzJVb16APdvgTXg= @@ -208,25 +186,20 @@ go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.29.0 h1:HV8lRxZC4l2cr3Zq1LvtOsi/ThTgWnUk/y64QSs8GwA= golang.org/x/mod v0.29.0/go.mod h1:NyhrlYXJ2H4eJiRy/WDBO6HMqZQ6q9nk4JzS3NuCK+w= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191116160921-f9c825593386/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= -golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.46.0 h1:giFlY12I07fugqwPuWJi68oOnpfqFnJIJzaIIm2JVV4= golang.org/x/net v0.46.0/go.mod h1:Q9BGdFy1y4nkUwiLvT5qtyhAnEHgnQ/zd8PfU6nc210= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.17.0 h1:l60nONMj9l5drqw6jlhIELNv9I0A4OFgRsG9k2oT9Ug= golang.org/x/sync v0.17.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -237,26 +210,18 @@ golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.37.0 h1:fdNQudmxPjkdUTPnLn5mdQv7Zwvbvpaxqs831goi9kQ= golang.org/x/sys v0.37.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.36.0 h1:zMPR+aF8gfksFprF/Nc/rd1wRS1EI6nDBGyWAvDzx2Q= golang.org/x/term v0.36.0/go.mod h1:Qu394IJq6V6dCBRgwqshf3mPF85AqzYEzofzRdZkWss= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= golang.org/x/text v0.30.0 h1:yznKA/E9zq54KzlzBEAWn1NXSQ8DIp/NYMy88xJjl4k= golang.org/x/text v0.30.0/go.mod h1:yDdHFIX9t+tORqspjENWgzaCVXgk0yYnYuSZ8UzzBVM= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -266,7 +231,6 @@ golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.38.0 h1:Hx2Xv8hISq8Lm16jvBZ2VQf+RLmbd7wVUsALibYI/IQ= golang.org/x/tools v0.38.0/go.mod h1:yEsQ/d/YK8cjh0L6rZlY8tgtlKiBNTL14pGDJPJpYQs= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -289,7 +253,6 @@ gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntN gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= @@ -299,5 +262,3 @@ gotest.tools/gotestsum v1.13.0/go.mod h1:7f0NS5hFb0dWr4NtcsAsF0y1kzjEFfAil0HiBQJ gotest.tools/v3 v3.5.2 h1:7koQfIKdy+I8UTetycgUqXWSDwpgv193Ka+qRsmBY8Q= gotest.tools/v3 v3.5.2/go.mod h1:LtdLGcnqToBH83WByAAi/wiwSFCArdFIUV/xxN4pcjA= honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= -rogchap.com/v8go v0.9.0 h1:wYbUCO4h6fjTamziHrzyrPnpFNuzPpjZY+nfmZjNaew= -rogchap.com/v8go v0.9.0/go.mod h1:MxgP3pL2MW4dpme/72QRs8sgNMmM0pRc8DPhcuLWPAs= diff --git a/execution/playground/files/playground.html b/execution/playground/files/playground.html new file mode 100644 index 0000000000..f7444f652e --- /dev/null +++ b/execution/playground/files/playground.html @@ -0,0 +1,98 @@ + + + + + + + GraphiQL 5 with React 19 and GraphiQL Explorer + + + + + + + + +
+
Loading…
+
+ + \ No newline at end of file diff --git a/v2/pkg/playground/playground.go b/execution/playground/playground.go similarity index 60% rename from v2/pkg/playground/playground.go rename to execution/playground/playground.go index 1addb7fc6f..f6e836e6f4 100644 --- a/v2/pkg/playground/playground.go +++ b/execution/playground/playground.go @@ -3,7 +3,6 @@ package playground import ( "embed" - "fmt" "html/template" "net/http" "path" @@ -11,18 +10,9 @@ import ( ) const ( - playgroundTemplate = "playgroundTemplate" - - contentTypeHeader = "Content-Type" - contentTypeImagePNG = "image/png" - contentTypeTextHTML = "text/html" - contentTypeTextCSS = "text/css" - contentTypeTextJavascript = "text/javascript" - - cssFile = "playground.css" - jsFile = "playground.js" - faviconFile = "favicon.png" - logoFile = "logo.png" + playgroundTemplate = "playgroundTemplate" + contentTypeHeader = "Content-Type" + contentTypeTextHTML = "text/html" ) //go:embed files/* @@ -41,10 +31,6 @@ type Config struct { } type playgroundTemplateData struct { - CssURL string - JsURL string - FavIconURL string - LogoURL string EndpointURL string SubscriptionEndpointURL string } @@ -76,70 +62,31 @@ func (h *Handlers) add(path string, handler http.HandlerFunc) { // Playground manages the configuration of all HTTP handlers responsible for serving the GraphQL Playground type Playground struct { - cfg Config - files []fileConfig - data playgroundTemplateData + cfg Config + data playgroundTemplateData } // New creates a Playground for given Config func New(config Config) *Playground { - prepareURL := func(file string) string { - return strings.TrimPrefix(path.Join(config.PlaygroundPath, file), "/") - } - data := playgroundTemplateData{ - CssURL: prepareURL(cssFile), - JsURL: prepareURL(jsFile), - FavIconURL: prepareURL(faviconFile), - LogoURL: prepareURL(logoFile), EndpointURL: config.GraphqlEndpointPath, SubscriptionEndpointURL: config.GraphQLSubscriptionEndpointPath, } - files := []fileConfig{ - { - name: cssFile, - url: path.Join(config.PathPrefix, config.PlaygroundPath, cssFile), - contentType: contentTypeTextCSS, - }, - { - name: jsFile, - url: path.Join(config.PathPrefix, config.PlaygroundPath, jsFile), - contentType: contentTypeTextJavascript, - }, - { - name: faviconFile, - url: path.Join(config.PathPrefix, config.PlaygroundPath, faviconFile), - contentType: contentTypeImagePNG, - }, - { - name: logoFile, - url: path.Join(config.PathPrefix, config.PlaygroundPath, logoFile), - contentType: contentTypeImagePNG, - }, - } - return &Playground{ - cfg: config, - files: files, - data: data, + cfg: config, + data: data, } } // Handlers configures and returns all Handlers for the Playground func (p *Playground) Handlers() (handlers Handlers, err error) { - handlers = make(Handlers, 0, len(p.files)+1) + handlers = make(Handlers, 0, 1) if err = p.configurePlaygroundHandler(&handlers); err != nil { return } - for _, file := range p.files { - if err = p.configureFileHandler(&handlers, file); err != nil { - return - } - } - return } @@ -170,17 +117,3 @@ func (p *Playground) configurePlaygroundHandler(handlers *Handlers) (err error) return nil } - -func (p *Playground) configureFileHandler(handlers *Handlers, file fileConfig) error { - data, err := files.ReadFile(fmt.Sprintf("files/%s", file.name)) - if err != nil { - return err - } - - handlers.add(file.url, func(writer http.ResponseWriter, request *http.Request) { - writer.Header().Add(contentTypeHeader, file.contentType) - _, _ = writer.Write(data) - }) - - return nil -} diff --git a/v2/pkg/playground/playground_test.go b/execution/playground/playground_test.go similarity index 73% rename from v2/pkg/playground/playground_test.go rename to execution/playground/playground_test.go index 82e436b9d3..e2fba06462 100644 --- a/v2/pkg/playground/playground_test.go +++ b/execution/playground/playground_test.go @@ -1,16 +1,10 @@ package playground import ( - "bytes" - "os" "testing" - "github.com/davecgh/go-spew/spew" - "github.com/jensneuse/diffview" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - - "github.com/wundergraph/graphql-go-tools/v2/pkg/testing/goldie" ) func TestNew(t *testing.T) { @@ -24,10 +18,8 @@ func TestNew(t *testing.T) { playground := New(config) - assert.Equal(t, playground.data.CssURL, "playground/playground.css") - assert.Equal(t, playground.data.JsURL, "playground/playground.js") - assert.Equal(t, playground.data.FavIconURL, "playground/favicon.png") - assert.Equal(t, playground.data.LogoURL, "playground/logo.png") + assert.Equal(t, "/graphql", playground.data.EndpointURL) + assert.Equal(t, "/graphqlws", playground.data.SubscriptionEndpointURL) }) } @@ -51,18 +43,7 @@ func TestConfigureHandlers(t *testing.T) { handlers[i].Handler = nil } - var out bytes.Buffer - spew.Fdump(&out, handlers) - - goldie.Assert(t, "handlers", out.Bytes()) - if t.Failed() { - fixture, err := os.ReadFile("./fixtures/handlers.golden") - if err != nil { - t.Fatal(err) - } - - diffview.NewGoland().DiffViewBytes("handlers", fixture, out.Bytes()) - } + assert.Equal(t, "/playground", handlers[0].Path) }) t.Run("should respect trailing slash for playground path", func(t *testing.T) { diff --git a/go.work b/go.work index 29af43e6d3..7c1e2be4c6 100644 --- a/go.work +++ b/go.work @@ -1,6 +1,7 @@ go 1.25 use ( + examples/engine examples/federation execution v2 diff --git a/go.work.sum b/go.work.sum index f3972893ca..fceab1ac76 100644 --- a/go.work.sum +++ b/go.work.sum @@ -24,6 +24,8 @@ github.com/alicebob/gopher-json v0.0.0-20230218143504-906a9b012302 h1:uvdUDbHQHO github.com/alicebob/gopher-json v0.0.0-20230218143504-906a9b012302/go.mod h1:SGnFV6hVsYE877CKEZ6tDNTjaSXYUk6QqoIK6PrAtcc= github.com/alicebob/miniredis/v2 v2.34.0 h1:mBFWMaJSNL9RwdGRyEDoAAv8OQc5UlEhLDQggTglU/0= github.com/alicebob/miniredis/v2 v2.34.0/go.mod h1:kWShP4b58T1CW0Y5dViCd5ztzrDqRWqM3nksiyXk5s8= +github.com/alitto/pond v1.8.3 h1:ydIqygCLVPqIX/USe5EaV/aSRXTRXDEI9JwuDdu+/xs= +github.com/alitto/pond v1.8.3/go.mod h1:CmvIIGd5jKLasGI3D87qDkQxjzChdKMmnXMg3fG6M6Q= github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1U3M= github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY= github.com/bahlo/generic-list-go v0.2.0 h1:5sz/EEAK+ls5wF+NeqDpk5+iNdMDXrh3z3nPnH1Wvgk= @@ -101,6 +103,8 @@ github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY= github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= github.com/go-pdf/fpdf v0.6.0 h1:MlgtGIfsdMEEQJr2le6b/HNr1ZlQwxyWr77r2aj2U/8= github.com/go-pdf/fpdf v0.6.0/go.mod h1:HzcnA+A23uwogo0tp9yU+l3V+KXhiESpt1PMayhOh5M= +github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= +github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= github.com/go-redis/redis_rate/v10 v10.0.1 h1:calPxi7tVlxojKunJwQ72kwfozdy25RjA0bCj1h0MUo= github.com/go-redis/redis_rate/v10 v10.0.1/go.mod h1:EMiuO9+cjRkR7UvdvwMO7vbgqJkltQHtwbdIQvaBKIU= github.com/go-viper/mapstructure/v2 v2.3.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= @@ -149,6 +153,8 @@ github.com/jensneuse/byte-template v0.0.0-20200214152254-4f3cf06e5c68/go.mod h1: github.com/jessevdk/go-flags v1.4.0 h1:4IU2WS7AumrZ/40jfhf4QVDMsQwqA7VEHozFRrGARJA= github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= +github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/kevinmbeaulieu/eq-go v1.0.0 h1:AQgYHURDOmnVJ62jnEk0W/7yFKEn+Lv8RHN6t7mB0Zo= github.com/kevinmbeaulieu/eq-go v1.0.0/go.mod h1:G3S8ajA56gKBZm4UB9AOyoOS37JO3roToPzKNM8dtdM= github.com/kisielk/gotool v1.0.0 h1:AV2c/EiW3KqPNT9ZKl07ehoAGi4C5/01Cfbblndcapg= @@ -158,6 +164,10 @@ github.com/klauspost/cpuid/v2 v2.2.8 h1:+StwCXwm9PdpiEkPyzBXIy+M9KUb4ODm0Zarf1kS github.com/klauspost/cpuid/v2 v2.2.8/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk= github.com/kr/pty v1.1.1 h1:VkoXIwSboBpnk99O/KFauAEILuNHv5DVFKZMBN/gUgw= +github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q= +github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4= +github.com/logrusorgru/aurora/v3 v3.0.0 h1:R6zcoZZbvVcGMvDCKo45A9U/lzYyzl5NfYIvznmDfE4= +github.com/logrusorgru/aurora/v3 v3.0.0/go.mod h1:vsR12bk5grlLvLXAYrBsb5Oc/N+LxAlxggSjiwMnCUc= github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ81pIr0yLvtUWk2if982qA3F3QD6H4= github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= github.com/lyft/protoc-gen-star/v2 v2.0.4-0.20230330145011-496ad1ac90a4 h1:sIXJOMrYnQZJu7OB7ANSF4MYri2fTEGIsRLz6LwI4xE= @@ -182,6 +192,8 @@ github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/nats-io/nats.go v1.35.0 h1:XFNqNM7v5B+MQMKqVGAyHwYhyKb48jrenXNxIU20ULk= @@ -251,22 +263,26 @@ github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+F github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9fESEdAacY= github.com/tonglil/opentelemetry-go-datadog-propagator v0.1.3 h1:Ozy1UnlID19jL6+vixEcA1t4NMf8hp01uDAY1nwGl8U= github.com/tonglil/opentelemetry-go-datadog-propagator v0.1.3/go.mod h1:Ijp5eaviP2mk8CJM+0EDYFKNULr+kicPSB9FOvxOhW0= +github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= +github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= github.com/twmb/franz-go v1.16.1 h1:rpWc7fB9jd7TgmCyfxzenBI+QbgS8ZfJOUQE+tzPtbE= github.com/twmb/franz-go v1.16.1/go.mod h1:/pER254UPPGp/4WfGqRi+SIRGE50RSQzVubQp6+N4FA= github.com/twmb/franz-go/pkg/kmsg v1.7.0 h1:a457IbvezYfA5UkiBvyV3zj0Is3y1i8EJgqjJYoij2E= github.com/twmb/franz-go/pkg/kmsg v1.7.0/go.mod h1:se9Mjdt0Nwzc9lnjJ0HyDtLyBnaBDAd7pCje47OhSyw= +github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU= +github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= github.com/vbatts/tar-split v0.12.1 h1:CqKoORW7BUWBe7UL/iqTVvkTBOF8UvOMKOIZykxnnbo= github.com/vbatts/tar-split v0.12.1/go.mod h1:eF6B6i6ftWQcDqEn3/iGFRFRo8cBIMSJVOpnNdfTMFA= github.com/wk8/go-ordered-map/v2 v2.1.8 h1:5h/BUHu93oj4gIdvHHHGsScSTMijfx5PeYkE/fJgbpc= github.com/wk8/go-ordered-map/v2 v2.1.8/go.mod h1:5nJHM5DyteebpVlHnWMV0rPz6Zp7+xBAnxjb1X5vnTw= github.com/wundergraph/astjson v0.0.0-20250106123708-be463c97e083/go.mod h1:eOTL6acwctsN4F3b7YE+eE2t8zcJ/doLm9sZzsxxxrE= -github.com/wundergraph/astjson v1.1.0 h1:xORDosrZ87zQFJwNGe/HIHXqzpdHOFmqWgykCLVL040= -github.com/wundergraph/astjson v1.1.0/go.mod h1:h12D/dxxnedtLzsKyBLK7/Oe4TAoGpRVC9nDpDrZSWw= github.com/wundergraph/go-arena v0.0.0-20251008210416-55cb97e6f68f h1:5snewyMaIpajTu4wj22L/DgrGimICqXtUVjkZInBH3Y= github.com/wundergraph/go-arena v0.0.0-20251008210416-55cb97e6f68f/go.mod h1:ROOysEHWJjLQ8FSfNxZCziagb7Qw2nXY3/vgKRh7eWw= +github.com/wundergraph/graphql-go-tools/v2 v2.0.0-rc.231/go.mod h1:ErOQH1ki2+SZB8JjpTyGVnoBpg5picIyjvuWQJP4abg= github.com/yosida95/uritemplate/v3 v3.0.2 h1:Ed3Oyj9yrmi9087+NczuL5BwkIc4wvTb5zIM+UJPGz4= github.com/yosida95/uritemplate/v3 v3.0.2/go.mod h1:ILOh0sOhIJR3+L/8afwt/kE++YT040gmv5BQTMR2HP4= github.com/yuin/goldmark v1.4.13 h1:fVcFKWvrslecOb/tg+Cc05dkeYx540o0FuFt3nUVDoE= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= github.com/yuin/gopher-lua v1.1.1 h1:kYKnWBjvbNP4XLT3+bPEwAXJx262OhaHDWDVOPjL46M= github.com/yuin/gopher-lua v1.1.1/go.mod h1:GBR0iDaNXjAgGg9zfCvksxSRnQx76gclCIb7kdAd1Pw= github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0= @@ -363,8 +379,6 @@ golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU= golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY= golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM= -golang.org/x/term v0.36.0 h1:zMPR+aF8gfksFprF/Nc/rd1wRS1EI6nDBGyWAvDzx2Q= -golang.org/x/term v0.36.0/go.mod h1:Qu394IJq6V6dCBRgwqshf3mPF85AqzYEzofzRdZkWss= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= @@ -392,5 +406,7 @@ google.golang.org/protobuf v1.36.4/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojt google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY= gopkg.in/errgo.v2 v2.1.0 h1:0vLT13EuvQ0hNvakwLuFZ/jYrLp5F3kcWHXdRggjCE8= honnef.co/go/tools v0.0.1-2019.2.3 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM= +nhooyr.io/websocket v1.8.7 h1:usjR2uOr/zjjkVMy0lW+PPohFok7PCow5sDjLgX4P4g= +nhooyr.io/websocket v1.8.7/go.mod h1:B70DZP8IakI65RVQ51MsWP/8jndNma26DVA/nFSCgW0= rsc.io/pdf v0.1.1 h1:k1MczvYDUvJBe93bYd7wrZLLUEcLZAuF824/I4e5Xr4= rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= diff --git a/release-please-config.json b/release-please-config.json index 9fdf777e9c..dd4a3177e0 100644 --- a/release-please-config.json +++ b/release-please-config.json @@ -29,7 +29,9 @@ "doc.go", "LICENSE", "Makefile", - "README.md" + "README.md", + "go.work", + "go.work.sum" ], "$schema": "https://raw.githubusercontent.com/googleapis/release-please/main/schemas/config.json" } diff --git a/v2/go.mod b/v2/go.mod index 534dfc0540..cc2e91d7a9 100644 --- a/v2/go.mod +++ b/v2/go.mod @@ -8,7 +8,6 @@ require ( github.com/buger/jsonparser v1.1.1 github.com/cespare/xxhash/v2 v2.3.0 github.com/coder/websocket v1.8.14 - github.com/davecgh/go-spew v1.1.1 github.com/golang/mock v1.6.0 github.com/google/go-cmp v0.7.0 github.com/google/uuid v1.6.0 @@ -45,6 +44,7 @@ require ( github.com/agnivade/levenshtein v1.2.1 // indirect github.com/bitfield/gotestdox v0.2.2 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.7 // indirect + github.com/davecgh/go-spew v1.1.1 // indirect github.com/dnephin/pflag v1.0.7 // indirect github.com/fatih/color v1.18.0 // indirect github.com/fsnotify/fsnotify v1.9.0 // indirect diff --git a/v2/pkg/playground/files/favicon.png b/v2/pkg/playground/files/favicon.png deleted file mode 100644 index ccbd94b3bf..0000000000 Binary files a/v2/pkg/playground/files/favicon.png and /dev/null differ diff --git a/v2/pkg/playground/files/logo.png b/v2/pkg/playground/files/logo.png deleted file mode 100644 index 8e3159a0b3..0000000000 Binary files a/v2/pkg/playground/files/logo.png and /dev/null differ diff --git a/v2/pkg/playground/files/playground.css b/v2/pkg/playground/files/playground.css deleted file mode 100644 index 965cddc656..0000000000 --- a/v2/pkg/playground/files/playground.css +++ /dev/null @@ -1 +0,0 @@ -body{margin:0;padding:0;font-family:sans-serif;overflow:hidden}#root{height:100%}body{font-family:Open Sans,sans-serif;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;color:rgba(0,0,0,.8);line-height:1.5;height:100vh;letter-spacing:.53px;margin-right:-1px!important}a,body,code,h1,h2,h3,h4,html,p,pre,ul{margin:0;padding:0;color:inherit}a:active,a:focus,button:focus,input:focus{outline:none}button,input,submit{border:none}button,input,pre{font-family:Open Sans,sans-serif}code{font-family:Consolas,monospace} \ No newline at end of file diff --git a/v2/pkg/playground/files/playground.html b/v2/pkg/playground/files/playground.html deleted file mode 100644 index b6c78d504c..0000000000 --- a/v2/pkg/playground/files/playground.html +++ /dev/null @@ -1,93 +0,0 @@ - - - - - GraphiQL - - - - - - - - - - - - - - - -
Loading...
- - - diff --git a/v2/pkg/playground/files/playground.js b/v2/pkg/playground/files/playground.js deleted file mode 100644 index 4b2e40ef6a..0000000000 --- a/v2/pkg/playground/files/playground.js +++ /dev/null @@ -1 +0,0 @@ -!function(e){function t(r){if(n[r])return n[r].exports;var i=n[r]={i:r,l:!1,exports:{}};return e[r].call(i.exports,i,i.exports,t),i.l=!0,i.exports}var n={};t.m=e,t.c=n,t.d=function(e,n,r){t.o(e,n)||Object.defineProperty(e,n,{configurable:!1,enumerable:!0,get:r})},t.n=function(e){var n=e&&e.__esModule?function(){return e.default}:function(){return e};return t.d(n,"a",n),n},t.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},t.p="/",t(t.s=794)}([function(e,t,n){"use strict";e.exports=n(313)},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),function(e){for(var n in e)t.hasOwnProperty(n)||(t[n]=e[n])}(n(87));var r=n(87);t.styled=r.default},function(e,t,n){!function(t,n){e.exports=n()}(0,function(){"use strict";function e(e){return new RegExp("(^|\\s)"+e+"(?:$|\\s)\\s*")}function t(e){for(var t=e.childNodes.length;t>0;--t)e.removeChild(e.firstChild);return e}function n(e,n){return t(e).appendChild(n)}function r(e,t,n,r){var i=document.createElement(e);if(n&&(i.className=n),r&&(i.style.cssText=r),"string"==typeof t)i.appendChild(document.createTextNode(t));else if(t)for(var o=0;o=t)return a+(t-o);a+=s-o,a+=n-a%n,o=s+1}}function f(e,t){for(var n=0;n=t)return r+Math.min(a,t-i);if(i+=o-r,i+=n-i%n,r=o+1,i>=t)return r}}function h(e){for(;Qa.length<=e;)Qa.push(m(Qa)+" ");return Qa[e]}function m(e){return e[e.length-1]}function g(e,t){for(var n=[],r=0;r"\x80"&&(e.toUpperCase()!=e.toLowerCase()||Ka.test(e))}function C(e,t){return t?!!(t.source.indexOf("\\w")>-1&&x(e))||t.test(e):x(e)}function E(e){for(var t in e)if(e.hasOwnProperty(t)&&e[t])return!1;return!0}function D(e){return e.charCodeAt(0)>=768&&Ja.test(e)}function w(e,t,n){for(;(n<0?t>0:tn?-1:1;;){if(t==n)return t;var i=(t+n)/2,o=r<0?Math.ceil(i):Math.floor(i);if(o==t)return e(o)?t:n;e(o)?n=o:t=o+r}}function k(e,t,n){var o=this;this.input=n,o.scrollbarFiller=r("div",null,"CodeMirror-scrollbar-filler"),o.scrollbarFiller.setAttribute("cm-not-content","true"),o.gutterFiller=r("div",null,"CodeMirror-gutter-filler"),o.gutterFiller.setAttribute("cm-not-content","true"),o.lineDiv=i("div",null,"CodeMirror-code"),o.selectionDiv=r("div",null,null,"position: relative; z-index: 1"),o.cursorDiv=r("div",null,"CodeMirror-cursors"),o.measure=r("div",null,"CodeMirror-measure"),o.lineMeasure=r("div",null,"CodeMirror-measure"),o.lineSpace=i("div",[o.measure,o.lineMeasure,o.selectionDiv,o.cursorDiv,o.lineDiv],null,"position: relative; outline: none");var a=i("div",[o.lineSpace],"CodeMirror-lines");o.mover=r("div",[a],null,"position: relative"),o.sizer=r("div",[o.mover],"CodeMirror-sizer"),o.sizerWidth=null,o.heightForcer=r("div",null,null,"position: absolute; height: "+Ga+"px; width: 1px;"),o.gutters=r("div",null,"CodeMirror-gutters"),o.lineGutter=null,o.scroller=r("div",[o.sizer,o.heightForcer,o.gutters],"CodeMirror-scroll"),o.scroller.setAttribute("tabIndex","-1"),o.wrapper=r("div",[o.scrollbarFiller,o.gutterFiller,o.scroller],"CodeMirror"),ba&&xa<8&&(o.gutters.style.zIndex=-1,o.scroller.style.paddingRight=0),Ca||ma&&Oa||(o.scroller.draggable=!0),e&&(e.appendChild?e.appendChild(o.wrapper):e(o.wrapper)),o.viewFrom=o.viewTo=t.first,o.reportedViewFrom=o.reportedViewTo=t.first,o.view=[],o.renderedView=null,o.externalMeasured=null,o.viewOffset=0,o.lastWrapHeight=o.lastWrapWidth=0,o.updateLineNumbers=null,o.nativeBarWidth=o.barHeight=o.barWidth=0,o.scrollbarsClipped=!1,o.lineNumWidth=o.lineNumInnerWidth=o.lineNumChars=null,o.alignWidgets=!1,o.cachedCharWidth=o.cachedTextHeight=o.cachedPaddingH=null,o.maxLine=null,o.maxLineLength=0,o.maxLineChanged=!1,o.wheelDX=o.wheelDY=o.wheelStartX=o.wheelStartY=null,o.shift=!1,o.selForContextMenu=null,o.activeTouch=null,n.init(o)}function A(e,t){if((t-=e.first)<0||t>=e.size)throw new Error("There is no line "+(t+e.first)+" in the document.");for(var n=e;!n.lines;)for(var r=0;;++r){var i=n.children[r],o=i.chunkSize();if(t=e.first&&tn?P(n,A(e,n).text.length):G(t,A(e,t.line).text.length)}function G(e,t){var n=e.ch;return null==n||n>t?P(e.line,t):n<0?P(e.line,0):e}function V(e,t){for(var n=[],r=0;r=t:o.to>t);(r||(r=[])).push(new W(a,o.from,u?null:o.to))}}return r}function X(e,t,n){var r;if(e)for(var i=0;i=t:o.to>t);if(s||o.from==t&&"bookmark"==a.type&&(!n||o.marker.insertLeft)){var u=null==o.from||(a.inclusiveLeft?o.from<=t:o.from0&&s)for(var C=0;C0)){var l=[u,1],p=M(c.from,s.from),d=M(c.to,s.to);(p<0||!a.inclusiveLeft&&!p)&&l.push({from:c.from,to:s.from}),(d>0||!a.inclusiveRight&&!d)&&l.push({from:s.to,to:c.to}),i.splice.apply(i,l),u+=l.length-3}}return i}function ne(e){var t=e.markedSpans;if(t){for(var n=0;nt)&&(!n||ae(n,o.marker)<0)&&(n=o.marker)}return n}function pe(e,t,n,r,i){var o=A(e,t),a=Xa&&o.markedSpans;if(a)for(var s=0;s=0&&p<=0||l<=0&&p>=0)&&(l<=0&&(u.marker.inclusiveRight&&i.inclusiveLeft?M(c.to,n)>=0:M(c.to,n)>0)||l>=0&&(u.marker.inclusiveRight&&i.inclusiveLeft?M(c.from,r)<=0:M(c.from,r)<0)))return!0}}}function fe(e){for(var t;t=ue(e);)e=t.find(-1,!0).line;return e}function de(e){for(var t;t=ce(e);)e=t.find(1,!0).line;return e}function he(e){for(var t,n;t=ce(e);)e=t.find(1,!0).line,(n||(n=[])).push(e);return n}function me(e,t){var n=A(e,t),r=fe(n);return n==r?t:F(r)}function ge(e,t){if(t>e.lastLine())return t;var n,r=A(e,t);if(!ye(e,r))return t;for(;n=ce(r);)r=n.find(1,!0).line;return F(r)+1}function ye(e,t){var n=Xa&&t.markedSpans;if(n)for(var r=void 0,i=0;it.maxLineLength&&(t.maxLineLength=n,t.maxLine=e)})}function Ee(e,t,n,r){if(!e)return r(t,n,"ltr",0);for(var i=!1,o=0;ot||t==n&&a.to==t)&&(r(Math.max(a.from,t),Math.min(a.to,n),1==a.level?"rtl":"ltr",o),i=!0)}i||r(t,n,"ltr")}function De(e,t,n){var r;Za=null;for(var i=0;it)return i;o.to==t&&(o.from!=o.to&&"before"==n?r=i:Za=i),o.from==t&&(o.from!=o.to&&"before"!=n?r=i:Za=i)}return null!=r?r:Za}function we(e,t){var n=e.order;return null==n&&(n=e.order=es(e.text,t)),n}function Se(e,t){return e._handlers&&e._handlers[t]||ts}function ke(e,t,n){if(e.removeEventListener)e.removeEventListener(t,n,!1);else if(e.detachEvent)e.detachEvent("on"+t,n);else{var r=e._handlers,i=r&&r[t];if(i){var o=f(i,n);o>-1&&(r[t]=i.slice(0,o).concat(i.slice(o+1)))}}}function Ae(e,t){var n=Se(e,t);if(n.length)for(var r=Array.prototype.slice.call(arguments,2),i=0;i0}function Fe(e){e.prototype.on=function(e,t){ns(this,e,t)},e.prototype.off=function(e,t){ke(this,e,t)}}function Ne(e){e.preventDefault?e.preventDefault():e.returnValue=!1}function Ie(e){e.stopPropagation?e.stopPropagation():e.cancelBubble=!0}function Le(e){return null!=e.defaultPrevented?e.defaultPrevented:0==e.returnValue}function Pe(e){Ne(e),Ie(e)}function Me(e){return e.target||e.srcElement}function je(e){var t=e.which;return null==t&&(1&e.button?t=1:2&e.button?t=3:4&e.button&&(t=2)),Fa&&e.ctrlKey&&1==t&&(t=3),t}function Re(e){if(null==Ua){var t=r("span","\u200b");n(e,r("span",[t,document.createTextNode("x")])),0!=e.firstChild.offsetHeight&&(Ua=t.offsetWidth<=1&&t.offsetHeight>2&&!(ba&&xa<8))}var i=Ua?r("span","\u200b"):r("span","\xa0",null,"display: inline-block; width: 1px; margin-right: -1px");return i.setAttribute("cm-text",""),i}function Be(e){if(null!=za)return za;var r=n(e,document.createTextNode("A\u062eA")),i=Pa(r,0,1).getBoundingClientRect(),o=Pa(r,1,2).getBoundingClientRect();return t(e),!(!i||i.left==i.right)&&(za=o.right-i.right<3)}function $e(e){if(null!=ss)return ss;var t=n(e,r("span","x")),i=t.getBoundingClientRect(),o=Pa(t,0,1).getBoundingClientRect();return ss=Math.abs(i.left-o.left)>1}function Ue(e,t){arguments.length>2&&(t.dependencies=Array.prototype.slice.call(arguments,2)),us[e]=t}function ze(e,t){cs[e]=t}function Ge(e){if("string"==typeof e&&cs.hasOwnProperty(e))e=cs[e];else if(e&&"string"==typeof e.name&&cs.hasOwnProperty(e.name)){var t=cs[e.name];"string"==typeof t&&(t={name:t}),e=b(t,e),e.name=t.name}else{if("string"==typeof e&&/^[\w\-]+\/[\w\-]+\+xml$/.test(e))return Ge("application/xml");if("string"==typeof e&&/^[\w\-]+\/[\w\-]+\+json$/.test(e))return Ge("application/json")}return"string"==typeof e?{name:e}:e||{name:"null"}}function Ve(e,t){t=Ge(t);var n=us[t.name];if(!n)return Ve(e,"text/plain");var r=n(e,t);if(ls.hasOwnProperty(t.name)){var i=ls[t.name];for(var o in i)i.hasOwnProperty(o)&&(r.hasOwnProperty(o)&&(r["_"+o]=r[o]),r[o]=i[o])}if(r.name=t.name,t.helperType&&(r.helperType=t.helperType),t.modeProps)for(var a in t.modeProps)r[a]=t.modeProps[a];return r}function qe(e,t){l(t,ls.hasOwnProperty(e)?ls[e]:ls[e]={})}function He(e,t){if(!0===t)return t;if(e.copyState)return e.copyState(t);var n={};for(var r in t){var i=t[r];i instanceof Array&&(i=i.concat([])),n[r]=i}return n}function We(e,t){for(var n;e.innerMode&&(n=e.innerMode(t))&&n.mode!=e;)t=n.state,e=n.mode;return n||{mode:e,state:t}}function Qe(e,t,n){return!e.startState||e.startState(t,n)}function Ke(e,t,n,r){var i=[e.state.modeGen],o={};rt(e,t.text,e.doc.mode,n,function(e,t){return i.push(e,t)},o,r);for(var a=n.state,s=0;se&&i.splice(u,1,e,i[u+1],r),u+=2,c=Math.min(e,r)}if(t)if(s.opaque)i.splice(n,u-n,e,"overlay "+t),u=n+2;else for(;ne.options.maxHighlightLength&&He(e.doc.mode,r.state),o=Ke(e,t,r);i&&(r.state=i),t.stateAfter=r.save(!i),t.styles=o.styles,o.classes?t.styleClasses=o.classes:t.styleClasses&&(t.styleClasses=null),n===e.doc.highlightFrontier&&(e.doc.modeFrontier=Math.max(e.doc.modeFrontier,++e.doc.highlightFrontier))}return t.styles}function Ye(e,t,n){var r=e.doc,i=e.display;if(!r.mode.startState)return new ds(r,!0,t);var o=it(e,t,n),a=o>r.first&&A(r,o-1).stateAfter,s=a?ds.fromSaved(r,a,o):new ds(r,Qe(r.mode),o);return r.iter(o,t,function(n){Xe(e,n.text,s);var r=s.line;n.stateAfter=r==t-1||r%5==0||r>=i.viewFrom&&rt.start)return o}throw new Error("Mode "+e.name+" failed to advance stream.")}function tt(e,t,n,r){var i,o=e.doc,a=o.mode;t=z(o,t);var s,u=A(o,t.line),c=Ye(e,t.line,n),l=new ps(u.text,e.options.tabSize,c);for(r&&(s=[]);(r||l.pose.options.maxHighlightLength?(s=!1,a&&Xe(e,t,r,p.pos),p.pos=t.length,u=null):u=nt(et(n,p,r.state,f),o),f){var d=f[0].name;d&&(u="m-"+(u?d+" "+u:d))}if(!s||l!=u){for(;ca;--s){if(s<=o.first)return o.first;var u=A(o,s-1),c=u.stateAfter;if(c&&(!n||s+(c instanceof fs?c.lookAhead:0)<=o.modeFrontier))return s;var l=p(u.text,null,e.options.tabSize);(null==i||r>l)&&(i=s-1,r=l)}return i}function ot(e,t){if(e.modeFrontier=Math.min(e.modeFrontier,t),!(e.highlightFrontiern;r--){var i=A(e,r).stateAfter;if(i&&(!(i instanceof fs)||r+i.lookAhead1&&!/ /.test(e))return e;for(var n=t,r="",i=0;ic&&p.from<=c));f++);if(p.to>=l)return e(n,r,i,o,a,s,u);e(n,r.slice(0,p.to-c),i,o,null,s,u),o=null,r=r.slice(p.to-c),c=p.to}}}function ht(e,t,n,r){var i=!r&&n.widgetNode;i&&e.map.push(e.pos,e.pos+t,i),!r&&e.cm.display.input.needsContentAttribute&&(i||(i=e.content.appendChild(document.createElement("span"))),i.setAttribute("cm-marker",n.id)),i&&(e.cm.display.input.setUneditable(i),e.content.appendChild(i)),e.pos+=t,e.trailingSpace=!1}function mt(e,t,n){var r=e.markedSpans,i=e.text,o=0;if(r)for(var a,s,u,c,l,p,f,d=i.length,h=0,m=1,g="",y=0;;){if(y==h){u=c=l=p=s="",f=null,y=1/0;for(var v=[],b=void 0,x=0;xh||E.collapsed&&C.to==h&&C.from==h)?(null!=C.to&&C.to!=h&&y>C.to&&(y=C.to,c=""),E.className&&(u+=" "+E.className),E.css&&(s=(s?s+";":"")+E.css),E.startStyle&&C.from==h&&(l+=" "+E.startStyle),E.endStyle&&C.to==y&&(b||(b=[])).push(E.endStyle,C.to),E.title&&!p&&(p=E.title),E.collapsed&&(!f||ae(f.marker,E)<0)&&(f=C)):C.from>h&&y>C.from&&(y=C.from)}if(b)for(var D=0;D=d)break;for(var S=Math.min(d,y);;){if(g){var k=h+g.length;if(!f){var A=k>S?g.slice(0,S-h):g;t.addToken(t,A,a?a+u:u,l,h+A.length==y?c:"",p,s)}if(k>=S){g=g.slice(S-h),h=S;break}h=k,l=""}g=i.slice(o,o=n[m++]),a=ut(n[m++],t.cm.options)}}else for(var _=1;_2&&o.push((u.bottom+c.top)/2-n.top)}}o.push(n.bottom-n.top)}}function Vt(e,t,n){if(e.line==t)return{map:e.measure.map,cache:e.measure.cache};for(var r=0;rn)return{map:e.measure.maps[i],cache:e.measure.caches[i],before:!0}}function qt(e,t){t=fe(t);var r=F(t),i=e.display.externalMeasured=new gt(e.doc,t,r);i.lineN=r;var o=i.built=ct(e,i);return i.text=o.pre,n(e.display.lineMeasure,o.pre),i}function Ht(e,t,n,r){return Kt(e,Qt(e,t),n,r)}function Wt(e,t){if(t>=e.display.viewFrom&&t=n.lineN&&tt)&&(o=u-s,i=o-1,t>=u&&(a="right")),null!=i){if(r=e[c+2],s==u&&n==(r.insertLeft?"left":"right")&&(a=n),"left"==n&&0==i)for(;c&&e[c-2]==e[c-3]&&e[c-1].insertLeft;)r=e[2+(c-=3)],a="left";if("right"==n&&i==u-s)for(;c=0&&(n=e[i]).left==n.right;i--);return n}function Xt(e,t,n,r){var i,o=Jt(t.map,n,r),a=o.node,s=o.start,u=o.end,c=o.collapse;if(3==a.nodeType){for(var l=0;l<4;l++){for(;s&&D(t.line.text.charAt(o.coverStart+s));)--s;for(;o.coverStart+u0&&(c=r="right");var p;i=e.options.lineWrapping&&(p=a.getClientRects()).length>1?p["right"==r?p.length-1:0]:a.getBoundingClientRect()}if(ba&&xa<9&&!s&&(!i||!i.left&&!i.right)){var f=a.parentNode.getClientRects()[0];i=f?{left:f.left,right:f.left+Cn(e.display),top:f.top,bottom:f.bottom}:Cs}for(var d=i.top-t.rect.top,h=i.bottom-t.rect.top,m=(d+h)/2,g=t.view.measure.heights,y=0;y=r.text.length?(c=r.text.length,l="before"):c<=0&&(c=0,l="after"),!u)return a("before"==l?c-1:c,"before"==l);var p=De(u,c,l),f=Za,d=s(c,p,"before"==l);return null!=f&&(d.other=s(c,f,"before"!=l)),d}function pn(e,t){var n=0;t=z(e.doc,t),e.options.lineWrapping||(n=Cn(e.display)*t.ch);var r=A(e.doc,t.line),i=be(r)+jt(e.display);return{left:n,right:n,top:i,bottom:i+r.height}}function fn(e,t,n,r,i){var o=P(e,t,n);return o.xRel=i,r&&(o.outside=!0),o}function dn(e,t,n){var r=e.doc;if((n+=e.display.viewOffset)<0)return fn(r.first,0,null,!0,-1);var i=N(r,n),o=r.first+r.size-1;if(i>o)return fn(r.first+r.size-1,A(r,o).text.length,null,!0,1);t<0&&(t=0);for(var a=A(r,i);;){var s=yn(e,a,i,t,n),u=le(a,s.ch+(s.xRel>0?1:0));if(!u)return s;var c=u.find(1);if(c.line==i)return c;a=A(r,i=c.line)}}function hn(e,t,n,r){r-=an(t);var i=t.text.length,o=S(function(t){return Kt(e,n,t-1).bottom<=r},i,0);return i=S(function(t){return Kt(e,n,t).top>r},o,i),{begin:o,end:i}}function mn(e,t,n,r){return n||(n=Qt(e,t)),hn(e,t,n,sn(e,t,Kt(e,n,r),"line").top)}function gn(e,t,n,r){return!(e.bottom<=n)&&(e.top>n||(r?e.left:e.right)>t)}function yn(e,t,n,r,i){i-=be(t);var o=Qt(e,t),a=an(t),s=0,u=t.text.length,c=!0,l=we(t,e.doc.direction);if(l){var p=(e.options.lineWrapping?bn:vn)(e,t,n,o,l,r,i);c=1!=p.level,s=c?p.from:p.to-1,u=c?p.to:p.from-1}var f,d,h=null,m=null,g=S(function(t){var n=Kt(e,o,t);return n.top+=a,n.bottom+=a,!!gn(n,r,i,!1)&&(n.top<=i&&n.left<=r&&(h=t,m=n),!0)},s,u),y=!1;if(m){var v=r-m.left=x.bottom}return g=w(t.text,g,1),fn(n,g,d,y,r-f)}function vn(e,t,n,r,i,o,a){var s=S(function(s){var u=i[s],c=1!=u.level;return gn(ln(e,P(n,c?u.to:u.from,c?"before":"after"),"line",t,r),o,a,!0)},0,i.length-1),u=i[s];if(s>0){var c=1!=u.level,l=ln(e,P(n,c?u.from:u.to,c?"after":"before"),"line",t,r);gn(l,o,a,!0)&&l.top>a&&(u=i[s-1])}return u}function bn(e,t,n,r,i,o,a){var s=hn(e,t,r,a),u=s.begin,c=s.end;/\s/.test(t.text.charAt(c-1))&&c--;for(var l=null,p=null,f=0;f=c||d.to<=u)){var h=1!=d.level,m=Kt(e,r,h?Math.min(c,d.to)-1:Math.max(u,d.from)).right,g=mg)&&(l=d,p=g)}}return l||(l=i[i.length-1]),l.fromc&&(l={from:l.from,to:c,level:l.level}),l}function xn(e){if(null!=e.cachedTextHeight)return e.cachedTextHeight;if(null==gs){gs=r("pre");for(var i=0;i<49;++i)gs.appendChild(document.createTextNode("x")),gs.appendChild(r("br"));gs.appendChild(document.createTextNode("x"))}n(e.measure,gs);var o=gs.offsetHeight/50;return o>3&&(e.cachedTextHeight=o),t(e.measure),o||1}function Cn(e){if(null!=e.cachedCharWidth)return e.cachedCharWidth;var t=r("span","xxxxxxxxxx"),i=r("pre",[t]);n(e.measure,i);var o=t.getBoundingClientRect(),a=(o.right-o.left)/10;return a>2&&(e.cachedCharWidth=a),a||10}function En(e){for(var t=e.display,n={},r={},i=t.gutters.clientLeft,o=t.gutters.firstChild,a=0;o;o=o.nextSibling,++a)n[e.options.gutters[a]]=o.offsetLeft+o.clientLeft+i,r[e.options.gutters[a]]=o.clientWidth;return{fixedPos:Dn(t),gutterTotalWidth:t.gutters.offsetWidth,gutterLeft:n,gutterWidth:r,wrapperWidth:t.wrapper.clientWidth}}function Dn(e){return e.scroller.getBoundingClientRect().left-e.sizer.getBoundingClientRect().left}function wn(e){var t=xn(e.display),n=e.options.lineWrapping,r=n&&Math.max(5,e.display.scroller.clientWidth/Cn(e.display)-3);return function(i){if(ye(e.doc,i))return 0;var o=0;if(i.widgets)for(var a=0;a=e.display.viewTo)return null;if((t-=e.display.viewFrom)<0)return null;for(var n=e.display.view,r=0;r=e.display.viewTo||s.to().line0?t.blinker=setInterval(function(){return t.cursorDiv.style.visibility=(n=!n)?"":"hidden"},e.options.cursorBlinkRate):e.options.cursorBlinkRate<0&&(t.cursorDiv.style.visibility="hidden")}}function Ln(e){e.state.focused||(e.display.input.focus(),Mn(e))}function Pn(e){e.state.delayingBlurEvent=!0,setTimeout(function(){e.state.delayingBlurEvent&&(e.state.delayingBlurEvent=!1,jn(e))},100)}function Mn(e,t){e.state.delayingBlurEvent&&(e.state.delayingBlurEvent=!1),"nocursor"!=e.options.readOnly&&(e.state.focused||(Ae(e,"focus",e,t),e.state.focused=!0,s(e.display.wrapper,"CodeMirror-focused"),e.curOp||e.display.selForContextMenu==e.doc.sel||(e.display.input.reset(),Ca&&setTimeout(function(){return e.display.input.reset(!0)},20)),e.display.input.receivedFocus()),In(e))}function jn(e,t){e.state.delayingBlurEvent||(e.state.focused&&(Ae(e,"blur",e,t),e.state.focused=!1,Ra(e.display.wrapper,"CodeMirror-focused")),clearInterval(e.display.blinker),setTimeout(function(){e.state.focused||(e.display.shift=!1)},150))}function Rn(e){for(var t=e.display,n=t.lineDiv.offsetTop,r=0;r.005||u<-.005)&&(O(i.line,o),Bn(i.line),i.rest))for(var c=0;c=a&&(o=N(t,be(A(t,u))-e.wrapper.clientHeight),a=u)}return{from:o,to:Math.max(a,o+1)}}function Un(e){var t=e.display,n=t.view;if(t.alignWidgets||t.gutters.firstChild&&e.options.fixedGutter){for(var r=Dn(t)-t.scroller.scrollLeft+e.doc.scrollLeft,i=t.gutters.offsetWidth,o=r+"px",a=0;a(window.innerHeight||document.documentElement.clientHeight)&&(o=!1),null!=o&&!Aa){var a=r("div","\u200b",null,"position: absolute;\n top: "+(t.top-n.viewOffset-jt(e.display))+"px;\n height: "+(t.bottom-t.top+$t(e)+n.barHeight)+"px;\n left: "+t.left+"px; width: "+Math.max(2,t.right-t.left)+"px;");e.display.lineSpace.appendChild(a),a.scrollIntoView(o),e.display.lineSpace.removeChild(a)}}}function Vn(e,t,n,r){null==r&&(r=0);var i;e.options.lineWrapping||t!=n||(t=t.ch?P(t.line,"before"==t.sticky?t.ch-1:t.ch,"after"):t,n="before"==t.sticky?P(t.line,t.ch+1,"before"):t);for(var o=0;o<5;o++){var a=!1,s=ln(e,t),u=n&&n!=t?ln(e,n):s;i={left:Math.min(s.left,u.left),top:Math.min(s.top,u.top)-r,right:Math.max(s.left,u.left),bottom:Math.max(s.bottom,u.bottom)+r};var c=Hn(e,i),l=e.doc.scrollTop,p=e.doc.scrollLeft;if(null!=c.scrollTop&&(Zn(e,c.scrollTop),Math.abs(e.doc.scrollTop-l)>1&&(a=!0)),null!=c.scrollLeft&&(tr(e,c.scrollLeft),Math.abs(e.doc.scrollLeft-p)>1&&(a=!0)),!a)break}return i}function qn(e,t){var n=Hn(e,t);null!=n.scrollTop&&Zn(e,n.scrollTop),null!=n.scrollLeft&&tr(e,n.scrollLeft)}function Hn(e,t){var n=e.display,r=xn(e.display);t.top<0&&(t.top=0);var i=e.curOp&&null!=e.curOp.scrollTop?e.curOp.scrollTop:n.scroller.scrollTop,o=zt(e),a={};t.bottom-t.top>o&&(t.bottom=t.top+o);var s=e.doc.height+Rt(n),u=t.tops-r;if(t.topi+o){var l=Math.min(t.top,(c?s:t.bottom)-o);l!=i&&(a.scrollTop=l)}var p=e.curOp&&null!=e.curOp.scrollLeft?e.curOp.scrollLeft:n.scroller.scrollLeft,f=Ut(e)-(e.options.fixedGutter?n.gutters.offsetWidth:0),d=t.right-t.left>f;return d&&(t.right=t.left+f),t.left<10?a.scrollLeft=0:t.leftf+p-3&&(a.scrollLeft=t.right+(d?0:10)-f),a}function Wn(e,t){null!=t&&(Yn(e),e.curOp.scrollTop=(null==e.curOp.scrollTop?e.doc.scrollTop:e.curOp.scrollTop)+t)}function Qn(e){Yn(e);var t=e.getCursor();e.curOp.scrollToPos={from:t,to:t,margin:e.options.cursorScrollMargin}}function Kn(e,t,n){null==t&&null==n||Yn(e),null!=t&&(e.curOp.scrollLeft=t),null!=n&&(e.curOp.scrollTop=n)}function Jn(e,t){Yn(e),e.curOp.scrollToPos=t}function Yn(e){var t=e.curOp.scrollToPos;if(t){e.curOp.scrollToPos=null;Xn(e,pn(e,t.from),pn(e,t.to),t.margin)}}function Xn(e,t,n,r){var i=Hn(e,{left:Math.min(t.left,n.left),top:Math.min(t.top,n.top)-r,right:Math.max(t.right,n.right),bottom:Math.max(t.bottom,n.bottom)+r});Kn(e,i.scrollLeft,i.scrollTop)}function Zn(e,t){Math.abs(e.doc.scrollTop-t)<2||(ma||Fr(e,{top:t}),er(e,t,!0),ma&&Fr(e),wr(e,100))}function er(e,t,n){t=Math.min(e.display.scroller.scrollHeight-e.display.scroller.clientHeight,t),(e.display.scroller.scrollTop!=t||n)&&(e.doc.scrollTop=t,e.display.scrollbars.setScrollTop(t),e.display.scroller.scrollTop!=t&&(e.display.scroller.scrollTop=t))}function tr(e,t,n,r){t=Math.min(t,e.display.scroller.scrollWidth-e.display.scroller.clientWidth),(n?t==e.doc.scrollLeft:Math.abs(e.doc.scrollLeft-t)<2)&&!r||(e.doc.scrollLeft=t,Un(e),e.display.scroller.scrollLeft!=t&&(e.display.scroller.scrollLeft=t),e.display.scrollbars.setScrollLeft(t))}function nr(e){var t=e.display,n=t.gutters.offsetWidth,r=Math.round(e.doc.height+Rt(e.display));return{clientHeight:t.scroller.clientHeight,viewHeight:t.wrapper.clientHeight,scrollWidth:t.scroller.scrollWidth,clientWidth:t.scroller.clientWidth,viewWidth:t.wrapper.clientWidth,barLeft:e.options.fixedGutter?n:0,docHeight:r,scrollHeight:r+$t(e)+t.barHeight,nativeBarWidth:t.nativeBarWidth,gutterWidth:n}}function rr(e,t){t||(t=nr(e));var n=e.display.barWidth,r=e.display.barHeight;ir(e,t);for(var i=0;i<4&&n!=e.display.barWidth||r!=e.display.barHeight;i++)n!=e.display.barWidth&&e.options.lineWrapping&&Rn(e),ir(e,nr(e)),n=e.display.barWidth,r=e.display.barHeight}function ir(e,t){var n=e.display,r=n.scrollbars.update(t);n.sizer.style.paddingRight=(n.barWidth=r.right)+"px",n.sizer.style.paddingBottom=(n.barHeight=r.bottom)+"px",n.heightForcer.style.borderBottom=r.bottom+"px solid transparent",r.right&&r.bottom?(n.scrollbarFiller.style.display="block",n.scrollbarFiller.style.height=r.bottom+"px",n.scrollbarFiller.style.width=r.right+"px"):n.scrollbarFiller.style.display="",r.bottom&&e.options.coverGutterNextToScrollbar&&e.options.fixedGutter?(n.gutterFiller.style.display="block",n.gutterFiller.style.height=r.bottom+"px",n.gutterFiller.style.width=t.gutterWidth+"px"):n.gutterFiller.style.display=""}function or(e){e.display.scrollbars&&(e.display.scrollbars.clear(),e.display.scrollbars.addClass&&Ra(e.display.wrapper,e.display.scrollbars.addClass)),e.display.scrollbars=new ws[e.options.scrollbarStyle](function(t){e.display.wrapper.insertBefore(t,e.display.scrollbarFiller),ns(t,"mousedown",function(){e.state.focused&&setTimeout(function(){return e.display.input.focus()},0)}),t.setAttribute("cm-not-content","true")},function(t,n){"horizontal"==n?tr(e,t):Zn(e,t)},e),e.display.scrollbars.addClass&&s(e.display.wrapper,e.display.scrollbars.addClass)}function ar(e){e.curOp={cm:e,viewChanged:!1,startHeight:e.doc.height,forceUpdate:!1,updateInput:null,typing:!1,changeObjs:null,cursorActivityHandlers:null,cursorActivityCalled:0,selectionChanged:!1,updateMaxLine:!1,scrollLeft:null,scrollTop:null,scrollToPos:null,focus:!1,id:++Ss},vt(e.curOp)}function sr(e){xt(e.curOp,function(e){for(var t=0;t=n.viewTo)||n.maxLineChanged&&t.options.lineWrapping,e.update=e.mustUpdate&&new ks(t,e.mustUpdate&&{top:e.scrollTop,ensure:e.scrollToPos},e.forceUpdate)}function lr(e){e.updatedDisplay=e.mustUpdate&&Tr(e.cm,e.update)}function pr(e){var t=e.cm,n=t.display;e.updatedDisplay&&Rn(t),e.barMeasure=nr(t),n.maxLineChanged&&!t.options.lineWrapping&&(e.adjustWidthTo=Ht(t,n.maxLine,n.maxLine.text.length).left+3,t.display.sizerWidth=e.adjustWidthTo,e.barMeasure.scrollWidth=Math.max(n.scroller.clientWidth,n.sizer.offsetLeft+e.adjustWidthTo+$t(t)+t.display.barWidth),e.maxScrollLeft=Math.max(0,n.sizer.offsetLeft+e.adjustWidthTo-Ut(t))),(e.updatedDisplay||e.selectionChanged)&&(e.preparedSelection=n.input.prepareSelection())}function fr(e){var t=e.cm;null!=e.adjustWidthTo&&(t.display.sizer.style.minWidth=e.adjustWidthTo+"px",e.maxScrollLeftt)&&(i.updateLineNumbers=t),e.curOp.viewChanged=!0,t>=i.viewTo)Xa&&me(e.doc,t)i.viewFrom?xr(e):(i.viewFrom+=r,i.viewTo+=r);else if(t<=i.viewFrom&&n>=i.viewTo)xr(e);else if(t<=i.viewFrom){var o=Cr(e,n,n+r,1);o?(i.view=i.view.slice(o.index),i.viewFrom=o.lineN,i.viewTo+=r):xr(e)}else if(n>=i.viewTo){var a=Cr(e,t,t,-1);a?(i.view=i.view.slice(0,a.index),i.viewTo=a.lineN):xr(e)}else{var s=Cr(e,t,t,-1),u=Cr(e,n,n+r,1);s&&u?(i.view=i.view.slice(0,s.index).concat(yt(e,s.lineN,u.lineN)).concat(i.view.slice(u.index)),i.viewTo+=r):xr(e)}var c=i.externalMeasured;c&&(n=i.lineN&&t=r.viewTo)){var o=r.view[An(e,t)];if(null!=o.node){var a=o.changes||(o.changes=[]);-1==f(a,n)&&a.push(n)}}}function xr(e){e.display.viewFrom=e.display.viewTo=e.doc.first,e.display.view=[],e.display.viewOffset=0}function Cr(e,t,n,r){var i,o=An(e,t),a=e.display.view;if(!Xa||n==e.doc.first+e.doc.size)return{index:o,lineN:n};for(var s=e.display.viewFrom,u=0;u0){if(o==a.length-1)return null;i=s+a[o].size-t,o++}else i=s-t;t+=i,n+=i}for(;me(e.doc,n)!=n;){if(o==(r<0?0:a.length-1))return null;n+=r*a[o-(r<0?1:0)].size,o+=r}return{index:o,lineN:n}}function Er(e,t,n){var r=e.display;0==r.view.length||t>=r.viewTo||n<=r.viewFrom?(r.view=yt(e,t,n),r.viewFrom=t):(r.viewFrom>t?r.view=yt(e,t,r.viewFrom).concat(r.view):r.viewFromn&&(r.view=r.view.slice(0,An(e,n)))),r.viewTo=n}function Dr(e){for(var t=e.display.view,n=0,r=0;r=e.display.viewTo)){var n=+new Date+e.options.workTime,r=Ye(e,t.highlightFrontier),i=[];t.iter(r.line,Math.min(t.first+t.size,e.display.viewTo+500),function(o){if(r.line>=e.display.viewFrom){var a=o.styles,s=o.text.length>e.options.maxHighlightLength?He(t.mode,r.state):null,u=Ke(e,o,r,!0);s&&(r.state=s),o.styles=u.styles;var c=o.styleClasses,l=u.classes;l?o.styleClasses=l:c&&(o.styleClasses=null);for(var p=!a||a.length!=o.styles.length||c!=l&&(!c||!l||c.bgClass!=l.bgClass||c.textClass!=l.textClass),f=0;!p&&fn)return wr(e,e.options.workDelay),!0}),t.highlightFrontier=r.line,t.modeFrontier=Math.max(t.modeFrontier,r.line),i.length&&hr(e,function(){for(var t=0;t=r.viewFrom&&n.visible.to<=r.viewTo&&(null==r.updateLineNumbers||r.updateLineNumbers>=r.viewTo)&&r.renderedView==r.view&&0==Dr(e))return!1;zn(e)&&(xr(e),n.dims=En(e));var o=i.first+i.size,a=Math.max(n.visible.from-e.options.viewportMargin,i.first),s=Math.min(o,n.visible.to+e.options.viewportMargin);r.viewFroms&&r.viewTo-s<20&&(s=Math.min(o,r.viewTo)),Xa&&(a=me(e.doc,a),s=ge(e.doc,s));var u=a!=r.viewFrom||s!=r.viewTo||r.lastWrapHeight!=n.wrapperHeight||r.lastWrapWidth!=n.wrapperWidth;Er(e,a,s),r.viewOffset=be(A(e.doc,r.viewFrom)),e.display.mover.style.top=r.viewOffset+"px";var c=Dr(e);if(!u&&0==c&&!n.force&&r.renderedView==r.view&&(null==r.updateLineNumbers||r.updateLineNumbers>=r.viewTo))return!1;var l=Ar(e);return c>4&&(r.lineDiv.style.display="none"),Nr(e,r.updateLineNumbers,n.dims),c>4&&(r.lineDiv.style.display=""),r.renderedView=r.view,_r(l),t(r.cursorDiv),t(r.selectionDiv),r.gutters.style.height=r.sizer.style.minHeight=0,u&&(r.lastWrapHeight=n.wrapperHeight,r.lastWrapWidth=n.wrapperWidth,wr(e,400)),r.updateLineNumbers=null,!0}function Or(e,t){for(var n=t.viewport,r=!0;(r&&e.options.lineWrapping&&t.oldDisplayWidth!=Ut(e)||(n&&null!=n.top&&(n={top:Math.min(e.doc.height+Rt(e.display)-zt(e),n.top)}),t.visible=$n(e.display,e.doc,n),!(t.visible.from>=e.display.viewFrom&&t.visible.to<=e.display.viewTo)))&&Tr(e,t);r=!1){Rn(e);var i=nr(e);_n(e),rr(e,i),Lr(e,i),t.force=!1}t.signal(e,"update",e),e.display.viewFrom==e.display.reportedViewFrom&&e.display.viewTo==e.display.reportedViewTo||(t.signal(e,"viewportChange",e,e.display.viewFrom,e.display.viewTo),e.display.reportedViewFrom=e.display.viewFrom,e.display.reportedViewTo=e.display.viewTo)}function Fr(e,t){var n=new ks(e,t);if(Tr(e,n)){Rn(e),Or(e,n);var r=nr(e);_n(e),rr(e,r),Lr(e,r),n.finish()}}function Nr(e,n,r){function i(t){var n=t.nextSibling;return Ca&&Fa&&e.display.currentWheelTarget==t?t.style.display="none":t.parentNode.removeChild(t),n}for(var o=e.display,a=e.options.lineNumbers,s=o.lineDiv,u=s.firstChild,c=o.view,l=o.viewFrom,p=0;p-1&&(h=!1),Dt(e,d,l,r)),h&&(t(d.lineNumber),d.lineNumber.appendChild(document.createTextNode(L(e.options,l)))),u=d.node.nextSibling}else{var m=Ft(e,d,l,r);s.insertBefore(m,u)}l+=d.size}for(;u;)u=i(u)}function Ir(e){var t=e.display.gutters.offsetWidth;e.display.sizer.style.marginLeft=t+"px"}function Lr(e,t){e.display.sizer.style.minHeight=t.docHeight+"px",e.display.heightForcer.style.top=t.docHeight+"px",e.display.gutters.style.height=t.docHeight+e.display.barHeight+$t(e)+"px"}function Pr(e){var n=e.display.gutters,i=e.options.gutters;t(n);for(var o=0;o-1&&!e.lineNumbers&&(e.gutters=e.gutters.slice(0),e.gutters.splice(t,1))}function jr(e){var t=e.wheelDeltaX,n=e.wheelDeltaY;return null==t&&e.detail&&e.axis==e.HORIZONTAL_AXIS&&(t=e.detail),null==n&&e.detail&&e.axis==e.VERTICAL_AXIS?n=e.detail:null==n&&(n=e.wheelDelta),{x:t,y:n}}function Rr(e){var t=jr(e);return t.x*=_s,t.y*=_s,t}function Br(e,t){var n=jr(t),r=n.x,i=n.y,o=e.display,a=o.scroller,s=a.scrollWidth>a.clientWidth,u=a.scrollHeight>a.clientHeight;if(r&&s||i&&u){if(i&&Fa&&Ca)e:for(var c=t.target,l=o.view;c!=a;c=c.parentNode)for(var p=0;p=0){var a=$(o.from(),i.from()),s=B(o.to(),i.to()),u=o.empty()?i.from()==i.head:o.from()==o.head;r<=t&&--t,e.splice(--r,2,new Os(u?s:a,u?a:s))}}return new Ts(e,t)}function Ur(e,t){return new Ts([new Os(e,t||e)],0)}function zr(e){return e.text?P(e.from.line+e.text.length-1,m(e.text).length+(1==e.text.length?e.from.ch:0)):e.to}function Gr(e,t){if(M(e,t.from)<0)return e;if(M(e,t.to)<=0)return zr(t);var n=e.line+t.text.length-(t.to.line-t.from.line)-1,r=e.ch;return e.line==t.to.line&&(r+=zr(t).ch-t.to.ch),P(n,r)}function Vr(e,t){for(var n=[],r=0;r1&&e.remove(s.line+1,h-1),e.insert(s.line+1,v)}Ct(e,"change",e,t)}function Yr(e,t,n){function r(e,i,o){if(e.linked)for(var a=0;a1&&!e.done[e.done.length-2].ranges?(e.done.pop(),m(e.done)):void 0}function oi(e,t,n,r){var i=e.history;i.undone.length=0;var o,a,s=+new Date;if((i.lastOp==r||i.lastOrigin==t.origin&&t.origin&&("+"==t.origin.charAt(0)&&i.lastModTime>s-(e.cm?e.cm.options.historyEventDelay:500)||"*"==t.origin.charAt(0)))&&(o=ii(i,i.lastOp==r)))a=m(o.changes),0==M(t.from,t.to)&&0==M(t.from,a.to)?a.to=zr(t):o.changes.push(ni(e,t));else{var u=m(i.done);for(u&&u.ranges||ui(e.sel,i.done),o={changes:[ni(e,t)],generation:i.generation},i.done.push(o);i.done.length>i.undoDepth;)i.done.shift(),i.done[0].ranges||i.done.shift()}i.done.push(n),i.generation=++i.maxGeneration,i.lastModTime=i.lastSelTime=s,i.lastOp=i.lastSelOp=r,i.lastOrigin=i.lastSelOrigin=t.origin,a||Ae(e,"historyAdded")}function ai(e,t,n,r){var i=t.charAt(0);return"*"==i||"+"==i&&n.ranges.length==r.ranges.length&&n.somethingSelected()==r.somethingSelected()&&new Date-e.history.lastSelTime<=(e.cm?e.cm.options.historyEventDelay:500)}function si(e,t,n,r){var i=e.history,o=r&&r.origin;n==i.lastSelOp||o&&i.lastSelOrigin==o&&(i.lastModTime==i.lastSelTime&&i.lastOrigin==o||ai(e,o,m(i.done),t))?i.done[i.done.length-1]=t:ui(t,i.done),i.lastSelTime=+new Date,i.lastSelOrigin=o,i.lastSelOp=n,r&&!1!==r.clearRedo&&ri(i.undone)}function ui(e,t){var n=m(t);n&&n.ranges&&n.equals(e)||t.push(e)}function ci(e,t,n,r){var i=t["spans_"+e.id],o=0;e.iter(Math.max(e.first,n),Math.min(e.first+e.size,r),function(n){n.markedSpans&&((i||(i=t["spans_"+e.id]={}))[o]=n.markedSpans),++o})}function li(e){if(!e)return null;for(var t,n=0;n-1&&(m(s)[p]=c[p],delete c[p])}}}return r}function hi(e,t,n,r){if(r){var i=e.anchor;if(n){var o=M(t,i)<0;o!=M(n,i)<0?(i=t,t=n):o!=M(t,n)<0&&(t=n)}return new Os(i,t)}return new Os(n||t,t)}function mi(e,t,n,r,i){null==i&&(i=e.cm&&(e.cm.display.shift||e.extend)),Ci(e,new Ts([hi(e.sel.primary(),t,n,i)],0),r)}function gi(e,t,n){for(var r=[],i=e.cm&&(e.cm.display.shift||e.extend),o=0;o=t.ch:s.to>t.ch))){if(i&&(Ae(u,"beforeCursorEnter"),u.explicitlyCleared)){if(o.markedSpans){--a;continue}break}if(!u.atomic)continue;if(n){var c=u.find(r<0?1:-1),l=void 0;if((r<0?u.inclusiveRight:u.inclusiveLeft)&&(c=_i(e,c,-r,c&&c.line==t.line?o:null)),c&&c.line==t.line&&(l=M(c,n))&&(r<0?l<0:l>0))return ki(e,c,t,r,i)}var p=u.find(r<0?-1:1);return(r<0?u.inclusiveLeft:u.inclusiveRight)&&(p=_i(e,p,r,p.line==t.line?o:null)),p?ki(e,p,t,r,i):null}}return t}function Ai(e,t,n,r,i){var o=r||1,a=ki(e,t,n,o,i)||!i&&ki(e,t,n,o,!0)||ki(e,t,n,-o,i)||!i&&ki(e,t,n,-o,!0);return a||(e.cantEdit=!0,P(e.first,0))}function _i(e,t,n,r){return n<0&&0==t.ch?t.line>e.first?z(e,P(t.line-1)):null:n>0&&t.ch==(r||A(e,t.line)).text.length?t.line=0;--i)Ni(e,{from:r[i].from,to:r[i].to,text:i?[""]:t.text,origin:t.origin});else Ni(e,t)}}function Ni(e,t){if(1!=t.text.length||""!=t.text[0]||0!=M(t.from,t.to)){var n=Vr(e,t);oi(e,t,n,e.cm?e.cm.curOp.id:NaN),Pi(e,t,n,Z(e,t));var r=[];Yr(e,function(e,n){n||-1!=f(r,e.history)||($i(e.history,t),r.push(e.history)),Pi(e,t,null,Z(e,t))})}}function Ii(e,t,n){var r=e.cm&&e.cm.state.suppressEdits;if(!r||n){for(var i,o=e.history,a=e.sel,s="undo"==t?o.done:o.undone,u="undo"==t?o.undone:o.done,c=0;c=0;--d){var h=function(n){var r=i.changes[n];if(r.origin=t,p&&!Oi(e,r,!1))return s.length=0,{};l.push(ni(e,r));var o=n?Vr(e,r):m(s);Pi(e,r,o,fi(e,r)),!n&&e.cm&&e.cm.scrollIntoView({from:r.from,to:zr(r)});var a=[];Yr(e,function(e,t){t||-1!=f(a,e.history)||($i(e.history,r),a.push(e.history)),Pi(e,r,null,fi(e,r))})}(d);if(h)return h.v}}}}function Li(e,t){if(0!=t&&(e.first+=t,e.sel=new Ts(g(e.sel.ranges,function(e){return new Os(P(e.anchor.line+t,e.anchor.ch),P(e.head.line+t,e.head.ch))}),e.sel.primIndex),e.cm)){vr(e.cm,e.first,e.first-t,t);for(var n=e.cm.display,r=n.viewFrom;re.lastLine())){if(t.from.lineo&&(t={from:t.from,to:P(o,A(e,o).text.length),text:[t.text[0]],origin:t.origin}),t.removed=_(e,t.from,t.to),n||(n=Vr(e,t)),e.cm?Mi(e.cm,t,r):Jr(e,t,r),Ei(e,n,qa)}}function Mi(e,t,n){var r=e.doc,i=e.display,o=t.from,a=t.to,s=!1,u=o.line;e.options.lineWrapping||(u=F(fe(A(r,o.line))),r.iter(u,a.line+1,function(e){if(e==i.maxLine)return s=!0,!0})),r.sel.contains(t.from,t.to)>-1&&Te(e),Jr(r,t,n,wn(e)),e.options.lineWrapping||(r.iter(u,o.line+t.text.length,function(e){var t=xe(e);t>i.maxLineLength&&(i.maxLine=e,i.maxLineLength=t,i.maxLineChanged=!0,s=!1)}),s&&(e.curOp.updateMaxLine=!0)),ot(r,o.line),wr(e,400);var c=t.text.length-(a.line-o.line)-1;t.full?vr(e):o.line!=a.line||1!=t.text.length||Kr(e.doc,t)?vr(e,o.line,a.line+1,c):br(e,o.line,"text");var l=Oe(e,"changes"),p=Oe(e,"change");if(p||l){var f={from:o,to:a,text:t.text,removed:t.removed,origin:t.origin};p&&Ct(e,"change",e,f),l&&(e.curOp.changeObjs||(e.curOp.changeObjs=[])).push(f)}e.display.selForContextMenu=null}function ji(e,t,n,r,i){if(r||(r=n),M(r,n)<0){var o;o=[r,n],n=o[0],r=o[1]}"string"==typeof t&&(t=e.splitLines(t)),Fi(e,{from:n,to:r,text:t,origin:i})}function Ri(e,t,n,r){n0||0==s&&!1!==a.clearWhenEmpty)return a;if(a.replacedWith&&(a.collapsed=!0,a.widgetNode=i("span",[a.replacedWith],"CodeMirror-widget"),r.handleMouseEvents||a.widgetNode.setAttribute("cm-ignore-events","true"),r.insertLeft&&(a.widgetNode.insertLeft=!0)),a.collapsed){if(pe(e,t.line,t,n,a)||t.line!=n.line&&pe(e,n.line,t,n,a))throw new Error("Inserting collapsed marker partially overlapping an existing one");H()}a.addToHistory&&oi(e,{from:t,to:n,origin:"markText"},e.sel,NaN);var u,c=t.line,p=e.cm;if(e.iter(c,n.line+1,function(e){p&&a.collapsed&&!p.options.lineWrapping&&fe(e)==p.display.maxLine&&(u=!0),a.collapsed&&c!=t.line&&O(e,0),J(e,new W(a,c==t.line?t.ch:null,c==n.line?n.ch:null)),++c}),a.collapsed&&e.iter(t.line,n.line+1,function(t){ye(e,t)&&O(t,0)}),a.clearOnEnter&&ns(a,"beforeCursorEnter",function(){return a.clear()}),a.readOnly&&(q(),(e.history.done.length||e.history.undone.length)&&e.clearHistory()),a.collapsed&&(a.id=++Ns,a.atomic=!0),p){if(u&&(p.curOp.updateMaxLine=!0),a.collapsed)vr(p,t.line,n.line+1);else if(a.className||a.title||a.startStyle||a.endStyle||a.css)for(var f=t.line;f<=n.line;f++)br(p,f,"text");a.atomic&&wi(p.doc),Ct(p,"markerAdded",p,a)}return a}function Wi(e,t,n,r,i){r=l(r),r.shared=!1;var o=[Hi(e,t,n,r,i)],a=o[0],s=r.widgetNode;return Yr(e,function(e){s&&(r.widgetNode=s.cloneNode(!0)),o.push(Hi(e,z(e,t),z(e,n),r,i));for(var u=0;u-1)return t.state.draggingText(e),void setTimeout(function(){return t.display.input.focus()},20);try{var u=e.dataTransfer.getData("Text");if(u){var c;if(t.state.draggingText&&!t.state.draggingText.copy&&(c=t.listSelections()),Ei(t.doc,Ur(n,n)),c)for(var l=0;l=0;t--)ji(e.doc,"",r[t].from,r[t].to,"+delete");Qn(e)})}function ho(e,t,n){var r=w(e.text,t+n,n);return r<0||r>e.text.length?null:r}function mo(e,t,n){var r=ho(e,t.ch,n);return null==r?null:new P(t.line,r,n<0?"after":"before")}function go(e,t,n,r,i){if(e){var o=we(n,t.doc.direction);if(o){var a,s=i<0?m(o):o[0],u=i<0==(1==s.level),c=u?"after":"before";if(s.level>0||"rtl"==t.doc.direction){var l=Qt(t,n);a=i<0?n.text.length-1:0;var p=Kt(t,l,a).top;a=S(function(e){return Kt(t,l,e).top==p},i<0==(1==s.level)?s.from:s.to-1,a),"before"==c&&(a=ho(n,a,1))}else a=i<0?s.to:s.from;return new P(r,a,c)}}return new P(r,i<0?n.text.length:0,i<0?"before":"after")}function yo(e,t,n,r){var i=we(t,e.doc.direction);if(!i)return mo(t,n,r);n.ch>=t.text.length?(n.ch=t.text.length,n.sticky="before"):n.ch<=0&&(n.ch=0,n.sticky="after");var o=De(i,n.ch,n.sticky),a=i[o];if("ltr"==e.doc.direction&&a.level%2==0&&(r>0?a.to>n.ch:a.from=a.from&&f>=l.begin)){var d=p?"before":"after";return new P(n.line,f,d)}}var h=function(e,t,r){for(var o=function(e,t){return t?new P(n.line,u(e,1),"before"):new P(n.line,e,"after")};e>=0&&e0==(1!=a.level),c=s?r.begin:u(r.end,-1);if(a.from<=c&&c0?l.end:u(l.begin,-1);return null==g||r>0&&g==t.text.length||!(m=h(r>0?0:i.length-1,r,c(g)))?null:m}function vo(e,t){var n=A(e.doc,t),r=fe(n);return r!=n&&(t=F(r)),go(!0,e,r,t,1)}function bo(e,t){var n=A(e.doc,t),r=de(n);return r!=n&&(t=F(r)),go(!0,e,n,t,-1)}function xo(e,t){var n=vo(e,t.line),r=A(e.doc,n.line),i=we(r,e.doc.direction);if(!i||0==i[0].level){var o=Math.max(0,r.text.search(/\S/)),a=t.line==n.line&&t.ch<=o&&t.ch;return P(n.line,a?0:o,n.sticky)}return n}function Co(e,t,n){if("string"==typeof t&&!(t=Vs[t]))return!1;e.display.input.ensurePolled();var r=e.display.shift,i=!1;try{e.isReadOnly()&&(e.state.suppressEdits=!0),n&&(e.display.shift=!1),i=t(e)!=Va}finally{e.display.shift=r,e.state.suppressEdits=!1}return i}function Eo(e,t,n){for(var r=0;r-1&&(M((i=s.ranges[i]).from(),t)<0||t.xRel>0)&&(M(i.to(),t)>0||t.xRel<0)?Mo(e,r,t,o):Ro(e,r,t,o)}function Mo(e,t,n,r){var i=e.display,o=!1,a=mr(e,function(t){Ca&&(i.scroller.draggable=!1),e.state.draggingText=!1,ke(i.wrapper.ownerDocument,"mouseup",a),ke(i.wrapper.ownerDocument,"mousemove",s),ke(i.scroller,"dragstart",u),ke(i.scroller,"drop",a),o||(Ne(t),r.addNew||mi(e.doc,n,null,null,r.extend),Ca||ba&&9==xa?setTimeout(function(){i.wrapper.ownerDocument.body.focus(),i.input.focus()},20):i.input.focus())}),s=function(e){o=o||Math.abs(t.clientX-e.clientX)+Math.abs(t.clientY-e.clientY)>=10},u=function(){return o=!0};Ca&&(i.scroller.draggable=!0),e.state.draggingText=a,a.copy=!r.moveOnDrag,i.scroller.dragDrop&&i.scroller.dragDrop(),ns(i.wrapper.ownerDocument,"mouseup",a),ns(i.wrapper.ownerDocument,"mousemove",s),ns(i.scroller,"dragstart",u),ns(i.scroller,"drop",a),Pn(e),setTimeout(function(){return i.input.focus()},20)}function jo(e,t,n){if("char"==n)return new Os(t,t);if("word"==n)return e.findWordAt(t);if("line"==n)return new Os(P(t.line,0),z(e.doc,P(t.line+1,0)));var r=n(e,t);return new Os(r.from,r.to)}function Ro(e,t,n,r){function i(t){if(0!=M(y,t))if(y=t,"rectangle"==r.unit){for(var i=[],o=e.options.tabSize,a=p(A(c,n.line).text,n.ch,o),s=p(A(c,t.line).text,t.ch,o),u=Math.min(a,s),m=Math.max(a,s),g=Math.min(n.line,t.line),v=Math.min(e.lastLine(),Math.max(n.line,t.line));g<=v;g++){var b=A(c,g).text,x=d(b,u,o);u==m?i.push(new Os(P(g,x),P(g,x))):b.length>x&&i.push(new Os(P(g,x),P(g,d(b,m,o))))}i.length||i.push(new Os(n,n)),Ci(c,$r(h.ranges.slice(0,f).concat(i),f),{origin:"*mouse",scroll:!1}),e.scrollIntoView(t)}else{var C,E=l,D=jo(e,t,r.unit),w=E.anchor;M(D.anchor,w)>0?(C=D.head,w=$(E.from(),D.anchor)):(C=D.anchor,w=B(E.to(),D.head));var S=h.ranges.slice(0);S[f]=Bo(e,new Os(z(c,w),C)),Ci(c,$r(S,f),Ha)}}function o(t){var n=++b,s=kn(e,t,!0,"rectangle"==r.unit);if(s)if(0!=M(s,y)){e.curOp.focus=a(),i(s);var l=$n(u,c);(s.line>=l.to||s.linev.bottom?20:0;p&&setTimeout(mr(e,function(){b==n&&(u.scroller.scrollTop+=p,o(t))}),50)}}function s(t){e.state.selectingText=!1,b=1/0,Ne(t),u.input.focus(),ke(u.wrapper.ownerDocument,"mousemove",x),ke(u.wrapper.ownerDocument,"mouseup",C),c.history.lastSelOrigin=null}var u=e.display,c=e.doc;Ne(t);var l,f,h=c.sel,m=h.ranges;if(r.addNew&&!r.extend?(f=c.sel.contains(n),l=f>-1?m[f]:new Os(n,n)):(l=c.sel.primary(),f=c.sel.primIndex),"rectangle"==r.unit)r.addNew||(l=new Os(n,n)),n=kn(e,t,!0,!0),f=-1;else{var g=jo(e,n,r.unit);l=r.extend?hi(l,g.anchor,g.head,r.extend):g}r.addNew?-1==f?(f=m.length,Ci(c,$r(m.concat([l]),f),{scroll:!1,origin:"*mouse"})):m.length>1&&m[f].empty()&&"char"==r.unit&&!r.extend?(Ci(c,$r(m.slice(0,f).concat(m.slice(f+1)),0),{scroll:!1,origin:"*mouse"}),h=c.sel):yi(c,f,l,Ha):(f=0,Ci(c,new Ts([l],0),Ha),h=c.sel);var y=n,v=u.wrapper.getBoundingClientRect(),b=0,x=mr(e,function(e){0!==e.buttons&&je(e)?o(e):s(e)}),C=mr(e,s);e.state.selectingText=C,ns(u.wrapper.ownerDocument,"mousemove",x),ns(u.wrapper.ownerDocument,"mouseup",C)}function Bo(e,t){var n=t.anchor,r=t.head,i=A(e.doc,n.line);if(0==M(n,r)&&n.sticky==r.sticky)return t;var o=we(i);if(!o)return t;var a=De(o,n.ch,n.sticky),s=o[a];if(s.from!=n.ch&&s.to!=n.ch)return t;var u=a+(s.from==n.ch==(1!=s.level)?0:1);if(0==u||u==o.length)return t;var c;if(r.line!=n.line)c=(r.line-n.line)*("ltr"==e.doc.direction?1:-1)>0;else{var l=De(o,r.ch,r.sticky),p=l-a||(r.ch-n.ch)*(1==s.level?-1:1);c=l==u-1||l==u?p<0:p>0}var f=o[u+(c?-1:0)],d=c==(1==f.level),h=d?f.from:f.to,m=d?"after":"before";return n.ch==h&&n.sticky==m?t:new Os(new P(n.line,h,m),r)}function $o(e,t,n,r){var i,o;if(t.touches)i=t.touches[0].clientX,o=t.touches[0].clientY;else try{i=t.clientX,o=t.clientY}catch(t){return!1}if(i>=Math.floor(e.display.gutters.getBoundingClientRect().right))return!1;r&&Ne(t);var a=e.display,s=a.lineDiv.getBoundingClientRect();if(o>s.bottom||!Oe(e,n))return Le(t);o-=s.top-a.viewOffset;for(var u=0;u=i){return Ae(e,n,e,N(e.doc,o),e.options.gutters[u],t),Le(t)}}}function Uo(e,t){return $o(e,t,"gutterClick",!0)}function zo(e,t){Mt(e.display,t)||Go(e,t)||_e(e,t,"contextmenu")||e.display.input.onContextMenu(t)}function Go(e,t){return!!Oe(e,"gutterContextMenu")&&$o(e,t,"gutterContextMenu",!1)}function Vo(e){e.display.wrapper.className=e.display.wrapper.className.replace(/\s*cm-s-\S+/g,"")+e.options.theme.replace(/(^|\s)\s*/g," cm-s-"),nn(e)}function qo(e){Pr(e),vr(e),Un(e)}function Ho(e,t,n){if(!t!=!(n&&n!=Js)){var r=e.display.dragFunctions,i=t?ns:ke;i(e.display.scroller,"dragstart",r.start),i(e.display.scroller,"dragenter",r.enter),i(e.display.scroller,"dragover",r.over),i(e.display.scroller,"dragleave",r.leave),i(e.display.scroller,"drop",r.drop)}}function Wo(e){e.options.lineWrapping?(s(e.display.wrapper,"CodeMirror-wrap"),e.display.sizer.style.minWidth="",e.display.sizerWidth=null):(Ra(e.display.wrapper,"CodeMirror-wrap"),Ce(e)),Sn(e),vr(e),nn(e),setTimeout(function(){return rr(e)},100)}function Qo(e,t){var n=this;if(!(this instanceof Qo))return new Qo(e,t);this.options=t=t?l(t):{},l(Ys,t,!1),Mr(t);var r=t.value;"string"==typeof r&&(r=new Ms(r,t.mode,null,t.lineSeparator,t.direction)),this.doc=r;var i=new Qo.inputStyles[t.inputStyle](this),o=this.display=new k(e,r,i);o.wrapper.CodeMirror=this,Pr(this),Vo(this),t.lineWrapping&&(this.display.wrapper.className+=" CodeMirror-wrap"),or(this),this.state={keyMaps:[],overlays:[],modeGen:0,overwrite:!1,delayingBlurEvent:!1,focused:!1,suppressEdits:!1,pasteIncoming:!1,cutIncoming:!1,selectingText:!1,draggingText:!1,highlight:new $a,keySeq:null,specialChars:null},t.autofocus&&!Oa&&o.input.focus(),ba&&xa<11&&setTimeout(function(){return n.display.input.reset(!0)},20),Ko(this),no(),ar(this),this.curOp.forceUpdate=!0,Xr(this,r),t.autofocus&&!Oa||this.hasFocus()?setTimeout(c(Mn,this),20):jn(this);for(var a in Xs)Xs.hasOwnProperty(a)&&Xs[a](n,t[a],Js);zn(this),t.finishInit&&t.finishInit(this);for(var s=0;s400}var i=e.display;ns(i.scroller,"mousedown",mr(e,No)),ba&&xa<11?ns(i.scroller,"dblclick",mr(e,function(t){if(!_e(e,t)){var n=kn(e,t);if(n&&!Uo(e,t)&&!Mt(e.display,t)){Ne(t);var r=e.findWordAt(n);mi(e.doc,r.anchor,r.head)}}})):ns(i.scroller,"dblclick",function(t){return _e(e,t)||Ne(t)}),ja||ns(i.scroller,"contextmenu",function(t){return zo(e,t)});var o,a={end:0};ns(i.scroller,"touchstart",function(t){if(!_e(e,t)&&!n(t)&&!Uo(e,t)){i.input.ensurePolled(),clearTimeout(o);var r=+new Date;i.activeTouch={start:r,moved:!1,prev:r-a.end<=300?a:null},1==t.touches.length&&(i.activeTouch.left=t.touches[0].pageX,i.activeTouch.top=t.touches[0].pageY)}}),ns(i.scroller,"touchmove",function(){i.activeTouch&&(i.activeTouch.moved=!0)}),ns(i.scroller,"touchend",function(n){var o=i.activeTouch;if(o&&!Mt(i,n)&&null!=o.left&&!o.moved&&new Date-o.start<300){var a,s=e.coordsChar(i.activeTouch,"page");a=!o.prev||r(o,o.prev)?new Os(s,s):!o.prev.prev||r(o,o.prev.prev)?e.findWordAt(s):new Os(P(s.line,0),z(e.doc,P(s.line+1,0))),e.setSelection(a.anchor,a.head),e.focus(),Ne(n)}t()}),ns(i.scroller,"touchcancel",t),ns(i.scroller,"scroll",function(){i.scroller.clientHeight&&(Zn(e,i.scroller.scrollTop),tr(e,i.scroller.scrollLeft,!0),Ae(e,"scroll",e))}),ns(i.scroller,"mousewheel",function(t){return Br(e,t)}),ns(i.scroller,"DOMMouseScroll",function(t){return Br(e,t)}),ns(i.wrapper,"scroll",function(){return i.wrapper.scrollTop=i.wrapper.scrollLeft=0}),i.dragFunctions={enter:function(t){_e(e,t)||Pe(t)},over:function(t){_e(e,t)||(Zi(e,t),Pe(t))},start:function(t){return Xi(e,t)},drop:mr(e,Yi),leave:function(t){_e(e,t)||eo(e)}};var s=i.input.getField();ns(s,"keyup",function(t){return To.call(e,t)}),ns(s,"keydown",mr(e,Ao)),ns(s,"keypress",mr(e,Oo)),ns(s,"focus",function(t){return Mn(e,t)}),ns(s,"blur",function(t){return jn(e,t)})}function Jo(e,t,n,r){var i,o=e.doc;null==n&&(n="add"),"smart"==n&&(o.mode.indent?i=Ye(e,t).state:n="prev");var a=e.options.tabSize,s=A(o,t),u=p(s.text,null,a);s.stateAfter&&(s.stateAfter=null);var c,l=s.text.match(/^\s*/)[0];if(r||/\S/.test(s.text)){if("smart"==n&&((c=o.mode.indent(i,s.text.slice(l.length),s.text))==Va||c>150)){if(!r)return;n="prev"}}else c=0,n="not";"prev"==n?c=t>o.first?p(A(o,t-1).text,null,a):0:"add"==n?c=u+e.options.indentUnit:"subtract"==n?c=u-e.options.indentUnit:"number"==typeof n&&(c=u+n),c=Math.max(0,c);var f="",d=0;if(e.options.indentWithTabs)for(var m=Math.floor(c/a);m;--m)d+=a,f+="\t";if(d1)if(eu&&eu.text.join("\n")==t){if(r.ranges.length%eu.text.length==0){u=[];for(var c=0;c=0;p--){var f=r.ranges[p],d=f.from(),h=f.to();f.empty()&&(n&&n>0?d=P(d.line,d.ch-n):e.state.overwrite&&!a?h=P(h.line,Math.min(A(o,h.line).text.length,h.ch+m(s).length)):eu&&eu.lineWise&&eu.text.join("\n")==t&&(d=h=P(d.line,0))),l=e.curOp.updateInput;var y={from:d,to:h,text:u?u[p%u.length]:s,origin:i||(a?"paste":e.state.cutIncoming?"cut":"+input")};Fi(e.doc,y),Ct(e,"inputRead",e,y)}t&&!a&&ea(e,t),Qn(e),e.curOp.updateInput=l,e.curOp.typing=!0,e.state.pasteIncoming=e.state.cutIncoming=!1}function Zo(e,t){var n=e.clipboardData&&e.clipboardData.getData("Text");if(n)return e.preventDefault(),t.isReadOnly()||t.options.disableInput||hr(t,function(){return Xo(t,n,0,null,"paste")}),!0}function ea(e,t){if(e.options.electricChars&&e.options.smartIndent)for(var n=e.doc.sel,r=n.ranges.length-1;r>=0;r--){var i=n.ranges[r];if(!(i.head.ch>100||r&&n.ranges[r-1].head.line==i.head.line)){var o=e.getModeAt(i.head),a=!1;if(o.electricChars){for(var s=0;s-1){a=Jo(e,i.head.line,"smart");break}}else o.electricInput&&o.electricInput.test(A(e.doc,i.head.line).text.slice(0,i.head.ch))&&(a=Jo(e,i.head.line,"smart"));a&&Ct(e,"electricInput",e,i.head.line)}}}function ta(e){for(var t=[],n=[],r=0;r=e.first+e.size)&&(t=new P(r,t.ch,t.sticky),c=A(e,r))}function a(r){var a;if(null==(a=i?yo(e.cm,c,t,n):mo(c,t,n))){if(r||!o())return!1;t=go(i,e.cm,c,t.line,n)}else t=a;return!0}var s=t,u=n,c=A(e,t.line);if("char"==r)a();else if("column"==r)a(!0);else if("word"==r||"group"==r)for(var l=null,p="group"==r,f=e.cm&&e.cm.getHelper(t,"wordChars"),d=!0;!(n<0)||a(!d);d=!1){var h=c.text.charAt(t.ch)||"\n",m=C(h,f)?"w":p&&"\n"==h?"n":!p||/\s/.test(h)?null:"p";if(!p||d||m||(m="s"),l&&l!=m){n<0&&(n=1,a(),t.sticky="after");break}if(m&&(l=m),n>0&&!a(!d))break}var g=Ai(e,t,s,u,!0);return j(s,g)&&(g.hitSide=!0),g}function oa(e,t,n,r){var i,o=e.doc,a=t.left;if("page"==r){var s=Math.min(e.display.wrapper.clientHeight,window.innerHeight||document.documentElement.clientHeight),u=Math.max(s-.5*xn(e.display),3);i=(n>0?t.bottom:t.top)+n*u}else"line"==r&&(i=n>0?t.bottom+3:t.top-3);for(var c;c=dn(e,a,i),c.outside;){if(n<0?i<=0:i>=o.height){c.hitSide=!0;break}i+=5*n}return c}function aa(e,t){var n=Wt(e,t.line);if(!n||n.hidden)return null;var r=A(e.doc,t.line),i=Vt(n,r,t.line),o=we(r,e.doc.direction),a="left";if(o){a=De(o,t.ch)%2?"right":"left"}var s=Jt(i.map,t.ch,a);return s.offset="right"==s.collapse?s.end:s.start,s}function sa(e){for(var t=e;t;t=t.parentNode)if(/CodeMirror-gutter-wrapper/.test(t.className))return!0;return!1}function ua(e,t){return t&&(e.bad=!0),e}function ca(e,t,n,r,i){function o(e){return function(t){return t.id==e}}function a(){l&&(c+=p,f&&(c+=p),l=f=!1)}function s(e){e&&(a(),c+=e)}function u(t){if(1==t.nodeType){var n=t.getAttribute("cm-text");if(n)return void s(n);var c,d=t.getAttribute("cm-marker");if(d){var h=e.findMarks(P(r,0),P(i+1,0),o(+d));return void(h.length&&(c=h[0].find(0))&&s(_(e.doc,c.from,c.to).join(p)))}if("false"==t.getAttribute("contenteditable"))return;var m=/^(pre|div|p|li|table|br)$/i.test(t.nodeName);if(!/^br$/i.test(t.nodeName)&&0==t.textContent.length)return;m&&a();for(var g=0;g=15&&(wa=!1,Ca=!0);var Pa,Ma=Fa&&(Ea||wa&&(null==La||La<12.11)),ja=ma||ba&&xa>=9,Ra=function(t,n){var r=t.className,i=e(n).exec(r);if(i){var o=r.slice(i.index+i[0].length);t.className=r.slice(0,i.index)+(o?i[1]+o:"")}};Pa=document.createRange?function(e,t,n,r){var i=document.createRange();return i.setEnd(r||e,n),i.setStart(e,t),i}:function(e,t,n){var r=document.body.createTextRange();try{r.moveToElementText(e.parentNode)}catch(e){return r}return r.collapse(!0),r.moveEnd("character",n),r.moveStart("character",t),r};var Ba=function(e){e.select()};_a?Ba=function(e){e.selectionStart=0,e.selectionEnd=e.value.length}:ba&&(Ba=function(e){try{e.select()}catch(e){}});var $a=function(){this.id=null};$a.prototype.set=function(e,t){clearTimeout(this.id),this.id=setTimeout(t,e)};var Ua,za,Ga=30,Va={toString:function(){return"CodeMirror.Pass"}},qa={scroll:!1},Ha={origin:"*mouse"},Wa={origin:"+move"},Qa=[""],Ka=/[\u00df\u0587\u0590-\u05f4\u0600-\u06ff\u3040-\u309f\u30a0-\u30ff\u3400-\u4db5\u4e00-\u9fcc\uac00-\ud7af]/,Ja=/[\u0300-\u036f\u0483-\u0489\u0591-\u05bd\u05bf\u05c1\u05c2\u05c4\u05c5\u05c7\u0610-\u061a\u064b-\u065e\u0670\u06d6-\u06dc\u06de-\u06e4\u06e7\u06e8\u06ea-\u06ed\u0711\u0730-\u074a\u07a6-\u07b0\u07eb-\u07f3\u0816-\u0819\u081b-\u0823\u0825-\u0827\u0829-\u082d\u0900-\u0902\u093c\u0941-\u0948\u094d\u0951-\u0955\u0962\u0963\u0981\u09bc\u09be\u09c1-\u09c4\u09cd\u09d7\u09e2\u09e3\u0a01\u0a02\u0a3c\u0a41\u0a42\u0a47\u0a48\u0a4b-\u0a4d\u0a51\u0a70\u0a71\u0a75\u0a81\u0a82\u0abc\u0ac1-\u0ac5\u0ac7\u0ac8\u0acd\u0ae2\u0ae3\u0b01\u0b3c\u0b3e\u0b3f\u0b41-\u0b44\u0b4d\u0b56\u0b57\u0b62\u0b63\u0b82\u0bbe\u0bc0\u0bcd\u0bd7\u0c3e-\u0c40\u0c46-\u0c48\u0c4a-\u0c4d\u0c55\u0c56\u0c62\u0c63\u0cbc\u0cbf\u0cc2\u0cc6\u0ccc\u0ccd\u0cd5\u0cd6\u0ce2\u0ce3\u0d3e\u0d41-\u0d44\u0d4d\u0d57\u0d62\u0d63\u0dca\u0dcf\u0dd2-\u0dd4\u0dd6\u0ddf\u0e31\u0e34-\u0e3a\u0e47-\u0e4e\u0eb1\u0eb4-\u0eb9\u0ebb\u0ebc\u0ec8-\u0ecd\u0f18\u0f19\u0f35\u0f37\u0f39\u0f71-\u0f7e\u0f80-\u0f84\u0f86\u0f87\u0f90-\u0f97\u0f99-\u0fbc\u0fc6\u102d-\u1030\u1032-\u1037\u1039\u103a\u103d\u103e\u1058\u1059\u105e-\u1060\u1071-\u1074\u1082\u1085\u1086\u108d\u109d\u135f\u1712-\u1714\u1732-\u1734\u1752\u1753\u1772\u1773\u17b7-\u17bd\u17c6\u17c9-\u17d3\u17dd\u180b-\u180d\u18a9\u1920-\u1922\u1927\u1928\u1932\u1939-\u193b\u1a17\u1a18\u1a56\u1a58-\u1a5e\u1a60\u1a62\u1a65-\u1a6c\u1a73-\u1a7c\u1a7f\u1b00-\u1b03\u1b34\u1b36-\u1b3a\u1b3c\u1b42\u1b6b-\u1b73\u1b80\u1b81\u1ba2-\u1ba5\u1ba8\u1ba9\u1c2c-\u1c33\u1c36\u1c37\u1cd0-\u1cd2\u1cd4-\u1ce0\u1ce2-\u1ce8\u1ced\u1dc0-\u1de6\u1dfd-\u1dff\u200c\u200d\u20d0-\u20f0\u2cef-\u2cf1\u2de0-\u2dff\u302a-\u302f\u3099\u309a\ua66f-\ua672\ua67c\ua67d\ua6f0\ua6f1\ua802\ua806\ua80b\ua825\ua826\ua8c4\ua8e0-\ua8f1\ua926-\ua92d\ua947-\ua951\ua980-\ua982\ua9b3\ua9b6-\ua9b9\ua9bc\uaa29-\uaa2e\uaa31\uaa32\uaa35\uaa36\uaa43\uaa4c\uaab0\uaab2-\uaab4\uaab7\uaab8\uaabe\uaabf\uaac1\uabe5\uabe8\uabed\udc00-\udfff\ufb1e\ufe00-\ufe0f\ufe20-\ufe26\uff9e\uff9f]/,Ya=!1,Xa=!1,Za=null,es=function(){function e(e){return e<=247?n.charAt(e):1424<=e&&e<=1524?"R":1536<=e&&e<=1785?r.charAt(e-1536):1774<=e&&e<=2220?"r":8192<=e&&e<=8203?"w":8204==e?"b":"L"}function t(e,t,n){this.level=e,this.from=t,this.to=n}var n="bbbbbbbbbtstwsbbbbbbbbbbbbbbssstwNN%%%NNNNNN,N,N1111111111NNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNbbbbbbsbbbbbbbbbbbbbbbbbbbbbbbbbb,N%%%%NNNNLNNNNN%%11NLNNN1LNNNNNLLLLLLLLLLLLLLLLLLLLLLLNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLN",r="nnnnnnNNr%%r,rNNmmmmmmmmmmmrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrmmmmmmmmmmmmmmmmmmmmmnnnnnnnnnn%nnrrrmrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrmmmmmmmnNmmmmmmrrmmNmmmmrr1111111111",i=/[\u0590-\u05f4\u0600-\u06ff\u0700-\u08ac]/,o=/[stwN]/,a=/[LRr]/,s=/[Lb1n]/,u=/[1n]/;return function(n,r){var c="ltr"==r?"L":"R";if(0==n.length||"ltr"==r&&!i.test(n))return!1;for(var l=n.length,p=[],f=0;f=this.string.length},ps.prototype.sol=function(){return this.pos==this.lineStart},ps.prototype.peek=function(){return this.string.charAt(this.pos)||void 0},ps.prototype.next=function(){if(this.post},ps.prototype.eatSpace=function(){for(var e=this,t=this.pos;/[\s\u00a0]/.test(this.string.charAt(this.pos));)++e.pos;return this.pos>t},ps.prototype.skipToEnd=function(){this.pos=this.string.length},ps.prototype.skipTo=function(e){var t=this.string.indexOf(e,this.pos);if(t>-1)return this.pos=t,!0},ps.prototype.backUp=function(e){this.pos-=e},ps.prototype.column=function(){return this.lastColumnPos0?null:(r&&!1!==t&&(this.pos+=r[0].length),r)}var i=function(e){return n?e.toLowerCase():e};if(i(this.string.substr(this.pos,e.length))==i(e))return!1!==t&&(this.pos+=e.length),!0},ps.prototype.current=function(){return this.string.slice(this.start,this.pos)},ps.prototype.hideFirstChars=function(e,t){this.lineStart+=e;try{return t()}finally{this.lineStart-=e}},ps.prototype.lookAhead=function(e){var t=this.lineOracle;return t&&t.lookAhead(e)},ps.prototype.baseToken=function(){var e=this.lineOracle;return e&&e.baseToken(this.pos)};var fs=function(e,t){this.state=e,this.lookAhead=t},ds=function(e,t,n,r){this.state=t,this.doc=e,this.line=n,this.maxLookAhead=r||0,this.baseTokens=null,this.baseTokenPos=1};ds.prototype.lookAhead=function(e){var t=this.doc.getLine(this.line+e);return null!=t&&e>this.maxLookAhead&&(this.maxLookAhead=e),t},ds.prototype.baseToken=function(e){var t=this;if(!this.baseTokens)return null;for(;this.baseTokens[this.baseTokenPos]<=e;)t.baseTokenPos+=2;var n=this.baseTokens[this.baseTokenPos+1];return{type:n&&n.replace(/( |^)overlay .*/,""),size:this.baseTokens[this.baseTokenPos]-e}},ds.prototype.nextLine=function(){this.line++,this.maxLookAhead>0&&this.maxLookAhead--},ds.fromSaved=function(e,t,n){return t instanceof fs?new ds(e,He(e.mode,t.state),n,t.lookAhead):new ds(e,He(e.mode,t),n)},ds.prototype.save=function(e){var t=!1!==e?He(this.doc.mode,this.state):this.state;return this.maxLookAhead>0?new fs(t,this.maxLookAhead):t};var hs=function(e,t,n){this.start=e.start,this.end=e.pos,this.string=e.current(),this.type=t||null,this.state=n},ms=function(e,t,n){this.text=e,re(this,t),this.height=n?n(this):1};ms.prototype.lineNo=function(){return F(this)},Fe(ms);var gs,ys={},vs={},bs=null,xs=null,Cs={left:0,right:0,top:0,bottom:0},Es=function(e,t,n){this.cm=n;var i=this.vert=r("div",[r("div",null,null,"min-width: 1px")],"CodeMirror-vscrollbar"),o=this.horiz=r("div",[r("div",null,null,"height: 100%; min-height: 1px")],"CodeMirror-hscrollbar");i.tabIndex=o.tabIndex=-1,e(i),e(o),ns(i,"scroll",function(){i.clientHeight&&t(i.scrollTop,"vertical")}),ns(o,"scroll",function(){o.clientWidth&&t(o.scrollLeft,"horizontal")}),this.checkedZeroWidth=!1,ba&&xa<8&&(this.horiz.style.minHeight=this.vert.style.minWidth="18px")};Es.prototype.update=function(e){var t=e.scrollWidth>e.clientWidth+1,n=e.scrollHeight>e.clientHeight+1,r=e.nativeBarWidth;if(n){this.vert.style.display="block",this.vert.style.bottom=t?r+"px":"0";var i=e.viewHeight-(t?r:0);this.vert.firstChild.style.height=Math.max(0,e.scrollHeight-e.clientHeight+i)+"px"}else this.vert.style.display="",this.vert.firstChild.style.height="0";if(t){this.horiz.style.display="block",this.horiz.style.right=n?r+"px":"0",this.horiz.style.left=e.barLeft+"px";var o=e.viewWidth-e.barLeft-(n?r:0);this.horiz.firstChild.style.width=Math.max(0,e.scrollWidth-e.clientWidth+o)+"px"}else this.horiz.style.display="",this.horiz.firstChild.style.width="0";return!this.checkedZeroWidth&&e.clientHeight>0&&(0==r&&this.zeroWidthHack(),this.checkedZeroWidth=!0),{right:n?r:0,bottom:t?r:0}},Es.prototype.setScrollLeft=function(e){this.horiz.scrollLeft!=e&&(this.horiz.scrollLeft=e),this.disableHoriz&&this.enableZeroWidthBar(this.horiz,this.disableHoriz,"horiz")},Es.prototype.setScrollTop=function(e){this.vert.scrollTop!=e&&(this.vert.scrollTop=e),this.disableVert&&this.enableZeroWidthBar(this.vert,this.disableVert,"vert")},Es.prototype.zeroWidthHack=function(){var e=Fa&&!ka?"12px":"18px";this.horiz.style.height=this.vert.style.width=e,this.horiz.style.pointerEvents=this.vert.style.pointerEvents="none",this.disableHoriz=new $a,this.disableVert=new $a},Es.prototype.enableZeroWidthBar=function(e,t,n){function r(){var i=e.getBoundingClientRect();("vert"==n?document.elementFromPoint(i.right-1,(i.top+i.bottom)/2):document.elementFromPoint((i.right+i.left)/2,i.bottom-1))!=e?e.style.pointerEvents="none":t.set(1e3,r)}e.style.pointerEvents="auto",t.set(1e3,r)},Es.prototype.clear=function(){var e=this.horiz.parentNode;e.removeChild(this.horiz),e.removeChild(this.vert)};var Ds=function(){};Ds.prototype.update=function(){return{bottom:0,right:0}},Ds.prototype.setScrollLeft=function(){},Ds.prototype.setScrollTop=function(){},Ds.prototype.clear=function(){};var ws={native:Es,null:Ds},Ss=0,ks=function(e,t,n){var r=e.display;this.viewport=t,this.visible=$n(r,e.doc,t),this.editorIsHidden=!r.wrapper.offsetWidth,this.wrapperHeight=r.wrapper.clientHeight,this.wrapperWidth=r.wrapper.clientWidth,this.oldDisplayWidth=Ut(e),this.force=n,this.dims=En(e),this.events=[]};ks.prototype.signal=function(e,t){Oe(e,t)&&this.events.push(arguments)},ks.prototype.finish=function(){for(var e=this,t=0;t=0&&M(e,i.to())<=0)return r}return-1};var Os=function(e,t){this.anchor=e,this.head=t};Os.prototype.from=function(){return $(this.anchor,this.head)},Os.prototype.to=function(){return B(this.anchor,this.head)},Os.prototype.empty=function(){return this.head.line==this.anchor.line&&this.head.ch==this.anchor.ch},zi.prototype={chunkSize:function(){return this.lines.length},removeInner:function(e,t){for(var n=this,r=e,i=e+t;r1||!(this.children[0]instanceof zi))){var u=[];this.collapse(u),this.children=[new zi(u)],this.children[0].parent=this}},collapse:function(e){for(var t=this,n=0;n50){for(var s=o.lines.length%25+25,u=s;u10);e.parent.maybeSpill()}},iterN:function(e,t,n){for(var r=this,i=0;it.display.maxLineLength&&(t.display.maxLine=l,t.display.maxLineLength=p,t.display.maxLineChanged=!0)}null!=i&&t&&this.collapsed&&vr(t,i,o+1),this.lines.length=0,this.explicitlyCleared=!0,this.atomic&&this.doc.cantEdit&&(this.doc.cantEdit=!1,t&&wi(t.doc)),t&&Ct(t,"markerCleared",t,this,i,o),n&&sr(t),this.parent&&this.parent.clear()}},Is.prototype.find=function(e,t){var n=this;null==e&&"bookmark"==this.type&&(e=1);for(var r,i,o=0;o=0;c--)Fi(r,i[c]);u?xi(this,u):this.cm&&Qn(this.cm)}),undo:yr(function(){Ii(this,"undo")}),redo:yr(function(){Ii(this,"redo")}),undoSelection:yr(function(){Ii(this,"undo",!0)}),redoSelection:yr(function(){Ii(this,"redo",!0)}),setExtending:function(e){this.extend=e},getExtending:function(){return this.extend},historySize:function(){for(var e=this.history,t=0,n=0,r=0;r=e.ch)&&t.push(i.marker.parent||i.marker)}return t},findMarks:function(e,t,n){e=z(this,e),t=z(this,t);var r=[],i=e.line;return this.iter(e.line,t.line+1,function(o){var a=o.markedSpans;if(a)for(var s=0;s=u.to||null==u.from&&i!=e.line||null!=u.from&&i==t.line&&u.from>=t.ch||n&&!n(u.marker)||r.push(u.marker.parent||u.marker)}++i}),r},getAllMarks:function(){var e=[];return this.iter(function(t){var n=t.markedSpans;if(n)for(var r=0;re)return t=e,!0;e-=o,++n}),z(this,P(n,t))},indexFromPos:function(e){e=z(this,e);var t=e.ch;if(e.linet&&(t=e.from),null!=e.to&&e.to0)i=new P(i.line,i.ch+1),e.replaceRange(o.charAt(i.ch-1)+o.charAt(i.ch-2),P(i.line,i.ch-2),i,"+transpose");else if(i.line>e.doc.first){var a=A(e.doc,i.line-1).text;a&&(i=new P(i.line,1),e.replaceRange(o.charAt(0)+e.doc.lineSeparator()+a.charAt(a.length-1),P(i.line-1,a.length-1),i,"+transpose"))}n.push(new Os(i,i))}e.setSelections(n)})},newlineAndIndent:function(e){return hr(e,function(){for(var t=e.listSelections(),n=t.length-1;n>=0;n--)e.replaceRange(e.doc.lineSeparator(),t[n].anchor,t[n].head,"+input");t=e.listSelections();for(var r=0;re&&0==M(t,this.pos)&&n==this.button};var Qs,Ks,Js={toString:function(){return"CodeMirror.Init"}},Ys={},Xs={};Qo.defaults=Ys,Qo.optionHandlers=Xs;var Zs=[];Qo.defineInitHook=function(e){return Zs.push(e)};var eu=null,tu=function(e){this.cm=e,this.lastAnchorNode=this.lastAnchorOffset=this.lastFocusNode=this.lastFocusOffset=null,this.polling=new $a,this.composing=null,this.gracePeriod=!1,this.readDOMTimeout=null};tu.prototype.init=function(e){function t(e){if(!_e(i,e)){if(i.somethingSelected())Yo({lineWise:!1,text:i.getSelections()}),"cut"==e.type&&i.replaceSelection("",null,"cut");else{if(!i.options.lineWiseCopyCut)return;var t=ta(i);Yo({lineWise:!0,text:t.text}),"cut"==e.type&&i.operation(function(){i.setSelections(t.ranges,0,qa),i.replaceSelection("",null,"cut")})}if(e.clipboardData){e.clipboardData.clearData();var n=eu.text.join("\n");if(e.clipboardData.setData("Text",n),e.clipboardData.getData("Text")==n)return void e.preventDefault()}var a=ra(),s=a.firstChild;i.display.lineSpace.insertBefore(a,i.display.lineSpace.firstChild),s.value=eu.text.join("\n");var u=document.activeElement;Ba(s),setTimeout(function(){i.display.lineSpace.removeChild(a),u.focus(),u==o&&r.showPrimarySelection()},50)}}var n=this,r=this,i=r.cm,o=r.div=e.lineDiv;na(o,i.options.spellcheck),ns(o,"paste",function(e){_e(i,e)||Zo(e,i)||xa<=11&&setTimeout(mr(i,function(){return n.updateFromDOM()}),20)}),ns(o,"compositionstart",function(e){n.composing={data:e.data,done:!1}}),ns(o,"compositionupdate",function(e){n.composing||(n.composing={data:e.data,done:!1})}),ns(o,"compositionend",function(e){n.composing&&(e.data!=n.composing.data&&n.readFromDOMSoon(),n.composing.done=!0)}),ns(o,"touchstart",function(){return r.forceCompositionEnd()}),ns(o,"input",function(){n.composing||n.readFromDOMSoon()}),ns(o,"copy",t),ns(o,"cut",t)},tu.prototype.prepareSelection=function(){var e=Tn(this.cm,!1);return e.focus=this.cm.state.focused,e},tu.prototype.showSelection=function(e,t){e&&this.cm.display.view.length&&((e.focus||t)&&this.showPrimarySelection(),this.showMultipleSelections(e))},tu.prototype.getSelection=function(){return this.cm.display.wrapper.ownerDocument.getSelection()},tu.prototype.showPrimarySelection=function(){var e=this.getSelection(),t=this.cm,n=t.doc.sel.primary(),r=n.from(),i=n.to();if(t.display.viewTo==t.display.viewFrom||r.line>=t.display.viewTo||i.line=t.display.viewFrom&&aa(t,r)||{node:s[0].measure.map[2],offset:0},c=i.linee.firstLine()&&(r=P(r.line-1,A(e.doc,r.line-1).length)),i.ch==A(e.doc,i.line).text.length&&i.linet.viewTo-1)return!1;var o,a,s;r.line==t.viewFrom||0==(o=An(e,r.line))?(a=F(t.view[0].line),s=t.view[0].node):(a=F(t.view[o].line),s=t.view[o-1].node.nextSibling);var u,c,l=An(e,i.line);if(l==t.view.length-1?(u=t.viewTo-1,c=t.lineDiv.lastChild):(u=F(t.view[l+1].line)-1,c=t.view[l+1].node.previousSibling),!s)return!1;for(var p=e.doc.splitLines(ca(e,s,c,a,u)),f=_(e.doc,P(a,0),P(u,A(e.doc,u).text.length));p.length>1&&f.length>1;)if(m(p)==m(f))p.pop(),f.pop(),u--;else{if(p[0]!=f[0])break;p.shift(),f.shift(),a++}for(var d=0,h=0,g=p[0],y=f[0],v=Math.min(g.length,y.length);dr.ch&&b.charCodeAt(b.length-h-1)==x.charCodeAt(x.length-h-1);)d--,h++;p[p.length-1]=b.slice(0,b.length-h).replace(/^\u200b+/,""),p[0]=p[0].slice(d).replace(/\u200b+$/,"");var E=P(a,d),D=P(u,f.length?m(f).length-h:0);return p.length>1||p[0]||M(E,D)?(ji(e.doc,p,E,D,"+input"),!0):void 0},tu.prototype.ensurePolled=function(){this.forceCompositionEnd()},tu.prototype.reset=function(){this.forceCompositionEnd()},tu.prototype.forceCompositionEnd=function(){this.composing&&(clearTimeout(this.readDOMTimeout),this.composing=null,this.updateFromDOM(),this.div.blur(),this.div.focus())},tu.prototype.readFromDOMSoon=function(){var e=this;null==this.readDOMTimeout&&(this.readDOMTimeout=setTimeout(function(){if(e.readDOMTimeout=null,e.composing){if(!e.composing.done)return;e.composing=null}e.updateFromDOM()},80))},tu.prototype.updateFromDOM=function(){var e=this;!this.cm.isReadOnly()&&this.pollContent()||hr(this.cm,function(){return vr(e.cm)})},tu.prototype.setUneditable=function(e){e.contentEditable="false"},tu.prototype.onKeyPress=function(e){0==e.charCode||this.composing||(e.preventDefault(),this.cm.isReadOnly()||mr(this.cm,Xo)(this.cm,String.fromCharCode(null==e.charCode?e.keyCode:e.charCode),0))},tu.prototype.readOnlyChanged=function(e){this.div.contentEditable=String("nocursor"!=e)},tu.prototype.onContextMenu=function(){},tu.prototype.resetPosition=function(){},tu.prototype.needsContentAttribute=!0;var nu=function(e){this.cm=e,this.prevInput="",this.pollingFast=!1,this.polling=new $a,this.hasSelection=!1,this.composing=null};nu.prototype.init=function(e){function t(e){if(!_e(i,e)){if(i.somethingSelected())Yo({lineWise:!1,text:i.getSelections()});else{if(!i.options.lineWiseCopyCut)return;var t=ta(i);Yo({lineWise:!0,text:t.text}),"cut"==e.type?i.setSelections(t.ranges,null,qa):(r.prevInput="",o.value=t.text.join("\n"),Ba(o))}"cut"==e.type&&(i.state.cutIncoming=!0)}}var n=this,r=this,i=this.cm;this.createField(e);var o=this.textarea;e.wrapper.insertBefore(this.wrapper,e.wrapper.firstChild),_a&&(o.style.width="0px"),ns(o,"input",function(){ba&&xa>=9&&n.hasSelection&&(n.hasSelection=null),r.poll()}),ns(o,"paste",function(e){_e(i,e)||Zo(e,i)||(i.state.pasteIncoming=!0,r.fastPoll())}),ns(o,"cut",t),ns(o,"copy",t),ns(e.scroller,"paste",function(t){Mt(e,t)||_e(i,t)||(i.state.pasteIncoming=!0,r.focus())}),ns(e.lineSpace,"selectstart",function(t){Mt(e,t)||Ne(t)}),ns(o,"compositionstart",function(){var e=i.getCursor("from");r.composing&&r.composing.range.clear(),r.composing={start:e,range:i.markText(e,i.getCursor("to"),{className:"CodeMirror-composing"})}}),ns(o,"compositionend",function(){r.composing&&(r.poll(),r.composing.range.clear(),r.composing=null)})},nu.prototype.createField=function(e){this.wrapper=ra(),this.textarea=this.wrapper.firstChild},nu.prototype.prepareSelection=function(){var e=this.cm,t=e.display,n=e.doc,r=Tn(e);if(e.options.moveInputWithCursor){var i=ln(e,n.sel.primary().head,"div"),o=t.wrapper.getBoundingClientRect(),a=t.lineDiv.getBoundingClientRect();r.teTop=Math.max(0,Math.min(t.wrapper.clientHeight-10,i.top+a.top-o.top)),r.teLeft=Math.max(0,Math.min(t.wrapper.clientWidth-10,i.left+a.left-o.left))}return r},nu.prototype.showSelection=function(e){var t=this.cm,r=t.display;n(r.cursorDiv,e.cursors),n(r.selectionDiv,e.selection),null!=e.teTop&&(this.wrapper.style.top=e.teTop+"px",this.wrapper.style.left=e.teLeft+"px")},nu.prototype.reset=function(e){if(!this.contextMenuPending&&!this.composing){var t=this.cm;if(t.somethingSelected()){this.prevInput="";var n=t.getSelection();this.textarea.value=n,t.state.focused&&Ba(this.textarea),ba&&xa>=9&&(this.hasSelection=n)}else e||(this.prevInput=this.textarea.value="",ba&&xa>=9&&(this.hasSelection=null))}},nu.prototype.getField=function(){return this.textarea},nu.prototype.supportsTouch=function(){return!1},nu.prototype.focus=function(){if("nocursor"!=this.cm.options.readOnly&&(!Oa||a()!=this.textarea))try{this.textarea.focus()}catch(e){}},nu.prototype.blur=function(){this.textarea.blur()},nu.prototype.resetPosition=function(){this.wrapper.style.top=this.wrapper.style.left=0},nu.prototype.receivedFocus=function(){this.slowPoll()},nu.prototype.slowPoll=function(){var e=this;this.pollingFast||this.polling.set(this.cm.options.pollInterval,function(){e.poll(),e.cm.state.focused&&e.slowPoll()})},nu.prototype.fastPoll=function(){function e(){n.poll()||t?(n.pollingFast=!1,n.slowPoll()):(t=!0,n.polling.set(60,e))}var t=!1,n=this;n.pollingFast=!0,n.polling.set(20,e)},nu.prototype.poll=function(){var e=this,t=this.cm,n=this.textarea,r=this.prevInput;if(this.contextMenuPending||!t.state.focused||os(n)&&!r&&!this.composing||t.isReadOnly()||t.options.disableInput||t.state.keySeq)return!1;var i=n.value;if(i==r&&!t.somethingSelected())return!1;if(ba&&xa>=9&&this.hasSelection===i||Fa&&/[\uf700-\uf7ff]/.test(i))return t.display.input.reset(),!1;if(t.doc.sel==t.display.selForContextMenu){var o=i.charCodeAt(0);if(8203!=o||r||(r="\u200b"),8666==o)return this.reset(),this.cm.execCommand("undo")}for(var a=0,s=Math.min(r.length,i.length);a1e3||i.indexOf("\n")>-1?n.value=e.prevInput="":e.prevInput=i,e.composing&&(e.composing.range.clear(),e.composing.range=t.markText(e.composing.start,t.getCursor("to"),{className:"CodeMirror-composing"}))}),!0},nu.prototype.ensurePolled=function(){this.pollingFast&&this.poll()&&(this.pollingFast=!1)},nu.prototype.onKeyPress=function(){ba&&xa>=9&&(this.hasSelection=null),this.fastPoll()},nu.prototype.onContextMenu=function(e){function t(){if(null!=a.selectionStart){var e=i.somethingSelected(),t="\u200b"+(e?a.value:"");a.value="\u21da",a.value=t,r.prevInput=e?"":"\u200b",a.selectionStart=1,a.selectionEnd=t.length,o.selForContextMenu=i.doc.sel}}function n(){if(r.contextMenuPending=!1,r.wrapper.style.cssText=l,a.style.cssText=c,ba&&xa<9&&o.scrollbars.setScrollTop(o.scroller.scrollTop=u),null!=a.selectionStart){(!ba||ba&&xa<9)&&t();var e=0,n=function(){o.selForContextMenu==i.doc.sel&&0==a.selectionStart&&a.selectionEnd>0&&"\u200b"==r.prevInput?mr(i,Ti)(i):e++<10?o.detectingSelectAll=setTimeout(n,500):(o.selForContextMenu=null,o.input.reset())};o.detectingSelectAll=setTimeout(n,200)}}var r=this,i=r.cm,o=i.display,a=r.textarea,s=kn(i,e),u=o.scroller.scrollTop;if(s&&!wa){i.options.resetSelectionOnContextMenu&&-1==i.doc.sel.contains(s)&&mr(i,Ci)(i.doc,Ur(s),qa);var c=a.style.cssText,l=r.wrapper.style.cssText;r.wrapper.style.cssText="position: absolute";var p=r.wrapper.getBoundingClientRect();a.style.cssText="position: absolute; width: 30px; height: 30px;\n top: "+(e.clientY-p.top-5)+"px; left: "+(e.clientX-p.left-5)+"px;\n z-index: 1000; background: "+(ba?"rgba(255, 255, 255, .05)":"transparent")+";\n outline: none; border-width: 0; outline: none; overflow: hidden; opacity: .05; filter: alpha(opacity=5);";var f;if(Ca&&(f=window.scrollY),o.input.focus(),Ca&&window.scrollTo(null,f),o.input.reset(),i.somethingSelected()||(a.value=r.prevInput=" "),r.contextMenuPending=!0,o.selForContextMenu=i.doc.sel,clearTimeout(o.detectingSelectAll),ba&&xa>=9&&t(),ja){Pe(e);var d=function(){ke(window,"mouseup",d),setTimeout(n,20)};ns(window,"mouseup",d)}else setTimeout(n,50)}},nu.prototype.readOnlyChanged=function(e){e||this.reset(),this.textarea.disabled="nocursor"==e},nu.prototype.setUneditable=function(){},nu.prototype.needsContentAttribute=!1,function(e){function t(t,r,i,o){e.defaults[t]=r,i&&(n[t]=o?function(e,t,n){n!=Js&&i(e,t,n)}:i)}var n=e.optionHandlers;e.defineOption=t,e.Init=Js,t("value","",function(e,t){return e.setValue(t)},!0),t("mode",null,function(e,t){e.doc.modeOption=t,Wr(e)},!0),t("indentUnit",2,Wr,!0),t("indentWithTabs",!1),t("smartIndent",!0),t("tabSize",4,function(e){Qr(e),nn(e),vr(e)},!0),t("lineSeparator",null,function(e,t){if(e.doc.lineSep=t,t){var n=[],r=e.doc.first;e.doc.iter(function(e){for(var i=0;;){var o=e.text.indexOf(t,i);if(-1==o)break;i=o+t.length,n.push(P(r,o))}r++});for(var i=n.length-1;i>=0;i--)ji(e.doc,t,n[i],P(n[i].line,n[i].ch+t.length))}}),t("specialChars",/[\u0000-\u001f\u007f-\u009f\u00ad\u061c\u200b-\u200f\u2028\u2029\ufeff]/g,function(e,t,n){e.state.specialChars=new RegExp(t.source+(t.test("\t")?"":"|\t"),"g"),n!=Js&&e.refresh()}),t("specialCharPlaceholder",lt,function(e){return e.refresh()},!0),t("electricChars",!0),t("inputStyle",Oa?"contenteditable":"textarea",function(){throw new Error("inputStyle can not (yet) be changed in a running editor")},!0),t("spellcheck",!1,function(e,t){return e.getInputField().spellcheck=t},!0),t("rtlMoveVisually",!Ia),t("wholeLineUpdateBefore",!0),t("theme","default",function(e){Vo(e),qo(e)},!0),t("keyMap","default",function(e,t,n){var r=po(t),i=n!=Js&&po(n);i&&i.detach&&i.detach(e,r),r.attach&&r.attach(e,i||null)}),t("extraKeys",null),t("configureMouse",null),t("lineWrapping",!1,Wo,!0),t("gutters",[],function(e){Mr(e.options),qo(e)},!0),t("fixedGutter",!0,function(e,t){e.display.gutters.style.left=t?Dn(e.display)+"px":"0",e.refresh()},!0),t("coverGutterNextToScrollbar",!1,function(e){return rr(e)},!0),t("scrollbarStyle","native",function(e){or(e),rr(e),e.display.scrollbars.setScrollTop(e.doc.scrollTop),e.display.scrollbars.setScrollLeft(e.doc.scrollLeft)},!0),t("lineNumbers",!1,function(e){Mr(e.options),qo(e)},!0),t("firstLineNumber",1,qo,!0),t("lineNumberFormatter",function(e){return e},qo,!0),t("showCursorWhenSelecting",!1,_n,!0),t("resetSelectionOnContextMenu",!0),t("lineWiseCopyCut",!0),t("pasteLinesPerSelection",!0),t("readOnly",!1,function(e,t){"nocursor"==t&&(jn(e),e.display.input.blur()),e.display.input.readOnlyChanged(t)}),t("disableInput",!1,function(e,t){t||e.display.input.reset()},!0),t("dragDrop",!0,Ho),t("allowDropFileTypes",null),t("cursorBlinkRate",530),t("cursorScrollMargin",0),t("cursorHeight",1,_n,!0),t("singleCursorHeightPerLine",!0,_n,!0),t("workTime",100),t("workDelay",100),t("flattenSpans",!0,Qr,!0),t("addModeClass",!1,Qr,!0),t("pollInterval",100),t("undoDepth",200,function(e,t){return e.doc.history.undoDepth=t}),t("historyEventDelay",1250),t("viewportMargin",10,function(e){return e.refresh()},!0),t("maxHighlightLength",1e4,Qr,!0),t("moveInputWithCursor",!0,function(e,t){t||e.display.input.resetPosition()}),t("tabindex",null,function(e,t){return e.display.input.getField().tabIndex=t||""}),t("autofocus",null),t("direction","ltr",function(e,t){return e.doc.setDirection(t)},!0)}(Qo),function(e){var t=e.optionHandlers,n=e.helpers={};e.prototype={constructor:e,focus:function(){window.focus(),this.display.input.focus()},setOption:function(e,n){var r=this.options,i=r[e];r[e]==n&&"mode"!=e||(r[e]=n,t.hasOwnProperty(e)&&mr(this,t[e])(this,n,i),Ae(this,"optionChange",this,e))},getOption:function(e){return this.options[e]},getDoc:function(){return this.doc},addKeyMap:function(e,t){this.state.keyMaps[t?"push":"unshift"](po(e))},removeKeyMap:function(e){for(var t=this.state.keyMaps,n=0;nr&&(Jo(t,o.head.line,e,!0),r=o.head.line,i==t.doc.sel.primIndex&&Qn(t));else{var a=o.from(),s=o.to(),u=Math.max(r,a.line);r=Math.min(t.lastLine(),s.line-(s.ch?0:1))+1;for(var c=u;c0&&yi(t.doc,i,new Os(a,l[i].to()),qa)}}}),getTokenAt:function(e,t){return tt(this,e,t)},getLineTokens:function(e,t){return tt(this,P(e),t,!0)},getTokenTypeAt:function(e){e=z(this.doc,e);var t,n=Je(this,A(this.doc,e.line)),r=0,i=(n.length-1)/2,o=e.ch;if(0==o)t=n[2];else for(;;){var a=r+i>>1;if((a?n[2*a-1]:0)>=o)i=a;else{if(!(n[2*a+1]o&&(e=o,i=!0),r=A(this.doc,e)}else r=e;return sn(this,r,{top:0,left:0},t||"page",n||i).top+(i?this.doc.height-be(r):0)},defaultTextHeight:function(){return xn(this.display)},defaultCharWidth:function(){return Cn(this.display)},getViewport:function(){return{from:this.display.viewFrom,to:this.display.viewTo}},addWidget:function(e,t,n,r,i){var o=this.display;e=ln(this,z(this.doc,e));var a=e.bottom,s=e.left;if(t.style.position="absolute",t.setAttribute("cm-ignore-events","true"),this.display.input.setUneditable(t),o.sizer.appendChild(t),"over"==r)a=e.top;else if("above"==r||"near"==r){var u=Math.max(o.wrapper.clientHeight,this.doc.height),c=Math.max(o.sizer.clientWidth,o.lineSpace.clientWidth);("above"==r||e.bottom+t.offsetHeight>u)&&e.top>t.offsetHeight?a=e.top-t.offsetHeight:e.bottom+t.offsetHeight<=u&&(a=e.bottom),s+t.offsetWidth>c&&(s=c-t.offsetWidth)}t.style.top=a+"px",t.style.left=t.style.right="","right"==i?(s=o.sizer.clientWidth-t.offsetWidth,t.style.right="0px"):("left"==i?s=0:"middle"==i&&(s=(o.sizer.clientWidth-t.offsetWidth)/2),t.style.left=s+"px"),n&&qn(this,{left:s,top:a,right:s+t.offsetWidth,bottom:a+t.offsetHeight})},triggerOnKeyDown:gr(Ao),triggerOnKeyPress:gr(Oo),triggerOnKeyUp:To,triggerOnMouseDown:gr(No),execCommand:function(e){if(Vs.hasOwnProperty(e))return Vs[e].call(null,this)},triggerElectric:gr(function(e){ea(this,e)}),findPosH:function(e,t,n,r){var i=this,o=1;t<0&&(o=-1,t=-t);for(var a=z(this.doc,e),s=0;s0&&s(n.charAt(r-1));)--r;for(;i.5)&&Sn(this),Ae(this,"refresh",this)}),swapDoc:gr(function(e){var t=this.doc;return t.cm=null,Xr(this,e),nn(this),this.display.input.reset(),Kn(this,e.scrollLeft,e.scrollTop),this.curOp.forceScroll=!0,Ct(this,"swapDoc",this,t),t}),getInputField:function(){return this.display.input.getField()},getWrapperElement:function(){return this.display.wrapper},getScrollerElement:function(){return this.display.scroller},getGutterElement:function(){return this.display.gutters}},Fe(e),e.registerHelper=function(t,r,i){n.hasOwnProperty(t)||(n[t]=e[t]={_global:[]}),n[t][r]=i},e.registerGlobalHelper=function(t,r,i,o){e.registerHelper(t,r,o),n[t]._global.push({pred:i,val:o})}}(Qo);var ru="iter insert remove copy getEditor constructor".split(" ");for(var iu in Ms.prototype)Ms.prototype.hasOwnProperty(iu)&&f(ru,iu)<0&&(Qo.prototype[iu]=function(e){return function(){return e.apply(this.doc,arguments)}}(Ms.prototype[iu]));return Fe(Ms),Qo.inputStyles={textarea:nu,contenteditable:tu},Qo.defineMode=function(e){Qo.defaults.mode||"null"==e||(Qo.defaults.mode=e),Ue.apply(this,arguments)},Qo.defineMIME=ze,Qo.defineMode("null",function(){return{token:function(e){return e.skipToEnd()}}}),Qo.defineMIME("text/plain","null"),Qo.defineExtension=function(e,t){Qo.prototype[e]=t},Qo.defineDocExtension=function(e,t){Ms.prototype[e]=t},Qo.fromTextArea=fa,function(e){e.off=ke,e.on=ns,e.wheelEventPixels=Rr,e.Doc=Ms,e.splitLines=is,e.countColumn=p,e.findColumn=d,e.isWordChar=x,e.Pass=Va,e.signal=Ae,e.Line=ms,e.changeEnd=zr,e.scrollbarModel=ws,e.Pos=P,e.cmpPos=M,e.modes=us,e.mimeModes=cs,e.resolveMode=Ge,e.getMode=Ve,e.modeExtensions=ls,e.extendMode=qe,e.copyState=He,e.startState=Qe,e.innerMode=We,e.commands=Vs,e.keyMap=Gs,e.keyName=lo,e.isModifierKey=uo,e.lookupKey=so,e.normalizeKeyMap=ao,e.StringStream=ps,e.SharedTextMarker=Ls,e.TextMarker=Is,e.LineWidget=Fs,e.e_preventDefault=Ne,e.e_stopPropagation=Ie,e.e_stop=Pe,e.addClass=s,e.contains=o,e.rmClass=Ra,e.keyNames=Bs}(Qo),Qo.version="5.38.0",Qo})},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var r=n(43);Object.defineProperty(t,"GraphQLError",{enumerable:!0,get:function(){return r.GraphQLError}});var i=n(391);Object.defineProperty(t,"syntaxError",{enumerable:!0,get:function(){return i.syntaxError}});var o=n(180);Object.defineProperty(t,"locatedError",{enumerable:!0,get:function(){return o.locatedError}});var a=n(392);Object.defineProperty(t,"formatError",{enumerable:!0,get:function(){return a.formatError}})},function(e,t,n){"use strict";function r(e){return Object.prototype.toString.call(e)}function i(e){return"[object String]"===r(e)}function o(e,t){return C.call(e,t)}function a(e){return Array.prototype.slice.call(arguments,1).forEach(function(t){if(t){if("object"!==typeof t)throw new TypeError(t+"must be object");Object.keys(t).forEach(function(n){e[n]=t[n]})}}),e}function s(e,t,n){return[].concat(e.slice(0,t),n,e.slice(t+1))}function u(e){return!(e>=55296&&e<=57343)&&(!(e>=64976&&e<=65007)&&(65535!==(65535&e)&&65534!==(65535&e)&&(!(e>=0&&e<=8)&&(11!==e&&(!(e>=14&&e<=31)&&(!(e>=127&&e<=159)&&!(e>1114111)))))))}function c(e){if(e>65535){e-=65536;var t=55296+(e>>10),n=56320+(1023&e);return String.fromCharCode(t,n)}return String.fromCharCode(e)}function l(e,t){var n=0;return o(k,t)?k[t]:35===t.charCodeAt(0)&&S.test(t)&&(n="x"===t[1].toLowerCase()?parseInt(t.slice(2),16):parseInt(t.slice(1),10),u(n))?c(n):e}function p(e){return e.indexOf("\\")<0?e:e.replace(E,"$1")}function f(e){return e.indexOf("\\")<0&&e.indexOf("&")<0?e:e.replace(w,function(e,t,n){return t||l(e,n)})}function d(e){return T[e]}function h(e){return A.test(e)?e.replace(_,d):e}function m(e){return e.replace(O,"\\$&")}function g(e){switch(e){case 9:case 32:return!0}return!1}function y(e){if(e>=8192&&e<=8202)return!0;switch(e){case 9:case 10:case 11:case 12:case 13:case 32:case 160:case 5760:case 8239:case 8287:case 12288:return!0}return!1}function v(e){return F.test(e)}function b(e){switch(e){case 33:case 34:case 35:case 36:case 37:case 38:case 39:case 40:case 41:case 42:case 43:case 44:case 45:case 46:case 47:case 58:case 59:case 60:case 61:case 62:case 63:case 64:case 91:case 92:case 93:case 94:case 95:case 96:case 123:case 124:case 125:case 126:return!0;default:return!1}}function x(e){return e.trim().replace(/\s+/g," ").toUpperCase()}var C=Object.prototype.hasOwnProperty,E=/\\([!"#$%&'()*+,\-.\/:;<=>?@[\\\]^_`{|}~])/g,D=/&([a-z#][a-z0-9]{1,31});/gi,w=new RegExp(E.source+"|"+D.source,"gi"),S=/^#((?:x[a-f0-9]{1,8}|[0-9]{1,8}))/i,k=n(261),A=/[&<>"]/,_=/[&<>"]/g,T={"&":"&","<":"<",">":">",'"':"""},O=/[.?*+^$[\]\\(){}|-]/g,F=n(263);t.lib={},t.lib.mdurl=n(88),t.lib.ucmicro=n(543),t.assign=a,t.isString=i,t.has=o,t.unescapeMd=p,t.unescapeAll=f,t.isValidEntityCode=u,t.fromCodePoint=c,t.escapeHtml=h,t.arrayReplaceAt=s,t.isSpace=g,t.isWhiteSpace=y,t.isMdAsciiPunct=b,t.isPunctChar=v,t.escapeRE=m,t.normalizeReference=x},function(e,t,n){"use strict";function r(e){return Object.prototype.toString.call(e)}function i(e){return"[object String]"===r(e)}function o(e,t){return C.call(e,t)}function a(e){return Array.prototype.slice.call(arguments,1).forEach(function(t){if(t){if("object"!==typeof t)throw new TypeError(t+"must be object");Object.keys(t).forEach(function(n){e[n]=t[n]})}}),e}function s(e,t,n){return[].concat(e.slice(0,t),n,e.slice(t+1))}function u(e){return!(e>=55296&&e<=57343)&&(!(e>=64976&&e<=65007)&&(65535!==(65535&e)&&65534!==(65535&e)&&(!(e>=0&&e<=8)&&(11!==e&&(!(e>=14&&e<=31)&&(!(e>=127&&e<=159)&&!(e>1114111)))))))}function c(e){if(e>65535){e-=65536;var t=55296+(e>>10),n=56320+(1023&e);return String.fromCharCode(t,n)}return String.fromCharCode(e)}function l(e,t){var n=0;return o(k,t)?k[t]:35===t.charCodeAt(0)&&S.test(t)&&(n="x"===t[1].toLowerCase()?parseInt(t.slice(2),16):parseInt(t.slice(1),10),u(n))?c(n):e}function p(e){return e.indexOf("\\")<0?e:e.replace(E,"$1")}function f(e){return e.indexOf("\\")<0&&e.indexOf("&")<0?e:e.replace(w,function(e,t,n){return t||l(e,n)})}function d(e){return T[e]}function h(e){return A.test(e)?e.replace(_,d):e}function m(e){return e.replace(O,"\\$&")}function g(e){switch(e){case 9:case 32:return!0}return!1}function y(e){if(e>=8192&&e<=8202)return!0;switch(e){case 9:case 10:case 11:case 12:case 13:case 32:case 160:case 5760:case 8239:case 8287:case 12288:return!0}return!1}function v(e){return F.test(e)}function b(e){switch(e){case 33:case 34:case 35:case 36:case 37:case 38:case 39:case 40:case 41:case 42:case 43:case 44:case 45:case 46:case 47:case 58:case 59:case 60:case 61:case 62:case 63:case 64:case 91:case 92:case 93:case 94:case 95:case 96:case 123:case 124:case 125:case 126:return!0;default:return!1}}function x(e){return e.trim().replace(/\s+/g," ").toUpperCase()}var C=Object.prototype.hasOwnProperty,E=/\\([!"#$%&'()*+,\-.\/:;<=>?@[\\\]^_`{|}~])/g,D=/&([a-z#][a-z0-9]{1,31});/gi,w=new RegExp(E.source+"|"+D.source,"gi"),S=/^#((?:x[a-f0-9]{1,8}|[0-9]{1,8}))/i,k=n(294),A=/[&<>"]/,_=/[&<>"]/g,T={"&":"&","<":"<",">":">",'"':"""},O=/[.?*+^$[\]\\(){}|-]/g,F=n(136);t.lib={},t.lib.mdurl=n(88),t.lib.ucmicro=n(647),t.assign=a,t.isString=i,t.has=o,t.unescapeMd=p,t.unescapeAll=f,t.isValidEntityCode=u,t.fromCodePoint=c,t.escapeHtml=h,t.arrayReplaceAt=s,t.isSpace=g,t.isWhiteSpace=y,t.isMdAsciiPunct=b,t.isPunctChar=v,t.escapeRE=m,t.normalizeReference=x},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}function i(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function o(e){return e instanceof j||e instanceof R||e instanceof B||e instanceof $||e instanceof U||e instanceof z||e instanceof G||e instanceof V}function a(e){return o(e)||(0,F.default)(0,"Expected "+String(e)+" to be a GraphQL type."),e}function s(e){return e instanceof j||e instanceof U||e instanceof z||e instanceof V&&s(e.ofType)||e instanceof G&&s(e.ofType)}function u(e){return s(e)||(0,F.default)(0,"Expected "+String(e)+" to be a GraphQL input type."),e}function c(e){return e instanceof j||e instanceof R||e instanceof B||e instanceof $||e instanceof U||e instanceof V&&c(e.ofType)||e instanceof G&&c(e.ofType)}function l(e){return c(e)||(0,F.default)(0,"Expected "+String(e)+" to be a GraphQL output type."),e}function p(e){return e instanceof j||e instanceof U}function f(e){return p(e)||(0,F.default)(0,"Expected "+String(e)+" to be a GraphQL leaf type."),e}function d(e){return e instanceof R||e instanceof B||e instanceof $}function h(e){return d(e)||(0,F.default)(0,"Expected "+String(e)+" to be a GraphQL composite type."),e}function m(e){return e instanceof B||e instanceof $}function g(e){return m(e)||(0,F.default)(0,"Expected "+String(e)+" to be a GraphQL abstract type."),e}function y(e){return e instanceof V?e.ofType:e}function v(e){return e instanceof j||e instanceof R||e instanceof B||e instanceof $||e instanceof U||e instanceof z}function b(e){return v(e)||(0,F.default)(0,"Expected "+String(e)+" to be a GraphQL named type."),e}function x(e){if(e){for(var t=e;t instanceof G||t instanceof V;)t=t.ofType;return t}}function C(e){return"function"===typeof e?e():e}function E(e,t){var n=C(t);if(!n)return[];Array.isArray(n)||(0,F.default)(0,e.name+" interfaces must be an Array or a function which returns an Array.");var r=Object.create(null);return n.forEach(function(t){t instanceof B||(0,F.default)(0,e.name+" may only implement Interface types, it cannot implement: "+String(t)+"."),r[t.name]&&(0,F.default)(0,e.name+" may declare it implements "+t.name+" only once."),r[t.name]=!0,"function"!==typeof t.resolveType&&"function"!==typeof e.isTypeOf&&(0,F.default)(0,"Interface Type "+t.name+' does not provide a "resolveType" function and implementing Type '+e.name+' does not provide a "isTypeOf" function. There is no way to resolve this implementing type during execution.')}),n}function D(e,t){var n=C(t);w(n)||(0,F.default)(0,e.name+" fields must be an object with field names as keys or a function which returns such an object.");var r=Object.keys(n);r.length>0||(0,F.default)(0,e.name+" fields must be an object with field names as keys or a function which returns such an object.");var i=Object.create(null);return r.forEach(function(t){(0,M.assertValidName)(t);var r=n[t];w(r)||(0,F.default)(0,e.name+"."+t+" field config must be an object"),r.hasOwnProperty("isDeprecated")&&(0,F.default)(0,e.name+"."+t+' should provide "deprecationReason" instead of "isDeprecated".');var o=T({},r,{isDeprecated:Boolean(r.deprecationReason),name:t});c(o.type)||(0,F.default)(0,e.name+"."+t+" field type must be Output Type but got: "+String(o.type)+"."),S(o.resolve)||(0,F.default)(0,e.name+"."+t+" field resolver must be a function if provided, but got: "+String(o.resolve)+".");var a=r.args;a?(w(a)||(0,F.default)(0,e.name+"."+t+" args must be an object with argument names as keys."),o.args=Object.keys(a).map(function(n){(0,M.assertValidName)(n);var r=a[n];return s(r.type)||(0,F.default)(0,e.name+"."+t+"("+n+":) argument type must be Input Type but got: "+String(r.type)+"."),{name:n,description:void 0===r.description?null:r.description,type:r.type,defaultValue:r.defaultValue,astNode:r.astNode}})):o.args=[],i[t]=o}),i}function w(e){return e&&"object"===("undefined"===typeof e?"undefined":_(e))&&!Array.isArray(e)}function S(e){return null==e||"function"===typeof e}function k(e,t){var n=C(t);Array.isArray(n)&&n.length>0||(0,F.default)(0,"Must provide Array of types or a function which returns such an array for Union "+e.name+".");var r=Object.create(null);return n.forEach(function(t){t instanceof R||(0,F.default)(0,e.name+" may only contain Object types, it cannot contain: "+String(t)+"."),r[t.name]&&(0,F.default)(0,e.name+" can include "+t.name+" type only once."),r[t.name]=!0,"function"!==typeof e.resolveType&&"function"!==typeof t.isTypeOf&&(0,F.default)(0,'Union type "'+e.name+'" does not provide a "resolveType" function and possible type "'+t.name+'" does not provide an "isTypeOf" function. There is no way to resolve this possible type during execution.')}),n}function A(e,t){w(t)||(0,F.default)(0,e.name+" values must be an object with value names as keys.");var n=Object.keys(t);return n.length>0||(0,F.default)(0,e.name+" values must be an object with value names as keys."),n.map(function(n){(0,M.assertValidName)(n),-1!==["true","false","null"].indexOf(n)&&(0,F.default)(0,'Name "'+n+'" can not be used as an Enum value.');var r=t[n];return w(r)||(0,F.default)(0,e.name+"."+n+' must refer to an object with a "value" key representing an internal value but got: '+String(r)+"."),r.hasOwnProperty("isDeprecated")&&(0,F.default)(0,e.name+"."+n+' should provide "deprecationReason" instead of "isDeprecated".'),{name:n,description:r.description,isDeprecated:Boolean(r.deprecationReason),deprecationReason:r.deprecationReason,astNode:r.astNode,value:r.hasOwnProperty("value")?r.value:n}})}Object.defineProperty(t,"__esModule",{value:!0}),t.GraphQLNonNull=t.GraphQLList=t.GraphQLInputObjectType=t.GraphQLEnumType=t.GraphQLUnionType=t.GraphQLInterfaceType=t.GraphQLObjectType=t.GraphQLScalarType=void 0;var _="function"===typeof Symbol&&"symbol"===typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"===typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},T=Object.assign||function(e){for(var t=1;t0||(0,F.default)(0,this.name+" fields must be an object with field names as keys or a function which returns such an object.");var r=Object.create(null);return n.forEach(function(n){(0,M.assertValidName)(n);var i=T({},t[n],{name:n});s(i.type)||(0,F.default)(0,e.name+"."+n+" field type must be Input Type but got: "+String(i.type)+"."),null!=i.resolve&&(0,F.default)(0,e.name+"."+n+" field type has a resolve property, but Input Types cannot define resolvers."),r[n]=i}),r},e.prototype.toString=function(){return this.name},e}();z.prototype.toJSON=z.prototype.inspect=z.prototype.toString;var G=t.GraphQLList=function(){function e(t){i(this,e),o(t)||(0,F.default)(0,"Can only create List of a GraphQLType but got: "+String(t)+"."),this.ofType=t}return e.prototype.toString=function(){return"["+String(this.ofType)+"]"},e}();G.prototype.toJSON=G.prototype.inspect=G.prototype.toString;var V=t.GraphQLNonNull=function(){function e(t){i(this,e),(!o(t)||t instanceof e)&&(0,F.default)(0,"Can only create NonNull of a Nullable GraphQLType but got: "+String(t)+"."),this.ofType=t}return e.prototype.toString=function(){return this.ofType.toString()+"!"},e}();V.prototype.toJSON=V.prototype.inspect=V.prototype.toString},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var r=n(390);Object.defineProperty(t,"graphql",{enumerable:!0,get:function(){return r.graphql}});var i=n(393);Object.defineProperty(t,"GraphQLSchema",{enumerable:!0,get:function(){return i.GraphQLSchema}}),Object.defineProperty(t,"GraphQLScalarType",{enumerable:!0,get:function(){return i.GraphQLScalarType}}),Object.defineProperty(t,"GraphQLObjectType",{enumerable:!0,get:function(){return i.GraphQLObjectType}}),Object.defineProperty(t,"GraphQLInterfaceType",{enumerable:!0,get:function(){return i.GraphQLInterfaceType}}),Object.defineProperty(t,"GraphQLUnionType",{enumerable:!0,get:function(){return i.GraphQLUnionType}}),Object.defineProperty(t,"GraphQLEnumType",{enumerable:!0,get:function(){return i.GraphQLEnumType}}),Object.defineProperty(t,"GraphQLInputObjectType",{enumerable:!0,get:function(){return i.GraphQLInputObjectType}}),Object.defineProperty(t,"GraphQLList",{enumerable:!0,get:function(){return i.GraphQLList}}),Object.defineProperty(t,"GraphQLNonNull",{enumerable:!0,get:function(){return i.GraphQLNonNull}}),Object.defineProperty(t,"GraphQLDirective",{enumerable:!0,get:function(){return i.GraphQLDirective}}),Object.defineProperty(t,"TypeKind",{enumerable:!0,get:function(){return i.TypeKind}}),Object.defineProperty(t,"DirectiveLocation",{enumerable:!0,get:function(){return i.DirectiveLocation}}),Object.defineProperty(t,"GraphQLInt",{enumerable:!0,get:function(){return i.GraphQLInt}}),Object.defineProperty(t,"GraphQLFloat",{enumerable:!0,get:function(){return i.GraphQLFloat}}),Object.defineProperty(t,"GraphQLString",{enumerable:!0,get:function(){return i.GraphQLString}}),Object.defineProperty(t,"GraphQLBoolean",{enumerable:!0,get:function(){return i.GraphQLBoolean}}),Object.defineProperty(t,"GraphQLID",{enumerable:!0,get:function(){return i.GraphQLID}}),Object.defineProperty(t,"specifiedDirectives",{enumerable:!0,get:function(){return i.specifiedDirectives}}),Object.defineProperty(t,"GraphQLIncludeDirective",{enumerable:!0,get:function(){return i.GraphQLIncludeDirective}}),Object.defineProperty(t,"GraphQLSkipDirective",{enumerable:!0,get:function(){return i.GraphQLSkipDirective}}),Object.defineProperty(t,"GraphQLDeprecatedDirective",{enumerable:!0,get:function(){return i.GraphQLDeprecatedDirective}}),Object.defineProperty(t,"DEFAULT_DEPRECATION_REASON",{enumerable:!0,get:function(){return i.DEFAULT_DEPRECATION_REASON}}),Object.defineProperty(t,"SchemaMetaFieldDef",{enumerable:!0,get:function(){return i.SchemaMetaFieldDef}}),Object.defineProperty(t,"TypeMetaFieldDef",{enumerable:!0,get:function(){return i.TypeMetaFieldDef}}),Object.defineProperty(t,"TypeNameMetaFieldDef",{enumerable:!0,get:function(){return i.TypeNameMetaFieldDef}}),Object.defineProperty(t,"__Schema",{enumerable:!0,get:function(){return i.__Schema}}),Object.defineProperty(t,"__Directive",{enumerable:!0,get:function(){return i.__Directive}}),Object.defineProperty(t,"__DirectiveLocation",{enumerable:!0,get:function(){return i.__DirectiveLocation}}),Object.defineProperty(t,"__Type",{enumerable:!0,get:function(){return i.__Type}}),Object.defineProperty(t,"__Field",{enumerable:!0,get:function(){return i.__Field}}),Object.defineProperty(t,"__InputValue",{enumerable:!0,get:function(){return i.__InputValue}}),Object.defineProperty(t,"__EnumValue",{enumerable:!0,get:function(){return i.__EnumValue}}),Object.defineProperty(t,"__TypeKind",{enumerable:!0,get:function(){return i.__TypeKind}}),Object.defineProperty(t,"isType",{enumerable:!0,get:function(){return i.isType}}),Object.defineProperty(t,"isInputType",{enumerable:!0,get:function(){return i.isInputType}}),Object.defineProperty(t,"isOutputType",{enumerable:!0,get:function(){return i.isOutputType}}),Object.defineProperty(t,"isLeafType",{enumerable:!0,get:function(){return i.isLeafType}}),Object.defineProperty(t,"isCompositeType",{enumerable:!0,get:function(){return i.isCompositeType}}),Object.defineProperty(t,"isAbstractType",{enumerable:!0,get:function(){return i.isAbstractType}}),Object.defineProperty(t,"isNamedType",{enumerable:!0,get:function(){return i.isNamedType}}),Object.defineProperty(t,"assertType",{enumerable:!0,get:function(){return i.assertType}}),Object.defineProperty(t,"assertInputType",{enumerable:!0,get:function(){return i.assertInputType}}),Object.defineProperty(t,"assertOutputType",{enumerable:!0,get:function(){return i.assertOutputType}}),Object.defineProperty(t,"assertLeafType",{enumerable:!0,get:function(){return i.assertLeafType}}),Object.defineProperty(t,"assertCompositeType",{enumerable:!0,get:function(){return i.assertCompositeType}}),Object.defineProperty(t,"assertAbstractType",{enumerable:!0,get:function(){return i.assertAbstractType}}),Object.defineProperty(t,"assertNamedType",{enumerable:!0,get:function(){return i.assertNamedType}}),Object.defineProperty(t,"getNullableType",{enumerable:!0,get:function(){return i.getNullableType}}),Object.defineProperty(t,"getNamedType",{enumerable:!0,get:function(){return i.getNamedType}});var o=n(394);Object.defineProperty(t,"Source",{enumerable:!0,get:function(){return o.Source}}),Object.defineProperty(t,"getLocation",{enumerable:!0,get:function(){return o.getLocation}}),Object.defineProperty(t,"parse",{enumerable:!0,get:function(){return o.parse}}),Object.defineProperty(t,"parseValue",{enumerable:!0,get:function(){return o.parseValue}}),Object.defineProperty(t,"parseType",{enumerable:!0,get:function(){return o.parseType}}),Object.defineProperty(t,"print",{enumerable:!0,get:function(){return o.print}}),Object.defineProperty(t,"visit",{enumerable:!0,get:function(){return o.visit}}),Object.defineProperty(t,"visitInParallel",{enumerable:!0,get:function(){return o.visitInParallel}}),Object.defineProperty(t,"visitWithTypeInfo",{enumerable:!0,get:function(){return o.visitWithTypeInfo}}),Object.defineProperty(t,"getVisitFn",{enumerable:!0,get:function(){return o.getVisitFn}}),Object.defineProperty(t,"Kind",{enumerable:!0,get:function(){return o.Kind}}),Object.defineProperty(t,"TokenKind",{enumerable:!0,get:function(){return o.TokenKind}}),Object.defineProperty(t,"BREAK",{enumerable:!0,get:function(){return o.BREAK}});var a=n(395);Object.defineProperty(t,"execute",{enumerable:!0,get:function(){return a.execute}}),Object.defineProperty(t,"defaultFieldResolver",{enumerable:!0,get:function(){return a.defaultFieldResolver}}),Object.defineProperty(t,"responsePathAsArray",{enumerable:!0,get:function(){return a.responsePathAsArray}}),Object.defineProperty(t,"getDirectiveValues",{enumerable:!0,get:function(){return a.getDirectiveValues}});var s=n(396);Object.defineProperty(t,"subscribe",{enumerable:!0,get:function(){return s.subscribe}}),Object.defineProperty(t,"createSourceEventStream",{enumerable:!0,get:function(){return s.createSourceEventStream}});var u=n(399);Object.defineProperty(t,"validate",{enumerable:!0,get:function(){return u.validate}}),Object.defineProperty(t,"ValidationContext",{enumerable:!0,get:function(){return u.ValidationContext}}),Object.defineProperty(t,"specifiedRules",{enumerable:!0,get:function(){return u.specifiedRules}}),Object.defineProperty(t,"ArgumentsOfCorrectTypeRule",{enumerable:!0,get:function(){return u.ArgumentsOfCorrectTypeRule}}),Object.defineProperty(t,"DefaultValuesOfCorrectTypeRule",{enumerable:!0,get:function(){return u.DefaultValuesOfCorrectTypeRule}}),Object.defineProperty(t,"FieldsOnCorrectTypeRule",{enumerable:!0,get:function(){return u.FieldsOnCorrectTypeRule}}),Object.defineProperty(t,"FragmentsOnCompositeTypesRule",{enumerable:!0,get:function(){return u.FragmentsOnCompositeTypesRule}}),Object.defineProperty(t,"KnownArgumentNamesRule",{enumerable:!0,get:function(){return u.KnownArgumentNamesRule}}),Object.defineProperty(t,"KnownDirectivesRule",{enumerable:!0,get:function(){return u.KnownDirectivesRule}}),Object.defineProperty(t,"KnownFragmentNamesRule",{enumerable:!0,get:function(){return u.KnownFragmentNamesRule}}),Object.defineProperty(t,"KnownTypeNamesRule",{enumerable:!0,get:function(){return u.KnownTypeNamesRule}}),Object.defineProperty(t,"LoneAnonymousOperationRule",{enumerable:!0,get:function(){return u.LoneAnonymousOperationRule}}),Object.defineProperty(t,"NoFragmentCyclesRule",{enumerable:!0,get:function(){return u.NoFragmentCyclesRule}}),Object.defineProperty(t,"NoUndefinedVariablesRule",{enumerable:!0,get:function(){return u.NoUndefinedVariablesRule}}),Object.defineProperty(t,"NoUnusedFragmentsRule",{enumerable:!0,get:function(){return u.NoUnusedFragmentsRule}}),Object.defineProperty(t,"NoUnusedVariablesRule",{enumerable:!0,get:function(){return u.NoUnusedVariablesRule}}),Object.defineProperty(t,"OverlappingFieldsCanBeMergedRule",{enumerable:!0,get:function(){return u.OverlappingFieldsCanBeMergedRule}}),Object.defineProperty(t,"PossibleFragmentSpreadsRule",{enumerable:!0,get:function(){return u.PossibleFragmentSpreadsRule}}),Object.defineProperty(t,"ProvidedNonNullArgumentsRule",{enumerable:!0,get:function(){return u.ProvidedNonNullArgumentsRule}}),Object.defineProperty(t,"ScalarLeafsRule",{enumerable:!0,get:function(){return u.ScalarLeafsRule}}),Object.defineProperty(t,"SingleFieldSubscriptionsRule",{enumerable:!0,get:function(){return u.SingleFieldSubscriptionsRule}}),Object.defineProperty(t,"UniqueArgumentNamesRule",{enumerable:!0,get:function(){return u.UniqueArgumentNamesRule}}),Object.defineProperty(t,"UniqueDirectivesPerLocationRule",{enumerable:!0,get:function(){return u.UniqueDirectivesPerLocationRule}}),Object.defineProperty(t,"UniqueFragmentNamesRule",{enumerable:!0,get:function(){return u.UniqueFragmentNamesRule}}),Object.defineProperty(t,"UniqueInputFieldNamesRule",{enumerable:!0,get:function(){return u.UniqueInputFieldNamesRule}}),Object.defineProperty(t,"UniqueOperationNamesRule",{enumerable:!0,get:function(){return u.UniqueOperationNamesRule}}),Object.defineProperty(t,"UniqueVariableNamesRule",{enumerable:!0,get:function(){return u.UniqueVariableNamesRule}}),Object.defineProperty(t,"VariablesAreInputTypesRule",{enumerable:!0,get:function(){return u.VariablesAreInputTypesRule}}),Object.defineProperty(t,"VariablesInAllowedPositionRule",{enumerable:!0,get:function(){return u.VariablesInAllowedPositionRule}});var c=n(3);Object.defineProperty(t,"GraphQLError",{enumerable:!0,get:function(){return c.GraphQLError}}),Object.defineProperty(t,"formatError",{enumerable:!0,get:function(){return c.formatError}});var l=n(400);Object.defineProperty(t,"introspectionQuery",{enumerable:!0,get:function(){return l.introspectionQuery}}),Object.defineProperty(t,"getOperationAST",{enumerable:!0,get:function(){return l.getOperationAST}}),Object.defineProperty(t,"buildClientSchema",{enumerable:!0,get:function(){return l.buildClientSchema}}),Object.defineProperty(t,"buildASTSchema",{enumerable:!0,get:function(){return l.buildASTSchema}}),Object.defineProperty(t,"buildSchema",{enumerable:!0,get:function(){return l.buildSchema}}),Object.defineProperty(t,"extendSchema",{enumerable:!0,get:function(){return l.extendSchema}}),Object.defineProperty(t,"printSchema",{enumerable:!0,get:function(){return l.printSchema}}),Object.defineProperty(t,"printIntrospectionSchema",{enumerable:!0,get:function(){return l.printIntrospectionSchema}}),Object.defineProperty(t,"printType",{enumerable:!0,get:function(){return l.printType}}),Object.defineProperty(t,"typeFromAST",{enumerable:!0,get:function(){return l.typeFromAST}}),Object.defineProperty(t,"valueFromAST",{enumerable:!0,get:function(){return l.valueFromAST}}),Object.defineProperty(t,"astFromValue",{enumerable:!0,get:function(){return l.astFromValue}}),Object.defineProperty(t,"TypeInfo",{enumerable:!0,get:function(){return l.TypeInfo}}),Object.defineProperty(t,"isValidJSValue",{enumerable:!0,get:function(){return l.isValidJSValue}}),Object.defineProperty(t,"isValidLiteralValue",{enumerable:!0,get:function(){return l.isValidLiteralValue}}),Object.defineProperty(t,"concatAST",{enumerable:!0,get:function(){return l.concatAST}}),Object.defineProperty(t,"separateOperations",{enumerable:!0,get:function(){return l.separateOperations}}),Object.defineProperty(t,"isEqualType",{enumerable:!0,get:function(){return l.isEqualType}}),Object.defineProperty(t,"isTypeSubTypeOf",{enumerable:!0,get:function(){return l.isTypeSubTypeOf}}),Object.defineProperty(t,"doTypesOverlap",{enumerable:!0,get:function(){return l.doTypesOverlap}}),Object.defineProperty(t,"assertValidName",{enumerable:!0,get:function(){return l.assertValidName}}),Object.defineProperty(t,"findBreakingChanges",{enumerable:!0,get:function(){return l.findBreakingChanges}}),Object.defineProperty(t,"findDangerousChanges",{enumerable:!0,get:function(){return l.findDangerousChanges}}),Object.defineProperty(t,"BreakingChangeType",{enumerable:!0,get:function(){return l.BreakingChangeType}}),Object.defineProperty(t,"DangerousChangeType",{enumerable:!0,get:function(){return l.DangerousChangeType}}),Object.defineProperty(t,"findDeprecatedUsages",{enumerable:!0,get:function(){return l.findDeprecatedUsages}})},function(e,t,n){"use strict";function r(e,t){return e===t}function i(e,t,n){if(null===t||null===n||t.length!==n.length)return!1;for(var r=t.length,i=0;i1&&void 0!==arguments[1]?arguments[1]:r,n=null,o=null;return function(){return i(t,n,arguments)||(o=e.apply(null,arguments)),n=arguments,o}}function a(e){var t=Array.isArray(e[0])?e[0]:e;if(!t.every(function(e){return"function"===typeof e})){var n=t.map(function(e){return typeof e}).join(", ");throw new Error("Selector creators expect all input-selectors to be functions, instead received the following types: ["+n+"]")}return t}function s(e){for(var t=arguments.length,n=Array(t>1?t-1:0),r=1;r1&&void 0!==arguments[1]?arguments[1]:c;if("object"!==typeof e)throw new Error("createStructuredSelector expects first argument to be an object where each property is a selector, instead received a "+typeof e);var n=Object.keys(e);return t(n.map(function(t){return e[t]}),function(){for(var e=arguments.length,t=Array(e),r=0;r>>0;if(""+n!==t||4294967295===n)return NaN;t=n}return t<0?a(e)+t:t}function u(){return!0}function c(e,t,n){return(0===e&&!d(e)||void 0!==n&&e<=-n)&&(void 0===t||void 0!==n&&t>=n)}function l(e,t){return f(e,t,0)}function p(e,t){return f(e,t,t)}function f(e,t,n){return void 0===e?n:d(e)?t===1/0?t:0|Math.max(0,t+e):void 0===t||t===e?e:0|Math.min(t,e)}function d(e){return e<0||0===e&&1/e===-1/0}function h(e){return m(e)||x(e)}function m(e){return!(!e||!e[hn])}function g(e){return!(!e||!e[mn])}function y(e){return!(!e||!e[gn])}function v(e){return g(e)||y(e)}function b(e){return!(!e||!e[yn])}function x(e){return!(!e||!e[vn])}function C(e){return!(!e||"function"!==typeof e.equals||"function"!==typeof e.hashCode)}function E(e,t,n,r){var i=0===e?t:1===e?n:[t,n];return r?r.value=i:r={value:i,done:!1},r}function D(){return{value:void 0,done:!0}}function w(e){return!!A(e)}function S(e){return e&&"function"===typeof e.next}function k(e){var t=A(e);return t&&t.call(e)}function A(e){var t=e&&(kn&&e[kn]||e[An]);if("function"===typeof t)return t}function _(e){return e&&"number"===typeof e.length}function T(e){return!(!e||!e[Pn])}function O(){return Rn||(Rn=new Mn([]))}function F(e){var t=Array.isArray(e)?new Mn(e):S(e)?new Un(e):w(e)?new $n(e):void 0;if(t)return t.fromEntrySeq();if("object"===typeof e)return new jn(e);throw new TypeError("Expected Array or collection object of [k, v] entries, or keyed object: "+e)}function N(e){var t=L(e);if(t)return t;throw new TypeError("Expected Array or collection object of values: "+e)}function I(e){var t=L(e);if(t)return t;if("object"===typeof e)return new jn(e);throw new TypeError("Expected Array or collection object of values, or keyed object: "+e)}function L(e){return _(e)?new Mn(e):S(e)?new Un(e):w(e)?new $n(e):void 0}function P(e,t){if(e===t||e!==e&&t!==t)return!0;if(!e||!t)return!1;if("function"===typeof e.valueOf&&"function"===typeof t.valueOf){if(e=e.valueOf(),t=t.valueOf(),e===t||e!==e&&t!==t)return!0;if(!e||!t)return!1}return!!(C(e)&&C(t)&&e.equals(t))}function M(e){return e>>>1&1073741824|3221225471&e}function j(e){if(!1===e||null===e||void 0===e)return 0;if("function"===typeof e.valueOf&&(!1===(e=e.valueOf())||null===e||void 0===e))return 0;if(!0===e)return 1;var t=typeof e;if("number"===t){if(e!==e||e===1/0)return 0;var n=0|e;for(n!==e&&(n^=4294967295*e);e>4294967295;)e/=4294967295,n^=e;return M(n)}if("string"===t)return e.length>Qn?R(e):B(e);if("function"===typeof e.hashCode)return M(e.hashCode());if("object"===t)return $(e);if("function"===typeof e.toString)return B(e.toString());throw new Error("Value type "+t+" cannot be hashed.")}function R(e){var t=Yn[e];return void 0===t&&(t=B(e),Jn===Kn&&(Jn=0,Yn={}),Jn++,Yn[e]=t),t}function B(e){for(var t=0,n=0;n0)switch(e.nodeType){case 1:return e.uniqueID;case 9:return e.documentElement&&e.documentElement.uniqueID}}function z(e){var t=ue(e);return t._iter=e,t.size=e.size,t.flip=function(){return e},t.reverse=function(){var t=e.reverse.apply(this);return t.flip=function(){return e.reverse()},t},t.has=function(t){return e.includes(t)},t.includes=function(t){return e.has(t)},t.cacheResult=ce,t.__iterateUncached=function(t,n){var r=this;return e.__iterate(function(e,n){return!1!==t(n,e,r)},n)},t.__iteratorUncached=function(t,n){if(t===Sn){var r=e.__iterator(t,n);return new Tn(function(){var e=r.next();if(!e.done){var t=e.value[0];e.value[0]=e.value[1],e.value[1]=t}return e})}return e.__iterator(t===wn?Dn:wn,n)},t}function G(e,t,n){var r=ue(e);return r.size=e.size,r.has=function(t){return e.has(t)},r.get=function(r,i){var o=e.get(r,pn);return o===pn?i:t.call(n,o,r,e)},r.__iterateUncached=function(r,i){var o=this;return e.__iterate(function(e,i,a){return!1!==r(t.call(n,e,i,a),i,o)},i)},r.__iteratorUncached=function(r,i){var o=e.__iterator(Sn,i);return new Tn(function(){var i=o.next();if(i.done)return i;var a=i.value,s=a[0];return E(r,s,t.call(n,a[1],s,e),i)})},r}function V(e,t){var n=this,r=ue(e);return r._iter=e,r.size=e.size,r.reverse=function(){return e},e.flip&&(r.flip=function(){var t=z(e);return t.reverse=function(){return e.flip()},t}),r.get=function(n,r){return e.get(t?n:-1-n,r)},r.has=function(n){return e.has(t?n:-1-n)},r.includes=function(t){return e.includes(t)},r.cacheResult=ce,r.__iterate=function(n,r){var i=this,o=0;return r&&a(e),e.__iterate(function(e,a){return n(e,t?a:r?i.size-++o:o++,i)},!r)},r.__iterator=function(r,i){var o=0;i&&a(e);var s=e.__iterator(Sn,!i);return new Tn(function(){var e=s.next();if(e.done)return e;var a=e.value;return E(r,t?a[0]:i?n.size-++o:o++,a[1],e)})},r}function q(e,t,n,r){var i=ue(e);return r&&(i.has=function(r){var i=e.get(r,pn);return i!==pn&&!!t.call(n,i,r,e)},i.get=function(r,i){var o=e.get(r,pn);return o!==pn&&t.call(n,o,r,e)?o:i}),i.__iterateUncached=function(i,o){var a=this,s=0;return e.__iterate(function(e,o,u){if(t.call(n,e,o,u))return s++,i(e,r?o:s-1,a)},o),s},i.__iteratorUncached=function(i,o){var a=e.__iterator(Sn,o),s=0;return new Tn(function(){for(;;){var o=a.next();if(o.done)return o;var u=o.value,c=u[0],l=u[1];if(t.call(n,l,c,e))return E(i,r?c:s++,l,o)}})},i}function H(e,t,n){var r=nr().asMutable();return e.__iterate(function(i,o){r.update(t.call(n,i,o,e),0,function(e){return e+1})}),r.asImmutable()}function W(e,t,n){var r=g(e),i=(b(e)?Cr():nr()).asMutable();e.__iterate(function(o,a){i.update(t.call(n,o,a,e),function(e){return e=e||[],e.push(r?[a,o]:o),e})});var o=se(e);return i.map(function(t){return oe(e,o(t))})}function Q(e,t,n,r){var i=e.size;if(c(t,n,i))return e;var o=l(t,i),a=p(n,i);if(o!==o||a!==a)return Q(e.toSeq().cacheResult(),t,n,r);var u,f=a-o;f===f&&(u=f<0?0:f);var d=ue(e);return d.size=0===u?u:e.size&&u||void 0,!r&&T(e)&&u>=0&&(d.get=function(t,n){return t=s(this,t),t>=0&&tu)return D();var e=i.next();return r||t===wn||e.done?e:t===Dn?E(t,s-1,void 0,e):E(t,s-1,e.value[1],e)})},d}function K(e,t,n){var r=ue(e);return r.__iterateUncached=function(r,i){var o=this;if(i)return this.cacheResult().__iterate(r,i);var a=0;return e.__iterate(function(e,i,s){return t.call(n,e,i,s)&&++a&&r(e,i,o)}),a},r.__iteratorUncached=function(r,i){var o=this;if(i)return this.cacheResult().__iterator(r,i);var a=e.__iterator(Sn,i),s=!0;return new Tn(function(){if(!s)return D();var e=a.next();if(e.done)return e;var i=e.value,u=i[0],c=i[1];return t.call(n,c,u,o)?r===Sn?e:E(r,u,c,e):(s=!1,D())})},r}function J(e,t,n,r){var i=ue(e);return i.__iterateUncached=function(i,o){var a=this;if(o)return this.cacheResult().__iterate(i,o);var s=!0,u=0;return e.__iterate(function(e,o,c){if(!s||!(s=t.call(n,e,o,c)))return u++,i(e,r?o:u-1,a)}),u},i.__iteratorUncached=function(i,o){var a=this;if(o)return this.cacheResult().__iterator(i,o);var s=e.__iterator(Sn,o),u=!0,c=0;return new Tn(function(){var e,o,l;do{if(e=s.next(),e.done)return r||i===wn?e:i===Dn?E(i,c++,void 0,e):E(i,c++,e.value[1],e);var p=e.value;o=p[0],l=p[1],u&&(u=t.call(n,l,o,a))}while(u);return i===Sn?e:E(i,o,l,e)})},i}function Y(e,t){var n=g(e),r=[e].concat(t).map(function(e){return m(e)?n&&(e=xn(e)):e=n?F(e):N(Array.isArray(e)?e:[e]),e}).filter(function(e){return 0!==e.size});if(0===r.length)return e;if(1===r.length){var i=r[0];if(i===e||n&&g(i)||y(e)&&y(i))return i}var o=new Mn(r);return n?o=o.toKeyedSeq():y(e)||(o=o.toSetSeq()),o=o.flatten(!0),o.size=r.reduce(function(e,t){if(void 0!==e){var n=t.size;if(void 0!==n)return e+n}},0),o}function X(e,t,n){var r=ue(e);return r.__iterateUncached=function(i,o){function a(e,c){e.__iterate(function(e,o){return(!t||c0}function ie(e,t,n,r){var i=ue(e),o=new Mn(n).map(function(e){return e.size});return i.size=r?o.max():o.min(),i.__iterate=function(e,t){for(var n,r=this,i=this.__iterator(wn,t),o=0;!(n=i.next()).done&&!1!==e(n.value,o++,r););return o},i.__iteratorUncached=function(e,i){var o=n.map(function(e){return e=bn(e),k(i?e.reverse():e)}),a=0,s=!1;return new Tn(function(){var n;return s||(n=o.map(function(e){return e.next()}),s=r?n.every(function(e){return e.done}):n.some(function(e){return e.done})),s?D():E(e,a++,t.apply(null,n.map(function(e){return e.value})))})},i}function oe(e,t){return e===t?e:T(e)?t:e.constructor(t)}function ae(e){if(e!==Object(e))throw new TypeError("Expected [K, V] tuple: "+e)}function se(e){return g(e)?xn:y(e)?Cn:En}function ue(e){return Object.create((g(e)?Nn:y(e)?In:Ln).prototype)}function ce(){return this._iter.cacheResult?(this._iter.cacheResult(),this.size=this._iter.size,this):Fn.prototype.cacheResult.call(this)}function le(e,t){return void 0===e&&void 0===t?0:void 0===e?1:void 0===t?-1:e>t?1:e0;)t[n]=arguments[n+1];return Le(this,t,e)}function Le(e,t,n){for(var r=[],i=0;i0;)t[n]=arguments[n+1];return $e(e,t)}function Me(e,t){for(var n=[],r=arguments.length-2;r-- >0;)n[r]=arguments[r+2];return $e(t,n,e)}function je(e){for(var t=[],n=arguments.length-1;n-- >0;)t[n]=arguments[n+1];return Be(e,t)}function Re(e,t){for(var n=[],r=arguments.length-2;r-- >0;)n[r]=arguments[r+2];return Be(t,n,e)}function Be(e,t,n){return $e(e,t,Ue(n))}function $e(e,t,n){if(!ge(e))throw new TypeError("Cannot merge into non-data-structure value: "+e);if(h(e))return e.mergeWith?e.mergeWith.apply(e,[n].concat(t)):e.concat.apply(e,t);for(var r=Array.isArray(e),i=e,o=r?Cn:xn,a=r?function(t){i===e&&(i=xe(i)),i.push(t)}:function(t,r){var o=On.call(i,r),a=o&&n?n(i[r],t,r):t;o&&a===i[r]||(i===e&&(i=xe(i)),i[r]=a)},s=0;s0;)t[n]=arguments[n+1];return Be(this,t,e)}function Ve(e){for(var t=[],n=arguments.length-1;n-- >0;)t[n]=arguments[n+1];return De(this,e,et(),function(e){return $e(e,t)})}function qe(e){for(var t=[],n=arguments.length-1;n-- >0;)t[n]=arguments[n+1];return De(this,e,et(),function(e){return Be(e,t)})}function He(e){var t=this.asMutable();return e(t),t.wasAltered()?t.__ensureOwner(this.__ownerID):this}function We(){return this.__ownerID?this:this.__ensureOwner(new o)}function Qe(){return this.__ensureOwner()}function Ke(){return this.__altered}function Je(e){return!(!e||!e[rr])}function Ye(e,t){return E(e,t[0],t[1])}function Xe(e,t){return{node:e,index:0,__prev:t}}function Ze(e,t,n,r){var i=Object.create(ir);return i.size=e,i._root=t,i.__ownerID=n,i.__hash=r,i.__altered=!1,i}function et(){return lr||(lr=Ze(0))}function tt(e,t,n){var i,o;if(e._root){var a=r(fn),s=r(dn);if(i=nt(e._root,e.__ownerID,0,void 0,t,n,a,s),!s.value)return e;o=e.size+(a.value?n===pn?-1:1:0)}else{if(n===pn)return e;o=1,i=new or(e.__ownerID,[[t,n]])}return e.__ownerID?(e.size=o,e._root=i,e.__hash=void 0,e.__altered=!0,e):i?Ze(o,i):et()}function nt(e,t,n,r,o,a,s,u){return e?e.update(t,n,r,o,a,s,u):a===pn?e:(i(u),i(s),new cr(t,r,[o,a]))}function rt(e){return e.constructor===cr||e.constructor===ur}function it(e,t,n,r,i){if(e.keyHash===r)return new ur(t,r,[e.entry,i]);var o,a=(0===n?e.keyHash:e.keyHash>>>n)&ln,s=(0===n?r:r>>>n)&ln,u=a===s?[it(e,t,n+un,r,i)]:(o=new cr(t,r,i),a>>=1)a[s]=1&n?t[o++]:void 0;return a[r]=i,new sr(e,o+1,a)}function ut(e){return e-=e>>1&1431655765,e=(858993459&e)+(e>>2&858993459),e=e+(e>>4)&252645135,e+=e>>8,127&(e+=e>>16)}function ct(e,t,n,r){var i=r?e:pe(e);return i[t]=n,i}function lt(e,t,n,r){var i=e.length+1;if(r&&t+1===i)return e[t]=n,e;for(var o=new Array(i),a=0,s=0;so?0:o-n,c=a-n;return c>cn&&(c=cn),function(){if(i===c)return xr;var e=t?--c:i++;return r&&r[e]}}function i(e,r,i){var s,u=e&&e.array,c=i>o?0:o-i>>r,l=1+(a-i>>r);return l>cn&&(l=cn),function(){for(;;){if(s){var e=s();if(e!==xr)return e;s=null}if(c===l)return xr;var o=t?--l:c++;s=n(u&&u[o],r-un,i+(o<=e.size||t<0)return e.withMutations(function(e){t<0?xt(e,t).set(0,n):xt(e,0,t+1).set(t,n)});t+=e._origin;var i=e._tail,o=e._root,a=r(dn);return t>=Ct(e._capacity)?i=yt(i,e.__ownerID,0,t,n,a):o=yt(o,e.__ownerID,e._level,t,n,a),a.value?e.__ownerID?(e._root=o,e._tail=i,e.__hash=void 0,e.__altered=!0,e):ht(e._origin,e._capacity,e._level,o,i):e}function yt(e,t,n,r,o,a){var s=r>>>n&ln,u=e&&s0){var l=e&&e.array[s],p=yt(l,t,n-un,r,o,a);return p===l?e:(c=vt(e,t),c.array[s]=p,c)}return u&&e.array[s]===o?e:(i(a),c=vt(e,t),void 0===o&&s===c.array.length-1?c.array.pop():c.array[s]=o,c)}function vt(e,t){return t&&e&&t===e.ownerID?e:new vr(e?e.array.slice():[],t)}function bt(e,t){if(t>=Ct(e._capacity))return e._tail;if(t<1<0;)n=n.array[t>>>r&ln],r-=un;return n}}function xt(e,t,n){void 0!==t&&(t|=0),void 0!==n&&(n|=0);var r=e.__ownerID||new o,i=e._origin,a=e._capacity,s=i+t,u=void 0===n?a:n<0?a+n:i+n;if(s===i&&u===a)return e;if(s>=u)return e.clear();for(var c=e._level,l=e._root,p=0;s+p<0;)l=new vr(l&&l.array.length?[void 0,l]:[],r),c+=un,p+=1<=1<f?new vr([],r):h;if(h&&d>f&&sun;y-=un){var v=f>>>y&ln;g=g.array[v]=vt(g.array[v],r)}g.array[f>>>un&ln]=h}if(u=d)s-=d,u-=d,c=un,l=null,m=m&&m.removeBefore(r,0,s);else if(s>i||d>>c&ln;if(b!==d>>>c&ln)break;b&&(p+=(1<i&&(l=l.removeBefore(r,c,s-p)),l&&d>>un<=cn&&a.size>=2*o.size?(i=a.filter(function(e,t){return void 0!==e&&s!==t}),r=i.toKeyedSeq().map(function(e){return e[0]}).flip().toMap(),e.__ownerID&&(r.__ownerID=i.__ownerID=e.__ownerID)):(r=o.remove(t),i=s===a.size-1?a.pop():a.set(s,void 0))}else if(u){if(n===a.get(s)[1])return e;r=o,i=a.set(s,[t,n])}else r=o.set(t,a.size),i=a.set(a.size,[t,n]);return e.__ownerID?(e.size=r.size,e._map=r,e._list=i,e.__hash=void 0,e):Dt(r,i)}function kt(e){return!(!e||!e[wr])}function At(e,t,n,r){var i=Object.create(Sr);return i.size=e,i._head=t,i.__ownerID=n,i.__hash=r,i.__altered=!1,i}function _t(){return kr||(kr=At(0))}function Tt(e,t){if(e===t)return!0;if(!m(t)||void 0!==e.size&&void 0!==t.size&&e.size!==t.size||void 0!==e.__hash&&void 0!==t.__hash&&e.__hash!==t.__hash||g(e)!==g(t)||y(e)!==y(t)||b(e)!==b(t))return!1;if(0===e.size&&0===t.size)return!0;var n=!v(e);if(b(e)){var r=e.entries();return t.every(function(e,t){var i=r.next().value;return i&&P(i[1],e)&&(n||P(i[0],t))})&&r.next().done}var i=!1;if(void 0===e.size)if(void 0===t.size)"function"===typeof e.cacheResult&&e.cacheResult();else{i=!0;var o=e;e=t,t=o}var a=!0,s=t.__iterate(function(t,r){if(n?!e.has(t):i?!P(t,e.get(r,pn)):!P(e.get(r,pn),t))return a=!1,!1});return a&&e.size===s}function Ot(e,t){var n=function(n){e.prototype[n]=t[n]};return Object.keys(t).forEach(n),Object.getOwnPropertySymbols&&Object.getOwnPropertySymbols(t).forEach(n),e}function Ft(e){return ge(e)?Fn(e).map(Ft).toJSON():e}function Nt(e){return!(!e||!e[_r])}function It(e,t){return e.__ownerID?(e.size=t.size,e._map=t,e):t===e._map?e:0===t.size?e.__empty():e.__make(t)}function Lt(e,t){var n=Object.create(Tr);return n.size=e?e.size:0,n._map=e,n.__ownerID=t,n}function Pt(){return Or||(Or=Lt(et()))}function Mt(e,t,n){for(var r=he(t),i=0;i!==r.length;)if((e=be(e,r[i++],pn))===pn)return n;return e}function jt(e,t){return Mt(this,e,t)}function Rt(e,t){return Mt(e,t,pn)!==pn}function Bt(e){return Rt(this,e)}function $t(){de(this.size);var e={};return this.__iterate(function(t,n){e[n]=t}),e}function Ut(e,t,n,r,i,o){return de(e.size),e.__iterate(function(e,o,a){i?(i=!1,n=e):n=t.call(r,n,e,o,a)},o),n}function zt(e,t){return t}function Gt(e,t){return[t,e]}function Vt(e){return function(){return!e.apply(this,arguments)}}function qt(e){return function(){return-e.apply(this,arguments)}}function Ht(){return pe(arguments)}function Wt(e,t){return et?-1:0}function Qt(e){if(e.size===1/0)return 0;var t=b(e),n=g(e),r=t?1:0;return Kt(e.__iterate(n?t?function(e,t){r=31*r+Jt(j(e),j(t))|0}:function(e,t){r=r+Jt(j(e),j(t))|0}:t?function(e){r=31*r+j(e)|0}:function(e){r=r+j(e)|0}),r)}function Kt(e,t){return t=zn(t,3432918353),t=zn(t<<15|t>>>-15,461845907),t=zn(t<<13|t>>>-13,5),t=(t+3864292196|0)^e,t=zn(t^t>>>16,2246822507),t=zn(t^t>>>13,3266489909),t=M(t^t>>>16)}function Jt(e,t){return e^t+2654435769+(e<<6)+(e>>2)|0}function Yt(e){return Nt(e)&&b(e)}function Xt(e,t){var n=Object.create(jr);return n.size=e?e.size:0,n._map=e,n.__ownerID=t,n}function Zt(){return Rr||(Rr=Xt(wt()))}function en(e,t,n){var r=Object.create(Object.getPrototypeOf(e));return r._values=t,r.__ownerID=n,r}function tn(e){return e._name||e.constructor.name||"Record"}function nn(e){return F(e._keys.map(function(t){return[t,e.get(t)]}))}function rn(e,t){try{Object.defineProperty(e,t,{get:function(){return this.get(t)},set:function(e){fe(this.__ownerID,"Cannot set on an immutable record."),this.set(t,e)}})}catch(e){}}function on(e,t){return an([],t||sn,e,"",t&&t.length>2?[]:void 0,{"":e})}function an(e,t,n,r,i,o){var a=Array.isArray(n)?In:me(n)?Nn:null;if(a){if(~e.indexOf(n))throw new TypeError("Cannot convert circular structure to Immutable");e.push(n),i&&""!==r&&i.push(r);var s=t.call(o,r,a(n).map(function(r,o){return an(e,t,r,o,i,n)}),i&&i.slice());return e.pop(),i&&i.pop(),s}return n}function sn(e,t){return g(t)?t.toMap():t.toList()}Object.defineProperty(t,"__esModule",{value:!0}),n.d(t,"version",function(){return Gr}),n.d(t,"Collection",function(){return bn}),n.d(t,"Iterable",function(){return qr}),n.d(t,"Seq",function(){return Fn}),n.d(t,"Map",function(){return nr}),n.d(t,"OrderedMap",function(){return Cr}),n.d(t,"List",function(){return mr}),n.d(t,"Stack",function(){return Dr}),n.d(t,"Set",function(){return Ar}),n.d(t,"OrderedSet",function(){return Mr}),n.d(t,"Record",function(){return Br}),n.d(t,"Range",function(){return Nr}),n.d(t,"Repeat",function(){return zr}),n.d(t,"is",function(){return P}),n.d(t,"fromJS",function(){return on}),n.d(t,"hash",function(){return j}),n.d(t,"isImmutable",function(){return h}),n.d(t,"isCollection",function(){return m}),n.d(t,"isKeyed",function(){return g}),n.d(t,"isIndexed",function(){return y}),n.d(t,"isAssociative",function(){return v}),n.d(t,"isOrdered",function(){return b}),n.d(t,"isValueObject",function(){return C}),n.d(t,"get",function(){return be}),n.d(t,"getIn",function(){return Mt}),n.d(t,"has",function(){return ve}),n.d(t,"hasIn",function(){return Rt}),n.d(t,"merge",function(){return Pe}),n.d(t,"mergeDeep",function(){return je}),n.d(t,"mergeWith",function(){return Me}),n.d(t,"mergeDeepWith",function(){return Re}),n.d(t,"remove",function(){return Ce}),n.d(t,"removeIn",function(){return Ae}),n.d(t,"set",function(){return Ee}),n.d(t,"setIn",function(){return Se}),n.d(t,"update",function(){return Te}),n.d(t,"updateIn",function(){return De});var un=5,cn=1<=r.length){var t=n.next();if(t.done)return t;r[i]=t.value}return E(e,i,r[i++])})},t}(In),zn="function"===typeof Math.imul&&-2===Math.imul(4294967295,2)?Math.imul:function(e,t){e|=0,t|=0;var n=65535&e,r=65535&t;return n*r+((e>>>16)*r+n*(t>>>16)<<16>>>0)|0},Gn=Object.isExtensible,Vn=function(){try{return Object.defineProperty({},"@",{}),!0}catch(e){return!1}}(),qn="function"===typeof WeakMap;qn&&(Bn=new WeakMap);var Hn=0,Wn="__immutablehash__";"function"===typeof Symbol&&(Wn=Symbol(Wn));var Qn=16,Kn=255,Jn=0,Yn={},Xn=function(e){function t(e,t){this._iter=e,this._useKeys=t,this.size=e.size}return e&&(t.__proto__=e),t.prototype=Object.create(e&&e.prototype),t.prototype.constructor=t,t.prototype.get=function(e,t){return this._iter.get(e,t)},t.prototype.has=function(e){return this._iter.has(e)},t.prototype.valueSeq=function(){return this._iter.valueSeq()},t.prototype.reverse=function(){var e=this,t=V(this,!0);return this._useKeys||(t.valueSeq=function(){return e._iter.toSeq().reverse()}),t},t.prototype.map=function(e,t){var n=this,r=G(this,e,t);return this._useKeys||(r.valueSeq=function(){return n._iter.toSeq().map(e,t)}),r},t.prototype.__iterate=function(e,t){var n=this;return this._iter.__iterate(function(t,r){return e(t,r,n)},t)},t.prototype.__iterator=function(e,t){return this._iter.__iterator(e,t)},t}(Nn);Xn.prototype[yn]=!0;var Zn=function(e){function t(e){this._iter=e,this.size=e.size}return e&&(t.__proto__=e),t.prototype=Object.create(e&&e.prototype),t.prototype.constructor=t,t.prototype.includes=function(e){return this._iter.includes(e)},t.prototype.__iterate=function(e,t){var n=this,r=0;return t&&a(this),this._iter.__iterate(function(i){return e(i,t?n.size-++r:r++,n)},t)},t.prototype.__iterator=function(e,t){var n=this,r=this._iter.__iterator(wn,t),i=0;return t&&a(this),new Tn(function(){var o=r.next();return o.done?o:E(e,t?n.size-++i:i++,o.value,o)})},t}(In),er=function(e){function t(e){this._iter=e,this.size=e.size}return e&&(t.__proto__=e),t.prototype=Object.create(e&&e.prototype),t.prototype.constructor=t,t.prototype.has=function(e){return this._iter.includes(e)},t.prototype.__iterate=function(e,t){var n=this;return this._iter.__iterate(function(t){return e(t,t,n)},t)},t.prototype.__iterator=function(e,t){var n=this._iter.__iterator(wn,t);return new Tn(function(){var t=n.next();return t.done?t:E(e,t.value,t.value,t)})},t}(Ln),tr=function(e){function t(e){this._iter=e,this.size=e.size}return e&&(t.__proto__=e),t.prototype=Object.create(e&&e.prototype),t.prototype.constructor=t,t.prototype.entrySeq=function(){return this._iter.toSeq()},t.prototype.__iterate=function(e,t){var n=this;return this._iter.__iterate(function(t){if(t){ae(t);var r=m(t);return e(r?t.get(1):t[1],r?t.get(0):t[0],n)}},t)},t.prototype.__iterator=function(e,t){var n=this._iter.__iterator(wn,t);return new Tn(function(){for(;;){var t=n.next();if(t.done)return t;var r=t.value;if(r){ae(r);var i=m(r);return E(e,i?r.get(0):r[0],i?r.get(1):r[1],t)}}})},t}(Nn);Zn.prototype.cacheResult=Xn.prototype.cacheResult=er.prototype.cacheResult=tr.prototype.cacheResult=ce;var nr=function(e){function t(t){return null===t||void 0===t?et():Je(t)&&!b(t)?t:et().withMutations(function(n){var r=e(t);de(r.size),r.forEach(function(e,t){return n.set(t,e)})})}return e&&(t.__proto__=e),t.prototype=Object.create(e&&e.prototype),t.prototype.constructor=t,t.of=function(){for(var e=[],t=arguments.length;t--;)e[t]=arguments[t];return et().withMutations(function(t){for(var n=0;n=e.length)throw new Error("Missing value for key: "+e[n]);t.set(e[n],e[n+1])}})},t.prototype.toString=function(){return this.__toString("Map {","}")},t.prototype.get=function(e,t){return this._root?this._root.get(0,void 0,e,t):t},t.prototype.set=function(e,t){return tt(this,e,t)},t.prototype.remove=function(e){return tt(this,e,pn)},t.prototype.deleteAll=function(e){var t=bn(e);return 0===t.size?this:this.withMutations(function(e){t.forEach(function(t){return e.remove(t)})})},t.prototype.clear=function(){return 0===this.size?this:this.__ownerID?(this.size=0,this._root=null,this.__hash=void 0,this.__altered=!0,this):et()},t.prototype.sort=function(e){return Cr(te(this,e))},t.prototype.sortBy=function(e,t){return Cr(te(this,t,e))},t.prototype.__iterator=function(e,t){return new pr(this,e,t)},t.prototype.__iterate=function(e,t){var n=this,r=0;return this._root&&this._root.iterate(function(t){return r++,e(t[1],t[0],n)},t),r},t.prototype.__ensureOwner=function(e){return e===this.__ownerID?this:e?Ze(this.size,this._root,e,this.__hash):0===this.size?et():(this.__ownerID=e,this.__altered=!1,this)},t}(xn);nr.isMap=Je;var rr="@@__IMMUTABLE_MAP__@@",ir=nr.prototype;ir[rr]=!0,ir.delete=ir.remove,ir.removeAll=ir.deleteAll,ir.concat=ir.merge,ir.setIn=ke,ir.removeIn=ir.deleteIn=_e,ir.update=Oe,ir.updateIn=Fe,ir.merge=Ne,ir.mergeWith=Ie,ir.mergeDeep=ze,ir.mergeDeepWith=Ge,ir.mergeIn=Ve,ir.mergeDeepIn=qe,ir.withMutations=He,ir.wasAltered=Ke,ir.asImmutable=Qe,ir["@@transducer/init"]=ir.asMutable=We,ir["@@transducer/step"]=function(e,t){return e.set(t[0],t[1])},ir["@@transducer/result"]=function(e){return e.asImmutable()};var or=function(e,t){this.ownerID=e,this.entries=t};or.prototype.get=function(e,t,n,r){for(var i=this.entries,o=0,a=i.length;o=fr)return ot(e,c,r,o);var d=e&&e===this.ownerID,h=d?c:pe(c);return f?u?l===p-1?h.pop():h[l]=h.pop():h[l]=[r,o]:h.push([r,o]),d?(this.entries=h,this):new or(e,h)}};var ar=function(e,t,n){this.ownerID=e,this.bitmap=t,this.nodes=n};ar.prototype.get=function(e,t,n,r){void 0===t&&(t=j(n));var i=1<<((0===e?t:t>>>e)&ln),o=this.bitmap;return 0===(o&i)?r:this.nodes[ut(o&i-1)].get(e+un,t,n,r)},ar.prototype.update=function(e,t,n,r,i,o,a){void 0===n&&(n=j(r));var s=(0===t?n:n>>>t)&ln,u=1<=dr)return st(e,f,c,s,h);if(l&&!h&&2===f.length&&rt(f[1^p]))return f[1^p];if(l&&h&&1===f.length&&rt(h))return h;var m=e&&e===this.ownerID,g=l?h?c:c^u:c|u,y=l?h?ct(f,p,h,m):pt(f,p,m):lt(f,p,h,m);return m?(this.bitmap=g,this.nodes=y,this):new ar(e,g,y)};var sr=function(e,t,n){this.ownerID=e,this.count=t,this.nodes=n};sr.prototype.get=function(e,t,n,r){void 0===t&&(t=j(n));var i=(0===e?t:t>>>e)&ln,o=this.nodes[i];return o?o.get(e+un,t,n,r):r},sr.prototype.update=function(e,t,n,r,i,o,a){void 0===n&&(n=j(r));var s=(0===t?n:n>>>t)&ln,u=i===pn,c=this.nodes,l=c[s];if(u&&!l)return this;var p=nt(l,e,t+un,n,r,i,o,a);if(p===l)return this;var f=this.count;if(l){if(!p&&--f0&&i=0&&e>>t&ln;if(r>=this.array.length)return new vr([],e);var i,o=0===r;if(t>0){var a=this.array[r];if((i=a&&a.removeBefore(e,t-un,n))===a&&o)return this}if(o&&!i)return this;var s=vt(this,e);if(!o)for(var u=0;u>>t&ln;if(r>=this.array.length)return this;var i;if(t>0){var o=this.array[r];if((i=o&&o.removeAfter(e,t-un,n))===o&&r===this.array.length-1)return this}var a=vt(this,e);return a.array.splice(r+1),i&&(a.array[r]=i),a};var br,xr={},Cr=function(e){function t(e){return null===e||void 0===e?wt():Et(e)?e:wt().withMutations(function(t){var n=xn(e);de(n.size),n.forEach(function(e,n){return t.set(n,e)})})}return e&&(t.__proto__=e),t.prototype=Object.create(e&&e.prototype),t.prototype.constructor=t,t.of=function(){return this(arguments)},t.prototype.toString=function(){return this.__toString("OrderedMap {","}")},t.prototype.get=function(e,t){var n=this._map.get(e);return void 0!==n?this._list.get(n)[1]:t},t.prototype.clear=function(){return 0===this.size?this:this.__ownerID?(this.size=0,this._map.clear(),this._list.clear(),this):wt()},t.prototype.set=function(e,t){return St(this,e,t)},t.prototype.remove=function(e){return St(this,e,pn)},t.prototype.wasAltered=function(){return this._map.wasAltered()||this._list.wasAltered()},t.prototype.__iterate=function(e,t){var n=this;return this._list.__iterate(function(t){return t&&e(t[1],t[0],n)},t)},t.prototype.__iterator=function(e,t){return this._list.fromEntrySeq().__iterator(e,t)},t.prototype.__ensureOwner=function(e){if(e===this.__ownerID)return this;var t=this._map.__ensureOwner(e),n=this._list.__ensureOwner(e);return e?Dt(t,n,e,this.__hash):0===this.size?wt():(this.__ownerID=e,this._map=t,this._list=n,this)},t}(nr);Cr.isOrderedMap=Et,Cr.prototype[yn]=!0,Cr.prototype.delete=Cr.prototype.remove;var Er,Dr=function(e){function t(e){return null===e||void 0===e?_t():kt(e)?e:_t().pushAll(e)}return e&&(t.__proto__=e),t.prototype=Object.create(e&&e.prototype),t.prototype.constructor=t,t.of=function(){return this(arguments)},t.prototype.toString=function(){return this.__toString("Stack [","]")},t.prototype.get=function(e,t){var n=this._head;for(e=s(this,e);n&&e--;)n=n.next;return n?n.value:t},t.prototype.peek=function(){return this._head&&this._head.value},t.prototype.push=function(){var e=arguments;if(0===arguments.length)return this;for(var t=this.size+arguments.length,n=this._head,r=arguments.length-1;r>=0;r--)n={value:e[r],next:n};return this.__ownerID?(this.size=t,this._head=n,this.__hash=void 0,this.__altered=!0,this):At(t,n)},t.prototype.pushAll=function(t){if(t=e(t),0===t.size)return this;if(0===this.size&&kt(t))return t;de(t.size);var n=this.size,r=this._head;return t.__iterate(function(e){n++,r={value:e,next:r}},!0),this.__ownerID?(this.size=n,this._head=r,this.__hash=void 0,this.__altered=!0,this):At(n,r)},t.prototype.pop=function(){return this.slice(1)},t.prototype.clear=function(){return 0===this.size?this:this.__ownerID?(this.size=0,this._head=void 0,this.__hash=void 0,this.__altered=!0,this):_t()},t.prototype.slice=function(t,n){if(c(t,n,this.size))return this;var r=l(t,this.size);if(p(n,this.size)!==this.size)return e.prototype.slice.call(this,t,n);for(var i=this.size-r,o=this._head;r--;)o=o.next;return this.__ownerID?(this.size=i,this._head=o,this.__hash=void 0,this.__altered=!0,this):At(i,o)},t.prototype.__ensureOwner=function(e){return e===this.__ownerID?this:e?At(this.size,this._head,e,this.__hash):0===this.size?_t():(this.__ownerID=e,this.__altered=!1,this)},t.prototype.__iterate=function(e,t){var n=this;if(t)return new Mn(this.toArray()).__iterate(function(t,r){return e(t,r,n)},t);for(var r=0,i=this._head;i&&!1!==e(i.value,r++,n);)i=i.next;return r},t.prototype.__iterator=function(e,t){if(t)return new Mn(this.toArray()).__iterator(e,t);var n=0,r=this._head;return new Tn(function(){if(r){var t=r.value;return r=r.next,E(e,n++,t)}return D()})},t}(Cn);Dr.isStack=kt;var wr="@@__IMMUTABLE_STACK__@@",Sr=Dr.prototype;Sr[wr]=!0,Sr.shift=Sr.pop,Sr.unshift=Sr.push,Sr.unshiftAll=Sr.pushAll,Sr.withMutations=He,Sr.wasAltered=Ke,Sr.asImmutable=Qe,Sr["@@transducer/init"]=Sr.asMutable=We,Sr["@@transducer/step"]=function(e,t){return e.unshift(t)},Sr["@@transducer/result"]=function(e){return e.asImmutable()};var kr,Ar=function(e){function t(t){return null===t||void 0===t?Pt():Nt(t)&&!b(t)?t:Pt().withMutations(function(n){var r=e(t);de(r.size),r.forEach(function(e){return n.add(e)})})}return e&&(t.__proto__=e),t.prototype=Object.create(e&&e.prototype),t.prototype.constructor=t,t.of=function(){return this(arguments)},t.fromKeys=function(e){return this(xn(e).keySeq())},t.intersect=function(e){return e=bn(e).toArray(),e.length?Tr.intersect.apply(t(e.pop()),e):Pt()},t.union=function(e){return e=bn(e).toArray(),e.length?Tr.union.apply(t(e.pop()),e):Pt()},t.prototype.toString=function(){return this.__toString("Set {","}")},t.prototype.has=function(e){return this._map.has(e)},t.prototype.add=function(e){return It(this,this._map.set(e,e))},t.prototype.remove=function(e){return It(this,this._map.remove(e))},t.prototype.clear=function(){return It(this,this._map.clear())},t.prototype.union=function(){for(var t=[],n=arguments.length;n--;)t[n]=arguments[n];return t=t.filter(function(e){return 0!==e.size}),0===t.length?this:0!==this.size||this.__ownerID||1!==t.length?this.withMutations(function(n){for(var r=0;r=0&&t=0&&nthis.size?t:this.find(function(t,n){return n===e},void 0,t)},has:function(e){return(e=s(this,e))>=0&&(void 0!==this.size?this.size===1/0||e=0&&e.splice(n,1)}function a(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},t=d({},e),n=new Promise(function(e,n){t.resolve=e,t.reject=n});return t.promise=n,t}function s(e){for(var t=[],n=0;n1&&void 0!==arguments[1])||arguments[1],n=void 0,r=new Promise(function(r){n=setTimeout(function(){return r(t)},e)});return r[b]=function(){return clearTimeout(n)},r}function c(){var e,t=!0,n=void 0,r=void 0;return e={},e[g]=!0,e.isRunning=function(){return t},e.result=function(){return n},e.error=function(){return r},e.setRunning=function(e){return t=e},e.setResult=function(e){return n=e},e.setError=function(e){return r=e},e}function l(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:F,n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:"",r=arguments[3],i={name:n,next:e,throw:t,return:N};return r&&(i[y]=!0),"undefined"!==typeof Symbol&&(i[Symbol.iterator]=function(){return i}),i}function p(e,t){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:"";"undefined"===typeof window?console.log("redux-saga "+e+": "+t+"\n"+(n&&n.stack||n)):console[e](t,n)}function f(e,t){return function(){return e.apply(void 0,arguments)}}n.d(t,"x",function(){return m}),n.d(t,"e",function(){return g}),n.d(t,"b",function(){return v}),n.d(t,"a",function(){return b}),n.d(t,"c",function(){return x}),n.d(t,"d",function(){return C}),n.d(t,"r",function(){return D}),n.d(t,"u",function(){return w}),n.d(t,"o",function(){return S}),t.h=r,n.d(t,"q",function(){return A}),n.d(t,"v",function(){return _}),t.w=o,n.d(t,"f",function(){return T}),t.l=a,t.g=s,t.m=u,t.j=c,n.d(t,"y",function(){return O}),t.t=l,t.s=p,t.n=f,n.d(t,"z",function(){return I}),n.d(t,"p",function(){return L}),n.d(t,"k",function(){return P}),n.d(t,"A",function(){return M}),n.d(t,"i",function(){return j});var d=Object.assign||function(e){for(var t=1;t0&&void 0!==arguments[0]?arguments[0]:0;return function(){return++e}}(),F=function(e){throw e},N=function(e){return{value:e,done:!0}},I=function(e,t){return e+" has been deprecated in favor of "+t+", please update your code"},L=function(e){return new Error("\n redux-saga: Error checking hooks detected an inconsistent state. This is likely a bug\n in redux-saga code and not yours. Thanks for reporting this in the project's github repo.\n Error: "+e+"\n")},P=function(e,t){return(e?e+".":"")+"setContext(props): argument "+t+" is not a plain object"},M=function(e){return function(t){return e(Object.defineProperty(t,x,{value:!0}))}},j=function e(t){return function(){for(var n=arguments.length,r=Array(n),i=0;i if provided but got: "+String(t.directives)+"."),this._directives=t.directives||c.specifiedDirectives,this.astNode=t.astNode||null;var r=[this.getQueryType(),this.getMutationType(),this.getSubscriptionType(),l.__Schema],p=t.types;p&&(r=r.concat(p)),this._typeMap=r.reduce(o,Object.create(null)),this._implementations=Object.create(null),Object.keys(this._typeMap).forEach(function(e){var t=n._typeMap[e];t instanceof u.GraphQLObjectType&&t.getInterfaces().forEach(function(e){var r=n._implementations[e.name];r?r.push(t):n._implementations[e.name]=[t]})}),Object.keys(this._typeMap).forEach(function(e){var t=n._typeMap[e];t instanceof u.GraphQLObjectType&&t.getInterfaces().forEach(function(e){return a(n,t,e)})})}return e.prototype.getQueryType=function(){return this._queryType},e.prototype.getMutationType=function(){return this._mutationType},e.prototype.getSubscriptionType=function(){return this._subscriptionType},e.prototype.getTypeMap=function(){return this._typeMap},e.prototype.getType=function(e){return this.getTypeMap()[e]},e.prototype.getPossibleTypes=function(e){return e instanceof u.GraphQLUnionType?e.getTypes():(e instanceof u.GraphQLInterfaceType||(0,h.default)(0),this._implementations[e.name])},e.prototype.isPossibleType=function(e,t){var n=this._possibleTypeMap;if(n||(this._possibleTypeMap=n=Object.create(null)),!n[e.name]){var r=this.getPossibleTypes(e);Array.isArray(r)||(0,h.default)(0,"Could not find possible implementing types for "+e.name+" in schema. Check that schema.types is defined and is an array of all possible types in the schema."),n[e.name]=r.reduce(function(e,t){return e[t.name]=!0,e},Object.create(null))}return Boolean(n[e.name][t.name])},e.prototype.getDirectives=function(){return this._directives},e.prototype.getDirective=function(e){return(0,f.default)(this.getDirectives(),function(t){return t.name===e})},e}()},function(e,t,n){"use strict";function r(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}Object.defineProperty(t,"__esModule",{value:!0}),t.specifiedDirectives=t.GraphQLDeprecatedDirective=t.DEFAULT_DEPRECATION_REASON=t.GraphQLSkipDirective=t.GraphQLIncludeDirective=t.GraphQLDirective=t.DirectiveLocation=void 0;var i=n(6),o=n(32),a=n(13),s=function(e){return e&&e.__esModule?e:{default:e}}(a),u=n(111),c=t.DirectiveLocation={QUERY:"QUERY",MUTATION:"MUTATION",SUBSCRIPTION:"SUBSCRIPTION",FIELD:"FIELD",FRAGMENT_DEFINITION:"FRAGMENT_DEFINITION",FRAGMENT_SPREAD:"FRAGMENT_SPREAD",INLINE_FRAGMENT:"INLINE_FRAGMENT",SCHEMA:"SCHEMA",SCALAR:"SCALAR",OBJECT:"OBJECT",FIELD_DEFINITION:"FIELD_DEFINITION",ARGUMENT_DEFINITION:"ARGUMENT_DEFINITION",INTERFACE:"INTERFACE",UNION:"UNION",ENUM:"ENUM",ENUM_VALUE:"ENUM_VALUE",INPUT_OBJECT:"INPUT_OBJECT",INPUT_FIELD_DEFINITION:"INPUT_FIELD_DEFINITION"},l=t.GraphQLDirective=function e(t){r(this,e),t.name||(0,s.default)(0,"Directive must be named."),(0,u.assertValidName)(t.name),Array.isArray(t.locations)||(0,s.default)(0,"Must provide locations for directive."),this.name=t.name,this.description=t.description,this.locations=t.locations,this.astNode=t.astNode;var n=t.args;n?(Array.isArray(n)&&(0,s.default)(0,"@"+t.name+" args must be an object with argument names as keys."),this.args=Object.keys(n).map(function(e){(0,u.assertValidName)(e);var r=n[e];return(0,i.isInputType)(r.type)||(0,s.default)(0,"@"+t.name+"("+e+":) argument type must be Input Type but got: "+String(r.type)+"."),{name:e,description:void 0===r.description?null:r.description,type:r.type,defaultValue:r.defaultValue,astNode:r.astNode}})):this.args=[]},p=t.GraphQLIncludeDirective=new l({name:"include",description:"Directs the executor to include this field or fragment only when the `if` argument is true.",locations:[c.FIELD,c.FRAGMENT_SPREAD,c.INLINE_FRAGMENT],args:{if:{type:new i.GraphQLNonNull(o.GraphQLBoolean),description:"Included when true."}}}),f=t.GraphQLSkipDirective=new l({name:"skip",description:"Directs the executor to skip this field or fragment when the `if` argument is true.",locations:[c.FIELD,c.FRAGMENT_SPREAD,c.INLINE_FRAGMENT],args:{if:{type:new i.GraphQLNonNull(o.GraphQLBoolean),description:"Skipped when true."}}}),d=t.DEFAULT_DEPRECATION_REASON="No longer supported",h=t.GraphQLDeprecatedDirective=new l({name:"deprecated",description:"Marks an element of a GraphQL schema as no longer supported.",locations:[c.FIELD_DEFINITION,c.ENUM_VALUE],args:{reason:{type:o.GraphQLString,description:"Explains why this element was deprecated, usually also including a suggestion for how to access supported similar data. Formatted in [Markdown](https://daringfireball.net/projects/markdown/).",defaultValue:d}}});t.specifiedDirectives=[p,f,h]},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.TypeNameMetaFieldDef=t.TypeMetaFieldDef=t.SchemaMetaFieldDef=t.__TypeKind=t.TypeKind=t.__EnumValue=t.__InputValue=t.__Field=t.__Type=t.__DirectiveLocation=t.__Directive=t.__Schema=void 0;var r=n(58),i=function(e){return e&&e.__esModule?e:{default:e}}(r),o=n(112),a=n(19),s=n(6),u=n(32),c=n(27),l=t.__Schema=new s.GraphQLObjectType({name:"__Schema",isIntrospection:!0,description:"A GraphQL Schema defines the capabilities of a GraphQL server. It exposes all available types and directives on the server, as well as the entry points for query, mutation, and subscription operations.",fields:function(){return{types:{description:"A list of all types supported by this server.",type:new s.GraphQLNonNull(new s.GraphQLList(new s.GraphQLNonNull(d))),resolve:function(e){var t=e.getTypeMap();return Object.keys(t).map(function(e){return t[e]})}},queryType:{description:"The type that query operations will be rooted at.",type:new s.GraphQLNonNull(d),resolve:function(e){return e.getQueryType()}},mutationType:{description:"If this server supports mutation, the type that mutation operations will be rooted at.",type:d,resolve:function(e){return e.getMutationType()}},subscriptionType:{description:"If this server support subscription, the type that subscription operations will be rooted at.",type:d,resolve:function(e){return e.getSubscriptionType()}},directives:{description:"A list of all directives supported by this server.",type:new s.GraphQLNonNull(new s.GraphQLList(new s.GraphQLNonNull(p))),resolve:function(e){return e.getDirectives()}}}}}),p=t.__Directive=new s.GraphQLObjectType({name:"__Directive",isIntrospection:!0,description:"A Directive provides a way to describe alternate runtime execution and type validation behavior in a GraphQL document.\n\nIn some cases, you need to provide options to alter GraphQL's execution behavior in ways field arguments will not suffice, such as conditionally including or skipping a field. Directives provide this by describing additional information to the executor.",fields:function(){return{name:{type:new s.GraphQLNonNull(u.GraphQLString)},description:{type:u.GraphQLString},locations:{type:new s.GraphQLNonNull(new s.GraphQLList(new s.GraphQLNonNull(f)))},args:{type:new s.GraphQLNonNull(new s.GraphQLList(new s.GraphQLNonNull(m))),resolve:function(e){return e.args||[]}},onOperation:{deprecationReason:"Use `locations`.",type:new s.GraphQLNonNull(u.GraphQLBoolean),resolve:function(e){return-1!==e.locations.indexOf(c.DirectiveLocation.QUERY)||-1!==e.locations.indexOf(c.DirectiveLocation.MUTATION)||-1!==e.locations.indexOf(c.DirectiveLocation.SUBSCRIPTION)}},onFragment:{deprecationReason:"Use `locations`.",type:new s.GraphQLNonNull(u.GraphQLBoolean),resolve:function(e){return-1!==e.locations.indexOf(c.DirectiveLocation.FRAGMENT_SPREAD)||-1!==e.locations.indexOf(c.DirectiveLocation.INLINE_FRAGMENT)||-1!==e.locations.indexOf(c.DirectiveLocation.FRAGMENT_DEFINITION)}},onField:{deprecationReason:"Use `locations`.",type:new s.GraphQLNonNull(u.GraphQLBoolean),resolve:function(e){return-1!==e.locations.indexOf(c.DirectiveLocation.FIELD)}}}}}),f=t.__DirectiveLocation=new s.GraphQLEnumType({name:"__DirectiveLocation",isIntrospection:!0,description:"A Directive can be adjacent to many parts of the GraphQL language, a __DirectiveLocation describes one such possible adjacencies.",values:{QUERY:{value:c.DirectiveLocation.QUERY,description:"Location adjacent to a query operation."},MUTATION:{value:c.DirectiveLocation.MUTATION,description:"Location adjacent to a mutation operation."},SUBSCRIPTION:{value:c.DirectiveLocation.SUBSCRIPTION,description:"Location adjacent to a subscription operation."},FIELD:{value:c.DirectiveLocation.FIELD,description:"Location adjacent to a field."},FRAGMENT_DEFINITION:{value:c.DirectiveLocation.FRAGMENT_DEFINITION,description:"Location adjacent to a fragment definition."},FRAGMENT_SPREAD:{value:c.DirectiveLocation.FRAGMENT_SPREAD,description:"Location adjacent to a fragment spread."},INLINE_FRAGMENT:{value:c.DirectiveLocation.INLINE_FRAGMENT,description:"Location adjacent to an inline fragment."},SCHEMA:{value:c.DirectiveLocation.SCHEMA,description:"Location adjacent to a schema definition."},SCALAR:{value:c.DirectiveLocation.SCALAR,description:"Location adjacent to a scalar definition."},OBJECT:{value:c.DirectiveLocation.OBJECT,description:"Location adjacent to an object type definition."},FIELD_DEFINITION:{value:c.DirectiveLocation.FIELD_DEFINITION,description:"Location adjacent to a field definition."},ARGUMENT_DEFINITION:{value:c.DirectiveLocation.ARGUMENT_DEFINITION,description:"Location adjacent to an argument definition."},INTERFACE:{value:c.DirectiveLocation.INTERFACE,description:"Location adjacent to an interface definition."},UNION:{value:c.DirectiveLocation.UNION,description:"Location adjacent to a union definition."},ENUM:{value:c.DirectiveLocation.ENUM,description:"Location adjacent to an enum definition."},ENUM_VALUE:{value:c.DirectiveLocation.ENUM_VALUE,description:"Location adjacent to an enum value definition."},INPUT_OBJECT:{value:c.DirectiveLocation.INPUT_OBJECT,description:"Location adjacent to an input object type definition."},INPUT_FIELD_DEFINITION:{value:c.DirectiveLocation.INPUT_FIELD_DEFINITION,description:"Location adjacent to an input object field definition."}}}),d=t.__Type=new s.GraphQLObjectType({name:"__Type",isIntrospection:!0,description:"The fundamental unit of any GraphQL Schema is the type. There are many kinds of types in GraphQL as represented by the `__TypeKind` enum.\n\nDepending on the kind of a type, certain fields describe information about that type. Scalar types provide no information beyond a name and description, while Enum types provide their values. Object and Interface types provide the fields they describe. Abstract types, Union and Interface, provide the Object types possible at runtime. List and NonNull types compose other types.",fields:function(){return{kind:{type:new s.GraphQLNonNull(v),resolve:function(e){if(e instanceof s.GraphQLScalarType)return y.SCALAR;if(e instanceof s.GraphQLObjectType)return y.OBJECT;if(e instanceof s.GraphQLInterfaceType)return y.INTERFACE;if(e instanceof s.GraphQLUnionType)return y.UNION;if(e instanceof s.GraphQLEnumType)return y.ENUM;if(e instanceof s.GraphQLInputObjectType)return y.INPUT_OBJECT;if(e instanceof s.GraphQLList)return y.LIST;if(e instanceof s.GraphQLNonNull)return y.NON_NULL;throw new Error("Unknown kind of type: "+e)}},name:{type:u.GraphQLString},description:{type:u.GraphQLString},fields:{type:new s.GraphQLList(new s.GraphQLNonNull(h)),args:{includeDeprecated:{type:u.GraphQLBoolean,defaultValue:!1}},resolve:function(e,t){var n=t.includeDeprecated;if(e instanceof s.GraphQLObjectType||e instanceof s.GraphQLInterfaceType){var r=e.getFields(),i=Object.keys(r).map(function(e){return r[e]});return n||(i=i.filter(function(e){return!e.deprecationReason})),i}return null}},interfaces:{type:new s.GraphQLList(new s.GraphQLNonNull(d)),resolve:function(e){if(e instanceof s.GraphQLObjectType)return e.getInterfaces()}},possibleTypes:{type:new s.GraphQLList(new s.GraphQLNonNull(d)),resolve:function(e,t,n,r){var i=r.schema;if((0,s.isAbstractType)(e))return i.getPossibleTypes(e)}},enumValues:{type:new s.GraphQLList(new s.GraphQLNonNull(g)),args:{includeDeprecated:{type:u.GraphQLBoolean,defaultValue:!1}},resolve:function(e,t){var n=t.includeDeprecated;if(e instanceof s.GraphQLEnumType){var r=e.getValues();return n||(r=r.filter(function(e){return!e.deprecationReason})),r}}},inputFields:{type:new s.GraphQLList(new s.GraphQLNonNull(m)),resolve:function(e){if(e instanceof s.GraphQLInputObjectType){var t=e.getFields();return Object.keys(t).map(function(e){return t[e]})}}},ofType:{type:d}}}}),h=t.__Field=new s.GraphQLObjectType({name:"__Field",isIntrospection:!0,description:"Object and Interface types are described by a list of Fields, each of which has a name, potentially a list of arguments, and a return type.",fields:function(){return{name:{type:new s.GraphQLNonNull(u.GraphQLString)},description:{type:u.GraphQLString},args:{type:new s.GraphQLNonNull(new s.GraphQLList(new s.GraphQLNonNull(m))),resolve:function(e){return e.args||[]}},type:{type:new s.GraphQLNonNull(d)},isDeprecated:{type:new s.GraphQLNonNull(u.GraphQLBoolean)},deprecationReason:{type:u.GraphQLString}}}}),m=t.__InputValue=new s.GraphQLObjectType({name:"__InputValue",isIntrospection:!0,description:"Arguments provided to Fields or Directives and the input fields of an InputObject are represented as Input Values which describe their type and optionally a default value.",fields:function(){return{name:{type:new s.GraphQLNonNull(u.GraphQLString)},description:{type:u.GraphQLString},type:{type:new s.GraphQLNonNull(d)},defaultValue:{type:u.GraphQLString,description:"A GraphQL-formatted string representing the default value for this input value.",resolve:function(e){return(0,i.default)(e.defaultValue)?null:(0,a.print)((0,o.astFromValue)(e.defaultValue,e.type))}}}}}),g=t.__EnumValue=new s.GraphQLObjectType({name:"__EnumValue",isIntrospection:!0,description:"One possible value for a given Enum. Enum values are unique values, not a placeholder for a string or numeric value. However an Enum value is returned in a JSON response as a string.",fields:function(){return{name:{type:new s.GraphQLNonNull(u.GraphQLString)},description:{type:u.GraphQLString},isDeprecated:{type:new s.GraphQLNonNull(u.GraphQLBoolean)},deprecationReason:{type:u.GraphQLString}}}}),y=t.TypeKind={SCALAR:"SCALAR",OBJECT:"OBJECT",INTERFACE:"INTERFACE",UNION:"UNION",ENUM:"ENUM",INPUT_OBJECT:"INPUT_OBJECT",LIST:"LIST",NON_NULL:"NON_NULL"},v=t.__TypeKind=new s.GraphQLEnumType({name:"__TypeKind",isIntrospection:!0,description:"An enum describing what kind of type a given `__Type` is.",values:{SCALAR:{value:y.SCALAR,description:"Indicates this type is a scalar."},OBJECT:{value:y.OBJECT,description:"Indicates this type is an object. `fields` and `interfaces` are valid fields."},INTERFACE:{value:y.INTERFACE,description:"Indicates this type is an interface. `fields` and `possibleTypes` are valid fields."},UNION:{value:y.UNION,description:"Indicates this type is a union. `possibleTypes` is a valid field."},ENUM:{value:y.ENUM,description:"Indicates this type is an enum. `enumValues` is a valid field."},INPUT_OBJECT:{value:y.INPUT_OBJECT,description:"Indicates this type is an input object. `inputFields` is a valid field."},LIST:{value:y.LIST,description:"Indicates this type is a list. `ofType` is a valid field."},NON_NULL:{value:y.NON_NULL,description:"Indicates this type is a non-null. `ofType` is a valid field."}}});t.SchemaMetaFieldDef={name:"__schema",type:new s.GraphQLNonNull(l),description:"Access the current type schema of this server.",args:[],resolve:function(e,t,n,r){return r.schema}},t.TypeMetaFieldDef={name:"__type",type:d,description:"Request the type information of a single type.",args:[{name:"name",type:new s.GraphQLNonNull(u.GraphQLString)}],resolve:function(e,t,n,r){var i=t.name;return r.schema.getType(i)}},t.TypeNameMetaFieldDef={name:"__typename",type:new s.GraphQLNonNull(u.GraphQLString),description:"The name of the current Object type at runtime.",args:[],resolve:function(e,t,n,r){return r.parentType.name}}},function(e,t,n){"use strict";function r(e,t){var n=void 0;return t.kind===s.LIST_TYPE?(n=c(e,t.type))&&new u.GraphQLList(n):t.kind===s.NON_NULL_TYPE?(n=c(e,t.type))&&new u.GraphQLNonNull(n):(t.kind!==s.NAMED_TYPE&&(0,o.default)(0,"Must be a named type."),e.getType(t.name.value))}Object.defineProperty(t,"__esModule",{value:!0}),t.typeFromAST=void 0;var i=n(13),o=function(e){return e&&e.__esModule?e:{default:e}}(i),a=n(10),s=function(e){if(e&&e.__esModule)return e;var t={};if(null!=e)for(var n in e)Object.prototype.hasOwnProperty.call(e,n)&&(t[n]=e[n]);return t.default=e,t}(a),u=n(6),c=t.typeFromAST=r},function(e,t,n){"use strict";function r(){if("undefined"!==typeof __REACT_DEVTOOLS_GLOBAL_HOOK__&&"function"===typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE)try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(r)}catch(e){console.error(e)}}r(),e.exports=n(314)},function(e,t,n){"use strict";function r(e){return null!=e&&"object"==typeof e}t.a=r},function(e,t,n){"use strict";function r(e){if(""===e)throw new TypeError("Int cannot represent non 32-bit signed integer value: (empty string)");var t=Number(e);if(t!==t||t>c||t=l)return t}return null}}),t.GraphQLFloat=new a.GraphQLScalarType({name:"Float",description:"The `Float` scalar type represents signed double-precision fractional values as specified by [IEEE 754](http://en.wikipedia.org/wiki/IEEE_floating_point). ",serialize:i,parseValue:i,parseLiteral:function(e){return e.kind===u.FLOAT||e.kind===u.INT?parseFloat(e.value):null}}),t.GraphQLString=new a.GraphQLScalarType({name:"String",description:"The `String` scalar type represents textual data, represented as UTF-8 character sequences. The String type is most often used by GraphQL to represent free-form human-readable text.",serialize:o,parseValue:o,parseLiteral:function(e){return e.kind===u.STRING?e.value:null}}),t.GraphQLBoolean=new a.GraphQLScalarType({name:"Boolean",description:"The `Boolean` scalar type represents `true` or `false`.",serialize:Boolean,parseValue:Boolean,parseLiteral:function(e){return e.kind===u.BOOLEAN?e.value:null}}),t.GraphQLID=new a.GraphQLScalarType({name:"ID",description:'The `ID` scalar type represents a unique identifier, often used to refetch an object or as key for a cache. The ID type appears in a JSON response as a String; however, it is not intended to be human-readable. When expected as an input type, any string (such as `"4"`) or integer (such as `4`) input value will be accepted as an ID.',serialize:String,parseValue:String,parseLiteral:function(e){return e.kind===u.STRING||e.kind===u.INT?e.value:null}})},function(e,t,n){"use strict";function r(e){return null==e?void 0===e?u:s:c&&c in Object(e)?Object(o.a)(e):Object(a.a)(e)}var i=n(103),o=n(349),a=n(350),s="[object Null]",u="[object Undefined]",c=i.a?i.a.toStringTag:void 0;t.a=r},function(e,t,n){"use strict";function r(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:"*";if(arguments.length&&Object(w.h)(arguments[0],w.q.notUndef,"take(patternOrChannel): patternOrChannel is undefined"),w.q.pattern(e))return G(A,{pattern:e});if(w.q.channel(e))return G(A,{channel:e});throw new Error("take(patternOrChannel): argument "+String(e)+" is not valid channel or a valid pattern")}function i(e,t){return arguments.length>1?(Object(w.h)(e,w.q.notUndef,"put(channel, action): argument channel is undefined"),Object(w.h)(e,w.q.channel,"put(channel, action): argument "+e+" is not a valid channel"),Object(w.h)(t,w.q.notUndef,"put(channel, action): argument action is undefined")):(Object(w.h)(e,w.q.notUndef,"put(action): argument action is undefined"),t=e,e=null),G(_,{channel:e,action:t})}function o(e){return G(T,e)}function a(e){return G(O,e)}function s(e,t,n){Object(w.h)(t,w.q.notUndef,e+": argument fn is undefined");var r=null;if(w.q.array(t)){var i=t;r=i[0],t=i[1]}else if(t.fn){var o=t;r=o.context,t=o.fn}return r&&w.q.string(t)&&w.q.func(r[t])&&(t=r[t]),Object(w.h)(t,w.q.func,e+": argument "+t+" is not a function"),{context:r,fn:t,args:n}}function u(e){for(var t=arguments.length,n=Array(t>1?t-1:0),r=1;r2&&void 0!==arguments[2]?arguments[2]:[];return G(F,s("apply",{context:e,fn:t},n))}function l(e){for(var t=arguments.length,n=Array(t>1?t-1:0),r=1;r1?t-1:0),r=1;r1?t-1:0),r=1;r1)return o(t.map(function(e){return d(e)}));var r=t[0];return Object(w.h)(r,w.q.notUndef,"join(task): argument task is undefined"),Object(w.h)(r,w.q.task,"join(task): argument "+r+" is not a valid Task object "+z),G(L,r)}function h(){for(var e=arguments.length,t=Array(e),n=0;n1)return o(t.map(function(e){return h(e)}));var r=t[0];return 1===t.length&&(Object(w.h)(r,w.q.notUndef,"cancel(task): argument task is undefined"),Object(w.h)(r,w.q.task,"cancel(task): argument "+r+" is not a valid Task object "+z)),G(P,r||w.d)}function m(e){for(var t=arguments.length,n=Array(t>1?t-1:0),r=1;r1&&(Object(w.h)(t,w.q.notUndef,"actionChannel(pattern, buffer): argument buffer is undefined"),Object(w.h)(t,w.q.buffer,"actionChannel(pattern, buffer): argument "+t+" is not a valid buffer")),G(j,{pattern:e,buffer:t})}function y(){return G(R,{})}function v(e){return Object(w.h)(e,w.q.channel,"flush(channel): argument "+e+" is not valid channel"),G(B,e)}function b(e){return Object(w.h)(e,w.q.string,"getContext(prop): argument "+e+" is not a string"),G($,e)}function x(e){return Object(w.h)(e,w.q.object,Object(w.k)(null,e)),G(U,e)}function C(e,t){for(var n=arguments.length,r=Array(n>2?n-2:0),i=2;i2?n-2:0),i=2;i3?r-3:0),o=3;o