Update vendor (#1330)

This commit is contained in:
Wim 2020-12-06 23:16:02 +01:00 committed by GitHub
parent 4913766d58
commit 0d7315249d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
28 changed files with 586 additions and 339 deletions

15
go.mod
View File

@ -3,16 +3,15 @@ module github.com/42wim/matterbridge
require ( require (
github.com/42wim/go-gitter v0.0.0-20170828205020-017310c2d557 github.com/42wim/go-gitter v0.0.0-20170828205020-017310c2d557
github.com/Baozisoftware/qrcode-terminal-go v0.0.0-20170407111555-c0650d8dff0f github.com/Baozisoftware/qrcode-terminal-go v0.0.0-20170407111555-c0650d8dff0f
github.com/Jeffail/gabs v1.1.1 // indirect
github.com/Philipp15b/go-steam v1.0.1-0.20200727090957-6ae9b3c0a560 github.com/Philipp15b/go-steam v1.0.1-0.20200727090957-6ae9b3c0a560
github.com/Rhymen/go-whatsapp v0.1.2-0.20201122130733-6e5488ac98df github.com/Rhymen/go-whatsapp v0.1.2-0.20201130210432-64cc8cf1437d
github.com/RocketChat/Rocket.Chat.Go.SDK v0.0.0-20200922220614-e4a51dfb52e4 // indirect
github.com/d5/tengo/v2 v2.6.2 github.com/d5/tengo/v2 v2.6.2
github.com/davecgh/go-spew v1.1.1 github.com/davecgh/go-spew v1.1.1
github.com/fsnotify/fsnotify v1.4.9 github.com/fsnotify/fsnotify v1.4.9
github.com/go-telegram-bot-api/telegram-bot-api v1.0.1-0.20200524105306-7434b0456e81 github.com/go-telegram-bot-api/telegram-bot-api v1.0.1-0.20200524105306-7434b0456e81
github.com/gomarkdown/markdown v0.0.0-20201113031856-722100d81a8e github.com/gomarkdown/markdown v0.0.0-20201113031856-722100d81a8e
github.com/google/gops v0.3.13 github.com/google/gops v0.3.13
github.com/gopackage/ddp v0.0.0-20170117053602-652027933df4 // indirect
github.com/gorilla/schema v1.2.0 github.com/gorilla/schema v1.2.0
github.com/gorilla/websocket v1.4.2 github.com/gorilla/websocket v1.4.2
github.com/hashicorp/golang-lru v0.5.4 github.com/hashicorp/golang-lru v0.5.4
@ -21,13 +20,13 @@ require (
github.com/labstack/echo/v4 v4.1.17 github.com/labstack/echo/v4 v4.1.17
github.com/lrstanley/girc v0.0.0-20190801035559-4fc93959e1a7 github.com/lrstanley/girc v0.0.0-20190801035559-4fc93959e1a7
github.com/matrix-org/gomatrix v0.0.0-20200827122206-7dd5e2a05bcd github.com/matrix-org/gomatrix v0.0.0-20200827122206-7dd5e2a05bcd
github.com/matterbridge/Rocket.Chat.Go.SDK v0.0.0-20201206161339-a8e64af17cde github.com/matterbridge/Rocket.Chat.Go.SDK v0.0.0-20201206215757-c1d86d75b9f8
github.com/matterbridge/discordgo v0.22.1 github.com/matterbridge/discordgo v0.22.1
github.com/matterbridge/emoji v2.1.1-0.20191117213217-af507f6b02db+incompatible github.com/matterbridge/emoji v2.1.1-0.20191117213217-af507f6b02db+incompatible
github.com/matterbridge/go-xmpp v0.0.0-20200418225040-c8a3a57b4050 github.com/matterbridge/go-xmpp v0.0.0-20200418225040-c8a3a57b4050
github.com/matterbridge/gozulipbot v0.0.0-20200820220548-be5824faa913 github.com/matterbridge/gozulipbot v0.0.0-20200820220548-be5824faa913
github.com/matterbridge/logrus-prefixed-formatter v0.5.3-0.20200523233437-d971309a77ba github.com/matterbridge/logrus-prefixed-formatter v0.5.3-0.20200523233437-d971309a77ba
github.com/mattermost/mattermost-server/v5 v5.29.0 github.com/mattermost/mattermost-server/v5 v5.29.1
github.com/mattn/godown v0.0.0-20201027140031-2c7783b24de7 github.com/mattn/godown v0.0.0-20201027140031-2c7783b24de7
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b // indirect github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b // indirect
github.com/missdeer/golib v1.0.4 github.com/missdeer/golib v1.0.4
@ -36,7 +35,7 @@ require (
github.com/nelsonken/gomf v0.0.0-20180504123937-a9dd2f9deae9 github.com/nelsonken/gomf v0.0.0-20180504123937-a9dd2f9deae9
github.com/paulrosania/go-charset v0.0.0-20190326053356-55c9d7a5834c github.com/paulrosania/go-charset v0.0.0-20190326053356-55c9d7a5834c
github.com/rs/xid v1.2.1 github.com/rs/xid v1.2.1
github.com/russross/blackfriday v1.5.2 github.com/russross/blackfriday v1.6.0
github.com/saintfish/chardet v0.0.0-20120816061221-3af4cd4741ca github.com/saintfish/chardet v0.0.0-20120816061221-3af4cd4741ca
github.com/shazow/ssh-chat v1.10.1 github.com/shazow/ssh-chat v1.10.1
github.com/sirupsen/logrus v1.7.0 github.com/sirupsen/logrus v1.7.0
@ -49,8 +48,8 @@ require (
github.com/yaegashi/msgraph.go v0.1.4 github.com/yaegashi/msgraph.go v0.1.4
github.com/zfjagann/golang-ring v0.0.0-20190304061218-d34796e0a6c2 github.com/zfjagann/golang-ring v0.0.0-20190304061218-d34796e0a6c2
golang.org/x/image v0.0.0-20200927104501-e162460cd6b5 golang.org/x/image v0.0.0-20200927104501-e162460cd6b5
golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58 golang.org/x/oauth2 v0.0.0-20201203001011-0b49973bad19
gomod.garykim.dev/nc-talk v0.1.5 gomod.garykim.dev/nc-talk v0.1.6
gopkg.in/olahol/melody.v1 v1.0.0-20170518105555-d52139073376 gopkg.in/olahol/melody.v1 v1.0.0-20170518105555-d52139073376
layeh.com/gumble v0.0.0-20200818122324-146f9205029b layeh.com/gumble v0.0.0-20200818122324-146f9205029b
) )

36
go.sum
View File

@ -55,8 +55,8 @@ github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym
github.com/CloudyKit/fastprinter v0.0.0-20170127035650-74b38d55f37a/go.mod h1:EFZQ978U7x8IRnstaskI3IysnWY5Ao3QgZUKOXlsAdw= github.com/CloudyKit/fastprinter v0.0.0-20170127035650-74b38d55f37a/go.mod h1:EFZQ978U7x8IRnstaskI3IysnWY5Ao3QgZUKOXlsAdw=
github.com/CloudyKit/jet v2.1.3-0.20180809161101-62edd43e4f88+incompatible/go.mod h1:HPYO+50pSWkPoj9Q/eq0aRGByCL6ScRlUmiEX5Zgm+w= github.com/CloudyKit/jet v2.1.3-0.20180809161101-62edd43e4f88+incompatible/go.mod h1:HPYO+50pSWkPoj9Q/eq0aRGByCL6ScRlUmiEX5Zgm+w=
github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ=
github.com/Jeffail/gabs v1.1.1 h1:V0uzR08Hj22EX8+8QMhyI9sX2hwRu+/RJhJUmnwda/E= github.com/Jeffail/gabs v1.4.0 h1://5fYRRTq1edjfIrQGvdkcd22pkYUrHZ5YC/H2GJVAo=
github.com/Jeffail/gabs v1.1.1/go.mod h1:6xMvQMK4k33lb7GUUpaAPh6nKMmemQeg5d4gn7/bOXc= github.com/Jeffail/gabs v1.4.0/go.mod h1:6xMvQMK4k33lb7GUUpaAPh6nKMmemQeg5d4gn7/bOXc=
github.com/Joker/hpp v1.0.0/go.mod h1:8x5n+M1Hp5hC0g8okX3sR3vFQwynaX/UgSOM9MeBKzY= github.com/Joker/hpp v1.0.0/go.mod h1:8x5n+M1Hp5hC0g8okX3sR3vFQwynaX/UgSOM9MeBKzY=
github.com/Joker/jade v1.0.1-0.20190614124447-d475f43051e7/go.mod h1:6E6s8o2AE4KhCrqr6GRJjdC/gNfTdxkIXvuGZZda2VM= github.com/Joker/jade v1.0.1-0.20190614124447-d475f43051e7/go.mod h1:6E6s8o2AE4KhCrqr6GRJjdC/gNfTdxkIXvuGZZda2VM=
github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0=
@ -71,14 +71,16 @@ github.com/PaulARoy/azurestoragecache v0.0.0-20170906084534-3c249a3ba788/go.mod
github.com/Philipp15b/go-steam v1.0.1-0.20200727090957-6ae9b3c0a560 h1:ItnC9PEEMESzTbFayxrhKBbuFQOXDBI8yy7NudTcEWs= github.com/Philipp15b/go-steam v1.0.1-0.20200727090957-6ae9b3c0a560 h1:ItnC9PEEMESzTbFayxrhKBbuFQOXDBI8yy7NudTcEWs=
github.com/Philipp15b/go-steam v1.0.1-0.20200727090957-6ae9b3c0a560/go.mod h1:o38AwUFFS4gzbjSoyIgrZ1h9UeDrKwcci1Pj6baifvI= github.com/Philipp15b/go-steam v1.0.1-0.20200727090957-6ae9b3c0a560/go.mod h1:o38AwUFFS4gzbjSoyIgrZ1h9UeDrKwcci1Pj6baifvI=
github.com/Rhymen/go-whatsapp v0.0.0/go.mod h1:rdQr95g2C1xcOfM7QGOhza58HeI3I+tZ/bbluv7VazA= github.com/Rhymen/go-whatsapp v0.0.0/go.mod h1:rdQr95g2C1xcOfM7QGOhza58HeI3I+tZ/bbluv7VazA=
github.com/Rhymen/go-whatsapp v0.1.2-0.20201122130733-6e5488ac98df h1:w1TSfL7OvTaHlYQlF8EGqnWKVn0It6Gyn7bXR0Mz7Qw= github.com/Rhymen/go-whatsapp v0.1.2-0.20201130210432-64cc8cf1437d h1:NBqC+ES9Max3fw7867h2efrpO8gbTr7HdLUGvnUXOP8=
github.com/Rhymen/go-whatsapp v0.1.2-0.20201122130733-6e5488ac98df/go.mod h1:o7jjkvKnigfu432dMbQ/w4PH0Yp5u4Y6ysCNjUlcYCk= github.com/Rhymen/go-whatsapp v0.1.2-0.20201130210432-64cc8cf1437d/go.mod h1:o7jjkvKnigfu432dMbQ/w4PH0Yp5u4Y6ysCNjUlcYCk=
github.com/Rhymen/go-whatsapp/examples/echo v0.0.0-20190325075644-cc2581bbf24d/go.mod h1:zgCiQtBtZ4P4gFWvwl9aashsdwOcbb/EHOGRmSzM8ME= github.com/Rhymen/go-whatsapp/examples/echo v0.0.0-20190325075644-cc2581bbf24d/go.mod h1:zgCiQtBtZ4P4gFWvwl9aashsdwOcbb/EHOGRmSzM8ME=
github.com/Rhymen/go-whatsapp/examples/restoreSession v0.0.0-20190325075644-cc2581bbf24d/go.mod h1:5sCUSpG616ZoSJhlt9iBNI/KXBqrVLcNUJqg7J9+8pU= github.com/Rhymen/go-whatsapp/examples/restoreSession v0.0.0-20190325075644-cc2581bbf24d/go.mod h1:5sCUSpG616ZoSJhlt9iBNI/KXBqrVLcNUJqg7J9+8pU=
github.com/Rhymen/go-whatsapp/examples/sendImage v0.0.0-20190325075644-cc2581bbf24d/go.mod h1:RdiyhanVEGXTam+mZ3k6Y3VDCCvXYCwReOoxGozqhHw= github.com/Rhymen/go-whatsapp/examples/sendImage v0.0.0-20190325075644-cc2581bbf24d/go.mod h1:RdiyhanVEGXTam+mZ3k6Y3VDCCvXYCwReOoxGozqhHw=
github.com/Rhymen/go-whatsapp/examples/sendTextMessages v0.0.0-20190325075644-cc2581bbf24d/go.mod h1:suwzklatySS3Q0+NCxCDh5hYfgXdQUWU1DNcxwAxStM= github.com/Rhymen/go-whatsapp/examples/sendTextMessages v0.0.0-20190325075644-cc2581bbf24d/go.mod h1:suwzklatySS3Q0+NCxCDh5hYfgXdQUWU1DNcxwAxStM=
github.com/RoaringBitmap/roaring v0.4.21/go.mod h1:D0gp8kJQgE1A4LQ5wFLggQEyvDi06Mq5mKs52e1TwOo= github.com/RoaringBitmap/roaring v0.4.21/go.mod h1:D0gp8kJQgE1A4LQ5wFLggQEyvDi06Mq5mKs52e1TwOo=
github.com/RoaringBitmap/roaring v0.5.0/go.mod h1:D0gp8kJQgE1A4LQ5wFLggQEyvDi06Mq5mKs52e1TwOo= github.com/RoaringBitmap/roaring v0.5.0/go.mod h1:D0gp8kJQgE1A4LQ5wFLggQEyvDi06Mq5mKs52e1TwOo=
github.com/RocketChat/Rocket.Chat.Go.SDK v0.0.0-20200922220614-e4a51dfb52e4 h1:u7UvmSK6McEMXFZB310/YZ6uvfDaSFrSoqWoy/qaOW0=
github.com/RocketChat/Rocket.Chat.Go.SDK v0.0.0-20200922220614-e4a51dfb52e4/go.mod h1:wVff6N8s2foRPCYeynerOM/FF44uyI60/HMiboL0SXw=
github.com/Shopify/goreferrer v0.0.0-20181106222321-ec9c9a553398/go.mod h1:a1uqRtAwp2Xwc6WNPJEufxJ7fx3npB4UV/JOLmbu5I0= github.com/Shopify/goreferrer v0.0.0-20181106222321-ec9c9a553398/go.mod h1:a1uqRtAwp2Xwc6WNPJEufxJ7fx3npB4UV/JOLmbu5I0=
github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo= github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo=
github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI=
@ -495,10 +497,8 @@ github.com/mailru/easyjson v0.7.3/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJ
github.com/marstr/guid v0.0.0-20170427235115-8bdf7d1a087c/go.mod h1:74gB1z2wpxxInTG6yaqA7KrtM0NZ+RbrcqDvYHefzho= github.com/marstr/guid v0.0.0-20170427235115-8bdf7d1a087c/go.mod h1:74gB1z2wpxxInTG6yaqA7KrtM0NZ+RbrcqDvYHefzho=
github.com/matrix-org/gomatrix v0.0.0-20200827122206-7dd5e2a05bcd h1:xVrqJK3xHREMNjwjljkAUaadalWc0rRbmVuQatzmgwg= github.com/matrix-org/gomatrix v0.0.0-20200827122206-7dd5e2a05bcd h1:xVrqJK3xHREMNjwjljkAUaadalWc0rRbmVuQatzmgwg=
github.com/matrix-org/gomatrix v0.0.0-20200827122206-7dd5e2a05bcd/go.mod h1:/gBX06Kw0exX1HrwmoBibFA98yBk/jxKpGVeyQbff+s= github.com/matrix-org/gomatrix v0.0.0-20200827122206-7dd5e2a05bcd/go.mod h1:/gBX06Kw0exX1HrwmoBibFA98yBk/jxKpGVeyQbff+s=
github.com/matterbridge/Rocket.Chat.Go.SDK v0.0.0-20200411204219-d5c18ce75048 h1:B9HaistmV+MD8/33BXmZe1zPIn+RImAFVXNNSOrwU2E= github.com/matterbridge/Rocket.Chat.Go.SDK v0.0.0-20201206215757-c1d86d75b9f8 h1:2iHni9FGPRRnaZrknLp+Kyr1CWbRIRUjp89TNpkqy3I=
github.com/matterbridge/Rocket.Chat.Go.SDK v0.0.0-20200411204219-d5c18ce75048/go.mod h1:c6MxwqHD+0HvtAJjsHMIdPCiAwGiQwPRPTp69ACMg8A= github.com/matterbridge/Rocket.Chat.Go.SDK v0.0.0-20201206215757-c1d86d75b9f8/go.mod h1:c6MxwqHD+0HvtAJjsHMIdPCiAwGiQwPRPTp69ACMg8A=
github.com/matterbridge/Rocket.Chat.Go.SDK v0.0.0-20201206161339-a8e64af17cde h1:7txV2EiAMLRUWabaSkLNd11TGclMHSOUGYSRMuE+sOI=
github.com/matterbridge/Rocket.Chat.Go.SDK v0.0.0-20201206161339-a8e64af17cde/go.mod h1:c6MxwqHD+0HvtAJjsHMIdPCiAwGiQwPRPTp69ACMg8A=
github.com/matterbridge/discordgo v0.22.1 h1:Wh2NXfvF4egJDxX7jEvtgxJgT/ZOqD/5tfcIsNnHJ9o= github.com/matterbridge/discordgo v0.22.1 h1:Wh2NXfvF4egJDxX7jEvtgxJgT/ZOqD/5tfcIsNnHJ9o=
github.com/matterbridge/discordgo v0.22.1/go.mod h1:411nZYv0UMMrtppR5glXop1foboJiFAowy+42U+Ahvw= github.com/matterbridge/discordgo v0.22.1/go.mod h1:411nZYv0UMMrtppR5glXop1foboJiFAowy+42U+Ahvw=
github.com/matterbridge/emoji v2.1.1-0.20191117213217-af507f6b02db+incompatible h1:oaOqwbg5HxHRxvAbd84ks0Okwoc1ISyUZ87EiVJFhGI= github.com/matterbridge/emoji v2.1.1-0.20191117213217-af507f6b02db+incompatible h1:oaOqwbg5HxHRxvAbd84ks0Okwoc1ISyUZ87EiVJFhGI=
@ -517,8 +517,8 @@ github.com/mattermost/ldap v0.0.0-20191128190019-9f62ba4b8d4d h1:2DV7VIlEv6J5R5o
github.com/mattermost/ldap v0.0.0-20191128190019-9f62ba4b8d4d/go.mod h1:HLbgMEI5K131jpxGazJ97AxfPDt31osq36YS1oxFQPQ= github.com/mattermost/ldap v0.0.0-20191128190019-9f62ba4b8d4d/go.mod h1:HLbgMEI5K131jpxGazJ97AxfPDt31osq36YS1oxFQPQ=
github.com/mattermost/logr v1.0.13 h1:6F/fM3csvH6Oy5sUpJuW7YyZSzZZAhJm5VcgKMxA2P8= github.com/mattermost/logr v1.0.13 h1:6F/fM3csvH6Oy5sUpJuW7YyZSzZZAhJm5VcgKMxA2P8=
github.com/mattermost/logr v1.0.13/go.mod h1:Mt4DPu1NXMe6JxPdwCC0XBoxXmN9eXOIRPoZarU2PXs= github.com/mattermost/logr v1.0.13/go.mod h1:Mt4DPu1NXMe6JxPdwCC0XBoxXmN9eXOIRPoZarU2PXs=
github.com/mattermost/mattermost-server/v5 v5.29.0 h1:v+qGNpMkgYRJY1qn4Rx2u1W7dbkmes47NnDZLSTIRGU= github.com/mattermost/mattermost-server/v5 v5.29.1 h1:qroK4khSvL0SFCwF9oOQrDdCFuTrNE0JSQe6Wnrh5LQ=
github.com/mattermost/mattermost-server/v5 v5.29.0/go.mod h1:9FfgZY9Ywx64bzPBYo4mmR05ApyOxO+tr43eDhpWups= github.com/mattermost/mattermost-server/v5 v5.29.1/go.mod h1:9FfgZY9Ywx64bzPBYo4mmR05ApyOxO+tr43eDhpWups=
github.com/mattermost/rsc v0.0.0-20160330161541-bbaefb05eaa0/go.mod h1:nV5bfVpT//+B1RPD2JvRnxbkLmJEYXmRaaVl15fsXjs= github.com/mattermost/rsc v0.0.0-20160330161541-bbaefb05eaa0/go.mod h1:nV5bfVpT//+B1RPD2JvRnxbkLmJEYXmRaaVl15fsXjs=
github.com/mattermost/viper v1.0.4/go.mod h1:uc5hKG9lv4/KRwPOt2c1omOyirS/UnuA2TytiZQSFHM= github.com/mattermost/viper v1.0.4/go.mod h1:uc5hKG9lv4/KRwPOt2c1omOyirS/UnuA2TytiZQSFHM=
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
@ -626,11 +626,15 @@ github.com/onsi/ginkgo v1.10.3/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
github.com/onsi/ginkgo v1.13.0 h1:M76yO2HkZASFjXL0HSoZJ1AYEmQxNJmY41Jx1zNUq1Y= github.com/onsi/ginkgo v1.13.0 h1:M76yO2HkZASFjXL0HSoZJ1AYEmQxNJmY41Jx1zNUq1Y=
github.com/onsi/ginkgo v1.13.0/go.mod h1:+REjRxOmWfHCjfv9TTWB1jD1Frx4XydAD3zm1lskyM0= github.com/onsi/ginkgo v1.13.0/go.mod h1:+REjRxOmWfHCjfv9TTWB1jD1Frx4XydAD3zm1lskyM0=
github.com/onsi/ginkgo v1.14.1 h1:jMU0WaQrP0a/YAEq8eJmJKjBoMs+pClEr1vDMlM/Do4=
github.com/onsi/ginkgo v1.14.1/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY=
github.com/onsi/gomega v1.4.3 h1:RE1xgDvH7imwFD45h+u2SgIfERHlS2yNG4DObb5BSKU= github.com/onsi/gomega v1.4.3 h1:RE1xgDvH7imwFD45h+u2SgIfERHlS2yNG4DObb5BSKU=
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
github.com/onsi/gomega v1.10.1 h1:o0+MgICZLuZ7xjH7Vx6zS/zcu93/BEp1VwkIW1mEXCE= github.com/onsi/gomega v1.10.1 h1:o0+MgICZLuZ7xjH7Vx6zS/zcu93/BEp1VwkIW1mEXCE=
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
github.com/onsi/gomega v1.10.2 h1:aY/nuoWlKJud2J6U0E3NWsjlg+0GtwXxgEqthRdzlcs=
github.com/onsi/gomega v1.10.2/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
github.com/oov/psd v0.0.0-20200705094106-99303fb2511f/go.mod h1:GHI1bnmAcbp96z6LNfBJvtrjxhaXGkbsk967utPlvL8= github.com/oov/psd v0.0.0-20200705094106-99303fb2511f/go.mod h1:GHI1bnmAcbp96z6LNfBJvtrjxhaXGkbsk967utPlvL8=
github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk= github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk=
github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492/go.mod h1:Ngi6UdF0k5OKD5t5wlmGhe/EDKPoUM3BXZSSfIuJbis= github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492/go.mod h1:Ngi6UdF0k5OKD5t5wlmGhe/EDKPoUM3BXZSSfIuJbis=
@ -723,6 +727,8 @@ github.com/rudderlabs/analytics-go v3.2.1+incompatible/go.mod h1:LF8/ty9kUX4PTY3
github.com/russellhaering/goxmldsig v0.0.0-20180430223755-7acd5e4a6ef7/go.mod h1:Oz4y6ImuOQZxynhbSXk7btjEfNBtGlj2dcaOvXl2FSM= github.com/russellhaering/goxmldsig v0.0.0-20180430223755-7acd5e4a6ef7/go.mod h1:Oz4y6ImuOQZxynhbSXk7btjEfNBtGlj2dcaOvXl2FSM=
github.com/russross/blackfriday v1.5.2 h1:HyvC0ARfnZBqnXwABFeSZHpKvJHJJfPz81GNueLj0oo= github.com/russross/blackfriday v1.5.2 h1:HyvC0ARfnZBqnXwABFeSZHpKvJHJJfPz81GNueLj0oo=
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
github.com/russross/blackfriday v1.6.0 h1:KqfZb0pUVN2lYqZUYRddxF4OR8ZMURnJIG5Y3VRLtww=
github.com/russross/blackfriday v1.6.0/go.mod h1:ti0ldHuxg49ri4ksnFxlkCfN+hvslNlmVHqNRXXJNAY=
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/rwcarlsen/goexif v0.0.0-20190401172101-9e8deecbddbd/go.mod h1:hPqNNc0+uJM6H+SuU8sEs5K5IQeKccPqeSjfgcKGgPk= github.com/rwcarlsen/goexif v0.0.0-20190401172101-9e8deecbddbd/go.mod h1:hPqNNc0+uJM6H+SuU8sEs5K5IQeKccPqeSjfgcKGgPk=
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
@ -1041,6 +1047,8 @@ golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81R
golang.org/x/net v0.0.0-20200813134508-3edf25e44fcc/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200813134508-3edf25e44fcc/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20200822124328-c89045814202 h1:VvcQYSHwXgi7W+TpUR6A9g6Up98WAHf3f/ulnJ62IyA= golang.org/x/net v0.0.0-20200822124328-c89045814202 h1:VvcQYSHwXgi7W+TpUR6A9g6Up98WAHf3f/ulnJ62IyA=
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20200904194848-62affa334b73 h1:MXfv8rhZWmFeqX3GNZRsd6vOLoaCHjYEX3qkRo3YBUA=
golang.org/x/net v0.0.0-20200904194848-62affa334b73/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
@ -1050,8 +1058,8 @@ golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4Iltr
golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d h1:TzXSXBo42m9gQenoE3b9BGiEpg5IG2JkU5FkPIawgtw= golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d h1:TzXSXBo42m9gQenoE3b9BGiEpg5IG2JkU5FkPIawgtw=
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58 h1:Mj83v+wSRNEar42a/MQgxk9X42TdEmrOl9i+y8WbxLo= golang.org/x/oauth2 v0.0.0-20201203001011-0b49973bad19 h1:ZD+2Sd/BnevwJp8PSli8WgGAGzb9IZtxBsv1iZMYeEA=
golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20201203001011-0b49973bad19/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/perf v0.0.0-20180704124530-6e6d33e29852/go.mod h1:JLpeXjPJfIyPr5TlbXLkXWLhP8nz10XfvxElABhCtcw= golang.org/x/perf v0.0.0-20180704124530-6e6d33e29852/go.mod h1:JLpeXjPJfIyPr5TlbXLkXWLhP8nz10XfvxElABhCtcw=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@ -1200,8 +1208,8 @@ golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IV
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gomod.garykim.dev/nc-talk v0.1.5 h1:zZ/FviVpwJuhD/YrKiAvs6Z3Oew/DL/w6RKbKaanhFA= gomod.garykim.dev/nc-talk v0.1.6 h1:ZanTsFiAYKwuEJkV5GjMHop5dEGuCNzEDi4kWh/aqYg=
gomod.garykim.dev/nc-talk v0.1.5/go.mod h1:zKg8yxCk2KaTy6aPDEfRac0Jik72czX+nRsG8CZuhtc= gomod.garykim.dev/nc-talk v0.1.6/go.mod h1:zKg8yxCk2KaTy6aPDEfRac0Jik72czX+nRsG8CZuhtc=
google.golang.org/api v0.0.0-20180910000450-7ca32eb868bf/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= google.golang.org/api v0.0.0-20180910000450-7ca32eb868bf/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=
google.golang.org/api v0.0.0-20181030000543-1d582fd0359e/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= google.golang.org/api v0.0.0-20181030000543-1d582fd0359e/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=
google.golang.org/api v0.0.0-20181220000619-583d854617af/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= google.golang.org/api v0.0.0-20181220000619-583d854617af/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=

View File

@ -7,21 +7,17 @@ It does nothing spectacular except for being fabulous.
https://godoc.org/github.com/Jeffail/gabs https://godoc.org/github.com/Jeffail/gabs
## How to install: ## Install
``` bash ``` bash
go get github.com/Jeffail/gabs go get github.com/Jeffail/gabs
``` ```
## How to use ## Use
### Parsing and searching JSON ### Parsing and searching JSON
``` go ``` go
...
import "github.com/Jeffail/gabs"
jsonParsed, err := gabs.ParseJSON([]byte(`{ jsonParsed, err := gabs.ParseJSON([]byte(`{
"outter":{ "outter":{
"inner":{ "inner":{
@ -29,7 +25,10 @@ jsonParsed, err := gabs.ParseJSON([]byte(`{
"value2":22 "value2":22
}, },
"alsoInner":{ "alsoInner":{
"value1":20 "value1":20,
"array1":[
30, 40
]
} }
} }
}`)) }`))
@ -43,26 +42,26 @@ value, ok = jsonParsed.Path("outter.inner.value1").Data().(float64)
value, ok = jsonParsed.Search("outter", "inner", "value1").Data().(float64) value, ok = jsonParsed.Search("outter", "inner", "value1").Data().(float64)
// value == 10.0, ok == true // value == 10.0, ok == true
gObj, err := jsonParsed.JSONPointer("/outter/alsoInner/array1/1")
if err != nil {
panic(err)
}
value, ok = gObj.Data().(float64)
// value == 40.0, ok == true
value, ok = jsonParsed.Path("does.not.exist").Data().(float64) value, ok = jsonParsed.Path("does.not.exist").Data().(float64)
// value == 0.0, ok == false // value == 0.0, ok == false
exists := jsonParsed.Exists("outter", "inner", "value1") exists := jsonParsed.Exists("outter", "inner", "value1")
// exists == true // exists == true
exists := jsonParsed.Exists("does", "not", "exist")
// exists == false
exists := jsonParsed.ExistsP("does.not.exist") exists := jsonParsed.ExistsP("does.not.exist")
// exists == false // exists == false
...
``` ```
### Iterating objects ### Iterating objects
``` go ``` go
...
jsonParsed, _ := gabs.ParseJSON([]byte(`{"object":{ "first": 1, "second": 2, "third": 3 }}`)) jsonParsed, _ := gabs.ParseJSON([]byte(`{"object":{ "first": 1, "second": 2, "third": 3 }}`))
// S is shorthand for Search // S is shorthand for Search
@ -70,24 +69,25 @@ children, _ := jsonParsed.S("object").ChildrenMap()
for key, child := range children { for key, child := range children {
fmt.Printf("key: %v, value: %v\n", key, child.Data().(string)) fmt.Printf("key: %v, value: %v\n", key, child.Data().(string))
} }
...
``` ```
### Iterating arrays ### Iterating arrays
``` go ``` go
... jsonParsed, err := gabs.ParseJSON([]byte(`{"array":[ "first", "second", "third" ]}`))
if err != nil {
jsonParsed, _ := gabs.ParseJSON([]byte(`{"array":[ "first", "second", "third" ]}`)) panic(err)
}
// S is shorthand for Search // S is shorthand for Search
children, _ := jsonParsed.S("array").Children() children, err := jsonParsed.S("array").Children()
if err != nil {
panic(err)
}
for _, child := range children { for _, child := range children {
fmt.Println(child.Data().(string)) fmt.Println(child.Data().(string))
} }
...
``` ```
Will print: Will print:
@ -108,12 +108,11 @@ objects within the array, this returns a JSON array containing the results for
each element. each element.
``` go ``` go
... jsonParsed, err := gabs.ParseJSON([]byte(`{"array":[ {"value":1}, {"value":2}, {"value":3} ]}`))
if err != nil {
jsonParsed, _ := gabs.ParseJSON([]byte(`{"array":[ {"value":1}, {"value":2}, {"value":3} ]}`)) panic(err)
}
fmt.Println(jsonParsed.Path("array.value").String()) fmt.Println(jsonParsed.Path("array.value").String())
...
``` ```
Will print: Will print:
@ -125,8 +124,6 @@ Will print:
### Generating JSON ### Generating JSON
``` go ``` go
...
jsonObj := gabs.New() jsonObj := gabs.New()
// or gabs.Consume(jsonObject) to work on an existing map[string]interface{} // or gabs.Consume(jsonObject) to work on an existing map[string]interface{}
@ -135,8 +132,6 @@ jsonObj.SetP(20, "outter.inner.value2")
jsonObj.Set(30, "outter", "inner2", "value3") jsonObj.Set(30, "outter", "inner2", "value3")
fmt.Println(jsonObj.String()) fmt.Println(jsonObj.String())
...
``` ```
Will print: Will print:
@ -148,11 +143,7 @@ Will print:
To pretty-print: To pretty-print:
``` go ``` go
...
fmt.Println(jsonObj.StringIndent("", " ")) fmt.Println(jsonObj.StringIndent("", " "))
...
``` ```
Will print: Will print:
@ -174,8 +165,6 @@ Will print:
### Generating Arrays ### Generating Arrays
``` go ``` go
...
jsonObj := gabs.New() jsonObj := gabs.New()
jsonObj.Array("foo", "array") jsonObj.Array("foo", "array")
@ -186,8 +175,6 @@ jsonObj.ArrayAppend(20, "foo", "array")
jsonObj.ArrayAppend(30, "foo", "array") jsonObj.ArrayAppend(30, "foo", "array")
fmt.Println(jsonObj.String()) fmt.Println(jsonObj.String())
...
``` ```
Will print: Will print:
@ -199,8 +186,6 @@ Will print:
Working with arrays by index: Working with arrays by index:
``` go ``` go
...
jsonObj := gabs.New() jsonObj := gabs.New()
// Create an array with the length of 3 // Create an array with the length of 3
@ -217,8 +202,6 @@ jsonObj.S("foo").Index(2).SetIndex(2, 1)
jsonObj.S("foo").Index(2).SetIndex(3, 2) jsonObj.S("foo").Index(2).SetIndex(3, 2)
fmt.Println(jsonObj.String()) fmt.Println(jsonObj.String())
...
``` ```
Will print: Will print:
@ -232,8 +215,6 @@ Will print:
This is the easiest part: This is the easiest part:
``` go ``` go
...
jsonParsedObj, _ := gabs.ParseJSON([]byte(`{ jsonParsedObj, _ := gabs.ParseJSON([]byte(`{
"outter":{ "outter":{
"values":{ "values":{
@ -246,15 +227,11 @@ jsonParsedObj, _ := gabs.ParseJSON([]byte(`{
jsonOutput := jsonParsedObj.String() jsonOutput := jsonParsedObj.String()
// Becomes `{"outter":{"values":{"first":10,"second":11}},"outter2":"hello world"}` // Becomes `{"outter":{"values":{"first":10,"second":11}},"outter2":"hello world"}`
...
``` ```
And to serialize a specific segment is as simple as: And to serialize a specific segment is as simple as:
``` go ``` go
...
jsonParsedObj := gabs.ParseJSON([]byte(`{ jsonParsedObj := gabs.ParseJSON([]byte(`{
"outter":{ "outter":{
"values":{ "values":{
@ -267,8 +244,6 @@ jsonParsedObj := gabs.ParseJSON([]byte(`{
jsonOutput := jsonParsedObj.Search("outter").String() jsonOutput := jsonParsedObj.Search("outter").String()
// Becomes `{"values":{"first":10,"second":11}}` // Becomes `{"values":{"first":10,"second":11}}`
...
``` ```
### Merge two containers ### Merge two containers

View File

@ -20,58 +20,85 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE. THE SOFTWARE.
*/ */
// Package gabs implements a simplified wrapper around creating and parsing JSON. // Package gabs implements a simplified wrapper around creating and parsing
// unknown or dynamic JSON.
package gabs package gabs
import ( import (
"bytes" "bytes"
"encoding/json" "encoding/json"
"errors" "errors"
"fmt"
"io" "io"
"io/ioutil" "io/ioutil"
"strconv"
"strings" "strings"
) )
//-------------------------------------------------------------------------------------------------- //------------------------------------------------------------------------------
var ( var (
// ErrOutOfBounds - Index out of bounds. // ErrOutOfBounds indicates an index was out of bounds.
ErrOutOfBounds = errors.New("out of bounds") ErrOutOfBounds = errors.New("out of bounds")
// ErrNotObjOrArray - The target is not an object or array type. // ErrNotObjOrArray is returned when a target is not an object or array type
// but needs to be for the intended operation.
ErrNotObjOrArray = errors.New("not an object or array") ErrNotObjOrArray = errors.New("not an object or array")
// ErrNotObj - The target is not an object type. // ErrNotObj is returned when a target is not an object but needs to be for
// the intended operation.
ErrNotObj = errors.New("not an object") ErrNotObj = errors.New("not an object")
// ErrNotArray - The target is not an array type. // ErrNotArray is returned when a target is not an array but needs to be for
// the intended operation.
ErrNotArray = errors.New("not an array") ErrNotArray = errors.New("not an array")
// ErrPathCollision - Creating a path failed because an element collided with an existing value. // ErrPathCollision is returned when creating a path failed because an
// element collided with an existing value.
ErrPathCollision = errors.New("encountered value collision whilst building path") ErrPathCollision = errors.New("encountered value collision whilst building path")
// ErrInvalidInputObj - The input value was not a map[string]interface{}. // ErrInvalidInputObj is returned when the input value was not a
// map[string]interface{}.
ErrInvalidInputObj = errors.New("invalid input object") ErrInvalidInputObj = errors.New("invalid input object")
// ErrInvalidInputText - The input data could not be parsed. // ErrInvalidInputText is returned when the input data could not be parsed.
ErrInvalidInputText = errors.New("input text could not be parsed") ErrInvalidInputText = errors.New("input text could not be parsed")
// ErrInvalidPath - The filepath was not valid. // ErrInvalidPath is returned when the filepath was not valid.
ErrInvalidPath = errors.New("invalid file path") ErrInvalidPath = errors.New("invalid file path")
// ErrInvalidBuffer - The input buffer contained an invalid JSON string // ErrInvalidBuffer is returned when the input buffer contained an invalid
// JSON string.
ErrInvalidBuffer = errors.New("input buffer contained invalid JSON") ErrInvalidBuffer = errors.New("input buffer contained invalid JSON")
) )
//-------------------------------------------------------------------------------------------------- //------------------------------------------------------------------------------
// Container - an internal structure that holds a reference to the core interface map of the parsed func resolveJSONPointerHierarchy(path string) ([]string, error) {
// json. Use this container to move context. if len(path) < 1 {
return nil, errors.New("failed to resolve JSON pointer: path must not be empty")
}
if path[0] != '/' {
return nil, errors.New("failed to resolve JSON pointer: path must begin with '/'")
}
hierarchy := strings.Split(path, "/")[1:]
for i, v := range hierarchy {
v = strings.Replace(v, "~1", "/", -1)
v = strings.Replace(v, "~0", "~", -1)
hierarchy[i] = v
}
return hierarchy, nil
}
//------------------------------------------------------------------------------
// Container references a specific element within a JSON structure.
type Container struct { type Container struct {
object interface{} object interface{}
} }
// Data - Return the contained data as an interface{}. // Data returns the underlying interface{} of the target element in the JSON
// structure.
func (g *Container) Data() interface{} { func (g *Container) Data() interface{} {
if g == nil { if g == nil {
return nil return nil
@ -79,17 +106,18 @@ func (g *Container) Data() interface{} {
return g.object return g.object
} }
//-------------------------------------------------------------------------------------------------- //------------------------------------------------------------------------------
// Path - Search for a value using dot notation. // Path searches the JSON structure following a path in dot notation.
func (g *Container) Path(path string) *Container { func (g *Container) Path(path string) *Container {
return g.Search(strings.Split(path, ".")...) return g.Search(strings.Split(path, ".")...)
} }
// Search - Attempt to find and return an object within the JSON structure by specifying the // Search attempts to find and return an object within the JSON structure by
// hierarchy of field names to locate the target. If the search encounters an array and has not // following a provided hierarchy of field names to locate the target. If the
// reached the end target then it will iterate each object of the array for the target and return // search encounters an array and has not reached the end target then it will
// all of the results in a JSON array. // iterate each object of the array for the target and return all of the results
// in a JSON array.
func (g *Container) Search(hierarchy ...string) *Container { func (g *Container) Search(hierarchy ...string) *Container {
var object interface{} var object interface{}
@ -120,22 +148,55 @@ func (g *Container) Search(hierarchy ...string) *Container {
return &Container{object} return &Container{object}
} }
// S - Shorthand method, does the same thing as Search. // JSONPointer parses a JSON pointer path (https://tools.ietf.org/html/rfc6901)
// and either returns a *gabs.Container containing the result or an error if the
// referenced item could not be found.
func (g *Container) JSONPointer(path string) (*Container, error) {
hierarchy, err := resolveJSONPointerHierarchy(path)
if err != nil {
return nil, err
}
object := g.Data()
for target := 0; target < len(hierarchy); target++ {
pathSeg := hierarchy[target]
if mmap, ok := object.(map[string]interface{}); ok {
object, ok = mmap[pathSeg]
if !ok {
return nil, fmt.Errorf("failed to resolve JSON pointer: index '%v' value '%v' was not found", target, pathSeg)
}
} else if marray, ok := object.([]interface{}); ok {
index, err := strconv.Atoi(pathSeg)
if err != nil {
return nil, fmt.Errorf("failed to resolve JSON pointer: could not parse index '%v' value '%v' into array index: %v", target, pathSeg, err)
}
if len(marray) <= index {
return nil, fmt.Errorf("failed to resolve JSON pointer: index '%v' value '%v' exceeded target array size of '%v'", target, pathSeg, len(marray))
}
object = marray[index]
} else {
return &Container{nil}, fmt.Errorf("failed to resolve JSON pointer: index '%v' field '%v' was not found", target, pathSeg)
}
}
return &Container{object}, nil
}
// S is a shorthand alias for Search.
func (g *Container) S(hierarchy ...string) *Container { func (g *Container) S(hierarchy ...string) *Container {
return g.Search(hierarchy...) return g.Search(hierarchy...)
} }
// Exists - Checks whether a path exists. // Exists checks whether a path exists.
func (g *Container) Exists(hierarchy ...string) bool { func (g *Container) Exists(hierarchy ...string) bool {
return g.Search(hierarchy...) != nil return g.Search(hierarchy...) != nil
} }
// ExistsP - Checks whether a dot notation path exists. // ExistsP checks whether a dot notation path exists.
func (g *Container) ExistsP(path string) bool { func (g *Container) ExistsP(path string) bool {
return g.Exists(strings.Split(path, ".")...) return g.Exists(strings.Split(path, ".")...)
} }
// Index - Attempt to find and return an object within a JSON array by index. // Index attempts to find and return an element within a JSON array by an index.
func (g *Container) Index(index int) *Container { func (g *Container) Index(index int) *Container {
if array, ok := g.Data().([]interface{}); ok { if array, ok := g.Data().([]interface{}); ok {
if index >= len(array) { if index >= len(array) {
@ -146,9 +207,9 @@ func (g *Container) Index(index int) *Container {
return &Container{nil} return &Container{nil}
} }
// Children - Return a slice of all the children of the array. This also works for objects, however, // Children returns a slice of all children of an array element. This also works
// the children returned for an object will NOT be in order and you lose the names of the returned // for objects, however, the children returned for an object will be in a random
// objects this way. // order and you lose the names of the returned objects this way.
func (g *Container) Children() ([]*Container, error) { func (g *Container) Children() ([]*Container, error) {
if array, ok := g.Data().([]interface{}); ok { if array, ok := g.Data().([]interface{}); ok {
children := make([]*Container, len(array)) children := make([]*Container, len(array))
@ -167,7 +228,7 @@ func (g *Container) Children() ([]*Container, error) {
return nil, ErrNotObjOrArray return nil, ErrNotObjOrArray
} }
// ChildrenMap - Return a map of all the children of an object. // ChildrenMap returns a map of all the children of an object element.
func (g *Container) ChildrenMap() (map[string]*Container, error) { func (g *Container) ChildrenMap() (map[string]*Container, error) {
if mmap, ok := g.Data().(map[string]interface{}); ok { if mmap, ok := g.Data().(map[string]interface{}); ok {
children := map[string]*Container{} children := map[string]*Container{}
@ -179,11 +240,11 @@ func (g *Container) ChildrenMap() (map[string]*Container, error) {
return nil, ErrNotObj return nil, ErrNotObj
} }
//-------------------------------------------------------------------------------------------------- //------------------------------------------------------------------------------
// Set - Set the value of a field at a JSON path, any parts of the path that do not exist will be // Set the value of a field at a JSON path, any parts of the path that do not
// constructed, and if a collision occurs with a non object type whilst iterating the path an error // exist will be constructed, and if a collision occurs with a non object type
// is returned. // whilst iterating the path an error is returned.
func (g *Container) Set(value interface{}, path ...string) (*Container, error) { func (g *Container) Set(value interface{}, path ...string) (*Container, error) {
if len(path) == 0 { if len(path) == 0 {
g.object = value g.object = value
@ -209,12 +270,14 @@ func (g *Container) Set(value interface{}, path ...string) (*Container, error) {
return &Container{object}, nil return &Container{object}, nil
} }
// SetP - Does the same as Set, but using a dot notation JSON path. // SetP sets the value of a field at a JSON path using dot notation, any parts
// of the path that do not exist will be constructed, and if a collision occurs
// with a non object type whilst iterating the path an error is returned.
func (g *Container) SetP(value interface{}, path string) (*Container, error) { func (g *Container) SetP(value interface{}, path string) (*Container, error) {
return g.Set(value, strings.Split(path, ".")...) return g.Set(value, strings.Split(path, ".")...)
} }
// SetIndex - Set a value of an array element based on the index. // SetIndex attempts to set a value of an array element based on an index.
func (g *Container) SetIndex(value interface{}, index int) (*Container, error) { func (g *Container) SetIndex(value interface{}, index int) (*Container, error) {
if array, ok := g.Data().([]interface{}); ok { if array, ok := g.Data().([]interface{}); ok {
if index >= len(array) { if index >= len(array) {
@ -226,60 +289,112 @@ func (g *Container) SetIndex(value interface{}, index int) (*Container, error) {
return &Container{nil}, ErrNotArray return &Container{nil}, ErrNotArray
} }
// Object - Create a new JSON object at a path. Returns an error if the path contains a collision // SetJSONPointer parses a JSON pointer path
// with a non object type. // (https://tools.ietf.org/html/rfc6901) and sets the leaf to a value. Returns
// an error if the pointer could not be resolved due to missing fields.
func (g *Container) SetJSONPointer(value interface{}, path string) error {
hierarchy, err := resolveJSONPointerHierarchy(path)
if err != nil {
return err
}
if len(hierarchy) == 0 {
g.object = value
return nil
}
object := g.object
for target := 0; target < len(hierarchy); target++ {
pathSeg := hierarchy[target]
if mmap, ok := object.(map[string]interface{}); ok {
if target == len(hierarchy)-1 {
object = value
mmap[pathSeg] = object
} else if object = mmap[pathSeg]; object == nil {
return fmt.Errorf("failed to resolve JSON pointer: index '%v' value '%v' was not found", target, pathSeg)
}
} else if marray, ok := object.([]interface{}); ok {
index, err := strconv.Atoi(pathSeg)
if err != nil {
return fmt.Errorf("failed to resolve JSON pointer: could not parse index '%v' value '%v' into array index: %v", target, pathSeg, err)
}
if len(marray) <= index {
return fmt.Errorf("failed to resolve JSON pointer: index '%v' value '%v' exceeded target array size of '%v'", target, pathSeg, len(marray))
}
if target == len(hierarchy)-1 {
object = value
marray[index] = object
} else if object = marray[index]; object == nil {
return fmt.Errorf("failed to resolve JSON pointer: index '%v' value '%v' was not found", target, pathSeg)
}
} else {
return fmt.Errorf("failed to resolve JSON pointer: index '%v' value '%v' was not found", target, pathSeg)
}
}
return nil
}
// Object creates a new JSON object at a target path. Returns an error if the
// path contains a collision with a non object type.
func (g *Container) Object(path ...string) (*Container, error) { func (g *Container) Object(path ...string) (*Container, error) {
return g.Set(map[string]interface{}{}, path...) return g.Set(map[string]interface{}{}, path...)
} }
// ObjectP - Does the same as Object, but using a dot notation JSON path. // ObjectP creates a new JSON object at a target path using dot notation.
// Returns an error if the path contains a collision with a non object type.
func (g *Container) ObjectP(path string) (*Container, error) { func (g *Container) ObjectP(path string) (*Container, error) {
return g.Object(strings.Split(path, ".")...) return g.Object(strings.Split(path, ".")...)
} }
// ObjectI - Create a new JSON object at an array index. Returns an error if the object is not an // ObjectI creates a new JSON object at an array index. Returns an error if the
// array or the index is out of bounds. // object is not an array or the index is out of bounds.
func (g *Container) ObjectI(index int) (*Container, error) { func (g *Container) ObjectI(index int) (*Container, error) {
return g.SetIndex(map[string]interface{}{}, index) return g.SetIndex(map[string]interface{}{}, index)
} }
// Array - Create a new JSON array at a path. Returns an error if the path contains a collision with // Array creates a new JSON array at a path. Returns an error if the path
// a non object type. // contains a collision with a non object type.
func (g *Container) Array(path ...string) (*Container, error) { func (g *Container) Array(path ...string) (*Container, error) {
return g.Set([]interface{}{}, path...) return g.Set([]interface{}{}, path...)
} }
// ArrayP - Does the same as Array, but using a dot notation JSON path. // ArrayP creates a new JSON array at a path using dot notation. Returns an
// error if the path contains a collision with a non object type.
func (g *Container) ArrayP(path string) (*Container, error) { func (g *Container) ArrayP(path string) (*Container, error) {
return g.Array(strings.Split(path, ".")...) return g.Array(strings.Split(path, ".")...)
} }
// ArrayI - Create a new JSON array at an array index. Returns an error if the object is not an // ArrayI creates a new JSON array within an array at an index. Returns an error
// array or the index is out of bounds. // if the element is not an array or the index is out of bounds.
func (g *Container) ArrayI(index int) (*Container, error) { func (g *Container) ArrayI(index int) (*Container, error) {
return g.SetIndex([]interface{}{}, index) return g.SetIndex([]interface{}{}, index)
} }
// ArrayOfSize - Create a new JSON array of a particular size at a path. Returns an error if the // ArrayOfSize creates a new JSON array of a particular size at a path. Returns
// path contains a collision with a non object type. // an error if the path contains a collision with a non object type.
func (g *Container) ArrayOfSize(size int, path ...string) (*Container, error) { func (g *Container) ArrayOfSize(size int, path ...string) (*Container, error) {
a := make([]interface{}, size) a := make([]interface{}, size)
return g.Set(a, path...) return g.Set(a, path...)
} }
// ArrayOfSizeP - Does the same as ArrayOfSize, but using a dot notation JSON path. // ArrayOfSizeP creates a new JSON array of a particular size at a path using
// dot notation. Returns an error if the path contains a collision with a non
// object type.
func (g *Container) ArrayOfSizeP(size int, path string) (*Container, error) { func (g *Container) ArrayOfSizeP(size int, path string) (*Container, error) {
return g.ArrayOfSize(size, strings.Split(path, ".")...) return g.ArrayOfSize(size, strings.Split(path, ".")...)
} }
// ArrayOfSizeI - Create a new JSON array of a particular size at an array index. Returns an error // ArrayOfSizeI create a new JSON array of a particular size within an array at
// if the object is not an array or the index is out of bounds. // an index. Returns an error if the element is not an array or the index is out
// of bounds.
func (g *Container) ArrayOfSizeI(size, index int) (*Container, error) { func (g *Container) ArrayOfSizeI(size, index int) (*Container, error) {
a := make([]interface{}, size) a := make([]interface{}, size)
return g.SetIndex(a, index) return g.SetIndex(a, index)
} }
// Delete - Delete an element at a JSON path, an error is returned if the element does not exist. // Delete an element at a path, an error is returned if the element does not
// exist.
func (g *Container) Delete(path ...string) error { func (g *Container) Delete(path ...string) error {
var object interface{} var object interface{}
@ -304,45 +419,40 @@ func (g *Container) Delete(path ...string) error {
return nil return nil
} }
// DeleteP - Does the same as Delete, but using a dot notation JSON path. // DeleteP deletes an element at a path using dot notation, an error is returned
// if the element does not exist.
func (g *Container) DeleteP(path string) error { func (g *Container) DeleteP(path string) error {
return g.Delete(strings.Split(path, ".")...) return g.Delete(strings.Split(path, ".")...)
} }
// Merge - Merges two gabs-containers // MergeFn merges two objects using a provided function to resolve collisions.
func (g *Container) Merge(toMerge *Container) error { //
// The collision function receives two interface{} arguments, destination (the
// original object) and source (the object being merged into the destination).
// Which ever value is returned becomes the new value in the destination object
// at the location of the collision.
func (g *Container) MergeFn(source *Container, collisionFn func(destination, source interface{}) interface{}) error {
var recursiveFnc func(map[string]interface{}, []string) error var recursiveFnc func(map[string]interface{}, []string) error
recursiveFnc = func(mmap map[string]interface{}, path []string) error { recursiveFnc = func(mmap map[string]interface{}, path []string) error {
for key, value := range mmap { for key, value := range mmap {
newPath := append(path, key) newPath := append(path, key)
if g.Exists(newPath...) { if g.Exists(newPath...) {
target := g.Search(newPath...) existingData := g.Search(newPath...).Data()
switch t := value.(type) { switch t := value.(type) {
case map[string]interface{}: case map[string]interface{}:
switch targetV := target.Data().(type) { switch existingVal := existingData.(type) {
case map[string]interface{}: case map[string]interface{}:
if err := recursiveFnc(t, newPath); err != nil { if err := recursiveFnc(t, newPath); err != nil {
return err return err
} }
case []interface{}:
g.Set(append(targetV, t), newPath...)
default: default:
newSlice := append([]interface{}{}, targetV) if _, err := g.Set(collisionFn(existingVal, t), newPath...); err != nil {
g.Set(append(newSlice, t), newPath...)
}
case []interface{}:
for _, valueOfSlice := range t {
if err := g.ArrayAppend(valueOfSlice, newPath...); err != nil {
return err return err
} }
} }
default: default:
switch targetV := target.Data().(type) { if _, err := g.Set(collisionFn(existingData, t), newPath...); err != nil {
case []interface{}: return err
g.Set(append(targetV, t), newPath...)
default:
newSlice := append([]interface{}{}, targetV)
g.Set(append(newSlice, t), newPath...)
} }
} }
} else { } else {
@ -354,21 +464,48 @@ func (g *Container) Merge(toMerge *Container) error {
} }
return nil return nil
} }
if mmap, ok := toMerge.Data().(map[string]interface{}); ok { if mmap, ok := source.Data().(map[string]interface{}); ok {
return recursiveFnc(mmap, []string{}) return recursiveFnc(mmap, []string{})
} }
return nil return nil
} }
//-------------------------------------------------------------------------------------------------- // Merge a source object into an existing destination object. When a collision
// is found within the merged structures (both a source and destination object
// contain the same non-object keys) the result will be an array containing both
// values, where values that are already arrays will be expanded into the
// resulting array.
//
// It is possible to merge structures will different collision behaviours with
// MergeFn.
func (g *Container) Merge(source *Container) error {
return g.MergeFn(source, func(dest, source interface{}) interface{} {
destArr, destIsArray := dest.([]interface{})
sourceArr, sourceIsArray := source.([]interface{})
if destIsArray {
if sourceIsArray {
return append(destArr, sourceArr...)
}
return append(destArr, source)
}
if sourceIsArray {
return append(append([]interface{}{}, dest), sourceArr...)
}
return []interface{}{dest, source}
})
}
//------------------------------------------------------------------------------
/* /*
Array modification/search - Keeping these options simple right now, no need for anything more Array modification/search - Keeping these options simple right now, no need for
complicated since you can just cast to []interface{}, modify and then reassign with Set. anything more complicated since you can just cast to []interface{}, modify and
then reassign with Set.
*/ */
// ArrayAppend - Append a value onto a JSON array. If the target is not a JSON array then it will be // ArrayAppend attempts to append a value onto a JSON array at a path. If the
// converted into one, with its contents as the first element of the array. // target is not a JSON array then it will be converted into one, with its
// original contents set to the first element of the array.
func (g *Container) ArrayAppend(value interface{}, path ...string) error { func (g *Container) ArrayAppend(value interface{}, path ...string) error {
if array, ok := g.Search(path...).Data().([]interface{}); ok { if array, ok := g.Search(path...).Data().([]interface{}); ok {
array = append(array, value) array = append(array, value)
@ -386,12 +523,15 @@ func (g *Container) ArrayAppend(value interface{}, path ...string) error {
return err return err
} }
// ArrayAppendP - Append a value onto a JSON array using a dot notation JSON path. // ArrayAppendP attempts to append a value onto a JSON array at a path using dot
// notation. If the target is not a JSON array then it will be converted into
// one, with its original contents set to the first element of the array.
func (g *Container) ArrayAppendP(value interface{}, path string) error { func (g *Container) ArrayAppendP(value interface{}, path string) error {
return g.ArrayAppend(value, strings.Split(path, ".")...) return g.ArrayAppend(value, strings.Split(path, ".")...)
} }
// ArrayRemove - Remove an element from a JSON array. // ArrayRemove attempts to remove an element identified by an index from a JSON
// array at a path.
func (g *Container) ArrayRemove(index int, path ...string) error { func (g *Container) ArrayRemove(index int, path ...string) error {
if index < 0 { if index < 0 {
return ErrOutOfBounds return ErrOutOfBounds
@ -409,12 +549,14 @@ func (g *Container) ArrayRemove(index int, path ...string) error {
return err return err
} }
// ArrayRemoveP - Remove an element from a JSON array using a dot notation JSON path. // ArrayRemoveP attempts to remove an element identified by an index from a JSON
// array at a path using dot notation.
func (g *Container) ArrayRemoveP(index int, path string) error { func (g *Container) ArrayRemoveP(index int, path string) error {
return g.ArrayRemove(index, strings.Split(path, ".")...) return g.ArrayRemove(index, strings.Split(path, ".")...)
} }
// ArrayElement - Access an element from a JSON array. // ArrayElement attempts to access an element by an index from a JSON array at a
// path.
func (g *Container) ArrayElement(index int, path ...string) (*Container, error) { func (g *Container) ArrayElement(index int, path ...string) (*Container, error) {
if index < 0 { if index < 0 {
return &Container{nil}, ErrOutOfBounds return &Container{nil}, ErrOutOfBounds
@ -429,12 +571,13 @@ func (g *Container) ArrayElement(index int, path ...string) (*Container, error)
return &Container{nil}, ErrOutOfBounds return &Container{nil}, ErrOutOfBounds
} }
// ArrayElementP - Access an element from a JSON array using a dot notation JSON path. // ArrayElementP attempts to access an element by an index from a JSON array at
// a path using dot notation.
func (g *Container) ArrayElementP(index int, path string) (*Container, error) { func (g *Container) ArrayElementP(index int, path string) (*Container, error) {
return g.ArrayElement(index, strings.Split(path, ".")...) return g.ArrayElement(index, strings.Split(path, ".")...)
} }
// ArrayCount - Count the number of elements in a JSON array. // ArrayCount counts the number of elements in a JSON array at a path.
func (g *Container) ArrayCount(path ...string) (int, error) { func (g *Container) ArrayCount(path ...string) (int, error) {
if array, ok := g.Search(path...).Data().([]interface{}); ok { if array, ok := g.Search(path...).Data().([]interface{}); ok {
return len(array), nil return len(array), nil
@ -442,14 +585,15 @@ func (g *Container) ArrayCount(path ...string) (int, error) {
return 0, ErrNotArray return 0, ErrNotArray
} }
// ArrayCountP - Count the number of elements in a JSON array using a dot notation JSON path. // ArrayCountP counts the number of elements in a JSON array at a path using dot
// notation.
func (g *Container) ArrayCountP(path string) (int, error) { func (g *Container) ArrayCountP(path string) (int, error) {
return g.ArrayCount(strings.Split(path, ".")...) return g.ArrayCount(strings.Split(path, ".")...)
} }
//-------------------------------------------------------------------------------------------------- //------------------------------------------------------------------------------
// Bytes - Converts the contained object back to a JSON []byte blob. // Bytes marshals an element to a JSON []byte blob.
func (g *Container) Bytes() []byte { func (g *Container) Bytes() []byte {
if g.Data() != nil { if g.Data() != nil {
if bytes, err := json.Marshal(g.object); err == nil { if bytes, err := json.Marshal(g.object); err == nil {
@ -459,7 +603,8 @@ func (g *Container) Bytes() []byte {
return []byte("{}") return []byte("{}")
} }
// BytesIndent - Converts the contained object to a JSON []byte blob formatted with prefix, indent. // BytesIndent marshals an element to a JSON []byte blob formatted with a prefix
// and indent string.
func (g *Container) BytesIndent(prefix string, indent string) []byte { func (g *Container) BytesIndent(prefix string, indent string) []byte {
if g.object != nil { if g.object != nil {
if bytes, err := json.MarshalIndent(g.object, prefix, indent); err == nil { if bytes, err := json.MarshalIndent(g.object, prefix, indent); err == nil {
@ -469,12 +614,13 @@ func (g *Container) BytesIndent(prefix string, indent string) []byte {
return []byte("{}") return []byte("{}")
} }
// String - Converts the contained object to a JSON formatted string. // String marshals an element to a JSON formatted string.
func (g *Container) String() string { func (g *Container) String() string {
return string(g.Bytes()) return string(g.Bytes())
} }
// StringIndent - Converts the contained object back to a JSON formatted string with prefix, indent. // StringIndent marshals an element to a JSON string formatted with a prefix and
// indent string.
func (g *Container) StringIndent(prefix string, indent string) string { func (g *Container) StringIndent(prefix string, indent string) string {
return string(g.BytesIndent(prefix, indent)) return string(g.BytesIndent(prefix, indent))
} }
@ -496,10 +642,9 @@ func EncodeOptIndent(prefix string, indent string) EncodeOpt {
} }
} }
// EncodeJSON - Encodes the contained object back to a JSON formatted []byte // EncodeJSON marshals an element to a JSON formatted []byte using a variant
// using a variant list of modifier functions for the encoder being used. // list of modifier functions for the encoder being used. Functions for
// Functions for modifying the output are prefixed with EncodeOpt, e.g. // modifying the output are prefixed with EncodeOpt, e.g. EncodeOptHTMLEscape.
// EncodeOptHTMLEscape.
func (g *Container) EncodeJSON(encodeOpts ...EncodeOpt) []byte { func (g *Container) EncodeJSON(encodeOpts ...EncodeOpt) []byte {
var b bytes.Buffer var b bytes.Buffer
encoder := json.NewEncoder(&b) encoder := json.NewEncoder(&b)
@ -517,17 +662,18 @@ func (g *Container) EncodeJSON(encodeOpts ...EncodeOpt) []byte {
return result return result
} }
// New - Create a new gabs JSON object. // New creates a new gabs JSON object.
func New() *Container { func New() *Container {
return &Container{map[string]interface{}{}} return &Container{map[string]interface{}{}}
} }
// Consume - Gobble up an already converted JSON object, or a fresh map[string]interface{} object. // Consume an already unmarshalled JSON object (or a new map[string]interface{})
// into a *Container.
func Consume(root interface{}) (*Container, error) { func Consume(root interface{}) (*Container, error) {
return &Container{root}, nil return &Container{root}, nil
} }
// ParseJSON - Convert a string into a representation of the parsed JSON. // ParseJSON unmarshals a JSON byte slice into a *Container.
func ParseJSON(sample []byte) (*Container, error) { func ParseJSON(sample []byte) (*Container, error) {
var gabs Container var gabs Container
@ -538,7 +684,7 @@ func ParseJSON(sample []byte) (*Container, error) {
return &gabs, nil return &gabs, nil
} }
// ParseJSONDecoder - Convert a json.Decoder into a representation of the parsed JSON. // ParseJSONDecoder applies a json.Decoder to a *Container.
func ParseJSONDecoder(decoder *json.Decoder) (*Container, error) { func ParseJSONDecoder(decoder *json.Decoder) (*Container, error) {
var gabs Container var gabs Container
@ -549,7 +695,7 @@ func ParseJSONDecoder(decoder *json.Decoder) (*Container, error) {
return &gabs, nil return &gabs, nil
} }
// ParseJSONFile - Read a file and convert into a representation of the parsed JSON. // ParseJSONFile reads a file and unmarshals the contents into a *Container.
func ParseJSONFile(path string) (*Container, error) { func ParseJSONFile(path string) (*Container, error) {
if len(path) > 0 { if len(path) > 0 {
cBytes, err := ioutil.ReadFile(path) cBytes, err := ioutil.ReadFile(path)
@ -567,7 +713,7 @@ func ParseJSONFile(path string) (*Container, error) {
return nil, ErrInvalidPath return nil, ErrInvalidPath
} }
// ParseJSONBuffer - Read the contents of a buffer into a representation of the parsed JSON. // ParseJSONBuffer reads a buffer and unmarshals the contents into a *Container.
func ParseJSONBuffer(buffer io.Reader) (*Container, error) { func ParseJSONBuffer(buffer io.Reader) (*Container, error) {
var gabs Container var gabs Container
jsonDecoder := json.NewDecoder(buffer) jsonDecoder := json.NewDecoder(buffer)
@ -578,4 +724,4 @@ func ParseJSONBuffer(buffer io.Reader) (*Container, error) {
return &gabs, nil return &gabs, nil
} }
//-------------------------------------------------------------------------------------------------- //------------------------------------------------------------------------------

1
vendor/github.com/Jeffail/gabs/go.mod generated vendored Normal file
View File

@ -0,0 +1 @@
module github.com/Jeffail/gabs

View File

@ -7,23 +7,21 @@ import (
) )
var ( var (
ErrAlreadyConnected = errors.New("already connected") ErrAlreadyConnected = errors.New("already connected")
ErrAlreadyLoggedIn = errors.New("already logged in") ErrAlreadyLoggedIn = errors.New("already logged in")
ErrInvalidSession = errors.New("invalid session") ErrInvalidSession = errors.New("invalid session")
ErrLoginInProgress = errors.New("login or restore already running") ErrLoginInProgress = errors.New("login or restore already running")
ErrNotConnected = errors.New("not connected") ErrNotConnected = errors.New("not connected")
ErrInvalidWsData = errors.New("received invalid data") ErrInvalidWsData = errors.New("received invalid data")
ErrInvalidWsState = errors.New("can't handle binary data when not logged in") ErrInvalidWsState = errors.New("can't handle binary data when not logged in")
ErrConnectionTimeout = errors.New("connection timed out") ErrConnectionTimeout = errors.New("connection timed out")
ErrMissingMessageTag = errors.New("no messageTag specified or to short") ErrMissingMessageTag = errors.New("no messageTag specified or to short")
ErrInvalidHmac = errors.New("invalid hmac") ErrInvalidHmac = errors.New("invalid hmac")
ErrInvalidServerResponse = errors.New("invalid response received from server") ErrInvalidServerResponse = errors.New("invalid response received from server")
ErrServerRespondedWith404 = errors.New("server responded with status 404") ErrServerRespondedWith404 = errors.New("server responded with status 404")
ErrMediaDownloadFailedWith404 = errors.New("download failed with status code 404") ErrInvalidWebsocket = errors.New("invalid websocket")
ErrMediaDownloadFailedWith410 = errors.New("download failed with status code 410") ErrMessageTypeNotImplemented = errors.New("message type not implemented")
ErrInvalidWebsocket = errors.New("invalid websocket") ErrOptionsNotProvided = errors.New("new conn options not provided")
ErrMessageTypeNotImplemented = errors.New("message type not implemented")
ErrOptionsNotProvided = errors.New("new conn options not provided")
) )
type ErrConnectionFailed struct { type ErrConnectionFailed struct {

View File

@ -10,6 +10,7 @@ import (
"fmt" "fmt"
"io" "io"
"io/ioutil" "io/ioutil"
"net"
"net/http" "net/http"
"net/url" "net/url"
"time" "time"
@ -71,16 +72,10 @@ func downloadMedia(url string) (file []byte, mac []byte, err error) {
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
if resp.StatusCode != 200 { defer resp.Body.Close()
if resp.StatusCode == 404 { if resp.StatusCode != http.StatusOK {
return nil, nil, ErrMediaDownloadFailedWith404
}
if resp.StatusCode == 410 {
return nil, nil, ErrMediaDownloadFailedWith410
}
return nil, nil, fmt.Errorf("download failed with status code %d", resp.StatusCode) return nil, nil, fmt.Errorf("download failed with status code %d", resp.StatusCode)
} }
defer resp.Body.Close()
if resp.ContentLength <= 10 { if resp.ContentLength <= 10 {
return nil, nil, fmt.Errorf("file to short") return nil, nil, fmt.Errorf("file to short")
} }
@ -101,8 +96,8 @@ type MediaConn struct {
Hosts []struct { Hosts []struct {
Hostname string `json:"hostname"` Hostname string `json:"hostname"`
IPs []struct { IPs []struct {
IP4 string `json:"ip4"` IP4 net.IP `json:"ip4"`
IP6 string `json:"ip6"` IP6 net.IP `json:"ip6"`
} `json:"ips"` } `json:"ips"`
} `json:"hosts"` } `json:"hosts"`
} `json:"media_conn"` } `json:"media_conn"`
@ -125,21 +120,17 @@ func (wac *Conn) queryMediaConn() (hostname, auth string, ttl int, err error) {
return "", "", 0, fmt.Errorf("query media conn timed out") return "", "", 0, fmt.Errorf("query media conn timed out")
} }
if resp.Status != 200 { if resp.Status != http.StatusOK {
return "", "", 0, fmt.Errorf("query media conn responded with %d", resp.Status) return "", "", 0, fmt.Errorf("query media conn responded with %d", resp.Status)
} }
var host string
for _, h := range resp.MediaConn.Hosts { for _, h := range resp.MediaConn.Hosts {
if h.Hostname != "" { if h.Hostname != "" {
host = h.Hostname return h.Hostname, resp.MediaConn.Auth, resp.MediaConn.TTL, nil
break
} }
} }
if host == "" {
return "", "", 0, fmt.Errorf("query media conn responded with no host") return "", "", 0, fmt.Errorf("query media conn responded with no host")
}
return host, resp.MediaConn.Auth, resp.MediaConn.TTL, nil
} }
var mediaTypeMap = map[MediaType]string{ var mediaTypeMap = map[MediaType]string{
@ -202,7 +193,7 @@ func (wac *Conn) Upload(reader io.Reader, appInfo MediaType) (downloadURL string
body := bytes.NewReader(append(enc, mac...)) body := bytes.NewReader(append(enc, mac...))
req, err := http.NewRequest("POST", uploadURL.String(), body) req, err := http.NewRequest(http.MethodPost, uploadURL.String(), body)
if err != nil { if err != nil {
return "", nil, nil, nil, 0, err return "", nil, nil, nil, 0, err
} }
@ -222,7 +213,9 @@ func (wac *Conn) Upload(reader io.Reader, appInfo MediaType) (downloadURL string
} }
var jsonRes map[string]string var jsonRes map[string]string
json.NewDecoder(res.Body).Decode(&jsonRes) if err := json.NewDecoder(res.Body).Decode(&jsonRes); err != nil {
return "", nil, nil, nil, 0, err
}
return jsonRes["url"], mediaKey, fileEncSha256, fileSha256, fileLength, nil return jsonRes["url"], mediaKey, fileEncSha256, fileSha256, fileLength, nil
} }

View File

@ -7,6 +7,7 @@ import (
"fmt" "fmt"
"io" "io"
"io/ioutil" "io/ioutil"
"net/http"
"strings" "strings"
"github.com/Rhymen/go-whatsapp/binary" "github.com/Rhymen/go-whatsapp/binary"
@ -111,16 +112,16 @@ func (wac *Conn) decryptBinaryMessage(msg []byte) (*binary.Node, error) {
var response struct { var response struct {
Status int `json:"status"` Status int `json:"status"`
} }
err := json.Unmarshal(msg, &response)
if err == nil { if err := json.Unmarshal(msg, &response); err == nil {
if response.Status == 404 { if response.Status == http.StatusNotFound {
return nil, ErrServerRespondedWith404 return nil, ErrServerRespondedWith404
} }
return nil, errors.New(fmt.Sprintf("server responded with %d", response.Status)) return nil, errors.New(fmt.Sprintf("server responded with %d", response.Status))
} else {
return nil, ErrInvalidServerResponse
} }
return nil, ErrInvalidServerResponse
} }
h2.Write([]byte(msg[32:])) h2.Write([]byte(msg[32:]))
if !hmac.Equal(h2.Sum(nil), msg[:32]) { if !hmac.Equal(h2.Sum(nil), msg[:32]) {

View File

@ -66,6 +66,9 @@ type Attachment struct {
AudioURL string `json:"audio_url,omitempty"` AudioURL string `json:"audio_url,omitempty"`
VideoURL string `json:"video_url,omitempty"` VideoURL string `json:"video_url,omitempty"`
Actions []AttachmentAction `json:"actions,omitempty"`
ActionButtonsAlignment AttachmentActionButtonsAlignment `json:"button_alignment,omitempty"`
Fields []AttachmentField `json:"fields,omitempty"` Fields []AttachmentField `json:"fields,omitempty"`
} }
@ -77,3 +80,37 @@ type AttachmentField struct {
Title string `json:"title"` Title string `json:"title"`
Value string `json:"value"` Value string `json:"value"`
} }
type AttachmentActionType string
const (
AttachmentActionTypeButton AttachmentActionType = "button"
)
// AttachmentAction are action buttons on message attachments
type AttachmentAction struct {
Type AttachmentActionType `json:"type"`
Text string `json:"text"`
Url string `json:"url"`
ImageURL string `json:"image_url"`
IsWebView bool `json:"is_webview"`
WebviewHeightRatio string `json:"webview_height_ratio"`
Msg string `json:"msg"`
MsgInChatWindow bool `json:"msg_in_chat_window"`
MsgProcessingType MessageProcessingType `json:"msg_processing_type"`
}
// AttachmentActionButtonAlignment configures how the actions buttons will be aligned
type AttachmentActionButtonsAlignment string
const (
ActionButtonAlignVertical AttachmentActionButtonsAlignment = "vertical"
ActionButtonAlignHorizontal AttachmentActionButtonsAlignment = "horizontal"
)
type MessageProcessingType string
const (
ProcessingTypeSendMessage MessageProcessingType = "sendMessage"
ProcessingTypeRespondWithMessage MessageProcessingType = "respondWithMessage"
)

View File

@ -14,6 +14,7 @@ type CreateUserRequest struct {
Email string `json:"email"` Email string `json:"email"`
Password string `json:"password"` Password string `json:"password"`
Username string `json:"username"` Username string `json:"username"`
Roles []string `json:"roles,omitempty"`
CustomFields map[string]string `json:"customFields,omitempty"` CustomFields map[string]string `json:"customFields,omitempty"`
} }

View File

@ -72,6 +72,7 @@ func (c *Client) GetChannelSubscriptions() ([]models.ChannelSubscription, error)
DisplayName: stringOrZero(sub.Path("fname").Data()), DisplayName: stringOrZero(sub.Path("fname").Data()),
Open: sub.Path("open").Data().(bool), Open: sub.Path("open").Data().(bool),
Type: stringOrZero(sub.Path("t").Data()), Type: stringOrZero(sub.Path("t").Data()),
RoomId: stringOrZero(sub.Path("rid").Data()),
User: models.User{ User: models.User{
ID: stringOrZero(sub.Path("u._id").Data()), ID: stringOrZero(sub.Path("u._id").Data()),
UserName: stringOrZero(sub.Path("u.username").Data()), UserName: stringOrZero(sub.Path("u.username").Data()),

View File

@ -2,6 +2,7 @@ package realtime
import ( import (
"fmt" "fmt"
"log"
"strconv" "strconv"
"time" "time"
@ -16,27 +17,54 @@ const (
default_buffer_size = 100 default_buffer_size = 100
) )
var messageListenerAdded = false
// NewMessage creates basic message with an ID, a RoomID, and a Msg
// Takes channel and text
func (c *Client) NewMessage(channel *models.Channel, text string) *models.Message {
return &models.Message{
ID: c.newRandomId(),
RoomID: channel.ID,
Msg: text,
}
}
// LoadHistory loads history // LoadHistory loads history
// Takes roomId // Takes roomID
// //
// https://rocket.chat/docs/developer-guides/realtime-api/method-calls/load-history // https://rocket.chat/docs/developer-guides/realtime-api/method-calls/load-history
func (c *Client) LoadHistory(roomId string) error { func (c *Client) LoadHistory(roomID string) ([]models.Message, error) {
_, err := c.ddp.Call("loadHistory", roomId) m, err := c.ddp.Call("loadHistory", roomID)
if err != nil { if err != nil {
return err return nil, err
} }
return nil history := m.(map[string]interface{})
document, _ := gabs.Consume(history["messages"])
msgs, err := document.Children()
if err != nil {
log.Printf("response is in an unexpected format: %v", err)
return make([]models.Message, 0), nil
}
messages := make([]models.Message, len(msgs))
for i, arg := range msgs {
messages[i] = *getMessageFromDocument(arg)
}
// log.Println(messages)
return messages, nil
} }
// SendMessage sends message to channel // SendMessage sends message to channel
// takes channel and message // takes message
// //
// https://rocket.chat/docs/developer-guides/realtime-api/method-calls/send-message // https://rocket.chat/docs/developer-guides/realtime-api/method-calls/send-message
func (c *Client) SendMessage(m *models.Message) (*models.Message, error) { func (c *Client) SendMessage(message *models.Message) (*models.Message, error) {
m.ID = c.newRandomId() rawResponse, err := c.ddp.Call("sendMessage", message)
rawResponse, err := c.ddp.Call("sendMessage", m)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -158,8 +186,10 @@ func (c *Client) SubscribeToMessageStream(channel *models.Channel, msgChannel ch
return err return err
} }
// msgChannel := make(chan models.Message, default_buffer_size) if !messageListenerAdded {
c.ddp.CollectionByName("stream-room-messages").AddUpdateListener(messageExtractor{msgChannel, "update"}) c.ddp.CollectionByName("stream-room-messages").AddUpdateListener(messageExtractor{msgChannel, "update"})
messageListenerAdded = true
}
return nil return nil
} }

View File

@ -56,9 +56,17 @@ func (c *Client) LeaveChannel(channel *models.Channel) error {
// https://rocket.chat/docs/developer-guides/rest-api/channels/info // https://rocket.chat/docs/developer-guides/rest-api/channels/info
func (c *Client) GetChannelInfo(channel *models.Channel) (*models.Channel, error) { func (c *Client) GetChannelInfo(channel *models.Channel) (*models.Channel, error) {
response := new(ChannelResponse) response := new(ChannelResponse)
if err := c.Get("channels.info", url.Values{"roomId": []string{channel.ID}}, response); err != nil { switch {
return nil, err case channel.Name != "" && channel.ID == "":
if err := c.Get("channels.info", url.Values{"roomName": []string{channel.Name}}, response); err != nil {
return nil, err
}
default:
if err := c.Get("channels.info", url.Values{"roomId": []string{channel.ID}}, response); err != nil {
return nil, err
}
} }
return &response.Channel, nil return &response.Channel, nil
} }

View File

@ -0,0 +1,33 @@
package rest
import (
"bytes"
"encoding/json"
"github.com/matterbridge/Rocket.Chat.Go.SDK/models"
)
type UpdatePermissionsRequest struct {
Permissions []models.Permission `json:"permissions"`
}
type UpdatePermissionsResponse struct {
Status
Permissions []models.Permission `json:"permissions"`
}
// UpdatePermissions updates permissions
//
// https://rocket.chat/docs/developer-guides/rest-api/permissions/update/
func (c *Client) UpdatePermissions(req *UpdatePermissionsRequest) (*UpdatePermissionsResponse, error) {
body, err := json.Marshal(req)
if err != nil {
return nil, err
}
response := new(UpdatePermissionsResponse)
if err := c.Post("permissions.update", bytes.NewBuffer(body), response); err != nil {
return nil, err
}
return response, nil
}

View File

@ -25,11 +25,12 @@ func (o *Thread) Etag() string {
} }
type ThreadMembership struct { type ThreadMembership struct {
PostId string `json:"post_id"` PostId string `json:"post_id"`
UserId string `json:"user_id"` UserId string `json:"user_id"`
Following bool `json:"following"` Following bool `json:"following"`
LastViewed int64 `json:"last_view_at"` LastViewed int64 `json:"last_view_at"`
LastUpdated int64 `json:"last_update_at"` LastUpdated int64 `json:"last_update_at"`
UnreadMentions int64 `json:"unread_mentions"`
} }
func (o *ThreadMembership) ToJson() string { func (o *ThreadMembership) ToJson() string {

View File

@ -3,6 +3,7 @@ language: go
go: go:
- "1.9.x" - "1.9.x"
- "1.10.x" - "1.10.x"
- "1.11.x"
- tip - tip
matrix: matrix:
fast_finish: true fast_finish: true

View File

@ -1,29 +1,28 @@
Blackfriday is distributed under the Simplified BSD License: Blackfriday is distributed under the Simplified BSD License:
> Copyright © 2011 Russ Ross Copyright © 2011 Russ Ross
> All rights reserved. All rights reserved.
>
> Redistribution and use in source and binary forms, with or without Redistribution and use in source and binary forms, with or without
> modification, are permitted provided that the following conditions modification, are permitted provided that the following conditions
> are met: are met:
>
> 1. Redistributions of source code must retain the above copyright 1. Redistributions of source code must retain the above copyright
> notice, this list of conditions and the following disclaimer. notice, this list of conditions and the following disclaimer.
> 2. Redistributions in binary form must reproduce the above
> 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following
> copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with
> disclaimer in the documentation and/or other materials provided with the distribution.
> the distribution.
> THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
> THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
> "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
> LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
> FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
> COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
> INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
> BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
> LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
> CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
> LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
> ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
> POSSIBILITY OF SUCH DAMAGE.

View File

@ -1,6 +1,6 @@
Blackfriday Blackfriday
[![Build Status][BuildSVG]][BuildURL] [![Build Status][BuildV2SVG]][BuildV2URL]
[![Godoc][GodocV2SVG]][GodocV2URL] [![PkgGoDev][PkgGoDevV2SVG]][PkgGoDevV2URL]
=========== ===========
Blackfriday is a [Markdown][1] processor implemented in [Go][2]. It Blackfriday is a [Markdown][1] processor implemented in [Go][2]. It
@ -18,12 +18,21 @@ It started as a translation from C of [Sundown][3].
Installation Installation
------------ ------------
Blackfriday is compatible with any modern Go release. With Go and git installed: Blackfriday is compatible with modern Go releases in module mode.
With Go installed:
go get -u gopkg.in/russross/blackfriday.v2 go get github.com/russross/blackfriday
will download, compile, and install the package into your `$GOPATH` directory will resolve and add the package to the current development module,
hierarchy. then build and install it. Alternatively, you can achieve the same
if you import it in a package:
import "github.com/russross/blackfriday"
and `go get` without parameters.
Old versions of Go and legacy GOPATH mode might work,
but no effort is made to keep them working.
Versions Versions
@ -32,13 +41,9 @@ Versions
Currently maintained and recommended version of Blackfriday is `v2`. It's being Currently maintained and recommended version of Blackfriday is `v2`. It's being
developed on its own branch: https://github.com/russross/blackfriday/tree/v2 and the developed on its own branch: https://github.com/russross/blackfriday/tree/v2 and the
documentation is available at documentation is available at
https://godoc.org/gopkg.in/russross/blackfriday.v2. https://pkg.go.dev/github.com/russross/blackfriday/v2.
It is `go get`-able via [gopkg.in][6] at `gopkg.in/russross/blackfriday.v2`, It is `go get`-able in module mode at `github.com/russross/blackfriday/v2`.
but we highly recommend using package management tool like [dep][7] or
[Glide][8] and make use of semantic versioning. With package management you
should import `github.com/russross/blackfriday` and specify that you're using
version 2.0.0.
Version 2 offers a number of improvements over v1: Version 2 offers a number of improvements over v1:
@ -60,22 +65,7 @@ Potential drawbacks:
If you are still interested in the legacy `v1`, you can import it from If you are still interested in the legacy `v1`, you can import it from
`github.com/russross/blackfriday`. Documentation for the legacy v1 can be found `github.com/russross/blackfriday`. Documentation for the legacy v1 can be found
here: https://godoc.org/github.com/russross/blackfriday here: https://pkg.go.dev/github.com/russross/blackfriday.
### Known issue with `dep`
There is a known problem with using Blackfriday v1 _transitively_ and `dep`.
Currently `dep` prioritizes semver versions over anything else, and picks the
latest one, plus it does not apply a `[[constraint]]` specifier to transitively
pulled in packages. So if you're using something that uses Blackfriday v1, but
that something does not use `dep` yet, you will get Blackfriday v2 pulled in and
your first dependency will fail to build.
There are couple of fixes for it, documented here:
https://github.com/golang/dep/blob/master/docs/FAQ.md#how-do-i-constrain-a-transitive-dependencys-version
Meanwhile, `dep` team is working on a more general solution to the constraints
on transitive dependencies problem: https://github.com/golang/dep/issues/1124.
Usage Usage
@ -86,12 +76,16 @@ Usage
For basic usage, it is as simple as getting your input into a byte For basic usage, it is as simple as getting your input into a byte
slice and calling: slice and calling:
output := blackfriday.MarkdownBasic(input) ```go
output := blackfriday.MarkdownBasic(input)
```
This renders it with no extensions enabled. To get a more useful This renders it with no extensions enabled. To get a more useful
feature set, use this instead: feature set, use this instead:
output := blackfriday.MarkdownCommon(input) ```go
output := blackfriday.MarkdownCommon(input)
```
### v2 ### v2
@ -121,7 +115,7 @@ Here's an example of simple usage of Blackfriday together with Bluemonday:
```go ```go
import ( import (
"github.com/microcosm-cc/bluemonday" "github.com/microcosm-cc/bluemonday"
"gopkg.in/russross/blackfriday.v2" "github.com/russross/blackfriday"
) )
// ... // ...
@ -154,7 +148,7 @@ markdown file using a standalone program. You can also browse the
source directly on github if you are just looking for some example source directly on github if you are just looking for some example
code: code:
* <http://github.com/russross/blackfriday-tool> * <https://github.com/russross/blackfriday-tool>
Note that if you have not already done so, installing Note that if you have not already done so, installing
`blackfriday-tool` will be sufficient to download and install `blackfriday-tool` will be sufficient to download and install
@ -171,12 +165,12 @@ anchors for headings when `EXTENSION_AUTO_HEADER_IDS` is enabled. The
algorithm has a specification, so that other packages can create algorithm has a specification, so that other packages can create
compatible anchor names and links to those anchors. compatible anchor names and links to those anchors.
The specification is located at https://godoc.org/github.com/russross/blackfriday#hdr-Sanitized_Anchor_Names. The specification is located at https://pkg.go.dev/github.com/russross/blackfriday#hdr-Sanitized_Anchor_Names.
[`SanitizedAnchorName`](https://godoc.org/github.com/russross/blackfriday#SanitizedAnchorName) exposes this functionality, and can be used to [`SanitizedAnchorName`](https://pkg.go.dev/github.com/russross/blackfriday#SanitizedAnchorName) exposes this functionality, and can be used to
create compatible links to the anchor names generated by blackfriday. create compatible links to the anchor names generated by blackfriday.
This algorithm is also implemented in a small standalone package at This algorithm is also implemented in a small standalone package at
[`github.com/shurcooL/sanitized_anchor_name`](https://godoc.org/github.com/shurcooL/sanitized_anchor_name). It can be useful for clients [`github.com/shurcooL/sanitized_anchor_name`](https://pkg.go.dev/github.com/shurcooL/sanitized_anchor_name). It can be useful for clients
that want a small package and don't need full functionality of blackfriday. that want a small package and don't need full functionality of blackfriday.
@ -246,7 +240,7 @@ implements the following extensions:
and supply a language (to make syntax highlighting simple). Just and supply a language (to make syntax highlighting simple). Just
mark it like this: mark it like this:
``` go ```go
func getTrue() bool { func getTrue() bool {
return true return true
} }
@ -258,7 +252,7 @@ implements the following extensions:
To preserve classes of fenced code blocks while using the bluemonday To preserve classes of fenced code blocks while using the bluemonday
HTML sanitizer, use the following policy: HTML sanitizer, use the following policy:
``` go ```go
p := bluemonday.UGCPolicy() p := bluemonday.UGCPolicy()
p.AllowAttrs("class").Matching(regexp.MustCompile("^language-[a-zA-Z0-9]+$")).OnElements("code") p.AllowAttrs("class").Matching(regexp.MustCompile("^language-[a-zA-Z0-9]+$")).OnElements("code")
html := p.SanitizeBytes(unsafe) html := p.SanitizeBytes(unsafe)
@ -269,7 +263,7 @@ implements the following extensions:
Cat Cat
: Fluffy animal everyone likes : Fluffy animal everyone likes
Internet Internet
: Vector of transmission for pictures of cats : Vector of transmission for pictures of cats
@ -280,7 +274,7 @@ implements the following extensions:
end of the document. A footnote looks like this: end of the document. A footnote looks like this:
This is a footnote.[^1] This is a footnote.[^1]
[^1]: the footnote text. [^1]: the footnote text.
* **Autolinking**. Blackfriday can find URLs that have not been * **Autolinking**. Blackfriday can find URLs that have not been
@ -317,7 +311,7 @@ Other renderers
Blackfriday is structured to allow alternative rendering engines. Here Blackfriday is structured to allow alternative rendering engines. Here
are a few of note: are a few of note:
* [github_flavored_markdown](https://godoc.org/github.com/shurcooL/github_flavored_markdown): * [github_flavored_markdown](https://pkg.go.dev/github.com/shurcooL/github_flavored_markdown):
provides a GitHub Flavored Markdown renderer with fenced code block provides a GitHub Flavored Markdown renderer with fenced code block
highlighting, clickable heading anchor links. highlighting, clickable heading anchor links.
@ -328,7 +322,7 @@ are a few of note:
* [markdownfmt](https://github.com/shurcooL/markdownfmt): like gofmt, * [markdownfmt](https://github.com/shurcooL/markdownfmt): like gofmt,
but for markdown. but for markdown.
* [LaTeX output](https://bitbucket.org/ambrevar/blackfriday-latex): * [LaTeX output](https://gitlab.com/ambrevar/blackfriday-latex):
renders output as LaTeX. renders output as LaTeX.
* [bfchroma](https://github.com/Depado/bfchroma/): provides convenience * [bfchroma](https://github.com/Depado/bfchroma/): provides convenience
@ -337,6 +331,10 @@ are a few of note:
provides a drop-in renderer ready to use with Blackfriday, as well as provides a drop-in renderer ready to use with Blackfriday, as well as
options and means for further customization. options and means for further customization.
* [Blackfriday-Confluence](https://github.com/kentaro-m/blackfriday-confluence): provides a [Confluence Wiki Markup](https://confluence.atlassian.com/doc/confluence-wiki-markup-251003035.html) renderer.
* [Blackfriday-Slack](https://github.com/karriereat/blackfriday-slack): converts markdown to slack message style
TODO TODO
---- ----
@ -357,13 +355,10 @@ License
[1]: https://daringfireball.net/projects/markdown/ "Markdown" [1]: https://daringfireball.net/projects/markdown/ "Markdown"
[2]: https://golang.org/ "Go Language" [2]: https://golang.org/ "Go Language"
[3]: https://github.com/vmg/sundown "Sundown" [3]: https://github.com/vmg/sundown "Sundown"
[4]: https://godoc.org/gopkg.in/russross/blackfriday.v2#Parse "Parse func" [4]: https://pkg.go.dev/github.com/russross/blackfriday/v2#Parse "Parse func"
[5]: https://github.com/microcosm-cc/bluemonday "Bluemonday" [5]: https://github.com/microcosm-cc/bluemonday "Bluemonday"
[6]: https://labix.org/gopkg.in "gopkg.in"
[7]: https://github.com/golang/dep/ "dep"
[8]: https://github.com/Masterminds/glide "Glide"
[BuildSVG]: https://travis-ci.org/russross/blackfriday.svg?branch=master [BuildV2SVG]: https://travis-ci.org/russross/blackfriday.svg?branch=v2
[BuildURL]: https://travis-ci.org/russross/blackfriday [BuildV2URL]: https://travis-ci.org/russross/blackfriday
[GodocV2SVG]: https://godoc.org/gopkg.in/russross/blackfriday.v2?status.svg [PkgGoDevV2SVG]: https://pkg.go.dev/badge/github.com/russross/blackfriday/v2
[GodocV2URL]: https://godoc.org/gopkg.in/russross/blackfriday.v2 [PkgGoDevV2URL]: https://pkg.go.dev/github.com/russross/blackfriday/v2

View File

@ -649,14 +649,17 @@ func isFenceLine(data []byte, info *string, oldmarker string, newlineOptional bo
} }
i = skipChar(data, i, ' ') i = skipChar(data, i, ' ')
if i >= len(data) || data[i] != '\n' { if i >= len(data) {
if newlineOptional && i == len(data) { if newlineOptional {
return i, marker return i, marker
} }
return 0, "" return 0, ""
} }
if data[i] == '\n' {
i++ // Take newline into account
}
return i + 1, marker // Take newline into account. return i, marker
} }
// fencedCodeBlock returns the end index if data contains a fenced code block at the beginning, // fencedCodeBlock returns the end index if data contains a fenced code block at the beginning,
@ -1133,6 +1136,15 @@ func (p *parser) listItem(out *bytes.Buffer, data []byte, flags *int) int {
i++ i++
} }
// process the following lines
containsBlankLine := false
sublist := 0
codeBlockMarker := ""
if p.flags&EXTENSION_FENCED_CODE != 0 && i > line {
// determine if codeblock starts on the first line
_, codeBlockMarker = isFenceLine(data[line:i], nil, "", false)
}
// get working buffer // get working buffer
var raw bytes.Buffer var raw bytes.Buffer
@ -1140,11 +1152,6 @@ func (p *parser) listItem(out *bytes.Buffer, data []byte, flags *int) int {
raw.Write(data[line:i]) raw.Write(data[line:i])
line = i line = i
// process the following lines
containsBlankLine := false
sublist := 0
codeBlockMarker := ""
gatherlines: gatherlines:
for line < len(data) { for line < len(data) {
i++ i++
@ -1153,7 +1160,6 @@ gatherlines:
for data[i-1] != '\n' { for data[i-1] != '\n' {
i++ i++
} }
// if it is an empty line, guess that it is part of this item // if it is an empty line, guess that it is part of this item
// and move on to the next line // and move on to the next line
if p.isEmpty(data[line:i]) > 0 { if p.isEmpty(data[line:i]) > 0 {

View File

@ -1 +1,3 @@
module github.com/russross/blackfriday module github.com/russross/blackfriday
go 1.13

View File

@ -32,6 +32,7 @@ const (
HTML_SAFELINK // only link to trusted protocols HTML_SAFELINK // only link to trusted protocols
HTML_NOFOLLOW_LINKS // only link with rel="nofollow" HTML_NOFOLLOW_LINKS // only link with rel="nofollow"
HTML_NOREFERRER_LINKS // only link with rel="noreferrer" HTML_NOREFERRER_LINKS // only link with rel="noreferrer"
HTML_NOOPENER_LINKS // only link with rel="noopener"
HTML_HREF_TARGET_BLANK // add a blank target HTML_HREF_TARGET_BLANK // add a blank target
HTML_TOC // generate a table of contents HTML_TOC // generate a table of contents
HTML_OMIT_CONTENTS // skip the main contents (for a standalone table of contents) HTML_OMIT_CONTENTS // skip the main contents (for a standalone table of contents)
@ -445,6 +446,9 @@ func (options *Html) AutoLink(out *bytes.Buffer, link []byte, kind int) {
if options.flags&HTML_NOREFERRER_LINKS != 0 && !isRelativeLink(link) { if options.flags&HTML_NOREFERRER_LINKS != 0 && !isRelativeLink(link) {
relAttrs = append(relAttrs, "noreferrer") relAttrs = append(relAttrs, "noreferrer")
} }
if options.flags&HTML_NOOPENER_LINKS != 0 && !isRelativeLink(link) {
relAttrs = append(relAttrs, "noopener")
}
if len(relAttrs) > 0 { if len(relAttrs) > 0 {
out.WriteString(fmt.Sprintf("\" rel=\"%s", strings.Join(relAttrs, " "))) out.WriteString(fmt.Sprintf("\" rel=\"%s", strings.Join(relAttrs, " ")))
} }
@ -559,6 +563,9 @@ func (options *Html) Link(out *bytes.Buffer, link []byte, title []byte, content
if options.flags&HTML_NOREFERRER_LINKS != 0 && !isRelativeLink(link) { if options.flags&HTML_NOREFERRER_LINKS != 0 && !isRelativeLink(link) {
relAttrs = append(relAttrs, "noreferrer") relAttrs = append(relAttrs, "noreferrer")
} }
if options.flags&HTML_NOOPENER_LINKS != 0 && !isRelativeLink(link) {
relAttrs = append(relAttrs, "noopener")
}
if len(relAttrs) > 0 { if len(relAttrs) > 0 {
out.WriteString(fmt.Sprintf("\" rel=\"%s", strings.Join(relAttrs, " "))) out.WriteString(fmt.Sprintf("\" rel=\"%s", strings.Join(relAttrs, " ")))
} }

View File

@ -252,7 +252,7 @@ func link(p *parser, out *bytes.Buffer, data []byte, offset int) int {
case data[i] == '\n': case data[i] == '\n':
textHasNl = true textHasNl = true
case data[i-1] == '\\': case isBackslashEscaped(data, i):
continue continue
case data[i] == '[': case data[i] == '[':

View File

@ -132,6 +132,7 @@ var blockTags = map[string]struct{}{
"article": {}, "article": {},
"aside": {}, "aside": {},
"canvas": {}, "canvas": {},
"details": {},
"figcaption": {}, "figcaption": {},
"figure": {}, "figure": {},
"footer": {}, "footer": {},
@ -142,6 +143,7 @@ var blockTags = map[string]struct{}{
"output": {}, "output": {},
"progress": {}, "progress": {},
"section": {}, "section": {},
"summary": {},
"video": {}, "video": {},
} }

View File

@ -2020,7 +2020,11 @@ func (sc *serverConn) newWriterAndRequest(st *stream, f *MetaHeadersFrame) (*res
} }
if bodyOpen { if bodyOpen {
if vv, ok := rp.header["Content-Length"]; ok { if vv, ok := rp.header["Content-Length"]; ok {
req.ContentLength, _ = strconv.ParseInt(vv[0], 10, 64) if cl, err := strconv.ParseUint(vv[0], 10, 63); err == nil {
req.ContentLength = int64(cl)
} else {
req.ContentLength = 0
}
} else { } else {
req.ContentLength = -1 req.ContentLength = -1
} }
@ -2403,9 +2407,8 @@ func (rws *responseWriterState) writeChunk(p []byte) (n int, err error) {
var ctype, clen string var ctype, clen string
if clen = rws.snapHeader.Get("Content-Length"); clen != "" { if clen = rws.snapHeader.Get("Content-Length"); clen != "" {
rws.snapHeader.Del("Content-Length") rws.snapHeader.Del("Content-Length")
clen64, err := strconv.ParseInt(clen, 10, 64) if cl, err := strconv.ParseUint(clen, 10, 63); err == nil {
if err == nil && clen64 >= 0 { rws.sentContentLen = int64(cl)
rws.sentContentLen = clen64
} else { } else {
clen = "" clen = ""
} }

View File

@ -2006,8 +2006,8 @@ func (rl *clientConnReadLoop) handleResponse(cs *clientStream, f *MetaHeadersFra
if !streamEnded || isHead { if !streamEnded || isHead {
res.ContentLength = -1 res.ContentLength = -1
if clens := res.Header["Content-Length"]; len(clens) == 1 { if clens := res.Header["Content-Length"]; len(clens) == 1 {
if clen64, err := strconv.ParseInt(clens[0], 10, 64); err == nil { if cl, err := strconv.ParseUint(clens[0], 10, 63); err == nil {
res.ContentLength = clen64 res.ContentLength = int64(cl)
} else { } else {
// TODO: care? unlike http/1, it won't mess up our framing, so it's // TODO: care? unlike http/1, it won't mess up our framing, so it's
// more safe smuggling-wise to ignore. // more safe smuggling-wise to ignore.

View File

@ -21,5 +21,5 @@ const (
// RemoteDavEndpoint returns the endpoint for the Dav API for Nextcloud // RemoteDavEndpoint returns the endpoint for the Dav API for Nextcloud
func RemoteDavEndpoint(username string, davType string) string { func RemoteDavEndpoint(username string, davType string) string {
return "/remote.php/dav/" + davType + "/" + username + "/" return "/remote.php/dav/" + username + "/" + davType + "/"
} }

View File

@ -62,7 +62,7 @@ func NewTalkRoom(tuser *user.TalkUser, token string) (*TalkRoom, error) {
// SendMessage sends a message in the Talk room // SendMessage sends a message in the Talk room
func (t *TalkRoom) SendMessage(msg string) (*ocs.TalkRoomMessageData, error) { func (t *TalkRoom) SendMessage(msg string) (*ocs.TalkRoomMessageData, error) {
url := t.User.NextcloudURL + constants.BaseEndpoint + "chat/" + t.Token url := t.User.NextcloudURL + constants.BaseEndpoint + "/chat/" + t.Token
requestParams := map[string]string{ requestParams := map[string]string{
"message": msg, "message": msg,
} }
@ -93,7 +93,7 @@ func (t *TalkRoom) ReceiveMessages(ctx context.Context) (chan ocs.TalkRoomMessag
if err != nil { if err != nil {
return nil, err return nil, err
} }
url := t.User.NextcloudURL + constants.BaseEndpoint + "chat/" + t.Token url := t.User.NextcloudURL + constants.BaseEndpoint + "/chat/" + t.Token
requestParam := map[string]string{ requestParam := map[string]string{
"lookIntoFuture": "1", "lookIntoFuture": "1",
"includeLastKnown": "0", "includeLastKnown": "0",
@ -154,7 +154,7 @@ func (t *TalkRoom) TestConnection() error {
if t.Token == "" { if t.Token == "" {
return ErrEmptyToken return ErrEmptyToken
} }
url := t.User.NextcloudURL + constants.BaseEndpoint + "chat/" + t.Token url := t.User.NextcloudURL + constants.BaseEndpoint + "/chat/" + t.Token
requestParam := map[string]string{ requestParam := map[string]string{
"lookIntoFuture": "0", "lookIntoFuture": "0",
"includeLastKnown": "0", "includeLastKnown": "0",

20
vendor/modules.txt vendored
View File

@ -4,8 +4,7 @@ github.com/42wim/go-gitter
# github.com/Baozisoftware/qrcode-terminal-go v0.0.0-20170407111555-c0650d8dff0f # github.com/Baozisoftware/qrcode-terminal-go v0.0.0-20170407111555-c0650d8dff0f
## explicit ## explicit
github.com/Baozisoftware/qrcode-terminal-go github.com/Baozisoftware/qrcode-terminal-go
# github.com/Jeffail/gabs v1.1.1 # github.com/Jeffail/gabs v1.4.0
## explicit
github.com/Jeffail/gabs github.com/Jeffail/gabs
# github.com/Philipp15b/go-steam v1.0.1-0.20200727090957-6ae9b3c0a560 # github.com/Philipp15b/go-steam v1.0.1-0.20200727090957-6ae9b3c0a560
## explicit ## explicit
@ -19,7 +18,7 @@ github.com/Philipp15b/go-steam/protocol/steamlang
github.com/Philipp15b/go-steam/rwu github.com/Philipp15b/go-steam/rwu
github.com/Philipp15b/go-steam/socialcache github.com/Philipp15b/go-steam/socialcache
github.com/Philipp15b/go-steam/steamid github.com/Philipp15b/go-steam/steamid
# github.com/Rhymen/go-whatsapp v0.1.2-0.20201122130733-6e5488ac98df # github.com/Rhymen/go-whatsapp v0.1.2-0.20201130210432-64cc8cf1437d
## explicit ## explicit
github.com/Rhymen/go-whatsapp github.com/Rhymen/go-whatsapp
github.com/Rhymen/go-whatsapp/binary github.com/Rhymen/go-whatsapp/binary
@ -28,6 +27,8 @@ github.com/Rhymen/go-whatsapp/binary/token
github.com/Rhymen/go-whatsapp/crypto/cbc github.com/Rhymen/go-whatsapp/crypto/cbc
github.com/Rhymen/go-whatsapp/crypto/curve25519 github.com/Rhymen/go-whatsapp/crypto/curve25519
github.com/Rhymen/go-whatsapp/crypto/hkdf github.com/Rhymen/go-whatsapp/crypto/hkdf
# github.com/RocketChat/Rocket.Chat.Go.SDK v0.0.0-20200922220614-e4a51dfb52e4
## explicit
# github.com/blang/semver v3.5.1+incompatible # github.com/blang/semver v3.5.1+incompatible
github.com/blang/semver github.com/blang/semver
# github.com/d5/tengo/v2 v2.6.2 # github.com/d5/tengo/v2 v2.6.2
@ -71,7 +72,6 @@ github.com/google/gops/signal
# github.com/google/uuid v1.1.1 # github.com/google/uuid v1.1.1
github.com/google/uuid github.com/google/uuid
# github.com/gopackage/ddp v0.0.0-20170117053602-652027933df4 # github.com/gopackage/ddp v0.0.0-20170117053602-652027933df4
## explicit
github.com/gopackage/ddp github.com/gopackage/ddp
# github.com/gorilla/schema v1.2.0 # github.com/gorilla/schema v1.2.0
## explicit ## explicit
@ -125,7 +125,7 @@ github.com/magiconair/properties
# github.com/matrix-org/gomatrix v0.0.0-20200827122206-7dd5e2a05bcd # github.com/matrix-org/gomatrix v0.0.0-20200827122206-7dd5e2a05bcd
## explicit ## explicit
github.com/matrix-org/gomatrix github.com/matrix-org/gomatrix
# github.com/matterbridge/Rocket.Chat.Go.SDK v0.0.0-20201206161339-a8e64af17cde # github.com/matterbridge/Rocket.Chat.Go.SDK v0.0.0-20201206215757-c1d86d75b9f8
## explicit ## explicit
github.com/matterbridge/Rocket.Chat.Go.SDK/models github.com/matterbridge/Rocket.Chat.Go.SDK/models
github.com/matterbridge/Rocket.Chat.Go.SDK/realtime github.com/matterbridge/Rocket.Chat.Go.SDK/realtime
@ -156,7 +156,7 @@ github.com/mattermost/ldap
github.com/mattermost/logr github.com/mattermost/logr
github.com/mattermost/logr/format github.com/mattermost/logr/format
github.com/mattermost/logr/target github.com/mattermost/logr/target
# github.com/mattermost/mattermost-server/v5 v5.29.0 # github.com/mattermost/mattermost-server/v5 v5.29.1
## explicit ## explicit
github.com/mattermost/mattermost-server/v5/mlog github.com/mattermost/mattermost-server/v5/mlog
github.com/mattermost/mattermost-server/v5/model github.com/mattermost/mattermost-server/v5/model
@ -212,7 +212,7 @@ github.com/rickb777/plural
# github.com/rs/xid v1.2.1 # github.com/rs/xid v1.2.1
## explicit ## explicit
github.com/rs/xid github.com/rs/xid
# github.com/russross/blackfriday v1.5.2 # github.com/russross/blackfriday v1.6.0
## explicit ## explicit
github.com/russross/blackfriday github.com/russross/blackfriday
# github.com/saintfish/chardet v0.0.0-20120816061221-3af4cd4741ca # github.com/saintfish/chardet v0.0.0-20120816061221-3af4cd4741ca
@ -323,7 +323,7 @@ golang.org/x/image/riff
golang.org/x/image/vp8 golang.org/x/image/vp8
golang.org/x/image/vp8l golang.org/x/image/vp8l
golang.org/x/image/webp golang.org/x/image/webp
# golang.org/x/net v0.0.0-20200822124328-c89045814202 # golang.org/x/net v0.0.0-20200904194848-62affa334b73
golang.org/x/net/context golang.org/x/net/context
golang.org/x/net/context/ctxhttp golang.org/x/net/context/ctxhttp
golang.org/x/net/html golang.org/x/net/html
@ -334,7 +334,7 @@ golang.org/x/net/http2/h2c
golang.org/x/net/http2/hpack golang.org/x/net/http2/hpack
golang.org/x/net/idna golang.org/x/net/idna
golang.org/x/net/websocket golang.org/x/net/websocket
# golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58 # golang.org/x/oauth2 v0.0.0-20201203001011-0b49973bad19
## explicit ## explicit
golang.org/x/oauth2 golang.org/x/oauth2
golang.org/x/oauth2/clientcredentials golang.org/x/oauth2/clientcredentials
@ -362,7 +362,7 @@ golang.org/x/text/transform
golang.org/x/text/unicode/bidi golang.org/x/text/unicode/bidi
golang.org/x/text/unicode/norm golang.org/x/text/unicode/norm
golang.org/x/text/width golang.org/x/text/width
# gomod.garykim.dev/nc-talk v0.1.5 # gomod.garykim.dev/nc-talk v0.1.6
## explicit ## explicit
gomod.garykim.dev/nc-talk/constants gomod.garykim.dev/nc-talk/constants
gomod.garykim.dev/nc-talk/ocs gomod.garykim.dev/nc-talk/ocs