From eb49bb1391e383235c315aad92633603c85aee23 Mon Sep 17 00:00:00 2001 From: thisisaaronland Date: Mon, 22 Nov 2021 12:44:32 -0800 Subject: [PATCH] update vendor deps --- go.mod | 10 +- go.sum | 21 + .../github.com/aaronland/go-json-query/go.mod | 2 +- .../github.com/aaronland/go-json-query/go.sum | 6 + vendor/github.com/paulmach/orb/ring.go | 3 +- vendor/github.com/sfomuseum/go-edtf/Makefile | 1 + vendor/github.com/sfomuseum/go-edtf/README.md | 20 + vendor/github.com/tidwall/gjson/README.md | 21 +- vendor/github.com/tidwall/gjson/SYNTAX.md | 2 + vendor/github.com/tidwall/gjson/gjson.go | 438 +++++++++++++++--- vendor/github.com/tidwall/gjson/go.mod | 2 +- vendor/github.com/tidwall/gjson/go.sum | 4 +- vendor/github.com/tidwall/match/match.go | 243 ++++++---- .../whosonfirst/go-ioutil/readseekcloser.go | 4 +- .../whosonfirst/go-reader/README.md | 2 +- .../github.com/whosonfirst/go-reader/go.mod | 2 +- .../github.com/whosonfirst/go-reader/go.sum | 2 + .../properties/alt_label.go | 10 + .../properties/centroid.go | 48 ++ .../properties/concordances.go | 12 +- .../properties/country.go | 16 + .../properties/created.go | 16 + .../go-whosonfirst-feature/properties/edtf.go | 34 ++ .../properties/hierarchies.go | 29 ++ .../go-whosonfirst-feature/properties/id.go | 2 +- .../properties/lastmodified.go | 16 + .../go-whosonfirst-feature/properties/name.go | 1 - .../properties/parent_id.go | 26 ++ .../properties/placetype.go | 19 + .../go-whosonfirst-feature/properties/repo.go | 18 + .../properties/superseded_by.go | 18 + .../properties/supersedes.go | 18 + vendor/modules.txt | 18 +- 33 files changed, 873 insertions(+), 211 deletions(-) create mode 100644 vendor/github.com/whosonfirst/go-whosonfirst-feature/properties/alt_label.go create mode 100644 vendor/github.com/whosonfirst/go-whosonfirst-feature/properties/centroid.go create mode 100644 vendor/github.com/whosonfirst/go-whosonfirst-feature/properties/country.go create mode 100644 vendor/github.com/whosonfirst/go-whosonfirst-feature/properties/created.go create mode 100644 vendor/github.com/whosonfirst/go-whosonfirst-feature/properties/edtf.go create mode 100644 vendor/github.com/whosonfirst/go-whosonfirst-feature/properties/hierarchies.go create mode 100644 vendor/github.com/whosonfirst/go-whosonfirst-feature/properties/lastmodified.go create mode 100644 vendor/github.com/whosonfirst/go-whosonfirst-feature/properties/parent_id.go create mode 100644 vendor/github.com/whosonfirst/go-whosonfirst-feature/properties/placetype.go create mode 100644 vendor/github.com/whosonfirst/go-whosonfirst-feature/properties/repo.go create mode 100644 vendor/github.com/whosonfirst/go-whosonfirst-feature/properties/superseded_by.go create mode 100644 vendor/github.com/whosonfirst/go-whosonfirst-feature/properties/supersedes.go diff --git a/go.mod b/go.mod index 69851a5..f07f5b4 100644 --- a/go.mod +++ b/go.mod @@ -4,11 +4,11 @@ go 1.16 require ( github.com/aaronland/go-roster v0.0.2 - github.com/paulmach/orb v0.2.2 + github.com/paulmach/orb v0.4.0 github.com/sfomuseum/go-sfomuseum-reader v0.0.1 - github.com/tidwall/gjson v1.9.1 - github.com/whosonfirst/go-reader v0.9.0 - github.com/whosonfirst/go-whosonfirst-feature v0.0.3 - github.com/whosonfirst/go-whosonfirst-iterate/v2 v2.0.0 + github.com/tidwall/gjson v1.11.0 + github.com/whosonfirst/go-reader v0.9.1 + github.com/whosonfirst/go-whosonfirst-feature v0.0.17 + github.com/whosonfirst/go-whosonfirst-iterate/v2 v2.0.1 github.com/whosonfirst/go-whosonfirst-uri v1.1.0 ) diff --git a/go.sum b/go.sum index 4b6c59e..e93992d 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,7 @@ github.com/aaronland/go-json-query v0.1.0 h1:ZHtbpW8jiGYuOXKDEscWDrDjyVXZhU9Qqfi3nkyI9Ho= github.com/aaronland/go-json-query v0.1.0/go.mod h1:Mj1i+9hS3cd2Nj7qlnahcUeRC5uydPuJ/3xZGlIgBFU= +github.com/aaronland/go-json-query v0.1.1 h1:2kwlEvJrH8Vr9gOMtfiVhBAqDtq3z7S0P2zj173mUhs= +github.com/aaronland/go-json-query v0.1.1/go.mod h1:lZHt3LmcrZ0bovlqvr1jQaQKJKpb2pMLN2er6RGHAIQ= github.com/aaronland/go-roster v0.0.2 h1:2Fu7v4VQLRLRL/Zgr6R9S5JxsW75Ab/K88QtMVX532s= github.com/aaronland/go-roster v0.0.2/go.mod h1:AcovpxlG1XxJxX2Fjqlm63fEIBhCjEIBV4lP87FZDmI= github.com/go-ini/ini v1.42.0/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8= @@ -22,6 +24,9 @@ github.com/paulmach/go.geojson v1.4.0 h1:5x5moCkCtDo5x8af62P9IOAYGQcYHtxz2QJ3x1D github.com/paulmach/go.geojson v1.4.0/go.mod h1:YaKx1hKpWF+T2oj2lFJPsW/t1Q5e1jQI61eoQSTwpIs= github.com/paulmach/orb v0.2.2 h1:PblToKAbU0xHVypex/GdZfibA1CeCfN5s0UjxyWExdo= github.com/paulmach/orb v0.2.2/go.mod h1:FkcWtplUAIVqAuhAOV2d3rpbnQyliDOjOcLW9dUrfdU= +github.com/paulmach/orb v0.3.0/go.mod h1:FkcWtplUAIVqAuhAOV2d3rpbnQyliDOjOcLW9dUrfdU= +github.com/paulmach/orb v0.4.0 h1:ilp1MQjRapLJ1+qcays1nZpe0mvkCY+b8JU/qBKRZ1A= +github.com/paulmach/orb v0.4.0/go.mod h1:FkcWtplUAIVqAuhAOV2d3rpbnQyliDOjOcLW9dUrfdU= github.com/paulmach/protoscan v0.2.1-0.20210522164731-4e53c6875432/go.mod h1:2sV+uZ/oQh66m4XJVZm5iqUZ62BN88Ex1E+TTS0nLzI= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/sfomuseum/go-edtf v0.2.2/go.mod h1:1rP0EJZ/84j3HO80vGcnG2T9MFBDAFyTNtjrr8cv3T4= @@ -29,6 +34,8 @@ github.com/sfomuseum/go-edtf v0.2.3 h1:wpcpwl1RD9W/sXFDi4zpoIpQcIwIk8em9CGwa7YWv github.com/sfomuseum/go-edtf v0.2.3/go.mod h1:1rP0EJZ/84j3HO80vGcnG2T9MFBDAFyTNtjrr8cv3T4= github.com/sfomuseum/go-edtf v0.3.0 h1:D9YI8FUR9mGge2aVFLIJE1IF+6KDKZddXCftPjUPnSo= github.com/sfomuseum/go-edtf v0.3.0/go.mod h1:1rP0EJZ/84j3HO80vGcnG2T9MFBDAFyTNtjrr8cv3T4= +github.com/sfomuseum/go-edtf v0.3.1 h1:22DEXVvGhnpF7PD4dvpgKH0/oD8u9I+a4cXCwy1x2f4= +github.com/sfomuseum/go-edtf v0.3.1/go.mod h1:1rP0EJZ/84j3HO80vGcnG2T9MFBDAFyTNtjrr8cv3T4= github.com/sfomuseum/go-flags v0.7.0/go.mod h1:ML3DTNbF9xnjExSdS/9FtVLjIUhRU5gm/ehzISv+t2w= github.com/sfomuseum/go-sfomuseum-geojson v0.1.2 h1:rZM4b1+LrdP3Yzrsoed7Ror33gThictCpgqLmhESfdA= github.com/sfomuseum/go-sfomuseum-geojson v0.1.2/go.mod h1:khGRObq7bqsMqr4VWrw0NmZQmTyV82YEYK90w7SF9mk= @@ -46,9 +53,15 @@ github.com/tidwall/gjson v1.7.5 h1:zmAN/xmX7OtpAkv4Ovfso60r/BiCi5IErCDYGNJu+uc= github.com/tidwall/gjson v1.7.5/go.mod h1:5/xDoumyyDNerp2U36lyolv46b3uF/9Bu6OfyQ9GImk= github.com/tidwall/gjson v1.9.1 h1:wrrRk7TyL7MmKanNRck/Mcr3VU1sdMvJHvJXzqBIUNo= github.com/tidwall/gjson v1.9.1/go.mod h1:jydLKE7s8J0+1/5jC4eXcuFlzKizGrCKvLmBVX/5oXc= +github.com/tidwall/gjson v1.9.3/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= +github.com/tidwall/gjson v1.10.2/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= +github.com/tidwall/gjson v1.11.0 h1:C16pk7tQNiH6VlCrtIXL1w8GaOsi1X3W8KDkE1BuYd4= +github.com/tidwall/gjson v1.11.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= github.com/tidwall/match v1.0.1/go.mod h1:LujAq0jyVjBy028G1WhWfIzbpQfMO8bBZ6Tyb0+pL9E= github.com/tidwall/match v1.0.3 h1:FQUVvBImDutD8wJLN6c5eMzWtjgONK9MwIBCOrUJKeE= github.com/tidwall/match v1.0.3/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= +github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= +github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= github.com/tidwall/pretty v1.0.2/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= github.com/tidwall/pretty v1.1.0 h1:K3hMW5epkdAVwibsQEfR/7Zj0Qgt4DxtNumTq/VloO8= @@ -57,14 +70,20 @@ github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs= github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= github.com/whosonfirst/go-ioutil v1.0.0 h1:sYpgJx7Wsp76e7PFGa8KKQBvWQW3+HMCWSJbKdD5m14= github.com/whosonfirst/go-ioutil v1.0.0/go.mod h1:2dS1vWdAIkiHDvDF8fYyjv6k2NISmwaIjJJeEDBEdvg= +github.com/whosonfirst/go-ioutil v1.0.1 h1:xITnQgEGdG+Qlph7jPY5htL7UpPSm2wEw1WiUlKTWPc= +github.com/whosonfirst/go-ioutil v1.0.1/go.mod h1:2dS1vWdAIkiHDvDF8fYyjv6k2NISmwaIjJJeEDBEdvg= github.com/whosonfirst/go-reader v0.2.0/go.mod h1:qUhz3OWefOUX/G1nzCEUzJskDjkF+l9oKPOM3K2fAJI= github.com/whosonfirst/go-reader v0.9.0 h1:u5PITZiAkPrpmZQHlkASdBEzF1pwby5vtgAmCEESWu4= github.com/whosonfirst/go-reader v0.9.0/go.mod h1:6byB+UfZFNLYFqgsC/EKxTnKY8ahNgGHhUJsTrv1Jig= +github.com/whosonfirst/go-reader v0.9.1 h1:gSQz3vQYWnLHP+LI6CKBXKCrpVQOMp8LG7ps1KJr3lM= +github.com/whosonfirst/go-reader v0.9.1/go.mod h1:YNcxm9xr0++Jz4nXWZjtQ/RRVq0fCjq1CwJdmJgfOh8= github.com/whosonfirst/go-whosonfirst-cli v0.1.0/go.mod h1:Edy+amD+fMq1QS1yxB3u8maA8I93q/LG7JRNh+fsdfc= github.com/whosonfirst/go-whosonfirst-crawl v0.2.1 h1:nNG7r7/4MaII/NM8Df2oqgfgVNBDoIKlseleoX1vw1Q= github.com/whosonfirst/go-whosonfirst-crawl v0.2.1/go.mod h1:MTD1TCgAkXlAtysPU98ylrz9Y5+ZCfRrsrBnRyiH/t8= github.com/whosonfirst/go-whosonfirst-feature v0.0.3 h1:WfwLjlOxbLdIxGF4RoeVCByHn8tRDnMFqr+UOnVOTmo= github.com/whosonfirst/go-whosonfirst-feature v0.0.3/go.mod h1:7ezV1UK9GwPInW7s4Mf16qxZsvKuzCYOa4oiw/ksNLo= +github.com/whosonfirst/go-whosonfirst-feature v0.0.17 h1:oDN8YcpuRlBxz5UQ8+M9MSdf3eduLEK8+roiUZHYTAI= +github.com/whosonfirst/go-whosonfirst-feature v0.0.17/go.mod h1:vwNwMQLTL+vb88CXtTe4N63TLCn8DYREqR/Zm2Fn5rA= github.com/whosonfirst/go-whosonfirst-flags v0.1.0/go.mod h1:bovMiQphaVhqemXFmNVf9Ts0tqnWtzHRFMUSKX+zTE8= github.com/whosonfirst/go-whosonfirst-flags v0.2.0/go.mod h1:ECd0AJJZIlybmjTGB9z+CPz9pSiMTwxur7fPKmDnoqI= github.com/whosonfirst/go-whosonfirst-flags v0.4.2 h1:HWjy/0MfAQMdCj4M9hi3LAITgK/D+cuDWGHP37mFeZo= @@ -81,6 +100,8 @@ github.com/whosonfirst/go-whosonfirst-iterate v1.2.0 h1:+wouZy6JPIrmLBZdFDqI1UJW github.com/whosonfirst/go-whosonfirst-iterate v1.2.0/go.mod h1:MOA6QCBONVG98p8kA8HaoBEAmv83jW4SNTfNhHpP9+o= github.com/whosonfirst/go-whosonfirst-iterate/v2 v2.0.0 h1:w2N2TfsaGcONmQzR4MMxuDvVpt8DuJnlVeS9Eh5Sffk= github.com/whosonfirst/go-whosonfirst-iterate/v2 v2.0.0/go.mod h1:NeChKAgakom3sWjPfTnxauSykSzmkfqnEbtuy6nSF6s= +github.com/whosonfirst/go-whosonfirst-iterate/v2 v2.0.1 h1:YW1Qa9qkhb9NlLGwpEJtcQQYdTa0WoFjrut9lO6jKP4= +github.com/whosonfirst/go-whosonfirst-iterate/v2 v2.0.1/go.mod h1:oGk1jhZiP1Hfe4QVQAMAVCkTTjxlr5/hrzk/xfxWVss= github.com/whosonfirst/go-whosonfirst-placetypes v0.1.0/go.mod h1:Jdmug2QQLbrmg+UcYGz8k575GnrOEg63vZVS46e5fMs= github.com/whosonfirst/go-whosonfirst-placetypes v0.2.4/go.mod h1:yl0zZ5tfK80C0kl34pJcPB3mZC5XXR7ybQJ5OJyEcDU= github.com/whosonfirst/go-whosonfirst-placetypes v0.3.0 h1:68kuizK8FXjfEIOKlqWemhs7gyMBIgpLJDbCZF8+8Ok= diff --git a/vendor/github.com/aaronland/go-json-query/go.mod b/vendor/github.com/aaronland/go-json-query/go.mod index 6c42bbe..2c9b25f 100644 --- a/vendor/github.com/aaronland/go-json-query/go.mod +++ b/vendor/github.com/aaronland/go-json-query/go.mod @@ -2,4 +2,4 @@ module github.com/aaronland/go-json-query go 1.12 -require github.com/tidwall/gjson v1.7.5 +require github.com/tidwall/gjson v1.9.3 diff --git a/vendor/github.com/aaronland/go-json-query/go.sum b/vendor/github.com/aaronland/go-json-query/go.sum index 82f9da4..210b168 100644 --- a/vendor/github.com/aaronland/go-json-query/go.sum +++ b/vendor/github.com/aaronland/go-json-query/go.sum @@ -2,11 +2,17 @@ github.com/tidwall/gjson v1.6.0 h1:9VEQWz6LLMUsUl6PueE49ir4Ka6CzLymOAZDxpFsTDc= github.com/tidwall/gjson v1.6.0/go.mod h1:P256ACg0Mn+j1RXIDXoss50DeIABTYK1PULOJHhxOls= github.com/tidwall/gjson v1.7.5 h1:zmAN/xmX7OtpAkv4Ovfso60r/BiCi5IErCDYGNJu+uc= github.com/tidwall/gjson v1.7.5/go.mod h1:5/xDoumyyDNerp2U36lyolv46b3uF/9Bu6OfyQ9GImk= +github.com/tidwall/gjson v1.9.3 h1:hqzS9wAHMO+KVBBkLxYdkEeeFHuqr95GfClRLKlgK0E= +github.com/tidwall/gjson v1.9.3/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= github.com/tidwall/match v1.0.1 h1:PnKP62LPNxHKTwvHHZZzdOAOCtsJTjo6dZLCwpKm5xc= github.com/tidwall/match v1.0.1/go.mod h1:LujAq0jyVjBy028G1WhWfIzbpQfMO8bBZ6Tyb0+pL9E= github.com/tidwall/match v1.0.3 h1:FQUVvBImDutD8wJLN6c5eMzWtjgONK9MwIBCOrUJKeE= github.com/tidwall/match v1.0.3/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= +github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= +github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= github.com/tidwall/pretty v1.0.0 h1:HsD+QiTn7sK6flMKIvNmpqz1qrpP3Ps6jOKIKMooyg4= github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= github.com/tidwall/pretty v1.1.0 h1:K3hMW5epkdAVwibsQEfR/7Zj0Qgt4DxtNumTq/VloO8= github.com/tidwall/pretty v1.1.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= +github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs= +github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= diff --git a/vendor/github.com/paulmach/orb/ring.go b/vendor/github.com/paulmach/orb/ring.go index efe2976..5fe88ac 100644 --- a/vendor/github.com/paulmach/orb/ring.go +++ b/vendor/github.com/paulmach/orb/ring.go @@ -17,8 +17,7 @@ func (r Ring) Dimensions() int { // ie. 4+ points and the first and last points match. // NOTE: this will not check for self-intersection. func (r Ring) Closed() bool { - // first must equal last - return r[0] == r[len(r)-1] + return (len(r) >= 4) && (r[0] == r[len(r)-1]) } // Reverse changes the direction of the ring. diff --git a/vendor/github.com/sfomuseum/go-edtf/Makefile b/vendor/github.com/sfomuseum/go-edtf/Makefile index 045089a..57a6e61 100644 --- a/vendor/github.com/sfomuseum/go-edtf/Makefile +++ b/vendor/github.com/sfomuseum/go-edtf/Makefile @@ -1,2 +1,3 @@ cli: go build -mod vendor -o bin/parse cmd/parse/main.go + go build -mod vendor -o bin/matches cmd/matches/main.go diff --git a/vendor/github.com/sfomuseum/go-edtf/README.md b/vendor/github.com/sfomuseum/go-edtf/README.md index f183947..4244899 100644 --- a/vendor/github.com/sfomuseum/go-edtf/README.md +++ b/vendor/github.com/sfomuseum/go-edtf/README.md @@ -209,6 +209,26 @@ To build binary versions of these tools run the `cli` Makefile target. For examp ``` $> make cli go build -mod vendor -o bin/parse cmd/parse/main.go +go build -mod vendor -o bin/matches cmd/matches/main.go +``` + +### matches + +Parse one or more EDTF strings and emit the EDTF level and feature name they match. + +``` +> ./bin/matches -h +Parse one or more EDTF strings and emit the EDTF level and feature name they match. +Usage: + ./bin/matches edtf_string(N) edtf_string(N) +``` + +For example: + +``` +> ./bin/matches 193X 2021-10-10T00:24:00Z +193X level 1 (Unspecified digit(s) from the right) +2021-10-10T00:24:00Z level 0 (Date and Time) ``` ### parse diff --git a/vendor/github.com/tidwall/gjson/README.md b/vendor/github.com/tidwall/gjson/README.md index b7848de..f489847 100644 --- a/vendor/github.com/tidwall/gjson/README.md +++ b/vendor/github.com/tidwall/gjson/README.md @@ -200,6 +200,8 @@ There are currently the following built-in modifiers: - `@valid`: Ensure the json document is valid. - `@flatten`: Flattens an array. - `@join`: Joins multiple objects into a single object. +- `@keys`: Returns an array of keys for an object. +- `@values`: Returns an array of values for an object. ### Modifier arguments @@ -434,14 +436,15 @@ Benchmarks of GJSON alongside [encoding/json](https://golang.org/pkg/encoding/js and [json-iterator](https://github.com/json-iterator/go) ``` -BenchmarkGJSONGet-8 3000000 372 ns/op 0 B/op 0 allocs/op -BenchmarkGJSONUnmarshalMap-8 900000 4154 ns/op 1920 B/op 26 allocs/op -BenchmarkJSONUnmarshalMap-8 600000 9019 ns/op 3048 B/op 69 allocs/op -BenchmarkJSONDecoder-8 300000 14120 ns/op 4224 B/op 184 allocs/op -BenchmarkFFJSONLexer-8 1500000 3111 ns/op 896 B/op 8 allocs/op -BenchmarkEasyJSONLexer-8 3000000 887 ns/op 613 B/op 6 allocs/op -BenchmarkJSONParserGet-8 3000000 499 ns/op 21 B/op 0 allocs/op -BenchmarkJSONIterator-8 3000000 812 ns/op 544 B/op 9 allocs/op +BenchmarkGJSONGet-16 11644512 311 ns/op 0 B/op 0 allocs/op +BenchmarkGJSONUnmarshalMap-16 1122678 3094 ns/op 1920 B/op 26 allocs/op +BenchmarkJSONUnmarshalMap-16 516681 6810 ns/op 2944 B/op 69 allocs/op +BenchmarkJSONUnmarshalStruct-16 697053 5400 ns/op 928 B/op 13 allocs/op +BenchmarkJSONDecoder-16 330450 10217 ns/op 3845 B/op 160 allocs/op +BenchmarkFFJSONLexer-16 1424979 2585 ns/op 880 B/op 8 allocs/op +BenchmarkEasyJSONLexer-16 3000000 729 ns/op 501 B/op 5 allocs/op +BenchmarkJSONParserGet-16 3000000 366 ns/op 21 B/op 0 allocs/op +BenchmarkJSONIterator-16 3000000 869 ns/op 693 B/op 14 allocs/op ``` JSON document used: @@ -482,4 +485,4 @@ widget.image.hOffset widget.text.onMouseUp ``` -*These benchmarks were run on a MacBook Pro 15" 2.8 GHz Intel Core i7 using Go 1.8 and can be found [here](https://github.com/tidwall/gjson-benchmarks).* +*These benchmarks were run on a MacBook Pro 16" 2.4 GHz Intel Core i9 using Go 1.17 and can be found [here](https://github.com/tidwall/gjson-benchmarks).* diff --git a/vendor/github.com/tidwall/gjson/SYNTAX.md b/vendor/github.com/tidwall/gjson/SYNTAX.md index 34fdccf..9bc18c8 100644 --- a/vendor/github.com/tidwall/gjson/SYNTAX.md +++ b/vendor/github.com/tidwall/gjson/SYNTAX.md @@ -236,6 +236,8 @@ There are currently the following built-in modifiers: - `@valid`: Ensure the json document is valid. - `@flatten`: Flattens an array. - `@join`: Joins multiple objects into a single object. +- `@keys`: Returns an array of keys for an object. +- `@values`: Returns an array of values for an object. #### Modifier arguments diff --git a/vendor/github.com/tidwall/gjson/gjson.go b/vendor/github.com/tidwall/gjson/gjson.go index 973c8af..ec2ce35 100644 --- a/vendor/github.com/tidwall/gjson/gjson.go +++ b/vendor/github.com/tidwall/gjson/gjson.go @@ -189,14 +189,15 @@ func (t Result) Time() time.Time { } // Array returns back an array of values. -// If the result represents a non-existent value, then an empty array will be -// returned. If the result is not a JSON array, the return value will be an +// If the result represents a null value or is non-existent, then an empty +// array will be returned. +// If the result is not a JSON array, the return value will be an // array containing one result. func (t Result) Array() []Result { if t.Type == Null { return []Result{} } - if t.Type != JSON { + if !t.IsArray() { return []Result{t} } r := t.arrayOrMap('[', false) @@ -248,6 +249,7 @@ func (t Result) ForEach(iterator func(key, value Result) bool) { var str string var vesc bool var ok bool + var idx int for ; i < len(json); i++ { if keys { if json[i] != '"' { @@ -264,7 +266,7 @@ func (t Result) ForEach(iterator func(key, value Result) bool) { key.Str = str[1 : len(str)-1] } key.Raw = str - key.Index = s + key.Index = s + t.Index } for ; i < len(json); i++ { if json[i] <= ' ' || json[i] == ',' || json[i] == ':' { @@ -277,10 +279,17 @@ func (t Result) ForEach(iterator func(key, value Result) bool) { if !ok { return } - value.Index = s + if t.Indexes != nil { + if idx < len(t.Indexes) { + value.Index = t.Indexes[idx] + } + } else { + value.Index = s + t.Index + } if !iterator(key, value) { return } + idx++ } } @@ -297,7 +306,15 @@ func (t Result) Map() map[string]Result { // Get searches result for the specified path. // The result should be a JSON array or object. func (t Result) Get(path string) Result { - return Get(t.Raw, path) + r := Get(t.Raw, path) + if r.Indexes != nil { + for i := 0; i < len(r.Indexes); i++ { + r.Indexes[i] += t.Index + } + } else { + r.Index += t.Index + } + return r } type arrayOrMapResult struct { @@ -388,6 +405,8 @@ func (t Result) arrayOrMap(vc byte, valueize bool) (r arrayOrMapResult) { value.Raw, value.Str = tostr(json[i:]) value.Num = 0 } + value.Index = i + t.Index + i += len(value.Raw) - 1 if r.vc == '{' { @@ -414,6 +433,17 @@ func (t Result) arrayOrMap(vc byte, valueize bool) (r arrayOrMapResult) { } } end: + if t.Indexes != nil { + if len(t.Indexes) != len(r.a) { + for i := 0; i < len(r.a); i++ { + r.a[i].Index = 0 + } + } else { + for i := 0; i < len(r.a); i++ { + r.a[i].Index = t.Indexes[i] + } + } + } return } @@ -425,7 +455,8 @@ end: // use the Valid function first. func Parse(json string) Result { var value Result - for i := 0; i < len(json); i++ { + i := 0 + for ; i < len(json); i++ { if json[i] == '{' || json[i] == '[' { value.Type = JSON value.Raw = json[i:] // just take the entire raw @@ -435,16 +466,20 @@ func Parse(json string) Result { continue } switch json[i] { - default: - if (json[i] >= '0' && json[i] <= '9') || json[i] == '-' { + case '+', '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + 'i', 'I', 'N': + value.Type = Number + value.Raw, value.Num = tonum(json[i:]) + case 'n': + if i+1 < len(json) && json[i+1] != 'u' { + // nan value.Type = Number value.Raw, value.Num = tonum(json[i:]) } else { - return Result{} + // null + value.Type = Null + value.Raw = tolit(json[i:]) } - case 'n': - value.Type = Null - value.Raw = tolit(json[i:]) case 't': value.Type = True value.Raw = tolit(json[i:]) @@ -454,9 +489,14 @@ func Parse(json string) Result { case '"': value.Type = String value.Raw, value.Str = tostr(json[i:]) + default: + return Result{} } break } + if value.Exists() { + value.Index = i + } return value } @@ -530,20 +570,12 @@ func tonum(json string) (raw string, num float64) { return } // could be a '+' or '-'. let's assume so. - continue - } - if json[i] < ']' { - // probably a valid number - continue - } - if json[i] == 'e' || json[i] == 'E' { - // allow for exponential numbers - continue + } else if json[i] == ']' || json[i] == '}' { + // break on ']' or '}' + raw = json[:i] + num, _ = strconv.ParseFloat(raw, 64) + return } - // likely a ']' or '}' - raw = json[:i] - num, _ = strconv.ParseFloat(raw, 64) - return } raw = json num, _ = strconv.ParseFloat(raw, 64) @@ -760,7 +792,7 @@ func parseArrayPath(path string) (r arrayPathResult) { // bad query, end now break } - if len(value) > 2 && value[0] == '"' && + if len(value) >= 2 && value[0] == '"' && value[len(value)-1] == '"' { value = value[1 : len(value)-1] if vesc { @@ -1089,9 +1121,9 @@ func parseObject(c *parseContext, i int, path string) (int, bool) { } if rp.wild { if kesc { - pmatch = match.Match(unescape(key), rp.part) + pmatch = matchLimit(unescape(key), rp.part) } else { - pmatch = match.Match(key, rp.part) + pmatch = matchLimit(key, rp.part) } } else { if kesc { @@ -1102,6 +1134,7 @@ func parseObject(c *parseContext, i int, path string) (int, bool) { } hit = pmatch && !rp.more for ; i < len(c.json); i++ { + var num bool switch c.json[i] { default: continue @@ -1149,15 +1182,13 @@ func parseObject(c *parseContext, i int, path string) (int, bool) { return i, true } } - case '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': - i, val = parseNumber(c.json, i) - if hit { - c.value.Raw = val - c.value.Type = Number - c.value.Num, _ = strconv.ParseFloat(val, 64) - return i, true + case 'n': + if i+1 < len(c.json) && c.json[i+1] != 'u' { + num = true + break } - case 't', 'f', 'n': + fallthrough + case 't', 'f': vc := c.json[i] i, val = parseLiteral(c.json, i) if hit { @@ -1170,12 +1201,33 @@ func parseObject(c *parseContext, i int, path string) (int, bool) { } return i, true } + case '+', '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + 'i', 'I', 'N': + num = true + } + if num { + i, val = parseNumber(c.json, i) + if hit { + c.value.Raw = val + c.value.Type = Number + c.value.Num, _ = strconv.ParseFloat(val, 64) + return i, true + } } break } } return i, false } + +// matchLimit will limit the complexity of the match operation to avoid ReDos +// attacks from arbritary inputs. +// See the github.com/tidwall/match.MatchLimit function for more information. +func matchLimit(str, pattern string) bool { + matched, _ := match.MatchLimit(str, pattern, 10000) + return matched +} + func queryMatches(rp *arrayPathResult, value Result) bool { rpv := rp.query.value if len(rpv) > 0 && rpv[0] == '~' { @@ -1213,9 +1265,9 @@ func queryMatches(rp *arrayPathResult, value Result) bool { case ">=": return value.Str >= rpv case "%": - return match.Match(value.Str, rpv) + return matchLimit(value.Str, rpv) case "!%": - return !match.Match(value.Str, rpv) + return !matchLimit(value.Str, rpv) } case Number: rpvn, _ := strconv.ParseFloat(rpv, 64) @@ -1348,6 +1400,7 @@ func parseArray(c *parseContext, i int, path string) (int, bool) { } else { ch = c.json[i] } + var num bool switch ch { default: continue @@ -1430,26 +1483,13 @@ func parseArray(c *parseContext, i int, path string) (int, bool) { return i, true } } - case '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': - i, val = parseNumber(c.json, i) - if rp.query.on { - var qval Result - qval.Raw = val - qval.Type = Number - qval.Num, _ = strconv.ParseFloat(val, 64) - if procQuery(qval) { - return i, true - } - } else if hit { - if rp.alogok { - break - } - c.value.Raw = val - c.value.Type = Number - c.value.Num, _ = strconv.ParseFloat(val, 64) - return i, true + case 'n': + if i+1 < len(c.json) && c.json[i+1] != 'u' { + num = true + break } - case 't', 'f', 'n': + fallthrough + case 't', 'f': vc := c.json[i] i, val = parseLiteral(c.json, i) if rp.query.on { @@ -1477,6 +1517,9 @@ func parseArray(c *parseContext, i int, path string) (int, bool) { } return i, true } + case '+', '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + 'i', 'I', 'N': + num = true case ']': if rp.arrch && rp.part == "#" { if rp.alogok { @@ -1501,7 +1544,6 @@ func parseArray(c *parseContext, i int, path string) (int, bool) { } if idx < len(c.json) && c.json[idx] != ']' { _, res, ok := parseAny(c.json, idx, true) - parentIndex := res.Index if ok { res := res.Get(rp.alogkey) if res.Exists() { @@ -1513,8 +1555,7 @@ func parseArray(c *parseContext, i int, path string) (int, bool) { raw = res.String() } jsons = append(jsons, []byte(raw)...) - indexes = append(indexes, - res.Index+parentIndex) + indexes = append(indexes, res.Index) k++ } } @@ -1552,6 +1593,26 @@ func parseArray(c *parseContext, i int, path string) (int, bool) { } return i + 1, false } + if num { + i, val = parseNumber(c.json, i) + if rp.query.on { + var qval Result + qval.Raw = val + qval.Type = Number + qval.Num, _ = strconv.ParseFloat(val, 64) + if procQuery(qval) { + return i, true + } + } else if hit { + if rp.alogok { + break + } + c.value.Raw = val + c.value.Type = Number + c.value.Num, _ = strconv.ParseFloat(val, 64) + return i, true + } + } break } } @@ -2071,6 +2132,7 @@ func parseAny(json string, i int, hit bool) (int, Result, bool) { if json[i] <= ' ' { continue } + var num bool switch json[i] { case '"': i++ @@ -2090,15 +2152,13 @@ func parseAny(json string, i int, hit bool) (int, Result, bool) { } } return i, res, true - case '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': - i, val = parseNumber(json, i) - if hit { - res.Raw = val - res.Type = Number - res.Num, _ = strconv.ParseFloat(val, 64) + case 'n': + if i+1 < len(json) && json[i+1] != 'u' { + num = true + break } - return i, res, true - case 't', 'f', 'n': + fallthrough + case 't', 'f': vc := json[i] i, val = parseLiteral(json, i) if hit { @@ -2111,7 +2171,20 @@ func parseAny(json string, i int, hit bool) (int, Result, bool) { } return i, res, true } + case '+', '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + 'i', 'I', 'N': + num = true + } + if num { + i, val = parseNumber(json, i) + if hit { + res.Raw = val + res.Type = Number + res.Num, _ = strconv.ParseFloat(val, 64) + } + return i, res, true } + } return i, res, false } @@ -2555,6 +2628,8 @@ var modifiers = map[string]func(json, arg string) string{ "flatten": modFlatten, "join": modJoin, "valid": modValid, + "keys": modKeys, + "values": modValues, } // AddModifier binds a custom modifier command to the GJSON syntax. @@ -2711,6 +2786,58 @@ func modFlatten(json, arg string) string { return bytesString(out) } +// @keys extracts the keys from an object. +// {"first":"Tom","last":"Smith"} -> ["first","last"] +func modKeys(json, arg string) string { + v := Parse(json) + if !v.Exists() { + return "[]" + } + obj := v.IsObject() + var out strings.Builder + out.WriteByte('[') + var i int + v.ForEach(func(key, _ Result) bool { + if i > 0 { + out.WriteByte(',') + } + if obj { + out.WriteString(key.Raw) + } else { + out.WriteString("null") + } + i++ + return true + }) + out.WriteByte(']') + return out.String() +} + +// @values extracts the values from an object. +// {"first":"Tom","last":"Smith"} -> ["Tom","Smith"] +func modValues(json, arg string) string { + v := Parse(json) + if !v.Exists() { + return "[]" + } + if v.IsArray() { + return json + } + var out strings.Builder + out.WriteByte('[') + var i int + v.ForEach(func(_, value Result) bool { + if i > 0 { + out.WriteByte(',') + } + out.WriteString(value.Raw) + i++ + return true + }) + out.WriteByte(']') + return out.String() +} + // @join multiple objects into a single object. // [{"first":"Tom"},{"last":"Smith"}] -> {"first","Tom","last":"Smith"} // The arg can be "true" to specify that duplicate keys should be preserved. @@ -2873,3 +3000,176 @@ func stringBytes(s string) []byte { func bytesString(b []byte) string { return *(*string)(unsafe.Pointer(&b)) } + +func revSquash(json string) string { + // reverse squash + // expects that the tail character is a ']' or '}' or ')' or '"' + // squash the value, ignoring all nested arrays and objects. + i := len(json) - 1 + var depth int + if json[i] != '"' { + depth++ + } + if json[i] == '}' || json[i] == ']' || json[i] == ')' { + i-- + } + for ; i >= 0; i-- { + switch json[i] { + case '"': + i-- + for ; i >= 0; i-- { + if json[i] == '"' { + esc := 0 + for i > 0 && json[i-1] == '\\' { + i-- + esc++ + } + if esc%2 == 1 { + continue + } + i += esc + break + } + } + if depth == 0 { + if i < 0 { + i = 0 + } + return json[i:] + } + case '}', ']', ')': + depth++ + case '{', '[', '(': + depth-- + if depth == 0 { + return json[i:] + } + } + } + return json +} + +func (t Result) Paths(json string) []string { + if t.Indexes == nil { + return nil + } + paths := make([]string, 0, len(t.Indexes)) + t.ForEach(func(_, value Result) bool { + paths = append(paths, value.Path(json)) + return true + }) + if len(paths) != len(t.Indexes) { + return nil + } + return paths +} + +// Path returns the original GJSON path for Result. +// The json param must be the original JSON used when calling Get. +func (t Result) Path(json string) string { + var path []byte + var comps []string // raw components + i := t.Index - 1 + if t.Index+len(t.Raw) > len(json) { + // JSON cannot safely contain Result. + goto fail + } + if !strings.HasPrefix(json[t.Index:], t.Raw) { + // Result is not at the JSON index as exepcted. + goto fail + } + for ; i >= 0; i-- { + if json[i] <= ' ' { + continue + } + if json[i] == ':' { + // inside of object, get the key + for ; i >= 0; i-- { + if json[i] != '"' { + continue + } + break + } + raw := revSquash(json[:i+1]) + i = i - len(raw) + comps = append(comps, raw) + // key gotten, now squash the rest + raw = revSquash(json[:i+1]) + i = i - len(raw) + i++ // increment the index for next loop step + } else if json[i] == '{' { + // Encountered an open object. The original result was probably an + // object key. + goto fail + } else if json[i] == ',' || json[i] == '[' { + // inside of an array, count the position + var arrIdx int + if json[i] == ',' { + arrIdx++ + i-- + } + for ; i >= 0; i-- { + if json[i] == ':' { + // Encountered an unexpected colon. The original result was + // probably an object key. + goto fail + } else if json[i] == ',' { + arrIdx++ + } else if json[i] == '[' { + comps = append(comps, strconv.Itoa(arrIdx)) + break + } else if json[i] == ']' || json[i] == '}' || json[i] == '"' { + raw := revSquash(json[:i+1]) + i = i - len(raw) + 1 + } + } + } + } + if len(comps) == 0 { + if DisableModifiers { + goto fail + } + return "@this" + } + for i := len(comps) - 1; i >= 0; i-- { + rcomp := Parse(comps[i]) + if !rcomp.Exists() { + goto fail + } + comp := escapeComp(rcomp.String()) + path = append(path, '.') + path = append(path, comp...) + } + if len(path) > 0 { + path = path[1:] + } + return string(path) +fail: + return "" +} + +// isSafePathKeyChar returns true if the input character is safe for not +// needing escaping. +func isSafePathKeyChar(c byte) bool { + return c <= ' ' || c > '~' || c == '_' || c == '-' || c == ':' || + (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || + (c >= '0' && c <= '9') +} + +// escapeComp escaped a path compontent, making it safe for generating a +// path for later use. +func escapeComp(comp string) string { + for i := 0; i < len(comp); i++ { + if !isSafePathKeyChar(comp[i]) { + ncomp := []byte(comp[:i]) + for ; i < len(comp); i++ { + if !isSafePathKeyChar(comp[i]) { + ncomp = append(ncomp, '\\') + } + ncomp = append(ncomp, comp[i]) + } + return string(ncomp) + } + } + return comp +} diff --git a/vendor/github.com/tidwall/gjson/go.mod b/vendor/github.com/tidwall/gjson/go.mod index 85b771d..6f64083 100644 --- a/vendor/github.com/tidwall/gjson/go.mod +++ b/vendor/github.com/tidwall/gjson/go.mod @@ -3,6 +3,6 @@ module github.com/tidwall/gjson go 1.12 require ( - github.com/tidwall/match v1.0.3 + github.com/tidwall/match v1.1.1 github.com/tidwall/pretty v1.2.0 ) diff --git a/vendor/github.com/tidwall/gjson/go.sum b/vendor/github.com/tidwall/gjson/go.sum index d0afaf4..be39c8c 100644 --- a/vendor/github.com/tidwall/gjson/go.sum +++ b/vendor/github.com/tidwall/gjson/go.sum @@ -1,4 +1,4 @@ -github.com/tidwall/match v1.0.3 h1:FQUVvBImDutD8wJLN6c5eMzWtjgONK9MwIBCOrUJKeE= -github.com/tidwall/match v1.0.3/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= +github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= +github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs= github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= diff --git a/vendor/github.com/tidwall/match/match.go b/vendor/github.com/tidwall/match/match.go index 57aabf4..11da28f 100644 --- a/vendor/github.com/tidwall/match/match.go +++ b/vendor/github.com/tidwall/match/match.go @@ -1,7 +1,9 @@ // Package match provides a simple pattern matcher with unicode support. package match -import "unicode/utf8" +import ( + "unicode/utf8" +) // Match returns true if str matches pattern. This is a very // simple wildcard match where '*' matches on any number characters @@ -16,127 +18,170 @@ import "unicode/utf8" // '\\' c matches character c // func Match(str, pattern string) bool { - return deepMatch(str, pattern) -} - -func deepMatch(str, pattern string) bool { if pattern == "*" { return true } - for len(pattern) > 1 && pattern[0] == '*' && pattern[1] == '*' { - pattern = pattern[1:] - } - for len(pattern) > 0 { - if pattern[0] > 0x7f { - return deepMatchRune(str, pattern) - } - switch pattern[0] { - default: - if len(str) == 0 { - return false - } - if str[0] > 0x7f { - return deepMatchRune(str, pattern) - } - if str[0] != pattern[0] { - return false - } - case '?': - if len(str) == 0 { - return false - } - case '*': - return deepMatch(str, pattern[1:]) || - (len(str) > 0 && deepMatch(str[1:], pattern)) - } - str = str[1:] - pattern = pattern[1:] - } - return len(str) == 0 && len(pattern) == 0 + return match(str, pattern, 0, nil, -1) == rMatch } -func deepMatchRune(str, pattern string) bool { +// MatchLimit is the same as Match but will limit the complexity of the match +// operation. This is to avoid long running matches, specifically to avoid ReDos +// attacks from arbritary inputs. +// +// How it works: +// The underlying match routine is recursive and may call itself when it +// encounters a sandwiched wildcard pattern, such as: `user:*:name`. +// Everytime it calls itself a counter is incremented. +// The operation is stopped when counter > maxcomp*len(str). +func MatchLimit(str, pattern string, maxcomp int) (matched, stopped bool) { if pattern == "*" { - return true + return true, false } - for len(pattern) > 1 && pattern[0] == '*' && pattern[1] == '*' { - pattern = pattern[1:] + counter := 0 + r := match(str, pattern, len(str), &counter, maxcomp) + if r == rStop { + return false, true } + return r == rMatch, false +} - var sr, pr rune - var srsz, prsz int +type result int - // read the first rune ahead of time - if len(str) > 0 { - if str[0] > 0x7f { - sr, srsz = utf8.DecodeRuneInString(str) - } else { - sr, srsz = rune(str[0]), 1 +const ( + rNoMatch result = iota + rMatch + rStop +) + +func match(str, pat string, slen int, counter *int, maxcomp int) result { + // check complexity limit + if maxcomp > -1 { + if *counter > slen*maxcomp { + return rStop } - } else { - sr, srsz = utf8.RuneError, 0 + *counter++ } - if len(pattern) > 0 { - if pattern[0] > 0x7f { - pr, prsz = utf8.DecodeRuneInString(pattern) - } else { - pr, prsz = rune(pattern[0]), 1 + + for len(pat) > 0 { + var wild bool + pc, ps := rune(pat[0]), 1 + if pc > 0x7f { + pc, ps = utf8.DecodeRuneInString(pat) } - } else { - pr, prsz = utf8.RuneError, 0 - } - // done reading - for pr != utf8.RuneError { - switch pr { - default: - if srsz == utf8.RuneError { - return false - } - if sr != pr { - return false + var sc rune + var ss int + if len(str) > 0 { + sc, ss = rune(str[0]), 1 + if sc > 0x7f { + sc, ss = utf8.DecodeRuneInString(str) } + } + switch pc { case '?': - if srsz == utf8.RuneError { - return false + if ss == 0 { + return rNoMatch } case '*': - return deepMatchRune(str, pattern[prsz:]) || - (srsz > 0 && deepMatchRune(str[srsz:], pattern)) - } - str = str[srsz:] - pattern = pattern[prsz:] - // read the next runes - if len(str) > 0 { - if str[0] > 0x7f { - sr, srsz = utf8.DecodeRuneInString(str) - } else { - sr, srsz = rune(str[0]), 1 + // Ignore repeating stars. + for len(pat) > 1 && pat[1] == '*' { + pat = pat[1:] } - } else { - sr, srsz = utf8.RuneError, 0 - } - if len(pattern) > 0 { - if pattern[0] > 0x7f { - pr, prsz = utf8.DecodeRuneInString(pattern) - } else { - pr, prsz = rune(pattern[0]), 1 + + // If this star is the last character then it must be a match. + if len(pat) == 1 { + return rMatch } - } else { - pr, prsz = utf8.RuneError, 0 + + // Match and trim any non-wildcard suffix characters. + var ok bool + str, pat, ok = matchTrimSuffix(str, pat) + if !ok { + return rNoMatch + } + + // Check for single star again. + if len(pat) == 1 { + return rMatch + } + + // Perform recursive wildcard search. + r := match(str, pat[1:], slen, counter, maxcomp) + if r != rNoMatch { + return r + } + if len(str) == 0 { + return rNoMatch + } + wild = true + default: + if ss == 0 { + return rNoMatch + } + if pc == '\\' { + pat = pat[ps:] + pc, ps = utf8.DecodeRuneInString(pat) + if ps == 0 { + return rNoMatch + } + } + if sc != pc { + return rNoMatch + } + } + str = str[ss:] + if !wild { + pat = pat[ps:] } - // done reading } - - return srsz == 0 && prsz == 0 + if len(str) == 0 { + return rMatch + } + return rNoMatch } -var maxRuneBytes = func() []byte { - b := make([]byte, 4) - if utf8.EncodeRune(b, '\U0010FFFF') != 4 { - panic("invalid rune encoding") +// matchTrimSuffix matches and trims any non-wildcard suffix characters. +// Returns the trimed string and pattern. +// +// This is called because the pattern contains extra data after the wildcard +// star. Here we compare any suffix characters in the pattern to the suffix of +// the target string. Basically a reverse match that stops when a wildcard +// character is reached. This is a little trickier than a forward match because +// we need to evaluate an escaped character in reverse. +// +// Any matched characters will be trimmed from both the target +// string and the pattern. +func matchTrimSuffix(str, pat string) (string, string, bool) { + // It's expected that the pattern has at least two bytes and the first byte + // is a wildcard star '*' + match := true + for len(str) > 0 && len(pat) > 1 { + pc, ps := utf8.DecodeLastRuneInString(pat) + var esc bool + for i := 0; ; i++ { + if pat[len(pat)-ps-i-1] != '\\' { + if i&1 == 1 { + esc = true + ps++ + } + break + } + } + if pc == '*' && !esc { + match = true + break + } + sc, ss := utf8.DecodeLastRuneInString(str) + if !((pc == '?' && !esc) || pc == sc) { + match = false + break + } + str = str[:len(str)-ss] + pat = pat[:len(pat)-ps] } - return b -}() + return str, pat, match +} + +var maxRuneBytes = [...]byte{244, 143, 191, 191} // Allowable parses the pattern and determines the minimum and maximum allowable // values that the pattern can represent. @@ -157,7 +202,7 @@ func Allowable(pattern string) (min, max string) { } if pattern[i] == '?' { minb = append(minb, 0) - maxb = append(maxb, maxRuneBytes...) + maxb = append(maxb, maxRuneBytes[:]...) } else { minb = append(minb, pattern[i]) maxb = append(maxb, pattern[i]) diff --git a/vendor/github.com/whosonfirst/go-ioutil/readseekcloser.go b/vendor/github.com/whosonfirst/go-ioutil/readseekcloser.go index 18bb37e..39b230b 100644 --- a/vendor/github.com/whosonfirst/go-ioutil/readseekcloser.go +++ b/vendor/github.com/whosonfirst/go-ioutil/readseekcloser.go @@ -33,8 +33,8 @@ func NewReadSeekCloser(fh interface{}) (io.ReadSeekCloser, error) { switch fh.(type) { case io.ReadSeekCloser: return fh.(io.ReadSeekCloser), nil - case io.Reader: - // pass + case io.Closer: + closer = true case io.ReadCloser: closer = true case io.ReadSeeker: diff --git a/vendor/github.com/whosonfirst/go-reader/README.md b/vendor/github.com/whosonfirst/go-reader/README.md index 1141902..c09b318 100644 --- a/vendor/github.com/whosonfirst/go-reader/README.md +++ b/vendor/github.com/whosonfirst/go-reader/README.md @@ -227,7 +227,7 @@ func main() { r, _ := reader.NewReader(ctx, "github://{GITHUB_OWNER}/{GITHUB_REPO}") // to specify a specific branch you would do this: - // r, _ := reader.NewReader(ctx, "github://{GITHUB_OWNER}/{GITHUB_REPO}/{GITHUB_BRANCH}") + // r, _ := reader.NewReader(ctx, "github://{GITHUB_OWNER}/{GITHUB_REPO}?branch={GITHUB_BRANCH}") } ``` diff --git a/vendor/github.com/whosonfirst/go-reader/go.mod b/vendor/github.com/whosonfirst/go-reader/go.mod index 310b1e6..257e587 100644 --- a/vendor/github.com/whosonfirst/go-reader/go.mod +++ b/vendor/github.com/whosonfirst/go-reader/go.mod @@ -4,5 +4,5 @@ go 1.16 require ( github.com/aaronland/go-roster v0.0.2 - github.com/whosonfirst/go-ioutil v1.0.0 + github.com/whosonfirst/go-ioutil v1.0.1 ) diff --git a/vendor/github.com/whosonfirst/go-reader/go.sum b/vendor/github.com/whosonfirst/go-reader/go.sum index 52e1991..799689b 100644 --- a/vendor/github.com/whosonfirst/go-reader/go.sum +++ b/vendor/github.com/whosonfirst/go-reader/go.sum @@ -16,6 +16,8 @@ github.com/whosonfirst/go-ioutil v0.0.1 h1:cCrEYen6NDvHfjzV2q4u/VB21u2kTOwDnUGRl github.com/whosonfirst/go-ioutil v0.0.1/go.mod h1:2dS1vWdAIkiHDvDF8fYyjv6k2NISmwaIjJJeEDBEdvg= github.com/whosonfirst/go-ioutil v1.0.0 h1:sYpgJx7Wsp76e7PFGa8KKQBvWQW3+HMCWSJbKdD5m14= github.com/whosonfirst/go-ioutil v1.0.0/go.mod h1:2dS1vWdAIkiHDvDF8fYyjv6k2NISmwaIjJJeEDBEdvg= +github.com/whosonfirst/go-ioutil v1.0.1 h1:xITnQgEGdG+Qlph7jPY5htL7UpPSm2wEw1WiUlKTWPc= +github.com/whosonfirst/go-ioutil v1.0.1/go.mod h1:2dS1vWdAIkiHDvDF8fYyjv6k2NISmwaIjJJeEDBEdvg= github.com/whosonfirst/go-whosonfirst-cache v0.1.0 h1:ryWTsHj7gAEjwHC/WjsjROpFflsz3SCa7W9Qnk4EU7k= github.com/whosonfirst/go-whosonfirst-cache v0.1.0/go.mod h1:P5Tx34j2M50qX/kTfXY516apwGzJGkFSBYQI7TGArKw= github.com/whosonfirst/go-whosonfirst-cli v0.1.0 h1:Wwj9z0R/ryHmPmpVm5jCbXdG4agJzKMWXDtPVReN/KA= diff --git a/vendor/github.com/whosonfirst/go-whosonfirst-feature/properties/alt_label.go b/vendor/github.com/whosonfirst/go-whosonfirst-feature/properties/alt_label.go new file mode 100644 index 0000000..62b959a --- /dev/null +++ b/vendor/github.com/whosonfirst/go-whosonfirst-feature/properties/alt_label.go @@ -0,0 +1,10 @@ +package properties + +import ( + "github.com/tidwall/gjson" +) + +func AltLabel(body []byte) (string, error) { + rsp := gjson.GetBytes(body, "properties.src:alt_label") + return rsp.String(), nil +} diff --git a/vendor/github.com/whosonfirst/go-whosonfirst-feature/properties/centroid.go b/vendor/github.com/whosonfirst/go-whosonfirst-feature/properties/centroid.go new file mode 100644 index 0000000..07a7443 --- /dev/null +++ b/vendor/github.com/whosonfirst/go-whosonfirst-feature/properties/centroid.go @@ -0,0 +1,48 @@ +package properties + +import ( + "fmt" + "github.com/paulmach/orb" + "github.com/tidwall/gjson" +) + +func Centroid(body []byte) (*orb.Point, string, error) { + + props := []string{ + "lbl", + "reversegeo", + "mps", + "geom", + } + + var pt *orb.Point + var source string + + for _, prefix := range props { + + path_lat := fmt.Sprintf("properties.%s:latitude", prefix) + path_lon := fmt.Sprintf("properties.%s:longitude", prefix) + + rsp_lat := gjson.GetBytes(body, path_lat) + rsp_lon := gjson.GetBytes(body, path_lon) + + if !rsp_lat.Exists() { + continue + } + + if !rsp_lon.Exists() { + continue + } + + pt = &orb.Point{rsp_lon.Float(), rsp_lat.Float()} + source = prefix + break + } + + if pt == nil { + pt = &orb.Point{0.0, 0.0} + source = "nullisland" + } + + return pt, source, nil +} diff --git a/vendor/github.com/whosonfirst/go-whosonfirst-feature/properties/concordances.go b/vendor/github.com/whosonfirst/go-whosonfirst-feature/properties/concordances.go index 7d3dae9..229164e 100644 --- a/vendor/github.com/whosonfirst/go-whosonfirst-feature/properties/concordances.go +++ b/vendor/github.com/whosonfirst/go-whosonfirst-feature/properties/concordances.go @@ -4,18 +4,14 @@ import ( "github.com/tidwall/gjson" ) -func Concordances(body []byte) map[string]string { +func Concordances(body []byte) map[string]interface{} { - rsp := gjson.GetBytes(body, "properties.wof:concordances") - - if !rsp.Exists() { - return nil - } + concordances := make(map[string]interface{}) - concordances := make(map[string]string) + rsp := gjson.GetBytes(body, "properties.wof:concordances") for k, v := range rsp.Map() { - concordances[k] = v.String() + concordances[k] = v.Value() } return concordances diff --git a/vendor/github.com/whosonfirst/go-whosonfirst-feature/properties/country.go b/vendor/github.com/whosonfirst/go-whosonfirst-feature/properties/country.go new file mode 100644 index 0000000..6f73e6b --- /dev/null +++ b/vendor/github.com/whosonfirst/go-whosonfirst-feature/properties/country.go @@ -0,0 +1,16 @@ +package properties + +import ( + "github.com/tidwall/gjson" +) + +func Country(body []byte) string { + + rsp := gjson.GetBytes(body, "properties.wof:country") + + if !rsp.Exists() { + return "XY" + } + + return rsp.String() +} diff --git a/vendor/github.com/whosonfirst/go-whosonfirst-feature/properties/created.go b/vendor/github.com/whosonfirst/go-whosonfirst-feature/properties/created.go new file mode 100644 index 0000000..6c884b2 --- /dev/null +++ b/vendor/github.com/whosonfirst/go-whosonfirst-feature/properties/created.go @@ -0,0 +1,16 @@ +package properties + +import ( + "github.com/tidwall/gjson" +) + +func Created(body []byte) int64 { + + rsp := gjson.GetBytes(body, "properties.wof:created") + + if !rsp.Exists() { + return -1 + } + + return rsp.Int() +} diff --git a/vendor/github.com/whosonfirst/go-whosonfirst-feature/properties/edtf.go b/vendor/github.com/whosonfirst/go-whosonfirst-feature/properties/edtf.go new file mode 100644 index 0000000..90a17f1 --- /dev/null +++ b/vendor/github.com/whosonfirst/go-whosonfirst-feature/properties/edtf.go @@ -0,0 +1,34 @@ +package properties + +import ( + "github.com/sfomuseum/go-edtf" + "github.com/tidwall/gjson" +) + +func Inception(body []byte) string { + + rsp := gjson.GetBytes(body, "properties.edtf:inception") + + if !rsp.Exists() { + return edtf.UNKNOWN + } + + return rsp.String() +} + +func Cessation(body []byte) string { + + rsp := gjson.GetBytes(body, "properties.edtf:cessation") + + if !rsp.Exists() { + return edtf.UNKNOWN + } + + return rsp.String() +} + +func Deprecated(body []byte) string { + + rsp := gjson.GetBytes(body, "properties.edtf:deprecated") + return rsp.String() +} diff --git a/vendor/github.com/whosonfirst/go-whosonfirst-feature/properties/hierarchies.go b/vendor/github.com/whosonfirst/go-whosonfirst-feature/properties/hierarchies.go new file mode 100644 index 0000000..c2c4690 --- /dev/null +++ b/vendor/github.com/whosonfirst/go-whosonfirst-feature/properties/hierarchies.go @@ -0,0 +1,29 @@ +package properties + +import ( + "github.com/tidwall/gjson" +) + +func Hierarchies(body []byte) []map[string]int64 { + + rsp := gjson.GetBytes(body, "properties.wof:hierarchy") + + if !rsp.Exists() { + return nil + } + + hierarchies := make([]map[string]int64, 0) + + for _, h := range rsp.Array() { + + dict := make(map[string]int64) + + for k, v := range h.Map() { + dict[k] = v.Int() + } + + hierarchies = append(hierarchies, dict) + } + + return hierarchies +} diff --git a/vendor/github.com/whosonfirst/go-whosonfirst-feature/properties/id.go b/vendor/github.com/whosonfirst/go-whosonfirst-feature/properties/id.go index 5f1a509..af6db95 100644 --- a/vendor/github.com/whosonfirst/go-whosonfirst-feature/properties/id.go +++ b/vendor/github.com/whosonfirst/go-whosonfirst-feature/properties/id.go @@ -15,7 +15,7 @@ func Id(body []byte) (int64, error) { id := rsp.Int() - if id < -4 { + if id < 0 { return 0, fmt.Errorf("Invalid or unrecognized ID value (%d)", id) } diff --git a/vendor/github.com/whosonfirst/go-whosonfirst-feature/properties/lastmodified.go b/vendor/github.com/whosonfirst/go-whosonfirst-feature/properties/lastmodified.go new file mode 100644 index 0000000..5beb0e4 --- /dev/null +++ b/vendor/github.com/whosonfirst/go-whosonfirst-feature/properties/lastmodified.go @@ -0,0 +1,16 @@ +package properties + +import ( + "github.com/tidwall/gjson" +) + +func LastModified(body []byte) int64 { + + rsp := gjson.GetBytes(body, "properties.wof:lastmodified") + + if !rsp.Exists() { + return -1 + } + + return rsp.Int() +} diff --git a/vendor/github.com/whosonfirst/go-whosonfirst-feature/properties/name.go b/vendor/github.com/whosonfirst/go-whosonfirst-feature/properties/name.go index 7b24702..73ed477 100644 --- a/vendor/github.com/whosonfirst/go-whosonfirst-feature/properties/name.go +++ b/vendor/github.com/whosonfirst/go-whosonfirst-feature/properties/name.go @@ -14,6 +14,5 @@ func Name(body []byte) (string, error) { } name := rsp.String() - return name, nil } diff --git a/vendor/github.com/whosonfirst/go-whosonfirst-feature/properties/parent_id.go b/vendor/github.com/whosonfirst/go-whosonfirst-feature/properties/parent_id.go new file mode 100644 index 0000000..bbd81af --- /dev/null +++ b/vendor/github.com/whosonfirst/go-whosonfirst-feature/properties/parent_id.go @@ -0,0 +1,26 @@ +package properties + +import ( + "fmt" + "github.com/tidwall/gjson" +) + +// https://github.com/whosonfirst/whosonfirst-properties/tree/main/properties/wof#parent_id +func ParentId(body []byte) (int64, error) { + + rsp := gjson.GetBytes(body, "properties.wof:parent_id") + + if !rsp.Exists() { + return 0, fmt.Errorf("Missing wof:parent_id property") + } + + id := rsp.Int() + + // https://github.com/whosonfirst/whosonfirst-properties/tree/main/properties/wof#parent_id + + if id < -4 { + return 0, fmt.Errorf("Invalid or unrecognized parent ID value (%d)", id) + } + + return id, nil +} diff --git a/vendor/github.com/whosonfirst/go-whosonfirst-feature/properties/placetype.go b/vendor/github.com/whosonfirst/go-whosonfirst-feature/properties/placetype.go new file mode 100644 index 0000000..80ce4cf --- /dev/null +++ b/vendor/github.com/whosonfirst/go-whosonfirst-feature/properties/placetype.go @@ -0,0 +1,19 @@ +package properties + +import ( + "fmt" + "github.com/tidwall/gjson" +) + +func Placetype(body []byte) (string, error) { + + rsp := gjson.GetBytes(body, "properties.wof:placetype") + + if !rsp.Exists() { + return "", fmt.Errorf("Missing wof:placetype property") + } + + placetype := rsp.String() + + return placetype, nil +} diff --git a/vendor/github.com/whosonfirst/go-whosonfirst-feature/properties/repo.go b/vendor/github.com/whosonfirst/go-whosonfirst-feature/properties/repo.go new file mode 100644 index 0000000..6e205b6 --- /dev/null +++ b/vendor/github.com/whosonfirst/go-whosonfirst-feature/properties/repo.go @@ -0,0 +1,18 @@ +package properties + +import ( + "fmt" + "github.com/tidwall/gjson" +) + +func Repo(body []byte) (string, error) { + + rsp := gjson.GetBytes(body, "properties.wof:repo") + + if !rsp.Exists() { + return "", fmt.Errorf("Missing wof:repo property") + } + + repo := rsp.String() + return repo, nil +} diff --git a/vendor/github.com/whosonfirst/go-whosonfirst-feature/properties/superseded_by.go b/vendor/github.com/whosonfirst/go-whosonfirst-feature/properties/superseded_by.go new file mode 100644 index 0000000..85b2909 --- /dev/null +++ b/vendor/github.com/whosonfirst/go-whosonfirst-feature/properties/superseded_by.go @@ -0,0 +1,18 @@ +package properties + +import ( + "github.com/tidwall/gjson" +) + +func SupersededBy(body []byte) []int64 { + + by := make([]int64, 0) + + rsp := gjson.GetBytes(body, "properties.wof:superseded_by") + + for _, r := range rsp.Array() { + by = append(by, r.Int()) + } + + return by +} diff --git a/vendor/github.com/whosonfirst/go-whosonfirst-feature/properties/supersedes.go b/vendor/github.com/whosonfirst/go-whosonfirst-feature/properties/supersedes.go new file mode 100644 index 0000000..4c8fb71 --- /dev/null +++ b/vendor/github.com/whosonfirst/go-whosonfirst-feature/properties/supersedes.go @@ -0,0 +1,18 @@ +package properties + +import ( + "github.com/tidwall/gjson" +) + +func Supersedes(body []byte) []int64 { + + by := make([]int64, 0) + + rsp := gjson.GetBytes(body, "properties.wof:supersedes") + + for _, r := range rsp.Array() { + by = append(by, r.Int()) + } + + return by +} diff --git a/vendor/modules.txt b/vendor/modules.txt index f34e155..9f701b5 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -1,4 +1,4 @@ -# github.com/aaronland/go-json-query v0.1.0 +# github.com/aaronland/go-json-query v0.1.1 github.com/aaronland/go-json-query # github.com/aaronland/go-roster v0.0.2 ## explicit @@ -11,13 +11,13 @@ github.com/hashicorp/go-multierror github.com/mmcloughlin/geohash # github.com/paulmach/go.geojson v1.4.0 github.com/paulmach/go.geojson -# github.com/paulmach/orb v0.2.2 +# github.com/paulmach/orb v0.4.0 ## explicit github.com/paulmach/orb github.com/paulmach/orb/geojson github.com/paulmach/orb/internal/length github.com/paulmach/orb/planar -# github.com/sfomuseum/go-edtf v0.3.0 +# github.com/sfomuseum/go-edtf v0.3.1 github.com/sfomuseum/go-edtf # github.com/sfomuseum/go-sfomuseum-geojson v0.1.2 github.com/sfomuseum/go-sfomuseum-geojson/feature @@ -26,21 +26,21 @@ github.com/sfomuseum/go-sfomuseum-geojson/feature github.com/sfomuseum/go-sfomuseum-reader # github.com/skelterjohn/geom v0.0.0-20180103142417-96f3e8a219c5 github.com/skelterjohn/geom -# github.com/tidwall/gjson v1.9.1 +# github.com/tidwall/gjson v1.11.0 ## explicit github.com/tidwall/gjson -# github.com/tidwall/match v1.0.3 +# github.com/tidwall/match v1.1.1 github.com/tidwall/match # github.com/tidwall/pretty v1.2.0 github.com/tidwall/pretty -# github.com/whosonfirst/go-ioutil v1.0.0 +# github.com/whosonfirst/go-ioutil v1.0.1 github.com/whosonfirst/go-ioutil -# github.com/whosonfirst/go-reader v0.9.0 +# github.com/whosonfirst/go-reader v0.9.1 ## explicit github.com/whosonfirst/go-reader # github.com/whosonfirst/go-whosonfirst-crawl v0.2.1 github.com/whosonfirst/go-whosonfirst-crawl -# github.com/whosonfirst/go-whosonfirst-feature v0.0.3 +# github.com/whosonfirst/go-whosonfirst-feature v0.0.17 ## explicit github.com/whosonfirst/go-whosonfirst-feature/properties # github.com/whosonfirst/go-whosonfirst-flags v0.4.3 @@ -55,7 +55,7 @@ github.com/whosonfirst/go-whosonfirst-geojson-v2/properties/whosonfirst github.com/whosonfirst/go-whosonfirst-geojson-v2/utils # github.com/whosonfirst/go-whosonfirst-hash v0.1.0 github.com/whosonfirst/go-whosonfirst-hash -# github.com/whosonfirst/go-whosonfirst-iterate/v2 v2.0.0 +# github.com/whosonfirst/go-whosonfirst-iterate/v2 v2.0.1 ## explicit github.com/whosonfirst/go-whosonfirst-iterate/v2/emitter github.com/whosonfirst/go-whosonfirst-iterate/v2/filters