From 187d0087eb72d78258eff0b60d2990e855585e7f Mon Sep 17 00:00:00 2001 From: Antoine GIRARD Date: Thu, 29 Aug 2019 01:00:55 +0200 Subject: [PATCH 01/11] first sanitize test --- modules/util/svg/svg.go | 18 +++++ modules/util/svg/svg_test.go | 138 +++++++++++++++++++++++++++++++++++ 2 files changed, 156 insertions(+) create mode 100644 modules/util/svg/svg.go create mode 100644 modules/util/svg/svg_test.go diff --git a/modules/util/svg/svg.go b/modules/util/svg/svg.go new file mode 100644 index 0000000000000..5727d90cc0cbd --- /dev/null +++ b/modules/util/svg/svg.go @@ -0,0 +1,18 @@ +// Copyright 2019 The Gitea Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package svg + +import "github.com/microcosm-cc/bluemonday" + +// SanitizeSVG remove potential malicious dom elements +func SanitizeSVG(svg string) string { + p := bluemonday.NewPolicy() + p.AllowElements("svg", "title", "path", "desc", "g") + p.AllowAttrs("id", "viewbox", "role", "aria-labelledby").OnElements("svg") + p.AllowAttrs("id").OnElements("title", "desc") + p.AllowAttrs("id", "data-name", "class", "aria-label").OnElements("g") + p.AllowAttrs("id", "data-name", "class", "d", "transform", "aria-haspopup").OnElements("path") + return p.Sanitize(svg) +} diff --git a/modules/util/svg/svg_test.go b/modules/util/svg/svg_test.go new file mode 100644 index 0000000000000..aeeae3bc79153 --- /dev/null +++ b/modules/util/svg/svg_test.go @@ -0,0 +1,138 @@ +// Copyright 2019 The Gitea Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package svg + +import "testing" + +func TestSanitizeSVG(t *testing.T) { + tests := []struct { + name string + input string + want string + }{ + { + name: "ariaData", + input: ` + Pixels, My Super-friendly Cat + An illustrated gray cat with bright green blinking eyes. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + `, + want: ` + Pixels, My Super-friendly Cat + An illustrated gray cat with bright green blinking eyes. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + `, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := SanitizeSVG(tt.input); got != tt.want { + t.Errorf("SanitizeSVG() = %v, want %v", got, tt.want) + } + }) + } +} From c685c0382169d986131daa11cb29ad2f069cfb5d Mon Sep 17 00:00:00 2001 From: Antoine GIRARD Date: Thu, 29 Aug 2019 01:03:03 +0200 Subject: [PATCH 02/11] update bluemonday --- vendor/modules.txt | 136 --------------------------------------------- 1 file changed, 136 deletions(-) diff --git a/vendor/modules.txt b/vendor/modules.txt index 729e7f88fd0c9..c2cdd4a176f92 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -1,44 +1,31 @@ # cloud.google.com/go v0.45.0 -## explicit cloud.google.com/go/compute/metadata # gitea.com/jolheiser/gitea-vet v0.1.0 -## explicit gitea.com/jolheiser/gitea-vet gitea.com/jolheiser/gitea-vet/checks # gitea.com/lunny/levelqueue v0.2.0 -## explicit gitea.com/lunny/levelqueue # gitea.com/macaron/binding v0.0.0-20190822013154-a5f53841ed2b -## explicit gitea.com/macaron/binding # gitea.com/macaron/cache v0.0.0-20190822004001-a6e7fee4ee76 -## explicit gitea.com/macaron/cache gitea.com/macaron/cache/memcache gitea.com/macaron/cache/redis # gitea.com/macaron/captcha v0.0.0-20190822015246-daa973478bae -## explicit gitea.com/macaron/captcha # gitea.com/macaron/cors v0.0.0-20190826180238-95aec09ea8b4 -## explicit gitea.com/macaron/cors # gitea.com/macaron/csrf v0.0.0-20190822024205-3dc5a4474439 -## explicit gitea.com/macaron/csrf # gitea.com/macaron/gzip v0.0.0-20191118041502-506895b47aae -## explicit gitea.com/macaron/gzip # gitea.com/macaron/i18n v0.0.0-20190822004228-474e714e2223 -## explicit gitea.com/macaron/i18n # gitea.com/macaron/inject v0.0.0-20190805023432-d4c86e31027a -## explicit gitea.com/macaron/inject # gitea.com/macaron/macaron v1.4.0 -## explicit gitea.com/macaron/macaron # gitea.com/macaron/session v0.0.0-20191207215012-613cebf0674d -## explicit gitea.com/macaron/session gitea.com/macaron/session/couchbase gitea.com/macaron/session/memcache @@ -47,20 +34,16 @@ gitea.com/macaron/session/nodb gitea.com/macaron/session/postgres gitea.com/macaron/session/redis # gitea.com/macaron/toolbox v0.0.0-20190822013122-05ff0fc766b7 -## explicit gitea.com/macaron/toolbox # github.com/BurntSushi/toml v0.3.1 -## explicit github.com/BurntSushi/toml # github.com/PuerkitoBio/goquery v1.5.0 -## explicit github.com/PuerkitoBio/goquery # github.com/PuerkitoBio/purell v1.1.1 github.com/PuerkitoBio/purell # github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 github.com/PuerkitoBio/urlesc # github.com/RoaringBitmap/roaring v0.4.21 -## explicit github.com/RoaringBitmap/roaring # github.com/andybalholm/cascadia v1.0.0 github.com/andybalholm/cascadia @@ -72,10 +55,7 @@ github.com/asaskevich/govalidator github.com/aymerick/douceur/css # github.com/beorn7/perks v1.0.1 github.com/beorn7/perks/quantile -# github.com/bgentry/speakeasy v0.1.0 -## explicit # github.com/blevesearch/bleve v0.8.1 -## explicit github.com/blevesearch/bleve github.com/blevesearch/bleve/analysis github.com/blevesearch/bleve/analysis/analyzer/custom @@ -116,16 +96,11 @@ github.com/blevesearch/bleve/search/query github.com/blevesearch/bleve/search/scorer github.com/blevesearch/bleve/search/searcher github.com/blevesearch/bleve/size -# github.com/blevesearch/blevex v0.0.0-20180227211930-4b158bb555a3 -## explicit # github.com/blevesearch/go-porterstemmer v1.0.2 -## explicit github.com/blevesearch/go-porterstemmer # github.com/blevesearch/segment v0.0.0-20160915185041-762005e7a34f -## explicit github.com/blevesearch/segment # github.com/boombuler/barcode v0.0.0-20161226211916-fe0f26ff6d26 -## explicit github.com/boombuler/barcode github.com/boombuler/barcode/qr github.com/boombuler/barcode/utils @@ -134,47 +109,34 @@ github.com/bradfitz/gomemcache/memcache # github.com/chris-ramon/douceur v0.2.0 github.com/chris-ramon/douceur/parser # github.com/couchbase/gomemcached v0.0.0-20191004160342-7b5da2ec40b2 -## explicit github.com/couchbase/gomemcached github.com/couchbase/gomemcached/client # github.com/couchbase/goutils v0.0.0-20191018232750-b49639060d85 github.com/couchbase/goutils/logging github.com/couchbase/goutils/scramsha # github.com/couchbase/vellum v0.0.0-20190829182332-ef2e028c01fd -## explicit github.com/couchbase/vellum github.com/couchbase/vellum/levenshtein github.com/couchbase/vellum/regexp github.com/couchbase/vellum/utf8 # github.com/couchbaselabs/go-couchbase v0.0.0-20190708161019-23e7ca2ce2b7 github.com/couchbaselabs/go-couchbase -# github.com/cznic/b v0.0.0-20181122101859-a26611c4d92d -## explicit -# github.com/cznic/mathutil v0.0.0-20181122101859-297441e03548 -## explicit -# github.com/cznic/strutil v0.0.0-20181122101858-275e90344537 -## explicit # github.com/davecgh/go-spew v1.1.1 github.com/davecgh/go-spew/spew # github.com/denisenkom/go-mssqldb v0.0.0-20191128021309-1d7a30a10f73 -## explicit github.com/denisenkom/go-mssqldb github.com/denisenkom/go-mssqldb/internal/cp github.com/denisenkom/go-mssqldb/internal/decimal github.com/denisenkom/go-mssqldb/internal/querytext # github.com/dgrijalva/jwt-go v3.2.0+incompatible -## explicit github.com/dgrijalva/jwt-go # github.com/dustin/go-humanize v1.0.0 -## explicit github.com/dustin/go-humanize # github.com/editorconfig/editorconfig-core-go/v2 v2.1.1 -## explicit github.com/editorconfig/editorconfig-core-go/v2 # github.com/edsrzf/mmap-go v1.0.0 github.com/edsrzf/mmap-go # github.com/emirpasic/gods v1.12.0 -## explicit github.com/emirpasic/gods/containers github.com/emirpasic/gods/lists github.com/emirpasic/gods/lists/arraylist @@ -182,17 +144,9 @@ github.com/emirpasic/gods/trees github.com/emirpasic/gods/trees/binaryheap github.com/emirpasic/gods/utils # github.com/etcd-io/bbolt v1.3.3 -## explicit github.com/etcd-io/bbolt # github.com/ethantkoenig/rupture v0.0.0-20180203182544-0a76f03a811a -## explicit github.com/ethantkoenig/rupture -# github.com/facebookgo/ensure v0.0.0-20160127193407-b4ab57deab51 -## explicit -# github.com/facebookgo/stack v0.0.0-20160209184415-751773369052 -## explicit -# github.com/facebookgo/subset v0.0.0-20150612182917-8dac2c3c4870 -## explicit # github.com/fatih/color v1.9.0 github.com/fatih/color # github.com/fatih/structtag v1.2.0 @@ -200,13 +154,10 @@ github.com/fatih/structtag # github.com/fsnotify/fsnotify v1.4.7 github.com/fsnotify/fsnotify # github.com/gliderlabs/ssh v0.2.2 -## explicit github.com/gliderlabs/ssh # github.com/glycerine/go-unsnap-stream v0.0.0-20190901134440-81cf024a9e0a -## explicit github.com/glycerine/go-unsnap-stream # github.com/go-enry/go-enry/v2 v2.3.0 -## explicit github.com/go-enry/go-enry/v2 github.com/go-enry/go-enry/v2/data github.com/go-enry/go-enry/v2/data/rule @@ -221,14 +172,12 @@ github.com/go-git/gcfg/scanner github.com/go-git/gcfg/token github.com/go-git/gcfg/types # github.com/go-git/go-billy/v5 v5.0.0 -## explicit github.com/go-git/go-billy/v5 github.com/go-git/go-billy/v5/helper/chroot github.com/go-git/go-billy/v5/helper/polyfill github.com/go-git/go-billy/v5/osfs github.com/go-git/go-billy/v5/util # github.com/go-git/go-git/v5 v5.0.0 -## explicit github.com/go-git/go-git/v5 github.com/go-git/go-git/v5/config github.com/go-git/go-git/v5/internal/revision @@ -282,7 +231,6 @@ github.com/go-openapi/inflect # github.com/go-openapi/jsonpointer v0.19.3 github.com/go-openapi/jsonpointer # github.com/go-openapi/jsonreference v0.19.3 -## explicit github.com/go-openapi/jsonreference # github.com/go-openapi/loads v0.19.3 github.com/go-openapi/loads @@ -304,7 +252,6 @@ github.com/go-openapi/swag # github.com/go-openapi/validate v0.19.3 github.com/go-openapi/validate # github.com/go-redis/redis v6.15.2+incompatible -## explicit github.com/go-redis/redis github.com/go-redis/redis/internal github.com/go-redis/redis/internal/consistenthash @@ -313,12 +260,10 @@ github.com/go-redis/redis/internal/pool github.com/go-redis/redis/internal/proto github.com/go-redis/redis/internal/util # github.com/go-sql-driver/mysql v1.4.1 -## explicit github.com/go-sql-driver/mysql # github.com/go-stack/stack v1.8.0 github.com/go-stack/stack # github.com/go-swagger/go-swagger v0.21.0 -## explicit github.com/go-swagger/go-swagger/cmd/swagger github.com/go-swagger/go-swagger/cmd/swagger/commands github.com/go-swagger/go-swagger/cmd/swagger/commands/diff @@ -328,7 +273,6 @@ github.com/go-swagger/go-swagger/codescan github.com/go-swagger/go-swagger/generator github.com/go-swagger/go-swagger/scan # github.com/gobwas/glob v0.2.3 -## explicit github.com/gobwas/glob github.com/gobwas/glob/compiler github.com/gobwas/glob/match @@ -338,25 +282,20 @@ github.com/gobwas/glob/syntax/lexer github.com/gobwas/glob/util/runes github.com/gobwas/glob/util/strings # github.com/gogs/chardet v0.0.0-20191104214054-4b6791f73a28 -## explicit github.com/gogs/chardet # github.com/gogs/cron v0.0.0-20171120032916-9f6c956d3e14 -## explicit github.com/gogs/cron # github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe github.com/golang-sql/civil # github.com/golang/protobuf v1.3.4 -## explicit github.com/golang/protobuf/proto # github.com/golang/snappy v0.0.1 github.com/golang/snappy # github.com/google/go-github/v24 v24.0.1 -## explicit github.com/google/go-github/v24/github # github.com/google/go-querystring v1.0.0 github.com/google/go-querystring/query # github.com/gorilla/context v1.1.1 -## explicit github.com/gorilla/context # github.com/gorilla/css v1.0.0 github.com/gorilla/css/scanner @@ -380,31 +319,20 @@ github.com/hashicorp/hcl/json/parser github.com/hashicorp/hcl/json/scanner github.com/hashicorp/hcl/json/token # github.com/huandu/xstrings v1.3.0 -## explicit github.com/huandu/xstrings -# github.com/issue9/assert v1.3.2 -## explicit # github.com/issue9/identicon v0.0.0-20160320065130-d36b54562f4c -## explicit github.com/issue9/identicon # github.com/jaytaylor/html2text v0.0.0-20160923191438-8fb95d837f7d -## explicit github.com/jaytaylor/html2text # github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 github.com/jbenet/go-context/io # github.com/jessevdk/go-flags v1.4.0 github.com/jessevdk/go-flags -# github.com/jmhodges/levigo v1.0.0 -## explicit -# github.com/joho/godotenv v1.3.0 -## explicit # github.com/kballard/go-shellquote v0.0.0-20170619183022-cd60e84ee657 -## explicit github.com/kballard/go-shellquote # github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd github.com/kevinburke/ssh_config # github.com/keybase/go-crypto v0.0.0-20200123153347-de78d2cb44f4 -## explicit github.com/keybase/go-crypto/brainpool github.com/keybase/go-crypto/cast5 github.com/keybase/go-crypto/curve25519 @@ -419,7 +347,6 @@ github.com/keybase/go-crypto/openpgp/packet github.com/keybase/go-crypto/openpgp/s2k github.com/keybase/go-crypto/rsa # github.com/klauspost/compress v1.10.2 -## explicit github.com/klauspost/compress/flate github.com/klauspost/compress/gzip # github.com/kr/pretty v0.1.0 @@ -427,16 +354,13 @@ github.com/kr/pretty # github.com/kr/text v0.2.0 github.com/kr/text # github.com/lafriks/xormstore v1.3.2 -## explicit github.com/lafriks/xormstore github.com/lafriks/xormstore/util # github.com/lib/pq v1.2.0 -## explicit github.com/lib/pq github.com/lib/pq/oid github.com/lib/pq/scram # github.com/lunny/dingtalk_webhook v0.0.0-20171025031554-e3534c89ef96 -## explicit github.com/lunny/dingtalk_webhook # github.com/lunny/log v0.0.0-20160921050905-7887c61bf0de github.com/lunny/log @@ -449,13 +373,11 @@ github.com/lunny/nodb/store/goleveldb # github.com/magiconair/properties v1.8.1 github.com/magiconair/properties # github.com/mailru/easyjson v0.7.0 -## explicit github.com/mailru/easyjson github.com/mailru/easyjson/buffer github.com/mailru/easyjson/jlexer github.com/mailru/easyjson/jwriter # github.com/markbates/goth v1.61.2 -## explicit github.com/markbates/goth github.com/markbates/goth/gothic github.com/markbates/goth/providers/bitbucket @@ -473,33 +395,24 @@ github.com/markbates/goth/providers/yandex # github.com/mattn/go-colorable v0.1.4 github.com/mattn/go-colorable # github.com/mattn/go-isatty v0.0.11 -## explicit github.com/mattn/go-isatty -# github.com/mattn/go-oci8 v0.0.0-20190320171441-14ba190cf52d -## explicit # github.com/mattn/go-runewidth v0.0.7 github.com/mattn/go-runewidth # github.com/mattn/go-sqlite3 v1.11.0 -## explicit github.com/mattn/go-sqlite3 # github.com/matttproud/golang_protobuf_extensions v1.0.1 github.com/matttproud/golang_protobuf_extensions/pbutil # github.com/mcuadros/go-version v0.0.0-20190308113854-92cdf37c5b75 -## explicit github.com/mcuadros/go-version # github.com/mgechev/dots v0.0.0-20190921121421-c36f7dcfbb81 -## explicit github.com/mgechev/dots # github.com/mgechev/revive v1.0.2 -## explicit github.com/mgechev/revive/formatter github.com/mgechev/revive/lint github.com/mgechev/revive/rule # github.com/microcosm-cc/bluemonday v1.0.3-0.20191119130333-0a75d7616912 -## explicit github.com/microcosm-cc/bluemonday # github.com/mitchellh/go-homedir v1.1.0 -## explicit github.com/mitchellh/go-homedir # github.com/mitchellh/mapstructure v1.1.2 github.com/mitchellh/mapstructure @@ -508,21 +421,16 @@ github.com/mrjones/oauth # github.com/mschoch/smat v0.0.0-20160514031455-90eadee771ae github.com/mschoch/smat # github.com/msteinert/pam v0.0.0-20151204160544-02ccfbfaf0cc -## explicit github.com/msteinert/pam # github.com/nfnt/resize v0.0.0-20160724205520-891127d8d1b5 -## explicit github.com/nfnt/resize # github.com/niklasfasching/go-org v0.1.9 -## explicit github.com/niklasfasching/go-org/org # github.com/olekukonko/tablewriter v0.0.4 github.com/olekukonko/tablewriter # github.com/oliamb/cutter v0.2.2 -## explicit github.com/oliamb/cutter # github.com/olivere/elastic/v7 v7.0.9 -## explicit github.com/olivere/elastic/v7 github.com/olivere/elastic/v7/config github.com/olivere/elastic/v7/uritemplates @@ -531,49 +439,37 @@ github.com/pelletier/go-toml # github.com/philhofer/fwd v1.0.0 github.com/philhofer/fwd # github.com/pkg/errors v0.9.1 -## explicit github.com/pkg/errors # github.com/pmezard/go-difflib v1.0.0 github.com/pmezard/go-difflib/difflib # github.com/pquerna/otp v0.0.0-20160912161815-54653902c20e -## explicit github.com/pquerna/otp github.com/pquerna/otp/hotp github.com/pquerna/otp/totp # github.com/prometheus/client_golang v1.1.0 -## explicit github.com/prometheus/client_golang/prometheus github.com/prometheus/client_golang/prometheus/internal github.com/prometheus/client_golang/prometheus/promhttp # github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4 -## explicit github.com/prometheus/client_model/go # github.com/prometheus/common v0.6.0 github.com/prometheus/common/expfmt github.com/prometheus/common/internal/bitbucket.org/ww/goautoneg github.com/prometheus/common/model # github.com/prometheus/procfs v0.0.4 -## explicit github.com/prometheus/procfs github.com/prometheus/procfs/internal/fs github.com/prometheus/procfs/internal/util # github.com/quasoft/websspi v1.0.0 -## explicit github.com/quasoft/websspi github.com/quasoft/websspi/secctx -# github.com/remyoudompheng/bigfft v0.0.0-20190321074620-2f0d2b0e0001 -## explicit # github.com/satori/go.uuid v1.2.0 -## explicit github.com/satori/go.uuid # github.com/sergi/go-diff v1.1.0 -## explicit github.com/sergi/go-diff/diffmatchpatch # github.com/shurcooL/httpfs v0.0.0-20190527155220-6a4d4a70508b -## explicit github.com/shurcooL/httpfs/vfsutil # github.com/shurcooL/vfsgen v0.0.0-20181202132449-6a9ea43bcacd -## explicit github.com/shurcooL/vfsgen # github.com/siddontang/go-snappy v0.0.0-20140704025258-d8f7bb82a96d github.com/siddontang/go-snappy/snappy @@ -589,10 +485,8 @@ github.com/spf13/pflag # github.com/spf13/viper v1.4.0 github.com/spf13/viper # github.com/steveyen/gtreap v0.0.0-20150807155958-0abe01ef9be2 -## explicit github.com/steveyen/gtreap # github.com/stretchr/testify v1.4.0 -## explicit github.com/stretchr/testify/assert github.com/stretchr/testify/require # github.com/syndtr/goleveldb v1.0.0 @@ -608,43 +502,32 @@ github.com/syndtr/goleveldb/leveldb/opt github.com/syndtr/goleveldb/leveldb/storage github.com/syndtr/goleveldb/leveldb/table github.com/syndtr/goleveldb/leveldb/util -# github.com/tecbot/gorocksdb v0.0.0-20181010114359-8752a9433481 -## explicit # github.com/tinylib/msgp v1.1.1 -## explicit github.com/tinylib/msgp/msgp # github.com/toqueteos/trie v1.0.0 github.com/toqueteos/trie # github.com/toqueteos/webbrowser v1.2.0 github.com/toqueteos/webbrowser # github.com/tstranex/u2f v1.0.0 -## explicit github.com/tstranex/u2f # github.com/unknwon/cae v1.0.0 -## explicit github.com/unknwon/cae github.com/unknwon/cae/zip # github.com/unknwon/com v1.0.1 -## explicit github.com/unknwon/com # github.com/unknwon/i18n v0.0.0-20190805065654-5c6446a380b6 -## explicit github.com/unknwon/i18n # github.com/unknwon/paginater v0.0.0-20151104151617-7748a72e0141 -## explicit github.com/unknwon/paginater # github.com/urfave/cli v1.20.0 -## explicit github.com/urfave/cli # github.com/willf/bitset v1.1.10 github.com/willf/bitset # github.com/xanzy/ssh-agent v0.2.1 github.com/xanzy/ssh-agent # github.com/yohcop/openid-go v0.0.0-20160914080427-2c050d2dae53 -## explicit github.com/yohcop/openid-go # github.com/yuin/goldmark v1.1.25 -## explicit github.com/yuin/goldmark github.com/yuin/goldmark/ast github.com/yuin/goldmark/extension @@ -655,10 +538,7 @@ github.com/yuin/goldmark/renderer/html github.com/yuin/goldmark/text github.com/yuin/goldmark/util # github.com/yuin/goldmark-meta v0.0.0-20191126180153-f0638e958b60 -## explicit github.com/yuin/goldmark-meta -# go.etcd.io/bbolt v1.3.3 -## explicit # go.mongodb.org/mongo-driver v1.1.1 go.mongodb.org/mongo-driver/bson go.mongodb.org/mongo-driver/bson/bsoncodec @@ -667,7 +547,6 @@ go.mongodb.org/mongo-driver/bson/bsontype go.mongodb.org/mongo-driver/bson/primitive go.mongodb.org/mongo-driver/x/bsonx/bsoncore # golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073 -## explicit golang.org/x/crypto/acme golang.org/x/crypto/acme/autocert golang.org/x/crypto/argon2 @@ -698,7 +577,6 @@ golang.org/x/crypto/ssh/knownhosts golang.org/x/mod/module golang.org/x/mod/semver # golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e -## explicit golang.org/x/net/context golang.org/x/net/context/ctxhttp golang.org/x/net/html @@ -708,21 +586,18 @@ golang.org/x/net/idna golang.org/x/net/internal/socks golang.org/x/net/proxy # golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45 -## explicit golang.org/x/oauth2 golang.org/x/oauth2/google golang.org/x/oauth2/internal golang.org/x/oauth2/jws golang.org/x/oauth2/jwt # golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd -## explicit golang.org/x/sys/cpu golang.org/x/sys/unix golang.org/x/sys/windows golang.org/x/sys/windows/svc golang.org/x/sys/windows/svc/debug # golang.org/x/text v0.3.2 -## explicit golang.org/x/text/encoding golang.org/x/text/encoding/charmap golang.org/x/text/encoding/htmlindex @@ -745,7 +620,6 @@ golang.org/x/text/unicode/bidi golang.org/x/text/unicode/norm golang.org/x/text/width # golang.org/x/tools v0.0.0-20200325010219-a49f79bcc224 -## explicit golang.org/x/tools/cover golang.org/x/tools/go/analysis golang.org/x/tools/go/analysis/internal/analysisflags @@ -782,22 +656,16 @@ google.golang.org/appengine/internal/remote_api google.golang.org/appengine/internal/urlfetch google.golang.org/appengine/urlfetch # gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc -## explicit gopkg.in/alexcesaro/quotedprintable.v3 # gopkg.in/asn1-ber.v1 v1.0.0-20150924051756-4e86f4367175 -## explicit gopkg.in/asn1-ber.v1 # gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df -## explicit gopkg.in/gomail.v2 # gopkg.in/ini.v1 v1.52.0 -## explicit gopkg.in/ini.v1 # gopkg.in/ldap.v3 v3.0.2 -## explicit gopkg.in/ldap.v3 # gopkg.in/testfixtures.v2 v2.5.0 -## explicit gopkg.in/testfixtures.v2 # gopkg.in/toqueteos/substring.v1 v1.0.2 gopkg.in/toqueteos/substring.v1 @@ -806,16 +674,12 @@ gopkg.in/warnings.v0 # gopkg.in/yaml.v2 v2.2.8 gopkg.in/yaml.v2 # mvdan.cc/xurls/v2 v2.1.0 -## explicit mvdan.cc/xurls/v2 # strk.kbt.io/projects/go/libravatar v0.0.0-20191008002943-06d1c002b251 -## explicit strk.kbt.io/projects/go/libravatar # xorm.io/builder v0.3.7 -## explicit xorm.io/builder # xorm.io/xorm v1.0.1 -## explicit xorm.io/xorm xorm.io/xorm/caches xorm.io/xorm/contexts From c6278cff6293057ec11fe2b681b430b059f1f258 Mon Sep 17 00:00:00 2001 From: Antoine GIRARD Date: Thu, 29 Aug 2019 01:34:29 +0200 Subject: [PATCH 03/11] compress svg to be able to compare --- go.mod | 3 + go.sum | 11 + modules/util/svg/svg.go | 23 +- modules/util/svg/svg_test.go | 17 +- .../tdewolff/minify/v2/.gitattributes | 1 + .../github.com/tdewolff/minify/v2/.gitignore | 4 + .../tdewolff/minify/v2/.goreleaser.yml | 28 + .../github.com/tdewolff/minify/v2/.travis.yml | 6 + .../github.com/tdewolff/minify/v2/LICENSE.md | 22 + .../github.com/tdewolff/minify/v2/README.md | 597 ++++++++++ .../github.com/tdewolff/minify/v2/common.go | 470 ++++++++ .../github.com/tdewolff/minify/v2/css/css.go | 1004 +++++++++++++++++ .../tdewolff/minify/v2/css/table.go | 165 +++ vendor/github.com/tdewolff/minify/v2/go.mod | 12 + vendor/github.com/tdewolff/minify/v2/go.sum | 16 + .../github.com/tdewolff/minify/v2/minify.go | 299 +++++ .../tdewolff/minify/v2/svg/buffer.go | 130 +++ .../tdewolff/minify/v2/svg/pathdata.go | 388 +++++++ .../github.com/tdewolff/minify/v2/svg/svg.go | 429 +++++++ .../tdewolff/minify/v2/svg/table.go | 84 ++ .../github.com/tdewolff/parse/v2/.travis.yml | 10 + .../github.com/tdewolff/parse/v2/LICENSE.md | 22 + vendor/github.com/tdewolff/parse/v2/README.md | 70 ++ .../tdewolff/parse/v2/buffer/buffer.go | 15 + .../tdewolff/parse/v2/buffer/lexer.go | 158 +++ .../tdewolff/parse/v2/buffer/reader.go | 44 + .../tdewolff/parse/v2/buffer/streamlexer.go | 223 ++++ .../tdewolff/parse/v2/buffer/writer.go | 41 + vendor/github.com/tdewolff/parse/v2/common.go | 231 ++++ .../tdewolff/parse/v2/css/README.md | 171 +++ .../github.com/tdewolff/parse/v2/css/hash.go | 757 +++++++++++++ .../github.com/tdewolff/parse/v2/css/lex.go | 710 ++++++++++++ .../github.com/tdewolff/parse/v2/css/parse.go | 454 ++++++++ .../github.com/tdewolff/parse/v2/css/util.go | 47 + vendor/github.com/tdewolff/parse/v2/error.go | 49 + vendor/github.com/tdewolff/parse/v2/go.mod | 3 + vendor/github.com/tdewolff/parse/v2/go.sum | 2 + .../github.com/tdewolff/parse/v2/position.go | 97 ++ .../tdewolff/parse/v2/strconv/float.go | 251 +++++ .../tdewolff/parse/v2/strconv/int.go | 83 ++ .../tdewolff/parse/v2/strconv/price.go | 83 ++ .../github.com/tdewolff/parse/v2/svg/hash.go | 295 +++++ vendor/github.com/tdewolff/parse/v2/util.go | 197 ++++ .../tdewolff/parse/v2/xml/README.md | 101 ++ .../github.com/tdewolff/parse/v2/xml/lex.go | 348 ++++++ .../github.com/tdewolff/parse/v2/xml/util.go | 108 ++ vendor/modules.txt | 11 + 47 files changed, 8282 insertions(+), 8 deletions(-) create mode 100644 vendor/github.com/tdewolff/minify/v2/.gitattributes create mode 100644 vendor/github.com/tdewolff/minify/v2/.gitignore create mode 100644 vendor/github.com/tdewolff/minify/v2/.goreleaser.yml create mode 100644 vendor/github.com/tdewolff/minify/v2/.travis.yml create mode 100644 vendor/github.com/tdewolff/minify/v2/LICENSE.md create mode 100644 vendor/github.com/tdewolff/minify/v2/README.md create mode 100644 vendor/github.com/tdewolff/minify/v2/common.go create mode 100644 vendor/github.com/tdewolff/minify/v2/css/css.go create mode 100644 vendor/github.com/tdewolff/minify/v2/css/table.go create mode 100644 vendor/github.com/tdewolff/minify/v2/go.mod create mode 100644 vendor/github.com/tdewolff/minify/v2/go.sum create mode 100644 vendor/github.com/tdewolff/minify/v2/minify.go create mode 100644 vendor/github.com/tdewolff/minify/v2/svg/buffer.go create mode 100644 vendor/github.com/tdewolff/minify/v2/svg/pathdata.go create mode 100644 vendor/github.com/tdewolff/minify/v2/svg/svg.go create mode 100644 vendor/github.com/tdewolff/minify/v2/svg/table.go create mode 100644 vendor/github.com/tdewolff/parse/v2/.travis.yml create mode 100644 vendor/github.com/tdewolff/parse/v2/LICENSE.md create mode 100644 vendor/github.com/tdewolff/parse/v2/README.md create mode 100644 vendor/github.com/tdewolff/parse/v2/buffer/buffer.go create mode 100644 vendor/github.com/tdewolff/parse/v2/buffer/lexer.go create mode 100644 vendor/github.com/tdewolff/parse/v2/buffer/reader.go create mode 100644 vendor/github.com/tdewolff/parse/v2/buffer/streamlexer.go create mode 100644 vendor/github.com/tdewolff/parse/v2/buffer/writer.go create mode 100644 vendor/github.com/tdewolff/parse/v2/common.go create mode 100644 vendor/github.com/tdewolff/parse/v2/css/README.md create mode 100644 vendor/github.com/tdewolff/parse/v2/css/hash.go create mode 100644 vendor/github.com/tdewolff/parse/v2/css/lex.go create mode 100644 vendor/github.com/tdewolff/parse/v2/css/parse.go create mode 100644 vendor/github.com/tdewolff/parse/v2/css/util.go create mode 100644 vendor/github.com/tdewolff/parse/v2/error.go create mode 100644 vendor/github.com/tdewolff/parse/v2/go.mod create mode 100644 vendor/github.com/tdewolff/parse/v2/go.sum create mode 100644 vendor/github.com/tdewolff/parse/v2/position.go create mode 100644 vendor/github.com/tdewolff/parse/v2/strconv/float.go create mode 100644 vendor/github.com/tdewolff/parse/v2/strconv/int.go create mode 100644 vendor/github.com/tdewolff/parse/v2/strconv/price.go create mode 100644 vendor/github.com/tdewolff/parse/v2/svg/hash.go create mode 100644 vendor/github.com/tdewolff/parse/v2/util.go create mode 100644 vendor/github.com/tdewolff/parse/v2/xml/README.md create mode 100644 vendor/github.com/tdewolff/parse/v2/xml/lex.go create mode 100644 vendor/github.com/tdewolff/parse/v2/xml/util.go diff --git a/go.mod b/go.mod index 404ca6d5c54df..9bcda32cb01a8 100644 --- a/go.mod +++ b/go.mod @@ -96,6 +96,9 @@ require ( github.com/shurcooL/vfsgen v0.0.0-20181202132449-6a9ea43bcacd github.com/steveyen/gtreap v0.0.0-20150807155958-0abe01ef9be2 // indirect github.com/stretchr/testify v1.4.0 + github.com/tdewolff/minify/v2 v2.5.1 + github.com/tdewolff/parse/v2 v2.3.9 // indirect + github.com/tdewolff/test v1.0.3 // indirect github.com/tecbot/gorocksdb v0.0.0-20181010114359-8752a9433481 // indirect github.com/tinylib/msgp v1.1.1 // indirect github.com/tstranex/u2f v1.0.0 diff --git a/go.sum b/go.sum index d904ed86daf6a..96e8793cda7b0 100644 --- a/go.sum +++ b/go.sum @@ -96,6 +96,7 @@ github.com/boombuler/barcode v0.0.0-20161226211916-fe0f26ff6d26/go.mod h1:paBWMc github.com/bradfitz/gomemcache v0.0.0-20190329173943-551aad21a668 h1:U/lr3Dgy4WK+hNk4tyD+nuGjpVLPEHuJSFXMw11/HPA= github.com/bradfitz/gomemcache v0.0.0-20190329173943-551aad21a668/go.mod h1:H0wQNHz2YrLsuXOZozoeDmnHXkNCRmMW0gwFWDfEZDA= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= +github.com/cheekybits/is v0.0.0-20150225183255-68e9c0620927/go.mod h1:h/aW8ynjgkuj+NQRlZcDbAbM1ORAbXjXX77sX7T289U= github.com/chris-ramon/douceur v0.2.0 h1:IDMEdxlEUUBYBKE4z/mJnFyVXox+MjuEVDJNN27glkU= github.com/chris-ramon/douceur v0.2.0/go.mod h1:wDW5xjJdeoMm1mRt4sD4c/LbF/mWdEpRXQKjTR8nIBE= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= @@ -416,6 +417,7 @@ github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7 github.com/markbates/going v1.0.0/go.mod h1:I6mnB4BPnEeqo85ynXIx1ZFLLbtiLHNXVgWeFO9OGOA= github.com/markbates/goth v1.61.2 h1:jDowrUH5qw8KGuQdKwFhLzkXkTYCIPfz3LHADJsiPIs= github.com/markbates/goth v1.61.2/go.mod h1:qh2QfwZoWRucQ+DR5KVKC6dUGkNCToWh4vS45GIzFsY= +github.com/matryer/try v0.0.0-20161228173917-9ac251b645a2/go.mod h1:0KeJpeMD6o+O4hW7qJOT7vyQPKrWmj26uf5wMc/IiIs= github.com/mattn/go-colorable v0.1.4 h1:snbPLB8fVfU9iwbbo30TPtbLRzwWu6aJS6Xh4eaaviA= github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= @@ -577,6 +579,14 @@ github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81P github.com/syndtr/goleveldb v0.0.0-20190203031304-2f17a3356c66/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ= github.com/syndtr/goleveldb v1.0.0 h1:fBdIW9lB4Iz0n9khmH8w27SJ3QEJ7+IgjPEwGSZiFdE= github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ= +github.com/tdewolff/minify/v2 v2.5.1 h1:5Or+sQBV+qUHDQG45lch0iFjUp1wxW0743nLl3qZDrs= +github.com/tdewolff/minify/v2 v2.5.1/go.mod h1:ltNgpU7tnfgNCIHP1D0aS8g9IV0qP7WWP1/HdXIGznE= +github.com/tdewolff/parse/v2 v2.3.8/go.mod h1:HansaqmN4I/U7L6/tUp0NcwT2tFO0F4EAWYGSDzkYNk= +github.com/tdewolff/parse/v2 v2.3.9 h1:d8/K6XOLy5JVpLTG9Kx+SxA72rlm5OowFmVSVgtOlmM= +github.com/tdewolff/parse/v2 v2.3.9/go.mod h1:HansaqmN4I/U7L6/tUp0NcwT2tFO0F4EAWYGSDzkYNk= +github.com/tdewolff/test v1.0.0/go.mod h1:DiQUlutnqlEvdvhSn2LPGy4TFwRauAaYDsL+683RNX4= +github.com/tdewolff/test v1.0.3 h1:oQqvxCCoUexB1bWZzvCzWG2VTqOIvWBV1JVg2OOFQi0= +github.com/tdewolff/test v1.0.3/go.mod h1:6DAvZliBAAnD7rhVgwaM7DE5/d9NMOAJ09SqYqeK4QE= github.com/tecbot/gorocksdb v0.0.0-20181010114359-8752a9433481 h1:HOxvxvnntLiPn123Fk+twfUhCQdMDaqmb0cclArW0T0= github.com/tecbot/gorocksdb v0.0.0-20181010114359-8752a9433481/go.mod h1:ahpPrc7HpcfEWDQRZEmnXMzHY03mLDYMCxeDzy46i+8= github.com/tidwall/pretty v1.0.0 h1:HsD+QiTn7sK6flMKIvNmpqz1qrpP3Ps6jOKIKMooyg4= @@ -705,6 +715,7 @@ golang.org/x/sys v0.0.0-20180824143301-4910a1d54f87/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181031143558-9b800f95dbbc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= diff --git a/modules/util/svg/svg.go b/modules/util/svg/svg.go index 5727d90cc0cbd..62b7eb372e46e 100644 --- a/modules/util/svg/svg.go +++ b/modules/util/svg/svg.go @@ -4,15 +4,32 @@ package svg -import "github.com/microcosm-cc/bluemonday" +import ( + "bytes" + "io" + + "github.com/microcosm-cc/bluemonday" + + minify "github.com/tdewolff/minify/v2" + "github.com/tdewolff/minify/v2/svg" +) + +// MinifySVG compact svg strings +func MinifySVG(svgData io.Reader) (*bytes.Buffer, error) { + m := minify.New() + m.AddFunc("image/svg+xml", svg.Minify) + var out bytes.Buffer + err := m.Minify("image/svg+xml", &out, svgData) + return &out, err +} // SanitizeSVG remove potential malicious dom elements -func SanitizeSVG(svg string) string { +func SanitizeSVG(svgData io.Reader) *bytes.Buffer { p := bluemonday.NewPolicy() p.AllowElements("svg", "title", "path", "desc", "g") p.AllowAttrs("id", "viewbox", "role", "aria-labelledby").OnElements("svg") p.AllowAttrs("id").OnElements("title", "desc") p.AllowAttrs("id", "data-name", "class", "aria-label").OnElements("g") p.AllowAttrs("id", "data-name", "class", "d", "transform", "aria-haspopup").OnElements("path") - return p.Sanitize(svg) + return p.SanitizeReader(svgData) } diff --git a/modules/util/svg/svg_test.go b/modules/util/svg/svg_test.go index aeeae3bc79153..7769d38aa14d9 100644 --- a/modules/util/svg/svg_test.go +++ b/modules/util/svg/svg_test.go @@ -4,7 +4,12 @@ package svg -import "testing" +import ( + "bytes" + "testing" + + "github.com/stretchr/testify/assert" +) func TestSanitizeSVG(t *testing.T) { tests := []struct { @@ -70,7 +75,7 @@ func TestSanitizeSVG(t *testing.T) { `, - want: ` + want: ` Pixels, My Super-friendly Cat An illustrated gray cat with bright green blinking eyes. @@ -130,9 +135,11 @@ func TestSanitizeSVG(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - if got := SanitizeSVG(tt.input); got != tt.want { - t.Errorf("SanitizeSVG() = %v, want %v", got, tt.want) - } + out, err := MinifySVG(SanitizeSVG(bytes.NewBufferString(tt.input))) + assert.NoError(t, err) + expected, err := MinifySVG(bytes.NewBufferString(tt.want)) //Compressed to limit the way it align text on clean-up + assert.NoError(t, err) + assert.Equal(t, expected.String(), out.String(), "The sanitized svg is not equal") }) } } diff --git a/vendor/github.com/tdewolff/minify/v2/.gitattributes b/vendor/github.com/tdewolff/minify/v2/.gitattributes new file mode 100644 index 0000000000000..4c50ee14b24e1 --- /dev/null +++ b/vendor/github.com/tdewolff/minify/v2/.gitattributes @@ -0,0 +1 @@ +benchmarks/sample_* linguist-generated=true diff --git a/vendor/github.com/tdewolff/minify/v2/.gitignore b/vendor/github.com/tdewolff/minify/v2/.gitignore new file mode 100644 index 0000000000000..3f3e864bfa62c --- /dev/null +++ b/vendor/github.com/tdewolff/minify/v2/.gitignore @@ -0,0 +1,4 @@ +dist/ +benchmarks/* +!benchmarks/*.go +!benchmarks/sample_* diff --git a/vendor/github.com/tdewolff/minify/v2/.goreleaser.yml b/vendor/github.com/tdewolff/minify/v2/.goreleaser.yml new file mode 100644 index 0000000000000..4edcdc20a2941 --- /dev/null +++ b/vendor/github.com/tdewolff/minify/v2/.goreleaser.yml @@ -0,0 +1,28 @@ +builds: + - binary: minify + main: ./cmd/minify/ + ldflags: -s -w -X main.Version={{.Version}} -X main.Commit={{.Commit}} -X main.Date={{.Date}} + env: + - CGO_ENABLED=0 + - GO111MODULE=on + goos: + - linux + - windows + - darwin + - freebsd + - netbsd + - openbsd + goarch: + - amd64 +archives: + - id: minify + format: tar.gz + format_overrides: + - goos: windows + format: zip + name_template: "{{.Binary}}_{{.Version}}_{{.Os}}_{{.Arch}}" + files: + - cmd/minify/README.md + - LICENSE.md +release: + disable: true diff --git a/vendor/github.com/tdewolff/minify/v2/.travis.yml b/vendor/github.com/tdewolff/minify/v2/.travis.yml new file mode 100644 index 0000000000000..9fd1c892dce48 --- /dev/null +++ b/vendor/github.com/tdewolff/minify/v2/.travis.yml @@ -0,0 +1,6 @@ +language: go +before_install: + - go get github.com/mattn/goveralls +script: + - go test -v -covermode=count -coverprofile=profile.cov . ./css ./html ./js ./json ./svg ./xml + - goveralls -v -coverprofile=profile.cov -service travis-ci -repotoken $COVERALLS_TOKEN diff --git a/vendor/github.com/tdewolff/minify/v2/LICENSE.md b/vendor/github.com/tdewolff/minify/v2/LICENSE.md new file mode 100644 index 0000000000000..41677de41ec1d --- /dev/null +++ b/vendor/github.com/tdewolff/minify/v2/LICENSE.md @@ -0,0 +1,22 @@ +Copyright (c) 2015 Taco de Wolff + + Permission is hereby granted, free of charge, to any person + obtaining a copy of this software and associated documentation + files (the "Software"), to deal in the Software without + restriction, including without limitation the rights to use, + copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following + conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/vendor/github.com/tdewolff/minify/v2/README.md b/vendor/github.com/tdewolff/minify/v2/README.md new file mode 100644 index 0000000000000..3f32185df6ee6 --- /dev/null +++ b/vendor/github.com/tdewolff/minify/v2/README.md @@ -0,0 +1,597 @@ +# Minify [![Build Status](https://travis-ci.org/tdewolff/minify.svg?branch=master)](https://travis-ci.org/tdewolff/minify) [![GoDoc](http://godoc.org/github.com/tdewolff/minify?status.svg)](http://godoc.org/github.com/tdewolff/minify) [![Coverage Status](https://coveralls.io/repos/github/tdewolff/minify/badge.svg?branch=master)](https://coveralls.io/github/tdewolff/minify?branch=master) [![Join the chat at https://gitter.im/tdewolff/minify](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/tdewolff/minify?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) + +***BE AWARE: YOU NEED GO 1.9.7+, 1.10.3+, 1.11 to run the latest release!!!*** + +If you cannot upgrade Go, please pin to **minify@v2.3.6** and **parse@v2.3.4** + +--- + +**[Online demo](https://go.tacodewolff.nl/minify) if you need to minify files *now*.** + +**[Command line tool](https://github.com/tdewolff/minify/tree/master/cmd/minify) that minifies concurrently and supports watching file changes.** + +**[All releases](https://github.com/tdewolff/minify/releases) for various platforms.** + +--- + +*Did you know that the shortest valid piece of HTML5 is `x`? See for yourself at the [W3C Validator](http://validator.w3.org/)!* + +Minify is a minifier package written in [Go][1]. It provides HTML5, CSS3, JS, JSON, SVG and XML minifiers and an interface to implement any other minifier. Minification is the process of removing bytes from a file (such as whitespace) without changing its output and therefore shrinking its size and speeding up transmission over the internet and possibly parsing. The implemented minifiers are designed for high performance. + +The core functionality associates mimetypes with minification functions, allowing embedded resources (like CSS or JS within HTML files) to be minified as well. Users can add new implementations that are triggered based on a mimetype (or pattern), or redirect to an external command (like ClosureCompiler, UglifyCSS, ...). + +#### Table of Contents + +- [Minify](#minify) + - [Prologue](#prologue) + - [Installation](#installation) + - [API stability](#api-stability) + - [Testing](#testing) + - [Performance](#performance) + - [HTML](#html) + - [Whitespace removal](#whitespace-removal) + - [CSS](#css) + - [JS](#js) + - [JSON](#json) + - [SVG](#svg) + - [XML](#xml) + - [Usage](#usage) + - [New](#new) + - [From reader](#from-reader) + - [From bytes](#from-bytes) + - [From string](#from-string) + - [To reader](#to-reader) + - [To writer](#to-writer) + - [Middleware](#middleware) + - [Custom minifier](#custom-minifier) + - [Mediatypes](#mediatypes) + - [Examples](#examples) + - [Common minifiers](#common-minifiers) + - [Custom minifier](#custom-minifier-example) + - [ResponseWriter](#responsewriter) + - [Templates](#templates) + - [License](#license) + +### Status + +* CSS: **fully implemented** +* HTML: **fully implemented** +* JS: improved JSmin implementation +* JSON: **fully implemented** +* SVG: partially implemented; in development +* XML: **fully implemented** + +### Roadmap + +- [ ] Use ASM/SSE to further speed-up core parts of the parsers/minifiers +- [ ] Improve JS minifiers by shortening variables and proper semicolon omission +- [ ] Speed-up SVG minifier, it is very slow +- [x] Proper parser error reporting and line number + column information +- [ ] Generation of source maps (uncertain, might slow down parsers too much if it cannot run separately nicely) +- [ ] Create a cmd to pack webfiles (much like webpack), ie. merging CSS and JS files, inlining small external files, minification and gzipping. This would work on HTML files. + +## Prologue +Minifiers or bindings to minifiers exist in almost all programming languages. Some implementations are merely using several regular expressions to trim whitespace and comments (even though regex for parsing HTML/XML is ill-advised, for a good read see [Regular Expressions: Now You Have Two Problems](http://blog.codinghorror.com/regular-expressions-now-you-have-two-problems/)). Some implementations are much more profound, such as the [YUI Compressor](http://yui.github.io/yuicompressor/) and [Google Closure Compiler](https://github.com/google/closure-compiler) for JS. As most existing implementations either use JavaScript, use regexes, and don't focus on performance, they are pretty slow. + +This minifier proves to be that fast and extensive minifier that can handle HTML and any other filetype it may contain (CSS, JS, ...). It is usually orders of magnitude faster than existing minifiers. + +## Installation +Run the following command + + go get -u github.com/tdewolff/minify/v2 + +or add the following imports and run the project with `go get` +``` go +import ( + "github.com/tdewolff/minify/v2" + "github.com/tdewolff/minify/v2/css" + "github.com/tdewolff/minify/v2/html" + "github.com/tdewolff/minify/v2/js" + "github.com/tdewolff/minify/v2/json" + "github.com/tdewolff/minify/v2/svg" + "github.com/tdewolff/minify/v2/xml" +) +``` + +## API stability +There is no guarantee for absolute stability, but I take issues and bugs seriously and don't take API changes lightly. The library will be maintained in a compatible way unless vital bugs prevent me from doing so. There has been one API change after v1 which added options support and I took the opportunity to push through some more API clean up as well. There are no plans whatsoever for future API changes. + +## Testing +For all subpackages and the imported `parse` package, test coverage of 100% is pursued. Besides full coverage, the minifiers are [fuzz tested](https://github.com/tdewolff/fuzz) using [github.com/dvyukov/go-fuzz](http://www.github.com/dvyukov/go-fuzz), see [the wiki](https://github.com/tdewolff/minify/wiki) for the most important bugs found by fuzz testing. These tests ensure that everything works as intended and that the code does not crash (whatever the input). If you still encounter a bug, please file a [bug report](https://github.com/tdewolff/minify/issues)! + +## Performance +The benchmarks directory contains a number of standardized samples used to compare performance between changes. To give an indication of the speed of this library, I've ran the tests on my Thinkpad T460 (i5-6300U quad-core 2.4GHz running Arch Linux) using Go 1.9.2. + +``` +name time/op +CSS/sample_bootstrap.css-4 2.26ms ± 0% +CSS/sample_gumby.css-4 2.92ms ± 1% +HTML/sample_amazon.html-4 2.33ms ± 2% +HTML/sample_bbc.html-4 1.02ms ± 1% +HTML/sample_blogpost.html-4 171µs ± 2% +HTML/sample_es6.html-4 14.5ms ± 0% +HTML/sample_stackoverflow.html-4 2.41ms ± 1% +HTML/sample_wikipedia.html-4 4.76ms ± 0% +JS/sample_ace.js-4 7.41ms ± 0% +JS/sample_dot.js-4 63.7µs ± 0% +JS/sample_jquery.js-4 2.99ms ± 0% +JS/sample_jqueryui.js-4 5.92ms ± 2% +JS/sample_moment.js-4 1.09ms ± 1% +JSON/sample_large.json-4 2.95ms ± 0% +JSON/sample_testsuite.json-4 1.51ms ± 1% +JSON/sample_twitter.json-4 6.75µs ± 1% +SVG/sample_arctic.svg-4 62.3ms ± 1% +SVG/sample_gopher.svg-4 218µs ± 0% +SVG/sample_usa.svg-4 33.1ms ± 3% +XML/sample_books.xml-4 36.2µs ± 0% +XML/sample_catalog.xml-4 14.9µs ± 0% +XML/sample_omg.xml-4 6.31ms ± 1% + +name speed +CSS/sample_bootstrap.css-4 60.8MB/s ± 0% +CSS/sample_gumby.css-4 63.9MB/s ± 1% +HTML/sample_amazon.html-4 203MB/s ± 2% +HTML/sample_bbc.html-4 113MB/s ± 1% +HTML/sample_blogpost.html-4 123MB/s ± 2% +HTML/sample_es6.html-4 70.7MB/s ± 0% +HTML/sample_stackoverflow.html-4 85.2MB/s ± 1% +HTML/sample_wikipedia.html-4 93.6MB/s ± 0% +JS/sample_ace.js-4 86.9MB/s ± 0% +JS/sample_dot.js-4 81.0MB/s ± 0% +JS/sample_jquery.js-4 82.8MB/s ± 0% +JS/sample_jqueryui.js-4 79.3MB/s ± 2% +JS/sample_moment.js-4 91.2MB/s ± 1% +JSON/sample_large.json-4 258MB/s ± 0% +JSON/sample_testsuite.json-4 457MB/s ± 1% +JSON/sample_twitter.json-4 226MB/s ± 1% +SVG/sample_arctic.svg-4 23.6MB/s ± 1% +SVG/sample_gopher.svg-4 26.7MB/s ± 0% +SVG/sample_usa.svg-4 30.9MB/s ± 3% +XML/sample_books.xml-4 122MB/s ± 0% +XML/sample_catalog.xml-4 130MB/s ± 0% +XML/sample_omg.xml-4 180MB/s ± 1% +``` + +## HTML + +HTML (with JS and CSS) minification typically shaves off about 10%. + +The HTML5 minifier uses these minifications: + +- strip unnecessary whitespace and otherwise collapse it to one space (or newline if it originally contained a newline) +- strip superfluous quotes, or uses single/double quotes whichever requires fewer escapes +- strip default attribute values and attribute boolean values +- strip some empty attributes +- strip unrequired tags (`html`, `head`, `body`, ...) +- strip unrequired end tags (`tr`, `td`, `li`, ... and often `p`) +- strip default protocols (`http:`, `https:` and `javascript:`) +- strip all comments (including conditional comments, old IE versions are not supported anymore by Microsoft) +- shorten `doctype` and `meta` charset +- lowercase tags, attributes and some values to enhance gzip compression + +Options: + +- `KeepConditionalComments` preserve all IE conditional comments such as `` and ``, see https://msdn.microsoft.com/en-us/library/ms537512(v=vs.85).aspx#syntax +- `KeepDefaultAttrVals` preserve default attribute values such as `
  • ` that have `display:inline-block` applied and have whitespace in between them. It is bad practise to rely on whitespace for element positioning anyways! + +## CSS + +Minification typically shaves off about 10%-15%. This CSS minifier will _not_ do structural changes to your stylesheets. Although this could result in smaller files, the complexity is quite high and the risk of breaking website is high too. + +The CSS minifier will only use safe minifications: + +- remove comments and unnecessary whitespace (but keep `/*! ... */` which usually contains the license) +- remove trailing semicolons +- optimize `margin`, `padding` and `border-width` number of sides +- shorten numbers by removing unnecessary `+` and zeros and rewriting with/without exponent +- remove dimension and percentage for zero values +- remove quotes for URLs +- remove quotes for font families and make lowercase +- rewrite hex colors to/from color names, or to three digit hex +- rewrite `rgb(`, `rgba(`, `hsl(` and `hsla(` colors to hex or name +- use four digit hex for alpha values (`transparent` → `#0000`) +- replace `normal` and `bold` by numbers for `font-weight` and `font` +- replace `none` → `0` for `border`, `background` and `outline` +- lowercase all identifiers except classes, IDs and URLs to enhance gzip compression +- shorten MS alpha function +- rewrite data URIs with base64 or ASCII whichever is shorter +- calls minifier for data URI mediatypes, thus you can compress embedded SVG files if you have that minifier attached +- shorten aggregate declarations such as `background` and `font` + +It does purposely not use the following techniques: + +- (partially) merge rulesets +- (partially) split rulesets +- collapse multiple declarations when main declaration is defined within a ruleset (don't put `font-weight` within an already existing `font`, too complex) +- remove overwritten properties in ruleset (this not always overwrites it, for example with `!important`) +- rewrite properties into one ruleset if possible (like `margin-top`, `margin-right`, `margin-bottom` and `margin-left` → `margin`) +- put nested ID selector at the front (`body > div#elem p` → `#elem p`) +- rewrite attribute selectors for IDs and classes (`div[id=a]` → `div#a`) +- put space after pseudo-selectors (IE6 is old, move on!) + +There are a couple of comparison tables online, such as [CSS Minifier Comparison](http://www.codenothing.com/benchmarks/css-compressor-3.0/full.html), [CSS minifiers comparison](http://www.phpied.com/css-minifiers-comparison/) and [CleanCSS tests](http://goalsmashers.github.io/css-minification-benchmark/). Comparing speed between each, this minifier will usually be between 10x-300x faster than existing implementations, and even rank among the top for minification ratios. It falls short with the purposely not implemented and often unsafe techniques. + +Options: + +- `Decimals` number of decimals to preserve for numbers, `-1` means no trimming +- `KeepCSS2` prohibits using CSS3 syntax (such as exponents in numbers, or `rgba(` → `rgb(`), might be incomplete + +## JS + +The JS minifier is pretty basic. It removes comments, whitespace and line breaks whenever it can. It employs all the rules that [JSMin](http://www.crockford.com/javascript/jsmin.html) does too, but has additional improvements. For example the prefix-postfix bug is fixed. + +Common speeds of PHP and JS implementations are about 100-300kB/s (see [Uglify2](http://lisperator.net/uglifyjs/), [Adventures in PHP web asset minimization](https://www.happyassassin.net/2014/12/29/adventures-in-php-web-asset-minimization/)). This implementation or orders of magnitude faster, around ~80MB/s. + +TODO: +- shorten local variables / function parameters names +- precise semicolon and newline omission + +## JSON + +Minification typically shaves off about 15% of filesize for common indented JSON such as generated by [JSON Generator](http://www.json-generator.com/). + +The JSON minifier only removes whitespace, which is the only thing that can be left out. + +## SVG + +The SVG minifier uses these minifications: + +- trim and collapse whitespace between all tags +- strip comments, empty `doctype`, XML prelude, `metadata` +- strip SVG version +- strip CDATA sections wherever possible +- collapse tags with no content to a void tag +- minify style tag and attributes with the CSS minifier +- minify colors +- shorten lengths and numbers and remove default `px` unit +- shorten `path` data +- convert `rect`, `line`, `polygon`, `polyline` to `path` +- use relative or absolute positions in path data whichever is shorter + +TODO: +- convert attributes to style attribute whenever shorter +- merge path data? (same style and no intersection -- the latter is difficult) + +Options: + +- `Decimals` number of decimals to preserve for numbers, `-1` means no trimming + +## XML + +The XML minifier uses these minifications: + +- strip unnecessary whitespace and otherwise collapse it to one space (or newline if it originally contained a newline) +- strip comments +- collapse tags with no content to a void tag +- strip CDATA sections wherever possible + +Options: + +- `KeepWhitespace` preserve whitespace between inline tags but still collapse multiple whitespace characters into one + +## Usage +Any input stream is being buffered by the minification functions. This is how the underlying buffer package inherently works to ensure high performance. The output stream however is not buffered. It is wise to preallocate a buffer as big as the input to which the output is written, or otherwise use `bufio` to buffer to a streaming writer. + +### New +Retrieve a minifier struct which holds a map of mediatype → minifier functions. +``` go +m := minify.New() +``` + +The following loads all provided minifiers. +``` go +m := minify.New() +m.AddFunc("text/css", css.Minify) +m.AddFunc("text/html", html.Minify) +m.AddFunc("image/svg+xml", svg.Minify) +m.AddFuncRegexp(regexp.MustCompile("^(application|text)/(x-)?(java|ecma)script$"), js.Minify) +m.AddFuncRegexp(regexp.MustCompile("[/+]json$"), json.Minify) +m.AddFuncRegexp(regexp.MustCompile("[/+]xml$"), xml.Minify) +``` + +You can set options to several minifiers. +``` go +m.Add("text/html", &html.Minifier{ + KeepDefaultAttrVals: true, + KeepWhitespace: true, +}) +``` + +### From reader +Minify from an `io.Reader` to an `io.Writer` for a specific mediatype. +``` go +if err := m.Minify(mediatype, w, r); err != nil { + panic(err) +} +``` + +### From bytes +Minify from and to a `[]byte` for a specific mediatype. +``` go +b, err = m.Bytes(mediatype, b) +if err != nil { + panic(err) +} +``` + +### From string +Minify from and to a `string` for a specific mediatype. +``` go +s, err = m.String(mediatype, s) +if err != nil { + panic(err) +} +``` + +### To reader +Get a minifying reader for a specific mediatype. +``` go +mr := m.Reader(mediatype, r) +if _, err := mr.Read(b); err != nil { + panic(err) +} +``` + +### To writer +Get a minifying writer for a specific mediatype. Must be explicitly closed because it uses an `io.Pipe` underneath. +``` go +mw := m.Writer(mediatype, w) +if mw.Write([]byte("input")); err != nil { + panic(err) +} +if err := mw.Close(); err != nil { + panic(err) +} +``` + +### Middleware +Minify resources on the fly using middleware. It passes a wrapped response writer to the handler that removes the Content-Length header. The minifier is chosen based on the Content-Type header or, if the header is empty, by the request URI file extension. This is on-the-fly processing, you should preferably cache the results though! +``` go +fs := http.FileServer(http.Dir("www/")) +http.Handle("/", m.Middleware(fs)) +``` + +### Custom minifier +Add a minifier for a specific mimetype. +``` go +type CustomMinifier struct { + KeepLineBreaks bool +} + +func (c *CustomMinifier) Minify(m *minify.M, w io.Writer, r io.Reader, params map[string]string) error { + // ... + return nil +} + +m.Add(mimetype, &CustomMinifier{KeepLineBreaks: true}) +// or +m.AddRegexp(regexp.MustCompile("/x-custom$"), &CustomMinifier{KeepLineBreaks: true}) +``` + +Add a minify function for a specific mimetype. +``` go +m.AddFunc(mimetype, func(m *minify.M, w io.Writer, r io.Reader, params map[string]string) error { + // ... + return nil +}) +m.AddFuncRegexp(regexp.MustCompile("/x-custom$"), func(m *minify.M, w io.Writer, r io.Reader, params map[string]string) error { + // ... + return nil +}) +``` + +Add a command `cmd` with arguments `args` for a specific mimetype. +``` go +m.AddCmd(mimetype, exec.Command(cmd, args...)) +m.AddCmdRegexp(regexp.MustCompile("/x-custom$"), exec.Command(cmd, args...)) +``` + +### Mediatypes +Using the `params map[string]string` argument one can pass parameters to the minifier such as seen in mediatypes (`type/subtype; key1=val2; key2=val2`). Examples are the encoding or charset of the data. Calling `Minify` will split the mimetype and parameters for the minifiers for you, but `MinifyMimetype` can be used if you already have them split up. + +Minifiers can also be added using a regular expression. For example a minifier with `image/.*` will match any image mime. + +## Examples +### Common minifiers +Basic example that minifies from stdin to stdout and loads the default HTML, CSS and JS minifiers. Optionally, one can enable `java -jar build/compiler.jar` to run for JS (for example the [ClosureCompiler](https://code.google.com/p/closure-compiler/)). Note that reading the file into a buffer first and writing to a pre-allocated buffer would be faster (but would disable streaming). +``` go +package main + +import ( + "log" + "os" + "os/exec" + + "github.com/tdewolff/minify/v2" + "github.com/tdewolff/minify/v2/css" + "github.com/tdewolff/minify/v2/html" + "github.com/tdewolff/minify/v2/js" + "github.com/tdewolff/minify/v2/json" + "github.com/tdewolff/minify/v2/svg" + "github.com/tdewolff/minify/v2/xml" +) + +func main() { + m := minify.New() + m.AddFunc("text/css", css.Minify) + m.AddFunc("text/html", html.Minify) + m.AddFunc("image/svg+xml", svg.Minify) + m.AddFuncRegexp(regexp.MustCompile("^(application|text)/(x-)?(java|ecma)script$"), js.Minify) + m.AddFuncRegexp(regexp.MustCompile("[/+]json$"), json.Minify) + m.AddFuncRegexp(regexp.MustCompile("[/+]xml$"), xml.Minify) + + // Or use the following for better minification of JS but lower speed: + // m.AddCmdRegexp(regexp.MustCompile("^(application|text)/(x-)?(java|ecma)script$"), exec.Command("java", "-jar", "build/compiler.jar")) + + if err := m.Minify("text/html", os.Stdout, os.Stdin); err != nil { + panic(err) + } +} +``` + +### Custom minifier +Custom minifier showing an example that implements the minifier function interface. Within a custom minifier, it is possible to call any minifier function (through `m minify.Minifier`) recursively when dealing with embedded resources. +``` go +package main + +import ( + "bufio" + "fmt" + "io" + "log" + "strings" + + "github.com/tdewolff/minify/v2" +) + +func main() { + m := minify.New() + m.AddFunc("text/plain", func(m *minify.M, w io.Writer, r io.Reader, _ map[string]string) error { + // remove newlines and spaces + rb := bufio.NewReader(r) + for { + line, err := rb.ReadString('\n') + if err != nil && err != io.EOF { + return err + } + if _, errws := io.WriteString(w, strings.Replace(line, " ", "", -1)); errws != nil { + return errws + } + if err == io.EOF { + break + } + } + return nil + }) + + in := "Because my coffee was too cold, I heated it in the microwave." + out, err := m.String("text/plain", in) + if err != nil { + panic(err) + } + fmt.Println(out) + // Output: Becausemycoffeewastoocold,Iheateditinthemicrowave. +} +``` + +### ResponseWriter +#### Middleware +``` go +func main() { + m := minify.New() + m.AddFunc("text/css", css.Minify) + m.AddFunc("text/html", html.Minify) + m.AddFunc("image/svg+xml", svg.Minify) + m.AddFuncRegexp(regexp.MustCompile("^(application|text)/(x-)?(java|ecma)script$"), js.Minify) + m.AddFuncRegexp(regexp.MustCompile("[/+]json$"), json.Minify) + m.AddFuncRegexp(regexp.MustCompile("[/+]xml$"), xml.Minify) + + fs := http.FileServer(http.Dir("www/")) + http.Handle("/", m.Middleware(fs)) +} +``` + +#### ResponseWriter +``` go +func Serve(w http.ResponseWriter, r *http.Request) { + mw := m.ResponseWriter(w, r) + defer mw.Close() + w = mw + + http.ServeFile(w, r, path.Join("www", r.URL.Path)) +} +``` + +#### Custom response writer +ResponseWriter example which returns a ResponseWriter that minifies the content and then writes to the original ResponseWriter. Any write after applying this filter will be minified. +``` go +type MinifyResponseWriter struct { + http.ResponseWriter + io.WriteCloser +} + +func (m MinifyResponseWriter) Write(b []byte) (int, error) { + return m.WriteCloser.Write(b) +} + +// MinifyResponseWriter must be closed explicitly by calling site. +func MinifyFilter(mediatype string, res http.ResponseWriter) MinifyResponseWriter { + m := minify.New() + // add minfiers + + mw := m.Writer(mediatype, res) + return MinifyResponseWriter{res, mw} +} +``` + +``` go +// Usage +func(w http.ResponseWriter, req *http.Request) { + w = MinifyFilter("text/html", w) + if _, err := io.WriteString(w, "

    This HTTP response will be minified.

    "); err != nil { + panic(err) + } + if err := w.Close(); err != nil { + panic(err) + } + // Output:

    This HTTP response will be minified. +} +``` + +### Templates + +Here's an example of a replacement for `template.ParseFiles` from `template/html`, which automatically minifies each template before parsing it. + +Be aware that minifying templates will work in most cases but not all. Because the HTML minifier only works for valid HTML5, your template must be valid HTML5 of itself. Template tags are parsed as regular text by the minifier. + +``` go +func compileTemplates(filenames ...string) (*template.Template, error) { + m := minify.New() + m.AddFunc("text/html", html.Minify) + + var tmpl *template.Template + for _, filename := range filenames { + name := filepath.Base(filename) + if tmpl == nil { + tmpl = template.New(name) + } else { + tmpl = tmpl.New(name) + } + + b, err := ioutil.ReadFile(filename) + if err != nil { + return nil, err + } + + mb, err := m.Bytes("text/html", b) + if err != nil { + return nil, err + } + tmpl.Parse(string(mb)) + } + return tmpl, nil +} +``` + +Example usage: + +``` go +templates := template.Must(compileTemplates("view.html", "home.html")) +``` + +## License +Released under the [MIT license](LICENSE.md). + +[1]: http://golang.org/ "Go Language" diff --git a/vendor/github.com/tdewolff/minify/v2/common.go b/vendor/github.com/tdewolff/minify/v2/common.go new file mode 100644 index 0000000000000..805eb0f0b9f16 --- /dev/null +++ b/vendor/github.com/tdewolff/minify/v2/common.go @@ -0,0 +1,470 @@ +package minify + +import ( + "bytes" + "encoding/base64" + "net/url" + + "github.com/tdewolff/parse/v2" + "github.com/tdewolff/parse/v2/strconv" +) + +// Epsilon is the closest number to zero that is not considered to be zero. +var Epsilon = 0.00001 + +// Mediatype minifies a given mediatype by removing all whitespace. +func Mediatype(b []byte) []byte { + j := 0 + start := 0 + inString := false + for i, c := range b { + if !inString && parse.IsWhitespace(c) { + if start != 0 { + j += copy(b[j:], b[start:i]) + } else { + j += i + } + start = i + 1 + } else if c == '"' { + inString = !inString + } + } + if start != 0 { + j += copy(b[j:], b[start:]) + return parse.ToLower(b[:j]) + } + return parse.ToLower(b) +} + +// DataURI minifies a data URI and calls a minifier by the specified mediatype. Specifications: https://www.ietf.org/rfc/rfc2397.txt. +func DataURI(m *M, dataURI []byte) []byte { + if mediatype, data, err := parse.DataURI(dataURI); err == nil { + dataURI, _ = m.Bytes(string(mediatype), data) + base64Len := len(";base64") + base64.StdEncoding.EncodedLen(len(dataURI)) + asciiLen := len(dataURI) + for _, c := range dataURI { + if 'A' <= c && c <= 'Z' || 'a' <= c && c <= 'z' || '0' <= c && c <= '9' || c == '-' || c == '_' || c == '.' || c == '~' || c == ' ' { + asciiLen++ + } else { + asciiLen += 2 + } + if asciiLen > base64Len { + break + } + } + if asciiLen > base64Len { + encoded := make([]byte, base64Len-len(";base64")) + base64.StdEncoding.Encode(encoded, dataURI) + dataURI = encoded + mediatype = append(mediatype, []byte(";base64")...) + } else { + dataURI = []byte(url.QueryEscape(string(dataURI))) + dataURI = bytes.Replace(dataURI, []byte("\""), []byte("\\\""), -1) + } + if len("text/plain") <= len(mediatype) && parse.EqualFold(mediatype[:len("text/plain")], []byte("text/plain")) { + mediatype = mediatype[len("text/plain"):] + } + for i := 0; i+len(";charset=us-ascii") <= len(mediatype); i++ { + // must start with semicolon and be followed by end of mediatype or semicolon + if mediatype[i] == ';' && parse.EqualFold(mediatype[i+1:i+len(";charset=us-ascii")], []byte("charset=us-ascii")) && (i+len(";charset=us-ascii") >= len(mediatype) || mediatype[i+len(";charset=us-ascii")] == ';') { + mediatype = append(mediatype[:i], mediatype[i+len(";charset=us-ascii"):]...) + break + } + } + dataURI = append(append(append([]byte("data:"), mediatype...), ','), dataURI...) + } + return dataURI +} + +const MaxInt = int(^uint(0) >> 1) +const MinInt = -MaxInt - 1 + +// Decimal minifies a given byte slice containing a number (see parse.Number) and removes superfluous characters. +// It does not parse or output exponents. +func Decimal(num []byte, prec int) []byte { + // omit first + and register mantissa start and end, whether it's negative and the exponent + neg := false + start := 0 + dot := -1 + end := len(num) + if 0 < end && (num[0] == '+' || num[0] == '-') { + if num[0] == '-' { + neg = true + } + start++ + } + for i, c := range num[start:] { + if c == '.' { + dot = start + i + break + } + } + if dot == -1 { + dot = end + } + + // trim leading zeros but leave at least one digit + for start < end-1 && num[start] == '0' { + start++ + } + // trim trailing zeros + i := end - 1 + for ; i > dot; i-- { + if num[i] != '0' { + end = i + 1 + break + } + } + if i == dot { + end = dot + if start == end { + num[start] = '0' + return num[start : start+1] + } + } else if start == end-1 && num[start] == '0' { + return num[start:end] + } + + // apply precision + if prec > -1 && dot+1+prec < end { + end = dot + 1 + prec + inc := num[end] >= '5' + if inc || num[end-1] == '0' { + // process either an increase from a lesser significant decimal (>= 5) + // or remove trailing zeros after the dot, or both + for i := end - 1; i > start; i-- { + if i == dot { + end-- + } else if inc { + if num[i] == '9' { + if i > dot { + end-- + } else { + num[i] = '0' + break + } + } else { + num[i]++ + inc = false + break + } + } else if i > dot && num[i] == '0' { + end-- + } else { + break + } + } + } + if dot == start && end == start+1 { + if inc { + num[start] = '1' + } else { + num[start] = '0' + } + } else { + if dot+1 == end { + end-- + } + if inc { + if num[start] == '9' { + num[start] = '0' + copy(num[start+1:], num[start:end]) + end++ + num[start] = '1' + } else { + num[start]++ + } + } + } + } + + if neg { + start-- + num[start] = '-' + } + return num[start:end] +} + +// Number minifies a given byte slice containing a number (see parse.Number) and removes superfluous characters. +func Number(num []byte, prec int) []byte { + // omit first + and register mantissa start and end, whether it's negative and the exponent + neg := false + start := 0 + dot := -1 + end := len(num) + origExp := 0 + if 0 < end && (num[0] == '+' || num[0] == '-') { + if num[0] == '-' { + neg = true + } + start++ + } + for i, c := range num[start:] { + if c == '.' { + dot = start + i + } else if c == 'e' || c == 'E' { + end = start + i + i += start + 1 + if i < len(num) && num[i] == '+' { + i++ + } + if tmpOrigExp, n := strconv.ParseInt(num[i:]); n > 0 && tmpOrigExp >= int64(MinInt) && tmpOrigExp <= int64(MaxInt) { + // range checks for when int is 32 bit + origExp = int(tmpOrigExp) + } else { + return num + } + break + } + } + if dot == -1 { + dot = end + } + + // trim leading zeros but leave at least one digit + for start < end-1 && num[start] == '0' { + start++ + } + // trim trailing zeros + i := end - 1 + for ; i > dot; i-- { + if num[i] != '0' { + end = i + 1 + break + } + } + if i == dot { + end = dot + if start == end { + num[start] = '0' + return num[start : start+1] + } + } else if start == end-1 && num[start] == '0' { + return num[start:end] + } + + // n is the number of significant digits + // normExp would be the exponent if it were normalised (0.1 <= f < 1) + n := 0 + normExp := 0 + if dot == start { + for i = dot + 1; i < end; i++ { + if num[i] != '0' { + n = end - i + normExp = dot - i + 1 + break + } + } + } else if dot == end { + normExp = end - start + for i = end - 1; i >= start; i-- { + if num[i] != '0' { + n = i + 1 - start + end = i + 1 + break + } + } + } else { + n = end - start - 1 + normExp = dot - start + } + + if origExp < 0 && (normExp < MinInt-origExp || normExp-n < MinInt-origExp) || origExp > 0 && (normExp > MaxInt-origExp || normExp-n > MaxInt-origExp) { + return num + } + normExp += origExp + + // intExp would be the exponent if it were an integer + intExp := normExp - n + lenIntExp := 1 + if intExp <= -10 || intExp >= 10 { + lenIntExp = strconv.LenInt(int64(intExp)) + } + + // there are three cases to consider when printing the number + // case 1: without decimals and with an exponent (large numbers) + // case 2: with decimals and without an exponent (around zero) + // case 3: without decimals and with a negative exponent (small numbers) + if normExp >= n { + // case 1 + if dot < end { + if dot == start { + start = end - n + } else { + // TODO: copy the other part if shorter? + copy(num[dot:], num[dot+1:end]) + end-- + } + } + if normExp >= n+3 { + num[end] = 'e' + end++ + for i := end + lenIntExp - 1; i >= end; i-- { + num[i] = byte(intExp%10) + '0' + intExp /= 10 + } + end += lenIntExp + } else if normExp == n+2 { + num[end] = '0' + num[end+1] = '0' + end += 2 + } else if normExp == n+1 { + num[end] = '0' + end++ + } + } else if normExp >= -lenIntExp-1 { + // case 2 + zeroes := -normExp + newDot := 0 + if zeroes > 0 { + // dot placed at the front and add zeroes + newDot = end - n - zeroes - 1 + if newDot != dot { + d := start - newDot + if d > 0 { + if dot < end { + // copy original digits behind the dot backwards + copy(num[dot+1+d:], num[dot+1:end]) + if dot > start { + // copy original digits before the dot backwards + copy(num[start+d+1:], num[start:dot]) + } + } else if dot > start { + // copy original digits before the dot backwards + copy(num[start+d:], num[start:dot]) + } + newDot = start + end += d + } else { + start += -d + } + num[newDot] = '.' + for i := 0; i < zeroes; i++ { + num[newDot+1+i] = '0' + } + } + } else { + // placed in the middle + if dot == start { + // TODO: try if placing at the end reduces copying + // when there are zeroes after the dot + dot = end - n - 1 + start = dot + } else if dot >= end { + // TODO: try if placing at the start reduces copying + // when input has no dot in it + dot = end + end++ + } + newDot = start + normExp + if newDot > dot { + // copy digits forwards + copy(num[dot:], num[dot+1:newDot+1]) + } else if newDot < dot { + // copy digits backwards + copy(num[newDot+1:], num[newDot:dot]) + } + num[newDot] = '.' + } + + // apply precision + dot = newDot + if prec > -1 && dot+1+prec < end { + end = dot + 1 + prec + inc := num[end] >= '5' + if inc || num[end-1] == '0' { + for i := end - 1; i > start; i-- { + if i == dot { + end-- + } else if inc { + if num[i] == '9' { + if i > dot { + end-- + } else { + num[i] = '0' + break + } + } else { + num[i]++ + inc = false + break + } + } else if i > dot && num[i] == '0' { + end-- + } else { + break + } + } + } + if dot == start && end == start+1 { + if inc { + num[start] = '1' + } else { + num[start] = '0' + } + } else { + if dot+1 == end { + end-- + } + if inc { + if num[start] == '9' { + num[start] = '0' + copy(num[start+1:], num[start:end]) + end++ + num[start] = '1' + } else { + num[start]++ + } + } + } + } + } else { + // case 3 + + // find new end, considering moving numbers to the front, removing the dot and increasing the length of the exponent + newEnd := end + if dot == start { + newEnd = start + n + } else { + newEnd-- + } + newEnd += 2 + lenIntExp + + exp := intExp + lenExp := lenIntExp + if newEnd < len(num) { + // it saves space to convert the decimal to an integer and decrease the exponent + if dot < end { + if dot == start { + copy(num[start:], num[end-n:end]) + end = start + n + } else { + copy(num[dot:], num[dot+1:end]) + end-- + } + } + } else { + // it does not save space and will panic, so we revert to the original representation + exp = origExp + lenExp = 1 + if origExp <= -10 || origExp >= 10 { + lenExp = strconv.LenInt(int64(origExp)) + } + } + num[end] = 'e' + num[end+1] = '-' + end += 2 + exp = -exp + for i := end + lenExp - 1; i >= end; i-- { + num[i] = byte(exp%10) + '0' + exp /= 10 + } + end += lenExp + } + + if neg { + start-- + num[start] = '-' + } + return num[start:end] +} diff --git a/vendor/github.com/tdewolff/minify/v2/css/css.go b/vendor/github.com/tdewolff/minify/v2/css/css.go new file mode 100644 index 0000000000000..d9cb254a07bc7 --- /dev/null +++ b/vendor/github.com/tdewolff/minify/v2/css/css.go @@ -0,0 +1,1004 @@ +// Package css minifies CSS3 following the specifications at http://www.w3.org/TR/css-syntax-3/. +package css + +import ( + "bytes" + "encoding/hex" + "fmt" + "io" + "strconv" + + "github.com/tdewolff/minify/v2" + "github.com/tdewolff/parse/v2" + "github.com/tdewolff/parse/v2/css" + strconvParse "github.com/tdewolff/parse/v2/strconv" +) + +var ( + spaceBytes = []byte(" ") + colonBytes = []byte(":") + semicolonBytes = []byte(";") + commaBytes = []byte(",") + leftBracketBytes = []byte("{") + rightBracketBytes = []byte("}") + zeroBytes = []byte("0") + transparentBytes = []byte("transparent") + importantBytes = []byte("!important") +) + +type cssMinifier struct { + m *minify.M + w io.Writer + p *css.Parser + o *Minifier + + valuesBuffer []Token +} + +//////////////////////////////////////////////////////////////// + +// DefaultMinifier is the default minifier. +var DefaultMinifier = &Minifier{Decimals: -1, KeepCSS2: false} + +// Minifier is a CSS minifier. +type Minifier struct { + Decimals int + KeepCSS2 bool +} + +// Minify minifies CSS data, it reads from r and writes to w. +func Minify(m *minify.M, w io.Writer, r io.Reader, params map[string]string) error { + return DefaultMinifier.Minify(m, w, r, params) +} + +type Token struct { + css.TokenType + Data []byte + Components []css.Token // only filled for functions +} + +func (t Token) String() string { + if len(t.Components) == 0 { + return t.TokenType.String() + "(" + string(t.Data) + ")" + } + return fmt.Sprint(t.Components) +} + +func (a Token) Equal(b Token) bool { + if a.TokenType == b.TokenType && bytes.Equal(a.Data, b.Data) && len(a.Components) == len(b.Components) { + for i := 0; i < len(a.Components); i++ { + if a.Components[i].TokenType != b.Components[i].TokenType || !bytes.Equal(a.Components[i].Data, b.Components[i].Data) { + return false + } + } + return true + } + return false +} + +// Minify minifies CSS data, it reads from r and writes to w. +func (o *Minifier) Minify(m *minify.M, w io.Writer, r io.Reader, params map[string]string) error { + isInline := params != nil && params["inline"] == "1" + c := &cssMinifier{ + m: m, + w: w, + p: css.NewParser(r, isInline), + o: o, + } + defer c.p.Restore() + + if err := c.minifyGrammar(); err != nil && err != io.EOF { + return err + } + return nil +} + +func (c *cssMinifier) minifyGrammar() error { + semicolonQueued := false + for { + gt, _, data := c.p.Next() + switch gt { + case css.ErrorGrammar: + if _, ok := c.p.Err().(*parse.Error); ok { + if semicolonQueued { + if _, err := c.w.Write(semicolonBytes); err != nil { + return err + } + } + + // write out the offending declaration (but save the semicolon) + vals := c.p.Values() + if len(vals) > 0 && vals[len(vals)-1].TokenType == css.SemicolonToken { + vals = vals[:len(vals)-1] + semicolonQueued = true + } + for _, val := range vals { + if _, err := c.w.Write(val.Data); err != nil { + return err + } + } + continue + } + return c.p.Err() + case css.EndAtRuleGrammar, css.EndRulesetGrammar: + if _, err := c.w.Write(rightBracketBytes); err != nil { + return err + } + semicolonQueued = false + continue + } + + if semicolonQueued { + if _, err := c.w.Write(semicolonBytes); err != nil { + return err + } + semicolonQueued = false + } + + switch gt { + case css.AtRuleGrammar: + if _, err := c.w.Write(data); err != nil { + return err + } + values := c.p.Values() + if css.ToHash(data[1:]) == css.Import && len(values) == 2 && values[1].TokenType == css.URLToken { + url := values[1].Data + if url[4] != '"' && url[4] != '\'' { + url = url[3:] + url[0] = '"' + url[len(url)-1] = '"' + } else { + url = url[4 : len(url)-1] + } + values[1].Data = url + } + for _, val := range values { + if _, err := c.w.Write(val.Data); err != nil { + return err + } + } + semicolonQueued = true + case css.BeginAtRuleGrammar: + if _, err := c.w.Write(data); err != nil { + return err + } + for _, val := range c.p.Values() { + if _, err := c.w.Write(val.Data); err != nil { + return err + } + } + if _, err := c.w.Write(leftBracketBytes); err != nil { + return err + } + case css.QualifiedRuleGrammar: + if err := c.minifySelectors(data, c.p.Values()); err != nil { + return err + } + if _, err := c.w.Write(commaBytes); err != nil { + return err + } + case css.BeginRulesetGrammar: + if err := c.minifySelectors(data, c.p.Values()); err != nil { + return err + } + if _, err := c.w.Write(leftBracketBytes); err != nil { + return err + } + case css.DeclarationGrammar: + if _, err := c.w.Write(data); err != nil { + return err + } + if _, err := c.w.Write(colonBytes); err != nil { + return err + } + if err := c.minifyDeclaration(data, c.p.Values()); err != nil { + return err + } + semicolonQueued = true + case css.CustomPropertyGrammar: + if _, err := c.w.Write(data); err != nil { + return err + } + if _, err := c.w.Write(colonBytes); err != nil { + return err + } + if _, err := c.w.Write(c.p.Values()[0].Data); err != nil { + return err + } + semicolonQueued = true + case css.CommentGrammar: + if len(data) > 5 && data[1] == '*' && data[2] == '!' { + if _, err := c.w.Write(data[:3]); err != nil { + return err + } + comment := parse.TrimWhitespace(parse.ReplaceMultipleWhitespace(data[3 : len(data)-2])) + if _, err := c.w.Write(comment); err != nil { + return err + } + if _, err := c.w.Write(data[len(data)-2:]); err != nil { + return err + } + } + default: + if _, err := c.w.Write(data); err != nil { + return err + } + } + } +} + +func (c *cssMinifier) minifySelectors(property []byte, values []css.Token) error { + inAttr := false + isClass := false + for _, val := range c.p.Values() { + if !inAttr { + if val.TokenType == css.IdentToken { + if !isClass { + parse.ToLower(val.Data) + } + isClass = false + } else if val.TokenType == css.DelimToken && val.Data[0] == '.' { + isClass = true + } else if val.TokenType == css.LeftBracketToken { + inAttr = true + } + } else { + if val.TokenType == css.StringToken && len(val.Data) > 2 { + s := val.Data[1 : len(val.Data)-1] + if css.IsIdent(s) { + if _, err := c.w.Write(s); err != nil { + return err + } + continue + } + } else if val.TokenType == css.RightBracketToken { + inAttr = false + } else if val.TokenType == css.IdentToken && len(val.Data) == 1 && (val.Data[0] == 'i' || val.Data[0] == 'I') { + if _, err := c.w.Write(spaceBytes); err != nil { + return err + } + } + } + if _, err := c.w.Write(val.Data); err != nil { + return err + } + } + return nil +} + +func (c *cssMinifier) minifyDeclaration(property []byte, components []css.Token) error { + if len(components) == 0 { + return nil + } + + // Strip !important from the component list, this will be added later separately + important := false + if len(components) > 2 && components[len(components)-2].TokenType == css.DelimToken && components[len(components)-2].Data[0] == '!' && css.ToHash(components[len(components)-1].Data) == css.Important { + components = components[:len(components)-2] + important = true + } + + // Check if this is a simple list of values separated by whitespace or commas, otherwise we'll not be processing + simple := true + prevSep := true + values := c.valuesBuffer[:0] + + for i := 0; i < len(components); i++ { + comp := components[i] + tt := comp.TokenType + + if tt == css.LeftParenthesisToken || tt == css.LeftBraceToken || tt == css.LeftBracketToken || + tt == css.RightParenthesisToken || tt == css.RightBraceToken || tt == css.RightBracketToken { + simple = false + break + } + + if !prevSep && tt != css.WhitespaceToken && tt != css.CommaToken && (tt != css.DelimToken || comp.Data[0] != '/') { + simple = false + break + } + + if tt == css.WhitespaceToken || tt == css.CommaToken || tt == css.DelimToken && comp.Data[0] == '/' { + prevSep = true + if tt != css.WhitespaceToken { + values = append(values, Token{tt, comp.Data, nil}) + } + } else if tt == css.FunctionToken { + prevSep = false + j := i + 1 + level := 0 + for ; j < len(components); j++ { + if components[j].TokenType == css.LeftParenthesisToken { + level++ + } else if components[j].TokenType == css.RightParenthesisToken { + if level == 0 { + j++ + break + } + level-- + } + } + values = append(values, Token{components[i].TokenType, components[i].Data, components[i:j]}) + i = j - 1 + } else { + prevSep = false + values = append(values, Token{components[i].TokenType, components[i].Data, nil}) + } + } + c.valuesBuffer = values + + prop := css.ToHash(property) + // Do not process complex values (eg. containing blocks or is not alternated between whitespace/commas and flat values + if !simple { + if prop == css.Filter && len(components) == 11 { + if bytes.Equal(components[0].Data, []byte("progid")) && + components[1].TokenType == css.ColonToken && + bytes.Equal(components[2].Data, []byte("DXImageTransform")) && + components[3].Data[0] == '.' && + bytes.Equal(components[4].Data, []byte("Microsoft")) && + components[5].Data[0] == '.' && + bytes.Equal(components[6].Data, []byte("Alpha(")) && + bytes.Equal(parse.ToLower(components[7].Data), []byte("opacity")) && + components[8].Data[0] == '=' && + components[10].Data[0] == ')' { + components = components[6:] + components[0].Data = []byte("alpha(") + } + } + + for _, component := range components { + if _, err := c.w.Write(component.Data); err != nil { + return err + } + } + if important { + if _, err := c.w.Write(importantBytes); err != nil { + return err + } + } + return nil + } + + for i := range values { + values[i].TokenType, values[i].Data = c.shortenToken(prop, values[i].TokenType, values[i].Data) + } + if len(values) > 0 { + values = c.minifyProperty(prop, values) + } + + prevSep = true + for _, value := range values { + if !prevSep && value.TokenType != css.CommaToken && (value.TokenType != css.DelimToken || value.Data[0] != '/') { + if _, err := c.w.Write(spaceBytes); err != nil { + return err + } + } + + if value.TokenType == css.FunctionToken { + err := c.minifyFunction(value.Components) + if err != nil { + return err + } + } else if _, err := c.w.Write(value.Data); err != nil { + return err + } + + if value.TokenType == css.CommaToken || value.TokenType == css.DelimToken && value.Data[0] == '/' { + prevSep = true + } else { + prevSep = false + } + } + + if important { + if _, err := c.w.Write(importantBytes); err != nil { + return err + } + } + return nil +} + +func (c *cssMinifier) minifyProperty(prop css.Hash, values []Token) []Token { + switch prop { + case css.Font: + if len(values) > 1 { + // the font-families are separated by commas and are at the end of font + // get index for the first font-family given + i := len(values) - 1 + for j, value := range values[2:] { + if value.TokenType == css.CommaToken { + i = 2 + j - 1 // identifier before first comma is a font-family + break + } + } + i-- + + // advance i while still at font-families when they contain spaces but no quotes + for ; i > 0; i-- { // i cannot be 0, font-family must be prepended by font-size + if values[i-1].TokenType == css.DelimToken && values[i-1].Data[0] == '/' { + break + } else if values[i].TokenType != css.IdentToken && values[i].TokenType != css.StringToken { + break + } else if values[i].TokenType == css.IdentToken { + h := css.ToHash(values[i].Data) + // inherit, initial and unset are followed by an IdentToken/StringToken, so must be for font-size + if h == css.Xx_Small || h == css.X_Small || h == css.Small || h == css.Medium || h == css.Large || h == css.X_Large || h == css.Xx_Large || h == css.Smaller || h == css.Larger || h == css.Inherit || h == css.Initial || h == css.Unset { + break + } + } + } + + // font-family minified in place + values = append(values[:i+1], c.minifyProperty(css.Font_Family, values[i+1:])...) + + if i > 0 { + // line-height + if i > 1 && values[i-1].TokenType == css.DelimToken && values[i-1].Data[0] == '/' { + if values[i].TokenType == css.IdentToken && bytes.Equal(values[i].Data, []byte("normal")) { + values = append(values[:i-1], values[i+1:]...) + } + i -= 2 + } + + // font-size + i-- + + for ; i > -1; i-- { + if values[i].TokenType == css.IdentToken { + val := css.ToHash(values[i].Data) + if val == css.Normal { + values = append(values[:i], values[i+1:]...) + } else if val == css.Bold { + values[i].TokenType = css.NumberToken + values[i].Data = []byte("700") + } + } else if values[i].TokenType == css.NumberToken && bytes.Equal(values[i].Data, []byte("400")) { + values = append(values[:i], values[i+1:]...) + } + } + } + } + case css.Font_Family: + for i, value := range values { + if value.TokenType == css.StringToken && len(value.Data) > 2 { + unquote := true + parse.ToLower(value.Data) + s := value.Data[1 : len(value.Data)-1] + if len(s) > 0 { + for _, split := range bytes.Split(s, spaceBytes) { + // if len is zero, it contains two consecutive spaces + if len(split) == 0 || !css.IsIdent(split) { + unquote = false + break + } + } + } + if unquote { + values[i].Data = s + } + } + } + case css.Font_Weight: + if len(values) == 1 && values[0].TokenType == css.IdentToken { + val := css.ToHash(values[0].Data) + if val == css.Normal { + values[0].TokenType = css.NumberToken + values[0].Data = []byte("400") + } else if val == css.Bold { + values[0].TokenType = css.NumberToken + values[0].Data = []byte("700") + } + } + case css.Margin, css.Padding, css.Border_Width: + switch len(values) { + case 2: + if values[0].Equal(values[1]) { + values = values[:1] + } + case 3: + if values[0].Equal(values[1]) && values[0].Equal(values[2]) { + values = values[:1] + } else if values[0].Equal(values[2]) { + values = values[:2] + } + case 4: + if values[0].Equal(values[1]) && values[0].Equal(values[2]) && values[0].Equal(values[3]) { + values = values[:1] + } else if values[0].Equal(values[2]) && values[1].Equal(values[3]) { + values = values[:2] + } else if values[1].Equal(values[3]) { + values = values[:3] + } + } + case css.Border, css.Border_Bottom, css.Border_Left, css.Border_Right, css.Border_Top: + for i := 0; i < len(values); i++ { + if values[i].TokenType == css.IdentToken { + val := css.ToHash(values[i].Data) + if val == css.None || val == css.Currentcolor || val == css.Medium { + values = append(values[:i], values[i+1:]...) + i-- + } + } + } + if len(values) == 0 { + values = []Token{{css.IdentToken, []byte("none"), nil}} + } + case css.Outline: + for i := 0; i < len(values); i++ { + if values[i].TokenType == css.IdentToken { + val := css.ToHash(values[i].Data) + if val == css.None || val == css.Medium { // color=invert is not supported by all browsers + values = append(values[:i], values[i+1:]...) + i-- + } + } + } + if len(values) == 0 { + values = []Token{{css.IdentToken, []byte("none"), nil}} + } + case css.Background: + // TODO: multiple background layers separated by comma + hasSize := false + for i := 0; i < len(values); i++ { + if values[i].TokenType == css.DelimToken && values[i].Data[0] == '/' { + hasSize = true + // background-size consists of either [ | auto | cover | contain] or [ | auto]{2} + // we can only minify the latter + if i+1 < len(values) && (values[i+1].TokenType == css.NumberToken || values[i+1].TokenType == css.PercentageToken || values[i+1].TokenType == css.IdentToken && bytes.Equal(values[i+1].Data, []byte("auto")) || values[i+1].TokenType == css.FunctionToken) { + if i+2 < len(values) && (values[i+2].TokenType == css.NumberToken || values[i+2].TokenType == css.PercentageToken || values[i+2].TokenType == css.IdentToken && bytes.Equal(values[i+2].Data, []byte("auto")) || values[i+2].TokenType == css.FunctionToken) { + sizeValues := c.minifyProperty(css.Background_Size, values[i+1:i+3]) + if len(sizeValues) == 1 && bytes.Equal(sizeValues[0].Data, []byte("auto")) { + // remove background-size if it is '/ auto' after minifying the property + values = append(values[:i], values[i+3:]...) + hasSize = false + i-- + } else { + values = append(values[:i+1], append(sizeValues, values[i+3:]...)...) + i += len(sizeValues) - 1 + } + } else if values[i+1].TokenType == css.IdentToken && bytes.Equal(values[i+1].Data, []byte("auto")) { + // remove background-size if it is '/ auto' + values = append(values[:i], values[i+2:]...) + hasSize = false + i-- + } + } + } + } + + var h css.Hash + iPaddingBox := -1 // position of background-origin that is padding-box + for i := 0; i < len(values); i++ { + if values[i].TokenType == css.IdentToken { + h = css.ToHash(values[i].Data) + if i+1 < len(values) && values[i+1].TokenType == css.IdentToken && (h == css.Space || h == css.Round || h == css.Repeat || h == css.No_Repeat) { + if h2 := css.ToHash(values[i+1].Data); h2 == css.Space || h2 == css.Round || h2 == css.Repeat || h2 == css.No_Repeat { + repeatValues := c.minifyProperty(css.Background_Repeat, values[i:i+2]) + if len(repeatValues) == 1 && bytes.Equal(repeatValues[0].Data, []byte("repeat")) { + values = append(values[:i], values[i+2:]...) + i-- + } else { + values = append(values[:i], append(repeatValues, values[i+2:]...)...) + i += len(repeatValues) - 1 + } + continue + } + } else if h == css.None || h == css.Scroll || h == css.Transparent { + values = append(values[:i], values[i+1:]...) + i-- + continue + } else if h == css.Border_Box || h == css.Padding_Box { + if iPaddingBox == -1 && h == css.Padding_Box { // background-origin + iPaddingBox = i + } else if iPaddingBox != -1 && h == css.Border_Box { // background-clip + values = append(values[:i], values[i+1:]...) + values = append(values[:iPaddingBox], values[iPaddingBox+1:]...) + i -= 2 + } + continue + } + } else if values[i].TokenType == css.HashToken && bytes.Equal(values[i].Data, []byte("#0000")) { + values = append(values[:i], values[i+1:]...) + i-- + continue + } + + // background-position or background-size + // TODO: allow only functions that return Number, Percentage or Dimension token? Make whitelist? + if values[i].TokenType == css.NumberToken || values[i].TokenType == css.DimensionToken || values[i].TokenType == css.PercentageToken || values[i].TokenType == css.IdentToken && (h == css.Left || h == css.Right || h == css.Top || h == css.Bottom || h == css.Center) || values[i].TokenType == css.FunctionToken { + j := i + 1 + for ; j < len(values); j++ { + if values[j].TokenType == css.IdentToken { + h := css.ToHash(values[j].Data) + if h == css.Left || h == css.Right || h == css.Top || h == css.Bottom || h == css.Center { + continue + } + } else if values[j].TokenType == css.NumberToken || values[j].TokenType == css.DimensionToken || values[j].TokenType == css.PercentageToken || values[j].TokenType == css.FunctionToken { + continue + } + break + } + + positionValues := c.minifyProperty(css.Background_Position, values[i:j]) + if !hasSize && len(positionValues) == 2 && positionValues[0].TokenType == css.NumberToken && bytes.Equal(positionValues[0].Data, []byte("0")) && positionValues[0].Equal(positionValues[1]) { + values = append(values[:i], values[j:]...) + i-- + } else { + values = append(values[:i], append(positionValues, values[j:]...)...) + i += len(positionValues) - 1 + } + } + } + + if len(values) == 0 { + values = []Token{{css.NumberToken, []byte("0"), nil}, {css.NumberToken, []byte("0"), nil}} + } + case css.Background_Size: + if len(values) == 2 && values[1].TokenType == css.IdentToken && bytes.Equal(values[1].Data, []byte("auto")) { + values = values[:1] + } + case css.Background_Repeat: + if len(values) == 2 && values[0].TokenType == css.IdentToken && values[1].TokenType == css.IdentToken { + h0 := css.ToHash(values[0].Data) + h1 := css.ToHash(values[1].Data) + if h0 == h1 { + values = values[:1] + } else if h0 == css.Repeat && h1 == css.No_Repeat { + values = values[:1] + values[0].Data = []byte("repeat-x") + } else if h0 == css.No_Repeat && h1 == css.Repeat { + values = values[:1] + values[0].Data = []byte("repeat-y") + } + } + case css.Background_Position: + if len(values) == 3 || len(values) == 4 { + // remove zero offsets + for _, i := range []int{len(values) - 1, 1} { + if values[i].TokenType == css.NumberToken && bytes.Equal(values[i].Data, []byte("0")) || values[i].TokenType == css.PercentageToken && bytes.Equal(values[i].Data, []byte("0%")) { + values = append(values[:i], values[i+1:]...) + } + } + + j := 1 // position of second set of horizontal/vertical values + if 2 < len(values) && values[2].TokenType == css.IdentToken { + j = 2 + } + hs := make([]css.Hash, 3) + hs[0] = css.ToHash(values[0].Data) + hs[j] = css.ToHash(values[j].Data) + + b := make([]byte, 0, 4) + offsets := make([]Token, 2) + for _, i := range []int{j, 0} { + if i+1 < len(values) && i+1 != j { + if values[i+1].TokenType == css.PercentageToken { + // change right or bottom with percentage offset to left or top respectively + if hs[i] == css.Right || hs[i] == css.Bottom { + n, _ := strconvParse.ParseInt(values[i+1].Data[:len(values[i+1].Data)-1]) + b = strconv.AppendInt(b[:0], 100-n, 10) + b = append(b, '%') + values[i+1].Data = b + if hs[i] == css.Right { + values[i].Data = []byte("left") + hs[i] = css.Left + } else { + values[i].Data = []byte("top") + hs[i] = css.Top + } + } + } + if hs[i] == css.Left { + offsets[0] = values[i+1] + } else if hs[i] == css.Top { + offsets[1] = values[i+1] + } + } else if hs[i] == css.Left { + offsets[0] = Token{css.NumberToken, []byte("0"), nil} + } else if hs[i] == css.Top { + offsets[1] = Token{css.NumberToken, []byte("0"), nil} + } else if hs[i] == css.Right { + offsets[0] = Token{css.PercentageToken, []byte("100%"), nil} + hs[i] = css.Left + } else if hs[i] == css.Bottom { + offsets[1] = Token{css.PercentageToken, []byte("100%"), nil} + hs[i] = css.Top + } + } + + if hs[0] == css.Center || hs[j] == css.Center { + if hs[0] == css.Left || hs[j] == css.Left { + offsets = offsets[:1] + } else if hs[0] == css.Top || hs[j] == css.Top { + offsets[0] = Token{css.NumberToken, []byte("50%"), nil} + } + } + + if offsets[0].Data != nil && (len(offsets) == 1 || offsets[1].Data != nil) { + values = offsets + } + } + // removing zero offsets in the previous loop might make it eligible for the next loop + if len(values) == 1 || len(values) == 2 { + if values[0].TokenType == css.IdentToken { + h := css.ToHash(values[0].Data) + if h == css.Top || h == css.Bottom { + if len(values) == 1 { + // we can't make this smaller, and converting to a number will break it + // (https://github.com/tdewolff/minify/issues/221#issuecomment-415419918) + break + } + // if it's a vertical position keyword, swap it with the next element + // since otherwise converted number positions won't be valid anymore + // (https://github.com/tdewolff/minify/issues/221#issue-353067229) + values[0], values[1] = values[1], values[0] + } + } + // transform keywords to lengths|percentages + for i := 0; i < len(values); i++ { + if values[i].TokenType == css.IdentToken { + h := css.ToHash(values[i].Data) + if h == css.Left || h == css.Top { + values[i].TokenType = css.NumberToken + values[i].Data = []byte("0") + } else if h == css.Right || h == css.Bottom { + values[i].TokenType = css.PercentageToken + values[i].Data = []byte("100%") + } else if h == css.Center { + if i == 0 { + values[i].TokenType = css.PercentageToken + values[i].Data = []byte("50%") + } else { + values = values[:1] + } + } + } else if i == 1 && values[i].TokenType == css.PercentageToken && bytes.Equal(values[i].Data, []byte("50%")) { + values = values[:1] + } else if values[i].TokenType == css.PercentageToken && bytes.Equal(values[i].Data, []byte("0%")) { + values[i].TokenType = css.NumberToken + values[i].Data = []byte("0") + } + } + } + case css.Box_Shadow: + if len(values) == 4 && len(values[0].Data) == 1 && values[0].Data[0] == '0' && len(values[1].Data) == 1 && values[1].Data[0] == '0' && len(values[2].Data) == 1 && values[2].Data[0] == '0' && len(values[3].Data) == 1 && values[3].Data[0] == '0' { + values = values[:2] + } + case css.Ms_Filter: + alpha := []byte("progid:DXImageTransform.Microsoft.Alpha(Opacity=") + if values[0].TokenType == css.StringToken && bytes.HasPrefix(values[0].Data[1:len(values[0].Data)-1], alpha) { + values[0].Data = append(append([]byte{values[0].Data[0]}, []byte("alpha(opacity=")...), values[0].Data[1+len(alpha):]...) + } + } + return values +} + +func (c *cssMinifier) minifyColorAsHex(rgba [3]byte) error { + val := make([]byte, 7) + val[0] = '#' + hex.Encode(val[1:], rgba[:]) + parse.ToLower(val) + if s, ok := ShortenColorHex[string(val[:7])]; ok { + if _, err := c.w.Write(s); err != nil { + return err + } + return nil + } else if val[1] == val[2] && val[3] == val[4] && val[5] == val[6] { + val[2] = val[3] + val[3] = val[5] + val = val[:4] + } else { + val = val[:7] + } + + _, err := c.w.Write(val) + return err +} + +func (c *cssMinifier) minifyFunction(values []css.Token) error { + if n := len(values); n > 2 { + fun := css.ToHash(values[0].Data[0 : len(values[0].Data)-1]) + if fun == css.Rgb || fun == css.Rgba || fun == css.Hsl || fun == css.Hsla { + valid := true + vals := make([]*css.Token, 0, 4) + for i, value := range values[1 : n-1] { + numeric := value.TokenType == css.NumberToken || value.TokenType == css.PercentageToken + separator := value.TokenType == css.CommaToken || i != 5 && value.TokenType == css.WhitespaceToken || i == 5 && value.TokenType == css.DelimToken && value.Data[0] == '/' + if i%2 == 0 && !numeric || i%2 == 1 && !separator { + valid = false + } else if numeric { + vals = append(vals, &values[i+1]) + } + } + + if valid { + for _, val := range vals { + val.TokenType, val.Data = c.shortenToken(0, val.TokenType, val.Data) + } + + a := byte(255) + if len(vals) == 4 { + d, _ := strconv.ParseFloat(string(values[7].Data), 32) // can never fail because if valid == true than this is a NumberToken or PercentageToken + if d < minify.Epsilon { // zero or less + _, err := c.w.Write(transparentBytes) + return err + } else if d >= 1.0 { + values = values[:7] + } else { + a = byte(d*255.0 + 0.5) + } + } + + if a == 255 { // only minify color if fully opaque + if (fun == css.Rgb || fun == css.Rgba) && (len(vals) == 3 || len(vals) == 4) { + rgb := [3]byte{} + + for j, val := range vals[:3] { + if val.TokenType == css.NumberToken { + d, _ := strconv.ParseInt(string(val.Data), 10, 32) + if d < 0 { + d = 0 + } else if d > 255 { + d = 255 + } + rgb[j] = byte(d) + } else if val.TokenType == css.PercentageToken { + d, _ := strconv.ParseFloat(string(val.Data[:len(val.Data)-1]), 32) + if d < 0.0 { + d = 0.0 + } else if d > 100.0 { + d = 100.0 + } + rgb[j] = byte((d / 100.0 * 255.0) + 0.5) + } + } + return c.minifyColorAsHex(rgb) + } else if (fun == css.Hsl || fun == css.Hsla) && (len(vals) == 3 || len(vals) == 4) && vals[0].TokenType == css.NumberToken && vals[1].TokenType == css.PercentageToken && vals[2].TokenType == css.PercentageToken { + h, _ := strconv.ParseFloat(string(vals[0].Data), 32) + s, _ := strconv.ParseFloat(string(vals[1].Data[:len(vals[1].Data)-1]), 32) + l, _ := strconv.ParseFloat(string(vals[2].Data[:len(vals[2].Data)-1]), 32) + for h > 360.0 { + h -= 360.0 + } + if s < 0.0 { + s = 0.0 + } else if s > 100.0 { + s = 100.0 + } + if l < 0.0 { + l = 0.0 + } else if l > 100.0 { + l = 100.0 + } + + r, g, b := css.HSL2RGB(h/360.0, s/100.0, l/100.0) + rgb := [3]byte{byte((r * 255.0) + 0.5), byte((g * 255.0) + 0.5), byte((b * 255.0) + 0.5)} + return c.minifyColorAsHex(rgb) + } + } + } + } else if fun == css.Local && n == 3 { + data := values[1].Data + if data[0] == '\'' || data[0] == '"' { + data = removeStringNewlinex(data) + if css.IsURLUnquoted(data[1 : len(data)-1]) { + data = data[1 : len(data)-1] + } + values[1].Data = data + } + } + } + + for _, value := range values { + if _, err := c.w.Write(value.Data); err != nil { + return err + } + } + return nil +} + +func (c *cssMinifier) shortenToken(prop css.Hash, tt css.TokenType, data []byte) (css.TokenType, []byte) { + switch tt { + case css.NumberToken, css.PercentageToken, css.DimensionToken: + if tt == css.NumberToken && (prop == css.Z_Index || prop == css.Counter_Increment || prop == css.Counter_Reset || prop == css.Orphans || prop == css.Widows) { + return tt, data // integers + } + n := len(data) + if tt == css.PercentageToken { + n-- + } else if tt == css.DimensionToken { + n = parse.Number(data) + } + dim := data[n:] + parse.ToLower(dim) + if !c.o.KeepCSS2 { + data = minify.Number(data[:n], c.o.Decimals) + } else { + data = minify.Decimal(data[:n], c.o.Decimals) // don't use exponents + } + if tt == css.DimensionToken && (len(data) != 1 || data[0] != '0' || !optionalZeroDimension[string(dim)] || prop == css.Flex) { + data = append(data, dim...) + } else if tt == css.PercentageToken { + data = append(data, '%') // TODO: drop percentage for properties that accept and + } + case css.IdentToken: + parse.ToLower(parse.Copy(data)) // not all identifiers are case-insensitive; all properties are case-sensitive + hash := css.ToHash(data) + if hexValue, ok := ShortenColorName[hash]; ok { + tt = css.HashToken + data = hexValue + } + case css.HashToken: + parse.ToLower(data) + if len(data) == 9 && data[7] == data[8] { + if data[7] == 'f' { + data = data[:7] + } else if data[7] == '0' { + data = []byte("#0000") + } + } + if ident, ok := ShortenColorHex[string(data)]; ok { + tt = css.IdentToken + data = ident + } else if len(data) == 7 && data[1] == data[2] && data[3] == data[4] && data[5] == data[6] { + tt = css.HashToken + data[2] = data[3] + data[3] = data[5] + data = data[:4] + } else if len(data) == 9 && data[1] == data[2] && data[3] == data[4] && data[5] == data[6] && data[7] == data[8] { + // from working draft Color Module Level 4 + tt = css.HashToken + data[2] = data[3] + data[3] = data[5] + data[4] = data[7] + data = data[:5] + } + case css.StringToken: + data = removeStringNewlinex(data) + case css.URLToken: + parse.ToLower(data[:3]) + if len(data) > 10 { + uri := parse.TrimWhitespace(data[4 : len(data)-1]) + delim := byte('"') + if uri[0] == '\'' || uri[0] == '"' { + delim = uri[0] + uri = removeStringNewlinex(uri) + uri = uri[1 : len(uri)-1] + } + uri = minify.DataURI(c.m, uri) + if css.IsURLUnquoted(uri) { + data = append(append([]byte("url("), uri...), ')') + } else { + data = append(append(append([]byte("url("), delim), uri...), delim, ')') + } + } + } + return tt, data +} + +func removeStringNewlinex(data []byte) []byte { + // remove any \\\r\n \\\r \\\n + for i := 1; i < len(data)-2; i++ { + if data[i] == '\\' && (data[i+1] == '\n' || data[i+1] == '\r') { + // encountered first replacee, now start to move bytes to the front + j := i + 2 + if data[i+1] == '\r' && len(data) > i+2 && data[i+2] == '\n' { + j++ + } + for ; j < len(data); j++ { + if data[j] == '\\' && len(data) > j+1 && (data[j+1] == '\n' || data[j+1] == '\r') { + if data[j+1] == '\r' && len(data) > j+2 && data[j+2] == '\n' { + j++ + } + j++ + } else { + data[i] = data[j] + i++ + } + } + data = data[:i] + break + } + } + return data +} diff --git a/vendor/github.com/tdewolff/minify/v2/css/table.go b/vendor/github.com/tdewolff/minify/v2/css/table.go new file mode 100644 index 0000000000000..7f22d0bab3bc3 --- /dev/null +++ b/vendor/github.com/tdewolff/minify/v2/css/table.go @@ -0,0 +1,165 @@ +package css + +import "github.com/tdewolff/parse/v2/css" + +var optionalZeroDimension = map[string]bool{ + "px": true, + "mm": true, + "q": true, + "cm": true, + "in": true, + "pt": true, + "pc": true, + "ch": true, + "em": true, + "ex": true, + "rem": true, + "vh": true, + "vw": true, + "vmin": true, + "vmax": true, + "deg": true, + "grad": true, + "rad": true, + "turn": true, +} + +// Uses http://www.w3.org/TR/2010/PR-css3-color-20101028/ for colors + +// ShortenColorHex maps a color hexcode to its shorter name +var ShortenColorHex = map[string][]byte{ + "#000080": []byte("navy"), + "#008000": []byte("green"), + "#008080": []byte("teal"), + "#4b0082": []byte("indigo"), + "#800000": []byte("maroon"), + "#800080": []byte("purple"), + "#808000": []byte("olive"), + "#808080": []byte("gray"), + "#a0522d": []byte("sienna"), + "#a52a2a": []byte("brown"), + "#c0c0c0": []byte("silver"), + "#cd853f": []byte("peru"), + "#d2b48c": []byte("tan"), + "#da70d6": []byte("orchid"), + "#dda0dd": []byte("plum"), + "#ee82ee": []byte("violet"), + "#f0e68c": []byte("khaki"), + "#f0ffff": []byte("azure"), + "#f5deb3": []byte("wheat"), + "#f5f5dc": []byte("beige"), + "#fa8072": []byte("salmon"), + "#faf0e6": []byte("linen"), + "#ff6347": []byte("tomato"), + "#ff7f50": []byte("coral"), + "#ffa500": []byte("orange"), + "#ffc0cb": []byte("pink"), + "#ffd700": []byte("gold"), + "#ffe4c4": []byte("bisque"), + "#fffafa": []byte("snow"), + "#fffff0": []byte("ivory"), + "#ff0000": []byte("red"), + "#f00": []byte("red"), +} + +// ShortenColorName maps a color name to its shorter hexcode +var ShortenColorName = map[css.Hash][]byte{ + css.Black: []byte("#000"), + css.Darkblue: []byte("#00008b"), + css.Mediumblue: []byte("#0000cd"), + css.Darkgreen: []byte("#006400"), + css.Darkcyan: []byte("#008b8b"), + css.Deepskyblue: []byte("#00bfff"), + css.Darkturquoise: []byte("#00ced1"), + css.Mediumspringgreen: []byte("#00fa9a"), + css.Springgreen: []byte("#00ff7f"), + css.Midnightblue: []byte("#191970"), + css.Dodgerblue: []byte("#1e90ff"), + css.Lightseagreen: []byte("#20b2aa"), + css.Forestgreen: []byte("#228b22"), + css.Seagreen: []byte("#2e8b57"), + css.Darkslategray: []byte("#2f4f4f"), + css.Limegreen: []byte("#32cd32"), + css.Mediumseagreen: []byte("#3cb371"), + css.Turquoise: []byte("#40e0d0"), + css.Royalblue: []byte("#4169e1"), + css.Steelblue: []byte("#4682b4"), + css.Darkslateblue: []byte("#483d8b"), + css.Mediumturquoise: []byte("#48d1cc"), + css.Darkolivegreen: []byte("#556b2f"), + css.Cadetblue: []byte("#5f9ea0"), + css.Cornflowerblue: []byte("#6495ed"), + css.Mediumaquamarine: []byte("#66cdaa"), + css.Slateblue: []byte("#6a5acd"), + css.Olivedrab: []byte("#6b8e23"), + css.Slategray: []byte("#708090"), + css.Lightslateblue: []byte("#789"), + css.Mediumslateblue: []byte("#7b68ee"), + css.Lawngreen: []byte("#7cfc00"), + css.Chartreuse: []byte("#7fff00"), + css.Aquamarine: []byte("#7fffd4"), + css.Lightskyblue: []byte("#87cefa"), + css.Blueviolet: []byte("#8a2be2"), + css.Darkmagenta: []byte("#8b008b"), + css.Saddlebrown: []byte("#8b4513"), + css.Darkseagreen: []byte("#8fbc8f"), + css.Lightgreen: []byte("#90ee90"), + css.Mediumpurple: []byte("#9370db"), + css.Darkviolet: []byte("#9400d3"), + css.Palegreen: []byte("#98fb98"), + css.Darkorchid: []byte("#9932cc"), + css.Yellowgreen: []byte("#9acd32"), + css.Darkgray: []byte("#a9a9a9"), + css.Lightblue: []byte("#add8e6"), + css.Greenyellow: []byte("#adff2f"), + css.Paleturquoise: []byte("#afeeee"), + css.Lightsteelblue: []byte("#b0c4de"), + css.Powderblue: []byte("#b0e0e6"), + css.Firebrick: []byte("#b22222"), + css.Darkgoldenrod: []byte("#b8860b"), + css.Mediumorchid: []byte("#ba55d3"), + css.Rosybrown: []byte("#bc8f8f"), + css.Darkkhaki: []byte("#bdb76b"), + css.Mediumvioletred: []byte("#c71585"), + css.Indianred: []byte("#cd5c5c"), + css.Chocolate: []byte("#d2691e"), + css.Lightgray: []byte("#d3d3d3"), + css.Goldenrod: []byte("#daa520"), + css.Palevioletred: []byte("#db7093"), + css.Gainsboro: []byte("#dcdcdc"), + css.Burlywood: []byte("#deb887"), + css.Lightcyan: []byte("#e0ffff"), + css.Lavender: []byte("#e6e6fa"), + css.Darksalmon: []byte("#e9967a"), + css.Palegoldenrod: []byte("#eee8aa"), + css.Lightcoral: []byte("#f08080"), + css.Aliceblue: []byte("#f0f8ff"), + css.Honeydew: []byte("#f0fff0"), + css.Sandybrown: []byte("#f4a460"), + css.Whitesmoke: []byte("#f5f5f5"), + css.Mintcream: []byte("#f5fffa"), + css.Ghostwhite: []byte("#f8f8ff"), + css.Antiquewhite: []byte("#faebd7"), + css.Lightgoldenrodyellow: []byte("#fafad2"), + css.Fuchsia: []byte("#f0f"), + css.Magenta: []byte("#f0f"), + css.Deeppink: []byte("#ff1493"), + css.Orangered: []byte("#ff4500"), + css.Darkorange: []byte("#ff8c00"), + css.Lightsalmon: []byte("#ffa07a"), + css.Lightpink: []byte("#ffb6c1"), + css.Peachpuff: []byte("#ffdab9"), + css.Navajowhite: []byte("#ffdead"), + css.Moccasin: []byte("#ffe4b5"), + css.Mistyrose: []byte("#ffe4e1"), + css.Blanchedalmond: []byte("#ffebcd"), + css.Papayawhip: []byte("#ffefd5"), + css.Lavenderblush: []byte("#fff0f5"), + css.Seashell: []byte("#fff5ee"), + css.Cornsilk: []byte("#fff8dc"), + css.Lemonchiffon: []byte("#fffacd"), + css.Floralwhite: []byte("#fffaf0"), + css.Yellow: []byte("#ff0"), + css.Lightyellow: []byte("#ffffe0"), + css.White: []byte("#fff"), +} diff --git a/vendor/github.com/tdewolff/minify/v2/go.mod b/vendor/github.com/tdewolff/minify/v2/go.mod new file mode 100644 index 0000000000000..6da2ecf360959 --- /dev/null +++ b/vendor/github.com/tdewolff/minify/v2/go.mod @@ -0,0 +1,12 @@ +module github.com/tdewolff/minify/v2 + +require ( + github.com/cheekybits/is v0.0.0-20150225183255-68e9c0620927 // indirect + github.com/dustin/go-humanize v1.0.0 + github.com/fsnotify/fsnotify v1.4.7 + github.com/matryer/try v0.0.0-20161228173917-9ac251b645a2 + github.com/spf13/pflag v1.0.3 + github.com/tdewolff/parse/v2 v2.3.8 + github.com/tdewolff/test v1.0.0 + golang.org/x/sys v0.0.0-20181031143558-9b800f95dbbc // indirect +) diff --git a/vendor/github.com/tdewolff/minify/v2/go.sum b/vendor/github.com/tdewolff/minify/v2/go.sum new file mode 100644 index 0000000000000..c13ce1e226e62 --- /dev/null +++ b/vendor/github.com/tdewolff/minify/v2/go.sum @@ -0,0 +1,16 @@ +github.com/cheekybits/is v0.0.0-20150225183255-68e9c0620927 h1:SKI1/fuSdodxmNNyVBR8d7X/HuLnRpvvFO0AgyQk764= +github.com/cheekybits/is v0.0.0-20150225183255-68e9c0620927/go.mod h1:h/aW8ynjgkuj+NQRlZcDbAbM1ORAbXjXX77sX7T289U= +github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo= +github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/matryer/try v0.0.0-20161228173917-9ac251b645a2 h1:JAEbJn3j/FrhdWA9jW8B5ajsLIjeuEHLi8xE4fk997o= +github.com/matryer/try v0.0.0-20161228173917-9ac251b645a2/go.mod h1:0KeJpeMD6o+O4hW7qJOT7vyQPKrWmj26uf5wMc/IiIs= +github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg= +github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/tdewolff/parse/v2 v2.3.8 h1:vjTRdg0BIGQHU5TNNc9zZpJ7ZANsmvacBw3VxHZ8Jl8= +github.com/tdewolff/parse/v2 v2.3.8/go.mod h1:HansaqmN4I/U7L6/tUp0NcwT2tFO0F4EAWYGSDzkYNk= +github.com/tdewolff/test v1.0.0 h1:jOwzqCXr5ePXEPGJaq2ivoR6HOCi+D5TPfpoyg8yvmU= +github.com/tdewolff/test v1.0.0/go.mod h1:DiQUlutnqlEvdvhSn2LPGy4TFwRauAaYDsL+683RNX4= +golang.org/x/sys v0.0.0-20181031143558-9b800f95dbbc h1:SdCq5U4J+PpbSDIl9bM0V1e1Ug1jsnBkAFvTs1htn7U= +golang.org/x/sys v0.0.0-20181031143558-9b800f95dbbc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= diff --git a/vendor/github.com/tdewolff/minify/v2/minify.go b/vendor/github.com/tdewolff/minify/v2/minify.go new file mode 100644 index 0000000000000..29722716aba5c --- /dev/null +++ b/vendor/github.com/tdewolff/minify/v2/minify.go @@ -0,0 +1,299 @@ +// Package minify relates MIME type to minifiers. Several minifiers are provided in the subpackages. +package minify + +import ( + "errors" + "io" + "mime" + "net/http" + "net/url" + "os/exec" + "path" + "regexp" + "sync" + + "github.com/tdewolff/parse/v2" + "github.com/tdewolff/parse/v2/buffer" +) + +// ErrNotExist is returned when no minifier exists for a given mimetype. +var ErrNotExist = errors.New("minifier does not exist for mimetype") + +//////////////////////////////////////////////////////////////// + +// MinifierFunc is a function that implements Minifer. +type MinifierFunc func(*M, io.Writer, io.Reader, map[string]string) error + +// Minify calls f(m, w, r, params) +func (f MinifierFunc) Minify(m *M, w io.Writer, r io.Reader, params map[string]string) error { + return f(m, w, r, params) +} + +// Minifier is the interface for minifiers. +// The *M parameter is used for minifying embedded resources, such as JS within HTML. +type Minifier interface { + Minify(*M, io.Writer, io.Reader, map[string]string) error +} + +//////////////////////////////////////////////////////////////// + +type patternMinifier struct { + pattern *regexp.Regexp + Minifier +} + +type cmdMinifier struct { + cmd *exec.Cmd +} + +func (c *cmdMinifier) Minify(_ *M, w io.Writer, r io.Reader, _ map[string]string) error { + cmd := &exec.Cmd{} + *cmd = *c.cmd // concurrency safety + cmd.Stdout = w + cmd.Stdin = r + return cmd.Run() +} + +//////////////////////////////////////////////////////////////// + +// M holds a map of mimetype => function to allow recursive minifier calls of the minifier functions. +type M struct { + mutex sync.RWMutex + literal map[string]Minifier + pattern []patternMinifier + + URL *url.URL +} + +// New returns a new M. +func New() *M { + return &M{ + sync.RWMutex{}, + map[string]Minifier{}, + []patternMinifier{}, + nil, + } +} + +// Add adds a minifier to the mimetype => function map (unsafe for concurrent use). +func (m *M) Add(mimetype string, minifier Minifier) { + m.mutex.Lock() + m.literal[mimetype] = minifier + m.mutex.Unlock() +} + +// AddFunc adds a minify function to the mimetype => function map (unsafe for concurrent use). +func (m *M) AddFunc(mimetype string, minifier MinifierFunc) { + m.mutex.Lock() + m.literal[mimetype] = minifier + m.mutex.Unlock() +} + +// AddRegexp adds a minifier to the mimetype => function map (unsafe for concurrent use). +func (m *M) AddRegexp(pattern *regexp.Regexp, minifier Minifier) { + m.mutex.Lock() + m.pattern = append(m.pattern, patternMinifier{pattern, minifier}) + m.mutex.Unlock() +} + +// AddFuncRegexp adds a minify function to the mimetype => function map (unsafe for concurrent use). +func (m *M) AddFuncRegexp(pattern *regexp.Regexp, minifier MinifierFunc) { + m.mutex.Lock() + m.pattern = append(m.pattern, patternMinifier{pattern, minifier}) + m.mutex.Unlock() +} + +// AddCmd adds a minify function to the mimetype => function map (unsafe for concurrent use) that executes a command to process the minification. +// It allows the use of external tools like ClosureCompiler, UglifyCSS, etc. for a specific mimetype. +func (m *M) AddCmd(mimetype string, cmd *exec.Cmd) { + m.mutex.Lock() + m.literal[mimetype] = &cmdMinifier{cmd} + m.mutex.Unlock() +} + +// AddCmdRegexp adds a minify function to the mimetype => function map (unsafe for concurrent use) that executes a command to process the minification. +// It allows the use of external tools like ClosureCompiler, UglifyCSS, etc. for a specific mimetype regular expression. +func (m *M) AddCmdRegexp(pattern *regexp.Regexp, cmd *exec.Cmd) { + m.mutex.Lock() + m.pattern = append(m.pattern, patternMinifier{pattern, &cmdMinifier{cmd}}) + m.mutex.Unlock() +} + +// Match returns the pattern and minifier that gets matched with the mediatype. +// It returns nil when no matching minifier exists. +// It has the same matching algorithm as Minify. +func (m *M) Match(mediatype string) (string, map[string]string, MinifierFunc) { + m.mutex.RLock() + defer m.mutex.RUnlock() + + mimetype, params := parse.Mediatype([]byte(mediatype)) + if minifier, ok := m.literal[string(mimetype)]; ok { // string conversion is optimized away + return string(mimetype), params, minifier.Minify + } + + for _, minifier := range m.pattern { + if minifier.pattern.Match(mimetype) { + return minifier.pattern.String(), params, minifier.Minify + } + } + return string(mimetype), params, nil +} + +// Minify minifies the content of a Reader and writes it to a Writer (safe for concurrent use). +// An error is returned when no such mimetype exists (ErrNotExist) or when an error occurred in the minifier function. +// Mediatype may take the form of 'text/plain', 'text/*', '*/*' or 'text/plain; charset=UTF-8; version=2.0'. +func (m *M) Minify(mediatype string, w io.Writer, r io.Reader) error { + mimetype, params := parse.Mediatype([]byte(mediatype)) + return m.MinifyMimetype(mimetype, w, r, params) +} + +// MinifyMimetype minifies the content of a Reader and writes it to a Writer (safe for concurrent use). +// It is a lower level version of Minify and requires the mediatype to be split up into mimetype and parameters. +// It is mostly used internally by minifiers because it is faster (no need to convert a byte-slice to string and vice versa). +func (m *M) MinifyMimetype(mimetype []byte, w io.Writer, r io.Reader, params map[string]string) error { + m.mutex.RLock() + defer m.mutex.RUnlock() + + err := ErrNotExist + if minifier, ok := m.literal[string(mimetype)]; ok { // string conversion is optimized away + err = minifier.Minify(m, w, r, params) + } else { + for _, minifier := range m.pattern { + if minifier.pattern.Match(mimetype) { + err = minifier.Minify(m, w, r, params) + break + } + } + } + return err +} + +// Bytes minifies an array of bytes (safe for concurrent use). When an error occurs it return the original array and the error. +// It returns an error when no such mimetype exists (ErrNotExist) or any error occurred in the minifier function. +func (m *M) Bytes(mediatype string, v []byte) ([]byte, error) { + out := buffer.NewWriter(make([]byte, 0, len(v))) + if err := m.Minify(mediatype, out, buffer.NewReader(v)); err != nil { + return v, err + } + return out.Bytes(), nil +} + +// String minifies a string (safe for concurrent use). When an error occurs it return the original string and the error. +// It returns an error when no such mimetype exists (ErrNotExist) or any error occurred in the minifier function. +func (m *M) String(mediatype string, v string) (string, error) { + out := buffer.NewWriter(make([]byte, 0, len(v))) + if err := m.Minify(mediatype, out, buffer.NewReader([]byte(v))); err != nil { + return v, err + } + return string(out.Bytes()), nil +} + +// Reader wraps a Reader interface and minifies the stream. +// Errors from the minifier are returned by the reader. +func (m *M) Reader(mediatype string, r io.Reader) io.Reader { + pr, pw := io.Pipe() + go func() { + if err := m.Minify(mediatype, pw, r); err != nil { + pw.CloseWithError(err) + } else { + pw.Close() + } + }() + return pr +} + +// minifyWriter makes sure that errors from the minifier are passed down through Close (can be blocking). +type minifyWriter struct { + pw *io.PipeWriter + wg sync.WaitGroup + err error +} + +// Write intercepts any writes to the writer. +func (w *minifyWriter) Write(b []byte) (int, error) { + return w.pw.Write(b) +} + +// Close must be called when writing has finished. It returns the error from the minifier. +func (w *minifyWriter) Close() error { + w.pw.Close() + w.wg.Wait() + return w.err +} + +// Writer wraps a Writer interface and minifies the stream. +// Errors from the minifier are returned by Close on the writer. +// The writer must be closed explicitly. +func (m *M) Writer(mediatype string, w io.Writer) *minifyWriter { + pr, pw := io.Pipe() + mw := &minifyWriter{pw, sync.WaitGroup{}, nil} + mw.wg.Add(1) + go func() { + defer mw.wg.Done() + + if err := m.Minify(mediatype, w, pr); err != nil { + io.Copy(w, pr) + mw.err = err + } + pr.Close() + }() + return mw +} + +// minifyResponseWriter wraps an http.ResponseWriter and makes sure that errors from the minifier are passed down through Close (can be blocking). +// All writes to the response writer are intercepted and minified on the fly. +// http.ResponseWriter loses all functionality such as Pusher, Hijacker, Flusher, ... +type minifyResponseWriter struct { + http.ResponseWriter + + writer *minifyWriter + m *M + mediatype string +} + +// WriteHeader intercepts any header writes and removes the Content-Length header. +func (w *minifyResponseWriter) WriteHeader(status int) { + w.ResponseWriter.Header().Del("Content-Length") + w.ResponseWriter.WriteHeader(status) +} + +// Write intercepts any writes to the response writer. +// The first write will extract the Content-Type as the mediatype. Otherwise it falls back to the RequestURI extension. +func (w *minifyResponseWriter) Write(b []byte) (int, error) { + if w.writer == nil { + // first write + if mediatype := w.ResponseWriter.Header().Get("Content-Type"); mediatype != "" { + w.mediatype = mediatype + } + w.writer = w.m.Writer(w.mediatype, w.ResponseWriter) + } + return w.writer.Write(b) +} + +// Close must be called when writing has finished. It returns the error from the minifier. +func (w *minifyResponseWriter) Close() error { + if w.writer != nil { + return w.writer.Close() + } + return nil +} + +// ResponseWriter minifies any writes to the http.ResponseWriter. +// http.ResponseWriter loses all functionality such as Pusher, Hijacker, Flusher, ... +// Minification might be slower than just sending the original file! Caching is advised. +func (m *M) ResponseWriter(w http.ResponseWriter, r *http.Request) *minifyResponseWriter { + mediatype := mime.TypeByExtension(path.Ext(r.RequestURI)) + return &minifyResponseWriter{w, nil, m, mediatype} +} + +// Middleware provides a middleware function that minifies content on the fly by intercepting writes to http.ResponseWriter. +// http.ResponseWriter loses all functionality such as Pusher, Hijacker, Flusher, ... +// Minification might be slower than just sending the original file! Caching is advised. +func (m *M) Middleware(next http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + mw := m.ResponseWriter(w, r) + defer mw.Close() + + next.ServeHTTP(mw, r) + }) +} diff --git a/vendor/github.com/tdewolff/minify/v2/svg/buffer.go b/vendor/github.com/tdewolff/minify/v2/svg/buffer.go new file mode 100644 index 0000000000000..25c76556373f4 --- /dev/null +++ b/vendor/github.com/tdewolff/minify/v2/svg/buffer.go @@ -0,0 +1,130 @@ +package svg + +import ( + "github.com/tdewolff/parse/v2" + "github.com/tdewolff/parse/v2/svg" + "github.com/tdewolff/parse/v2/xml" +) + +// Token is a single token unit with an attribute value (if given) and hash of the data. +type Token struct { + xml.TokenType + Hash svg.Hash + Data []byte + Text []byte + AttrVal []byte +} + +// TokenBuffer is a buffer that allows for token look-ahead. +type TokenBuffer struct { + l *xml.Lexer + + buf []Token + pos int + + attrBuffer []*Token +} + +// NewTokenBuffer returns a new TokenBuffer. +func NewTokenBuffer(l *xml.Lexer) *TokenBuffer { + return &TokenBuffer{ + l: l, + buf: make([]Token, 0, 8), + } +} + +func (z *TokenBuffer) read(t *Token) { + t.TokenType, t.Data = z.l.Next() + t.Text = z.l.Text() + if t.TokenType == xml.AttributeToken { + t.AttrVal = z.l.AttrVal() + if len(t.AttrVal) > 1 && (t.AttrVal[0] == '"' || t.AttrVal[0] == '\'') { + t.AttrVal = parse.ReplaceMultipleWhitespace(parse.TrimWhitespace(t.AttrVal[1 : len(t.AttrVal)-1])) // quotes will be readded in attribute loop if necessary + } + t.Hash = svg.ToHash(t.Text) + } else if t.TokenType == xml.StartTagToken || t.TokenType == xml.EndTagToken { + t.AttrVal = nil + t.Hash = svg.ToHash(t.Text) + } else { + t.AttrVal = nil + t.Hash = 0 + } +} + +// Peek returns the ith element and possibly does an allocation. +// Peeking past an error will panic. +func (z *TokenBuffer) Peek(pos int) *Token { + pos += z.pos + if pos >= len(z.buf) { + if len(z.buf) > 0 && z.buf[len(z.buf)-1].TokenType == xml.ErrorToken { + return &z.buf[len(z.buf)-1] + } + + c := cap(z.buf) + d := len(z.buf) - z.pos + p := pos - z.pos + 1 // required peek length + var buf []Token + if 2*p > c { + buf = make([]Token, 0, 2*c+p) + } else { + buf = z.buf + } + copy(buf[:d], z.buf[z.pos:]) + + buf = buf[:p] + pos -= z.pos + for i := d; i < p; i++ { + z.read(&buf[i]) + if buf[i].TokenType == xml.ErrorToken { + buf = buf[:i+1] + pos = i + break + } + } + z.pos, z.buf = 0, buf + } + return &z.buf[pos] +} + +// Shift returns the first element and advances position. +func (z *TokenBuffer) Shift() *Token { + if z.pos >= len(z.buf) { + t := &z.buf[:1][0] + z.read(t) + return t + } + t := &z.buf[z.pos] + z.pos++ + return t +} + +// Attributes extracts the gives attribute hashes from a tag. +// It returns in the same order pointers to the requested token data or nil. +func (z *TokenBuffer) Attributes(hashes ...svg.Hash) ([]*Token, *Token) { + n := 0 + for { + if t := z.Peek(n); t.TokenType != xml.AttributeToken { + break + } + n++ + } + if len(hashes) > cap(z.attrBuffer) { + z.attrBuffer = make([]*Token, len(hashes)) + } else { + z.attrBuffer = z.attrBuffer[:len(hashes)] + for i := range z.attrBuffer { + z.attrBuffer[i] = nil + } + } + var replacee *Token + for i := z.pos; i < z.pos+n; i++ { + attr := &z.buf[i] + for j, hash := range hashes { + if hash == attr.Hash { + z.attrBuffer[j] = attr + replacee = attr + } + } + } + return z.attrBuffer, replacee +} diff --git a/vendor/github.com/tdewolff/minify/v2/svg/pathdata.go b/vendor/github.com/tdewolff/minify/v2/svg/pathdata.go new file mode 100644 index 0000000000000..217e5dfe6a86b --- /dev/null +++ b/vendor/github.com/tdewolff/minify/v2/svg/pathdata.go @@ -0,0 +1,388 @@ +package svg + +import ( + "math" + strconvStdlib "strconv" + + "github.com/tdewolff/minify/v2" + "github.com/tdewolff/parse/v2" + "github.com/tdewolff/parse/v2/strconv" +) + +type PathData struct { + o *Minifier + + x, y float64 + x0, y0 float64 + coords [][]byte + coordFloats []float64 + cx, cy float64 // last control point for cubic bezier + qx, qy float64 // last control point for quadratic bezier + + state PathDataState + curBuffer []byte + altBuffer []byte + coordBuffer []byte +} + +type PathDataState struct { + cmd byte + prevDigit bool + prevDigitIsInt bool +} + +func NewPathData(o *Minifier) *PathData { + return &PathData{ + o: o, + cx: math.NaN(), + cy: math.NaN(), + qx: math.NaN(), + qy: math.NaN(), + } +} + +// ShortenPathData takes a full pathdata string and returns a shortened version. The original string is overwritten. +// It parses all commands (M, A, Z, ...) and coordinates (numbers) and calls copyInstruction for each command. +func (p *PathData) ShortenPathData(b []byte) []byte { + var cmd byte + + p.x, p.y = 0.0, 0.0 + p.coords = p.coords[:0] + p.coordFloats = p.coordFloats[:0] + p.state = PathDataState{} + + j := 0 + for i := 0; i < len(b); i++ { + c := b[i] + if c == ' ' || c == ',' || c == '\n' || c == '\r' || c == '\t' { + continue + } else if c >= 'A' && (cmd == 0 || cmd != c || c == 'M' || c == 'm') { // any command + if cmd != 0 { + j += p.copyInstruction(b[j:], cmd) + } + cmd = c + p.coords = p.coords[:0] + p.coordFloats = p.coordFloats[:0] + } else if n := parse.Number(b[i:]); n > 0 { + f, _ := strconv.ParseFloat(b[i : i+n]) + p.coords = append(p.coords, b[i:i+n]) + p.coordFloats = append(p.coordFloats, f) + i += n - 1 + } + } + if cmd != 0 { + j += p.copyInstruction(b[j:], cmd) + } + return b[:j] +} + +// copyInstruction copies pathdata of a single command, but may be comprised of multiple sets for that command. For example, L takes two coordinates, but this function may process 2*N coordinates. Lowercase commands are relative commands, where the coordinates are relative to the previous point. Uppercase commands have absolute coordinates. +// We update p.x and p.y (the current coordinates) according to the commands given. For each set of coordinates we call shortenCurPosInstruction and shortenAltPosInstruction. The former just minifies the coordinates, the latter will inverse the lowercase/uppercase of the command, and see if the coordinates get smaller due to that. The shortest is chosen and copied to `b`. +func (p *PathData) copyInstruction(b []byte, cmd byte) int { + n := len(p.coords) + if n == 0 { + if cmd == 'Z' || cmd == 'z' { + p.x = p.x0 + p.y = p.y0 + b[0] = 'z' + return 1 + } + return 0 + } + isRelCmd := cmd >= 'a' + + // get new cursor coordinates + di := 0 + if (cmd == 'M' || cmd == 'm' || cmd == 'L' || cmd == 'l' || cmd == 'T' || cmd == 't') && n%2 == 0 { + di = 2 + // reprint M always, as the first pair is a move but subsequent pairs are L + if cmd == 'M' || cmd == 'm' { + p.state.cmd = byte(0) + } + } else if cmd == 'H' || cmd == 'h' || cmd == 'V' || cmd == 'v' { + di = 1 + } else if (cmd == 'S' || cmd == 's' || cmd == 'Q' || cmd == 'q') && n%4 == 0 { + di = 4 + } else if (cmd == 'C' || cmd == 'c') && n%6 == 0 { + di = 6 + } else if (cmd == 'A' || cmd == 'a') && n%7 == 0 { + di = 7 + } else { + return 0 + } + + j := 0 + origCmd := cmd + for i := 0; i < n; i += di { + // subsequent coordinate pairs for M are really L + if i > 0 && (origCmd == 'M' || origCmd == 'm') { + origCmd = 'L' + (origCmd - 'M') + } + + cmd = origCmd + coords := p.coords[i : i+di] + coordFloats := p.coordFloats[i : i+di] + + // set next coordinate + var ax, ay float64 + if cmd == 'H' || cmd == 'h' { + ax = coordFloats[di-1] + if isRelCmd { + ay = 0 + } else { + ay = p.y + } + } else if cmd == 'V' || cmd == 'v' { + if isRelCmd { + ax = 0 + } else { + ax = p.x + } + ay = coordFloats[di-1] + } else { + ax = coordFloats[di-2] + ay = coordFloats[di-1] + } + + // switch from C to S whenever possible + if cmd == 'C' || cmd == 'c' || cmd == 'S' || cmd == 's' { + if math.IsNaN(p.cx) { + p.cx, p.cy = p.x, p.y + } else { + p.cx, p.cy = 2*p.x-p.cx, 2*p.y-p.cy + } + + var cp1x, cp1y float64 + cp2x, cp2y := coordFloats[di-4], coordFloats[di-3] + if cmd == 'C' || cmd == 'c' { + cp1x, cp1y = coordFloats[di-6], coordFloats[di-5] + if cp1x == p.cx && cp1y == p.cy { + if isRelCmd { + cmd = 's' + } else { + cmd = 'S' + } + coords = coords[2:] + coordFloats = coordFloats[2:] + } + } else { + cp1x, cp1y = p.cx, p.cy + } + + // if control points overlap begin/end points, this is a straight line + // even though if the control points would be along the straight line, we won't minify that as the control points influence the speed along the curve (important for dashes for example) + // only change to a lines if we are sure no 'S' or 's' follows + if (cmd == 'C' || cmd == 'c' || i+di >= n) && (cp1x == p.x || cp1x == ax) && (cp1y == p.y || cp1y == ay) && (cp2x == p.x || cp2x == ax) && (cp2y == p.y || cp2y == ay) { + if isRelCmd { + cmd = 'l' + } else { + cmd = 'L' + } + coords = coords[len(coords)-2:] + coordFloats = coordFloats[len(coordFloats)-2:] + cp2x, cp2y = math.NaN(), math.NaN() + } + p.cx, p.cy = cp2x, cp2y + } else { + p.cx, p.cy = math.NaN(), math.NaN() + } + + // switch from Q to T whenever possible + if cmd == 'Q' || cmd == 'q' || cmd == 'T' || cmd == 't' { + if math.IsNaN(p.qx) { + p.qx, p.qy = p.x, p.y + } else { + p.qx, p.qy = 2*p.x-p.qx, 2*p.y-p.qy + } + + var cpx, cpy float64 + if cmd == 'Q' || cmd == 'q' { + cpx, cpy = coordFloats[di-4], coordFloats[di-3] + if cpx == p.qx && cpy == p.qy { + if isRelCmd { + cmd = 't' + } else { + cmd = 'T' + } + coords = coords[2:] + coordFloats = coordFloats[2:] + } + } else { + cpx, cpy = p.qx, p.qy + } + + // if control point overlaps begin/end points, this is a straight line + // even though if the control point would be along the straight line, we won't minify that as the control point influences the speed along the curve (important for dashes for example) + // only change to a lines if we are sure no 'T' or 't' follows + if (cmd == 'Q' || cmd == 'q' || i+di >= n) && (cpx == p.x || cpx == ax) && (cpy == p.y || cpy == ay) { + if isRelCmd { + cmd = 'l' + } else { + cmd = 'L' + } + coords = coords[len(coords)-2:] + coordFloats = coordFloats[len(coordFloats)-2:] + cpx, cpy = math.NaN(), math.NaN() + } + p.qx, p.qy = cpx, cpy + } else { + p.qx, p.qy = math.NaN(), math.NaN() + } + + // switch from L to H or V whenever possible + if cmd == 'L' || cmd == 'l' { + if isRelCmd { + if ax == 0 && ay == 0 { + continue + } else if ax == 0 { + cmd = 'v' + coords = coords[1:] + coordFloats = coordFloats[1:] + ax = 0 + } else if ay == 0 { + cmd = 'h' + coords = coords[:1] + coordFloats = coordFloats[:1] + ay = 0 + } + } else { + if ax == p.x && ay == p.y { + continue + } else if ax == p.x { + cmd = 'V' + coords = coords[1:] + coordFloats = coordFloats[1:] + } else if ay == p.y { + cmd = 'H' + coords = coords[:1] + coordFloats = coordFloats[:1] + } + } + } + + // make a current and alternated path with absolute/relative altered + var curState, altState PathDataState + curState = p.shortenCurPosInstruction(cmd, coords) + if isRelCmd { + altState = p.shortenAltPosInstruction(cmd-'a'+'A', coordFloats, p.x, p.y) + } else { + altState = p.shortenAltPosInstruction(cmd-'A'+'a', coordFloats, -p.x, -p.y) + } + + // choose shortest, relative or absolute path? + if len(p.altBuffer) < len(p.curBuffer) { + j += copy(b[j:], p.altBuffer) + p.state = altState + } else { + j += copy(b[j:], p.curBuffer) + p.state = curState + } + + if isRelCmd { + p.x += ax + p.y += ay + } else { + p.x = ax + p.y = ay + } + if i == 0 && (origCmd == 'M' || origCmd == 'm') { + p.x0 = p.x + p.y0 = p.y + } + } + return j +} + +// shortenCurPosInstruction only minifies the coordinates. +func (p *PathData) shortenCurPosInstruction(cmd byte, coords [][]byte) PathDataState { + state := p.state + p.curBuffer = p.curBuffer[:0] + if cmd != state.cmd && !(state.cmd == 'M' && cmd == 'L' || state.cmd == 'm' && cmd == 'l') { + p.curBuffer = append(p.curBuffer, cmd) + state.cmd = cmd + state.prevDigit = false + state.prevDigitIsInt = false + } + for i, coord := range coords { + isFlag := false + // Arc has boolean flags that can only be 0 or 1. Setting isFlag prevents from adding a dot before a zero (instead of a space). However, when the dot already was there, the command is malformed and could make the path longer than before, introducing bugs. + if (cmd == 'A' || cmd == 'a') && (i%7 == 3 || i%7 == 4) && coord[0] != '.' { + isFlag = true + } + + coord = minify.Number(coord, p.o.Decimals) + state.copyNumber(&p.curBuffer, coord, isFlag) + } + return state +} + +// shortenAltPosInstruction toggles the command between absolute / relative coordinates and minifies the coordinates. +func (p *PathData) shortenAltPosInstruction(cmd byte, coordFloats []float64, x, y float64) PathDataState { + state := p.state + p.altBuffer = p.altBuffer[:0] + if cmd != state.cmd && !(state.cmd == 'M' && cmd == 'L' || state.cmd == 'm' && cmd == 'l') { + p.altBuffer = append(p.altBuffer, cmd) + state.cmd = cmd + state.prevDigit = false + state.prevDigitIsInt = false + } + for i, f := range coordFloats { + isFlag := false + if cmd == 'L' || cmd == 'l' || cmd == 'C' || cmd == 'c' || cmd == 'S' || cmd == 's' || cmd == 'Q' || cmd == 'q' || cmd == 'T' || cmd == 't' || cmd == 'M' || cmd == 'm' { + if i%2 == 0 { + f += x + } else { + f += y + } + } else if cmd == 'H' || cmd == 'h' { + f += x + } else if cmd == 'V' || cmd == 'v' { + f += y + } else if cmd == 'A' || cmd == 'a' { + if i%7 == 5 { + f += x + } else if i%7 == 6 { + f += y + } else if i%7 == 3 || i%7 == 4 { + isFlag = true + } + } + + p.coordBuffer = strconvStdlib.AppendFloat(p.coordBuffer[:0], f, 'g', -1, 64) + coord := minify.Number(p.coordBuffer, p.o.Decimals) + state.copyNumber(&p.altBuffer, coord, isFlag) + } + return state +} + +// copyNumber will copy a number to the destination buffer, taking into account space or dot insertion to guarantee the shortest pathdata. +func (state *PathDataState) copyNumber(buffer *[]byte, coord []byte, isFlag bool) { + if state.prevDigit && (coord[0] >= '0' && coord[0] <= '9' || coord[0] == '.' && state.prevDigitIsInt) { + if coord[0] == '0' && !state.prevDigitIsInt { + if isFlag { + *buffer = append(*buffer, ' ', '0') + state.prevDigitIsInt = true + } else { + *buffer = append(*buffer, '.', '0') // aggresively add dot so subsequent numbers could drop leading space + // prevDigit stays true and prevDigitIsInt stays false + } + return + } + *buffer = append(*buffer, ' ') + } + state.prevDigit = true + state.prevDigitIsInt = true + if len(coord) > 2 && coord[len(coord)-2] == '0' && coord[len(coord)-1] == '0' { + coord[len(coord)-2] = 'e' + coord[len(coord)-1] = '2' + state.prevDigitIsInt = false + } else { + for _, c := range coord { + if c == '.' || c == 'e' || c == 'E' { + state.prevDigitIsInt = false + break + } + } + } + *buffer = append(*buffer, coord...) +} diff --git a/vendor/github.com/tdewolff/minify/v2/svg/svg.go b/vendor/github.com/tdewolff/minify/v2/svg/svg.go new file mode 100644 index 0000000000000..e48ae3a1cdb88 --- /dev/null +++ b/vendor/github.com/tdewolff/minify/v2/svg/svg.go @@ -0,0 +1,429 @@ +// Package svg minifies SVG1.1 following the specifications at http://www.w3.org/TR/SVG11/. +package svg + +import ( + "bytes" + "io" + + "github.com/tdewolff/minify/v2" + minifyCSS "github.com/tdewolff/minify/v2/css" + "github.com/tdewolff/parse/v2" + "github.com/tdewolff/parse/v2/buffer" + "github.com/tdewolff/parse/v2/css" + "github.com/tdewolff/parse/v2/svg" + "github.com/tdewolff/parse/v2/xml" +) + +var ( + voidBytes = []byte("/>") + isBytes = []byte("=") + spaceBytes = []byte(" ") + cdataEndBytes = []byte("]]>") + pathBytes = []byte(" 0 && t.Text[len(t.Text)-1] == ']' { + if _, err := w.Write(t.Data); err != nil { + return err + } + } + case xml.TextToken: + t.Data = parse.ReplaceMultipleWhitespace(parse.TrimWhitespace(t.Data)) + if tag == svg.Style && len(t.Data) > 0 { + if err := m.MinifyMimetype(defaultStyleType, w, buffer.NewReader(t.Data), defaultStyleParams); err != nil { + if err != minify.ErrNotExist { + return err + } else if _, err := w.Write(t.Data); err != nil { + return err + } + } + } else if _, err := w.Write(t.Data); err != nil { + return err + } + case xml.CDATAToken: + if tag == svg.Style { + minifyBuffer.Reset() + if err := m.MinifyMimetype(defaultStyleType, minifyBuffer, buffer.NewReader(t.Text), defaultStyleParams); err == nil { + t.Data = append(t.Data[:9], minifyBuffer.Bytes()...) + t.Text = t.Data[9:] + t.Data = append(t.Data, cdataEndBytes...) + } else if err != minify.ErrNotExist { + return err + } + } + var useText bool + if t.Text, useText = xml.EscapeCDATAVal(&attrByteBuffer, t.Text); useText { + t.Text = parse.ReplaceMultipleWhitespace(parse.TrimWhitespace(t.Text)) + if _, err := w.Write(t.Text); err != nil { + return err + } + } else if _, err := w.Write(t.Data); err != nil { + return err + } + case xml.StartTagPIToken: + for { + if t := *tb.Shift(); t.TokenType == xml.StartTagClosePIToken || t.TokenType == xml.ErrorToken { + break + } + } + case xml.StartTagToken: + tag = t.Hash + if tag == svg.Metadata { + t.Data = nil + } else if tag == svg.Line { + o.shortenLine(tb, &t, p) + } else if tag == svg.Rect { + o.shortenRect(tb, &t, p) + } else if tag == svg.Polygon || tag == svg.Polyline { + o.shortenPoly(tb, &t, p) + } + if t.Data == nil { + skipTag(tb) + } else if _, err := w.Write(t.Data); err != nil { + return err + } + case xml.AttributeToken: + if len(t.AttrVal) == 0 || t.Text == nil { // data is nil when attribute has been removed + continue + } + + attr := t.Hash + val := t.AttrVal + if n, m := parse.Dimension(val); n+m == len(val) && attr != svg.Version { // TODO: inefficient, temporary measure + val, _ = o.shortenDimension(val) + } + if attr == svg.Xml_Space && bytes.Equal(val, []byte("preserve")) || + tag == svg.Svg && (attr == svg.Version && bytes.Equal(val, []byte("1.1")) || + attr == svg.X && bytes.Equal(val, []byte("0")) || + attr == svg.Y && bytes.Equal(val, []byte("0")) || + attr == svg.Width && bytes.Equal(val, []byte("100%")) || + attr == svg.Height && bytes.Equal(val, []byte("100%")) || + attr == svg.PreserveAspectRatio && bytes.Equal(val, []byte("xMidYMid meet")) || + attr == svg.BaseProfile && bytes.Equal(val, []byte("none")) || + attr == svg.ContentScriptType && bytes.Equal(val, []byte("application/ecmascript")) || + attr == svg.ContentStyleType && bytes.Equal(val, []byte("text/css"))) || + tag == svg.Style && attr == svg.Type && bytes.Equal(val, []byte("text/css")) { + continue + } + + if _, err := w.Write(spaceBytes); err != nil { + return err + } + if _, err := w.Write(t.Text); err != nil { + return err + } + if _, err := w.Write(isBytes); err != nil { + return err + } + + if tag == svg.Svg && attr == svg.ContentStyleType { + val = minify.Mediatype(val) + defaultStyleType = val + } else if attr == svg.Style { + minifyBuffer.Reset() + if err := m.MinifyMimetype(defaultStyleType, minifyBuffer, buffer.NewReader(val), defaultInlineStyleParams); err == nil { + val = minifyBuffer.Bytes() + } else if err != minify.ErrNotExist { + return err + } + } else if attr == svg.D { + val = p.ShortenPathData(val) + } else if attr == svg.ViewBox { + j := 0 + newVal := val[:0] + for i := 0; i < 4; i++ { + if i != 0 { + if j >= len(val) || val[j] != ' ' && val[j] != ',' { + newVal = append(newVal, val[j:]...) + break + } + newVal = append(newVal, ' ') + j++ + } + if dim, n := o.shortenDimension(val[j:]); n > 0 { + newVal = append(newVal, dim...) + j += n + } else { + newVal = append(newVal, val[j:]...) + break + } + } + val = newVal + } else if colorAttrMap[attr] && len(val) > 0 && (len(val) < 5 || !parse.EqualFold(val[:4], urlBytes)) { + parse.ToLower(val) + if val[0] == '#' { + if name, ok := minifyCSS.ShortenColorHex[string(val)]; ok { + val = name + } else if len(val) == 7 && val[1] == val[2] && val[3] == val[4] && val[5] == val[6] { + val[2] = val[3] + val[3] = val[5] + val = val[:4] + } + } else if hex, ok := minifyCSS.ShortenColorName[css.ToHash(val)]; ok { + val = hex + // } else if len(val) > 5 && bytes.Equal(val[:4], []byte("rgb(")) && val[len(val)-1] == ')' { + // TODO: handle rgb(x, y, z) and hsl(x, y, z) + } + } + + // prefer single or double quotes depending on what occurs more often in value + val = xml.EscapeAttrVal(&attrByteBuffer, val) + if _, err := w.Write(val); err != nil { + return err + } + case xml.StartTagCloseToken: + next := tb.Peek(0) + skipExtra := false + if next.TokenType == xml.TextToken && parse.IsAllWhitespace(next.Data) { + next = tb.Peek(1) + skipExtra = true + } + if next.TokenType == xml.EndTagToken { + // collapse empty tags to single void tag + tb.Shift() + if skipExtra { + tb.Shift() + } + if _, err := w.Write(voidBytes); err != nil { + return err + } + } else { + if _, err := w.Write(t.Data); err != nil { + return err + } + } + case xml.StartTagCloseVoidToken: + tag = 0 + if _, err := w.Write(t.Data); err != nil { + return err + } + case xml.EndTagToken: + tag = 0 + if len(t.Data) > 3+len(t.Text) { + t.Data[2+len(t.Text)] = '>' + t.Data = t.Data[:3+len(t.Text)] + } + if _, err := w.Write(t.Data); err != nil { + return err + } + } + } +} + +func (o *Minifier) shortenDimension(b []byte) ([]byte, int) { + if n, m := parse.Dimension(b); n > 0 { + unit := b[n : n+m] + b = minify.Number(b[:n], o.Decimals) + if len(b) != 1 || b[0] != '0' { + if m == 2 && unit[0] == 'p' && unit[1] == 'x' { + unit = nil + } else if m > 1 { // only percentage is length 1 + parse.ToLower(unit) + } + b = append(b, unit...) + } + return b, n + m + } + return b, 0 +} + +func (o *Minifier) shortenLine(tb *TokenBuffer, t *Token, p *PathData) { + x1, y1, x2, y2 := zeroBytes, zeroBytes, zeroBytes, zeroBytes + if attrs, replacee := tb.Attributes(svg.X1, svg.Y1, svg.X2, svg.Y2); replacee != nil { + // skip converting to path if any attribute contains dimensions, TODO: convert non-percentage dimensions to px + for _, attr := range attrs { + if attr != nil { + if _, dim := parse.Dimension(attr.AttrVal); dim != 0 { + return + } + } + } + + if attrs[0] != nil { + x1 = minify.Number(attrs[0].AttrVal, o.Decimals) + attrs[0].Text = nil + } + if attrs[1] != nil { + y1 = minify.Number(attrs[1].AttrVal, o.Decimals) + attrs[1].Text = nil + } + if attrs[2] != nil { + x2 = minify.Number(attrs[2].AttrVal, o.Decimals) + attrs[2].Text = nil + } + if attrs[3] != nil { + y2 = minify.Number(attrs[3].AttrVal, o.Decimals) + attrs[3].Text = nil + } + + d := make([]byte, 0, 5+len(x1)+len(y1)+len(x2)+len(y2)) + d = append(d, 'M') + d = append(d, x1...) + d = append(d, ' ') + d = append(d, y1...) + d = append(d, 'L') + d = append(d, x2...) + d = append(d, ' ') + d = append(d, y2...) + d = append(d, 'z') + d = p.ShortenPathData(d) + + t.Data = pathBytes + replacee.Text = dBytes + replacee.AttrVal = d + } +} + +func (o *Minifier) shortenRect(tb *TokenBuffer, t *Token, p *PathData) { + if attrs, replacee := tb.Attributes(svg.X, svg.Y, svg.Width, svg.Height, svg.Rx, svg.Ry); replacee != nil && attrs[4] == nil && attrs[5] == nil { + // skip converting to path if any attribute contains dimensions, TODO: convert non-percentage dimensions to px + for _, attr := range attrs { + if attr != nil { + if _, dim := parse.Dimension(attr.AttrVal); dim != 0 { + return + } + } + } + + x, y, w, h := zeroBytes, zeroBytes, zeroBytes, zeroBytes + if attrs[0] != nil { + x = minify.Number(attrs[0].AttrVal, o.Decimals) + attrs[0].Text = nil + } + if attrs[1] != nil { + y = minify.Number(attrs[1].AttrVal, o.Decimals) + attrs[1].Text = nil + } + if attrs[2] != nil { + w = minify.Number(attrs[2].AttrVal, o.Decimals) + attrs[2].Text = nil + } + if attrs[3] != nil { + h = minify.Number(attrs[3].AttrVal, o.Decimals) + attrs[3].Text = nil + } + if len(w) == 0 || w[0] == '0' || len(h) == 0 || h[0] == '0' { + t.Data = nil + return + } + + d := make([]byte, 0, 6+2*len(x)+len(y)+len(w)+len(h)) + d = append(d, 'M') + d = append(d, x...) + d = append(d, ' ') + d = append(d, y...) + d = append(d, 'h') + d = append(d, w...) + d = append(d, 'v') + d = append(d, h...) + d = append(d, 'H') + d = append(d, x...) + d = append(d, 'z') + d = p.ShortenPathData(d) + + t.Data = pathBytes + replacee.Text = dBytes + replacee.AttrVal = d + } +} + +func (o *Minifier) shortenPoly(tb *TokenBuffer, t *Token, p *PathData) { + if attrs, replacee := tb.Attributes(svg.Points); replacee != nil && attrs[0] != nil { + points := attrs[0].AttrVal + + i := 0 + for i < len(points) && !(points[i] == ' ' || points[i] == ',' || points[i] == '\n' || points[i] == '\r' || points[i] == '\t') { + i++ + } + for i < len(points) && (points[i] == ' ' || points[i] == ',' || points[i] == '\n' || points[i] == '\r' || points[i] == '\t') { + i++ + } + for i < len(points) && !(points[i] == ' ' || points[i] == ',' || points[i] == '\n' || points[i] == '\r' || points[i] == '\t') { + i++ + } + endMoveTo := i + for i < len(points) && (points[i] == ' ' || points[i] == ',' || points[i] == '\n' || points[i] == '\r' || points[i] == '\t') { + i++ + } + startLineTo := i + + if i == len(points) { + return + } + + d := make([]byte, 0, len(points)+3) + d = append(d, 'M') + d = append(d, points[:endMoveTo]...) + d = append(d, 'L') + d = append(d, points[startLineTo:]...) + if t.Hash == svg.Polygon { + d = append(d, 'z') + } + d = p.ShortenPathData(d) + + t.Data = pathBytes + replacee.Text = dBytes + replacee.AttrVal = d + } +} + +//////////////////////////////////////////////////////////////// + +func skipTag(tb *TokenBuffer) { + level := 0 + for { + if t := *tb.Shift(); t.TokenType == xml.ErrorToken { + break + } else if t.TokenType == xml.EndTagToken || t.TokenType == xml.StartTagCloseVoidToken { + if level == 0 { + break + } + level-- + } else if t.TokenType == xml.StartTagToken { + level++ + } + } +} diff --git a/vendor/github.com/tdewolff/minify/v2/svg/table.go b/vendor/github.com/tdewolff/minify/v2/svg/table.go new file mode 100644 index 0000000000000..524aee6135e40 --- /dev/null +++ b/vendor/github.com/tdewolff/minify/v2/svg/table.go @@ -0,0 +1,84 @@ +package svg + +import "github.com/tdewolff/parse/v2/svg" + +var colorAttrMap = map[svg.Hash]bool{ + svg.Color: true, + svg.Fill: true, + svg.Stroke: true, + svg.Stop_Color: true, + svg.Flood_Color: true, + svg.Lighting_Color: true, +} + +// var styleAttrMap = map[svg.Hash]bool{ +// svg.Font: true, +// svg.Font_Family: true, +// svg.Font_Size: true, +// svg.Font_Size_Adjust: true, +// svg.Font_Stretch: true, +// svg.Font_Style: true, +// svg.Font_Variant: true, +// svg.Font_Weight: true, +// svg.Direction: true, +// svg.Letter_Spacing: true, +// svg.Text_Decoration: true, +// svg.Unicode_Bidi: true, +// svg.White_Space: true, +// svg.Word_Spacing: true, +// svg.Clip: true, +// svg.Color: true, +// svg.Cursor: true, +// svg.Display: true, +// svg.Overflow: true, +// svg.Visibility: true, +// svg.Clip_Path: true, +// svg.Clip_Rule: true, +// svg.Mask: true, +// svg.Opacity: true, +// svg.Enable_Background: true, +// svg.Filter: true, +// svg.Flood_Color: true, +// svg.Flood_Opacity: true, +// svg.Lighting_Color: true, +// svg.Solid_Color: true, +// svg.Solid_Opacity: true, +// svg.Stop_Color: true, +// svg.Stop_Opacity: true, +// svg.Pointer_Events: true, +// svg.Buffered_Rendering: true, +// svg.Color_Interpolation: true, +// svg.Color_Interpolation_Filters: true, +// svg.Color_Profile: true, +// svg.Color_Rendering: true, +// svg.Fill: true, +// svg.Fill_Opacity: true, +// svg.Fill_Rule: true, +// svg.Image_Rendering: true, +// svg.Marker: true, +// svg.Marker_End: true, +// svg.Marker_Mid: true, +// svg.Marker_Start: true, +// svg.Shape_Rendering: true, +// svg.Stroke: true, +// svg.Stroke_Dasharray: true, +// svg.Stroke_Dashoffset: true, +// svg.Stroke_Linecap: true, +// svg.Stroke_Linejoin: true, +// svg.Stroke_Miterlimit: true, +// svg.Stroke_Opacity: true, +// svg.Stroke_Width: true, +// svg.Paint_Order: true, +// svg.Vector_Effect: true, +// svg.Viewport_Fill: true, +// svg.Viewport_Fill_Opacity: true, +// svg.Text_Rendering: true, +// svg.Alignment_Baseline: true, +// svg.Baseline_Shift: true, +// svg.Dominant_Baseline: true, +// svg.Glyph_Orientation_Horizontal: true, +// svg.Glyph_Orientation_Vertical: true, +// svg.Kerning: true, +// svg.Text_Anchor: true, +// svg.Writing_Mode: true, +// } diff --git a/vendor/github.com/tdewolff/parse/v2/.travis.yml b/vendor/github.com/tdewolff/parse/v2/.travis.yml new file mode 100644 index 0000000000000..17287237792e9 --- /dev/null +++ b/vendor/github.com/tdewolff/parse/v2/.travis.yml @@ -0,0 +1,10 @@ +language: go +go: + - 1.12.x +env: + - GO111MODULE=on +before_install: + - go get github.com/mattn/goveralls +script: + - go test -covermode=count -coverprofile=profile.cov . ./buffer ./css ./html ./js ./json ./strconv ./svg ./xml + - goveralls -coverprofile=profile.cov -service travis-ci diff --git a/vendor/github.com/tdewolff/parse/v2/LICENSE.md b/vendor/github.com/tdewolff/parse/v2/LICENSE.md new file mode 100644 index 0000000000000..41677de41ec1d --- /dev/null +++ b/vendor/github.com/tdewolff/parse/v2/LICENSE.md @@ -0,0 +1,22 @@ +Copyright (c) 2015 Taco de Wolff + + Permission is hereby granted, free of charge, to any person + obtaining a copy of this software and associated documentation + files (the "Software"), to deal in the Software without + restriction, including without limitation the rights to use, + copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following + conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/vendor/github.com/tdewolff/parse/v2/README.md b/vendor/github.com/tdewolff/parse/v2/README.md new file mode 100644 index 0000000000000..865ae57ddefda --- /dev/null +++ b/vendor/github.com/tdewolff/parse/v2/README.md @@ -0,0 +1,70 @@ +# Parse [![Build Status](https://travis-ci.org/tdewolff/parse.svg?branch=master)](https://travis-ci.org/tdewolff/parse) [![GoDoc](http://godoc.org/github.com/tdewolff/parse?status.svg)](http://godoc.org/github.com/tdewolff/parse) [![Coverage Status](https://coveralls.io/repos/github/tdewolff/parse/badge.svg?branch=master)](https://coveralls.io/github/tdewolff/parse?branch=master) + +***BE AWARE: YOU NEED GO 1.9.7+, 1.10.3+, 1.11 to run the latest release!!!*** + +If you cannot upgrade Go, please pin to **parse@v2.3.4** + +--- + +This package contains several lexers and parsers written in [Go][1]. All subpackages are built to be streaming, high performance and to be in accordance with the official (latest) specifications. + +The lexers are implemented using `buffer.Lexer` in https://github.com/tdewolff/parse/buffer and the parsers work on top of the lexers. Some subpackages have hashes defined (using [Hasher](https://github.com/tdewolff/hasher)) that speed up common byte-slice comparisons. + +## Buffer +### Reader +Reader is a wrapper around a `[]byte` that implements the `io.Reader` interface. It is comparable to `bytes.Reader` but has slightly different semantics (and a slightly smaller memory footprint). + +### Writer +Writer is a buffer that implements the `io.Writer` interface and expands the buffer as needed. The reset functionality allows for better memory reuse. After calling `Reset`, it will overwrite the current buffer and thus reduce allocations. + +### Lexer +Lexer is a read buffer specifically designed for building lexers. It keeps track of two positions: a start and end position. The start position is the beginning of the current token being parsed, the end position is being moved forward until a valid token is found. Calling `Shift` will collapse the positions to the end and return the parsed `[]byte`. + +Moving the end position can go through `Move(int)` which also accepts negative integers. One can also use `Pos() int` to try and parse a token, and if it fails rewind with `Rewind(int)`, passing the previously saved position. + +`Peek(int) byte` will peek forward (relative to the end position) and return the byte at that location. `PeekRune(int) (rune, int)` returns UTF-8 runes and its length at the given **byte** position. Upon an error `Peek` will return `0`, the **user must peek at every character** and not skip any, otherwise it may skip a `0` and panic on out-of-bounds indexing. + +`Lexeme() []byte` will return the currently selected bytes, `Skip()` will collapse the selection. `Shift() []byte` is a combination of `Lexeme() []byte` and `Skip()`. + +When the passed `io.Reader` returned an error, `Err() error` will return that error even if not at the end of the buffer. + +### StreamLexer +StreamLexer behaves like Lexer but uses a buffer pool to read in chunks from `io.Reader`, retaining old buffers in memory that are still in use, and re-using old buffers otherwise. Calling `Free(n int)` frees up `n` bytes from the internal buffer(s). It holds an array of buffers to accommodate for keeping everything in-memory. Calling `ShiftLen() int` returns the number of bytes that have been shifted since the previous call to `ShiftLen`, which can be used to specify how many bytes need to be freed up from the buffer. If you don't need to keep returned byte slices around, call `Free(ShiftLen())` after every `Shift` call. + +## Strconv +This package contains string conversion function much like the standard library's `strconv` package, but it is specifically tailored for the performance needs within the `minify` package. + +For example, the floating-point to string conversion function is approximately twice as fast as the standard library, but it is not as precise. + +## CSS +This package is a CSS3 lexer and parser. Both follow the specification at [CSS Syntax Module Level 3](http://www.w3.org/TR/css-syntax-3/). The lexer takes an io.Reader and converts it into tokens until the EOF. The parser returns a parse tree of the full io.Reader input stream, but the low-level `Next` function can be used for stream parsing to returns grammar units until the EOF. + +[See README here](https://github.com/tdewolff/parse/tree/master/css). + +## HTML +This package is an HTML5 lexer. It follows the specification at [The HTML syntax](http://www.w3.org/TR/html5/syntax.html). The lexer takes an io.Reader and converts it into tokens until the EOF. + +[See README here](https://github.com/tdewolff/parse/tree/master/html). + +## JS +This package is a JS lexer (ECMA-262, edition 6.0). It follows the specification at [ECMAScript Language Specification](http://www.ecma-international.org/ecma-262/6.0/). The lexer takes an io.Reader and converts it into tokens until the EOF. + +[See README here](https://github.com/tdewolff/parse/tree/master/js). + +## JSON +This package is a JSON parser (ECMA-404). It follows the specification at [JSON](http://json.org/). The parser takes an io.Reader and converts it into tokens until the EOF. + +[See README here](https://github.com/tdewolff/parse/tree/master/json). + +## SVG +This package contains common hashes for SVG1.1 tags and attributes. + +## XML +This package is an XML1.0 lexer. It follows the specification at [Extensible Markup Language (XML) 1.0 (Fifth Edition)](http://www.w3.org/TR/xml/). The lexer takes an io.Reader and converts it into tokens until the EOF. + +[See README here](https://github.com/tdewolff/parse/tree/master/xml). + +## License +Released under the [MIT license](LICENSE.md). + +[1]: http://golang.org/ "Go Language" diff --git a/vendor/github.com/tdewolff/parse/v2/buffer/buffer.go b/vendor/github.com/tdewolff/parse/v2/buffer/buffer.go new file mode 100644 index 0000000000000..d9e14d14800e2 --- /dev/null +++ b/vendor/github.com/tdewolff/parse/v2/buffer/buffer.go @@ -0,0 +1,15 @@ +/* +Package buffer contains buffer and wrapper types for byte slices. It is useful for writing lexers or other high-performance byte slice handling. + +The `Reader` and `Writer` types implement the `io.Reader` and `io.Writer` respectively and provide a thinner and faster interface than `bytes.Buffer`. +The `Lexer` type is useful for building lexers because it keeps track of the start and end position of a byte selection, and shifts the bytes whenever a valid token is found. +The `StreamLexer` does the same, but keeps a buffer pool so that it reads a limited amount at a time, allowing to parse from streaming sources. +*/ +package buffer + +// defaultBufSize specifies the default initial length of internal buffers. +var defaultBufSize = 4096 + +// MinBuf specifies the default initial length of internal buffers. +// Solely here to support old versions of parse. +var MinBuf = defaultBufSize diff --git a/vendor/github.com/tdewolff/parse/v2/buffer/lexer.go b/vendor/github.com/tdewolff/parse/v2/buffer/lexer.go new file mode 100644 index 0000000000000..d2909d0f5f2a9 --- /dev/null +++ b/vendor/github.com/tdewolff/parse/v2/buffer/lexer.go @@ -0,0 +1,158 @@ +package buffer + +import ( + "io" + "io/ioutil" +) + +var nullBuffer = []byte{0} + +// Lexer is a buffered reader that allows peeking forward and shifting, taking an io.Reader. +// It keeps data in-memory until Free, taking a byte length, is called to move beyond the data. +type Lexer struct { + buf []byte + pos int // index in buf + start int // index in buf + err error + + restore func() +} + +// NewLexerBytes returns a new Lexer for a given io.Reader, and uses ioutil.ReadAll to read it into a byte slice. +// If the io.Reader implements Bytes, that is used instead. +// It will append a NULL at the end of the buffer. +func NewLexer(r io.Reader) *Lexer { + var b []byte + if r != nil { + if buffer, ok := r.(interface { + Bytes() []byte + }); ok { + b = buffer.Bytes() + } else { + var err error + b, err = ioutil.ReadAll(r) + if err != nil { + return &Lexer{ + buf: []byte{0}, + err: err, + } + } + } + } + return NewLexerBytes(b) +} + +// NewLexerBytes returns a new Lexer for a given byte slice, and appends NULL at the end. +// To avoid reallocation, make sure the capacity has room for one more byte. +func NewLexerBytes(b []byte) *Lexer { + z := &Lexer{ + buf: b, + } + + n := len(b) + if n == 0 { + z.buf = nullBuffer + } else if b[n-1] != 0 { + // Append NULL to buffer, but try to avoid reallocation + if cap(b) > n { + // Overwrite next byte but restore when done + b = b[:n+1] + c := b[n] + b[n] = 0 + + z.buf = b + z.restore = func() { + b[n] = c + } + } else { + z.buf = append(b, 0) + } + } + return z +} + +// Restore restores the replaced byte past the end of the buffer by NULL. +func (z *Lexer) Restore() { + if z.restore != nil { + z.restore() + z.restore = nil + } +} + +// Err returns the error returned from io.Reader or io.EOF when the end has been reached. +func (z *Lexer) Err() error { + return z.PeekErr(0) +} + +// PeekErr returns the error at position pos. When pos is zero, this is the same as calling Err(). +func (z *Lexer) PeekErr(pos int) error { + if z.err != nil { + return z.err + } else if z.pos+pos >= len(z.buf)-1 { + return io.EOF + } + return nil +} + +// Peek returns the ith byte relative to the end position. +// Peek returns 0 when an error has occurred, Err returns the error. +func (z *Lexer) Peek(pos int) byte { + pos += z.pos + return z.buf[pos] +} + +// PeekRune returns the rune and rune length of the ith byte relative to the end position. +func (z *Lexer) PeekRune(pos int) (rune, int) { + // from unicode/utf8 + c := z.Peek(pos) + if c < 0xC0 || z.Peek(pos+1) == 0 { + return rune(c), 1 + } else if c < 0xE0 || z.Peek(pos+2) == 0 { + return rune(c&0x1F)<<6 | rune(z.Peek(pos+1)&0x3F), 2 + } else if c < 0xF0 || z.Peek(pos+3) == 0 { + return rune(c&0x0F)<<12 | rune(z.Peek(pos+1)&0x3F)<<6 | rune(z.Peek(pos+2)&0x3F), 3 + } + return rune(c&0x07)<<18 | rune(z.Peek(pos+1)&0x3F)<<12 | rune(z.Peek(pos+2)&0x3F)<<6 | rune(z.Peek(pos+3)&0x3F), 4 +} + +// Move advances the position. +func (z *Lexer) Move(n int) { + z.pos += n +} + +// Pos returns a mark to which can be rewinded. +func (z *Lexer) Pos() int { + return z.pos - z.start +} + +// Rewind rewinds the position to the given position. +func (z *Lexer) Rewind(pos int) { + z.pos = z.start + pos +} + +// Lexeme returns the bytes of the current selection. +func (z *Lexer) Lexeme() []byte { + return z.buf[z.start:z.pos] +} + +// Skip collapses the position to the end of the selection. +func (z *Lexer) Skip() { + z.start = z.pos +} + +// Shift returns the bytes of the current selection and collapses the position to the end of the selection. +func (z *Lexer) Shift() []byte { + b := z.buf[z.start:z.pos] + z.start = z.pos + return b +} + +// Offset returns the character position in the buffer. +func (z *Lexer) Offset() int { + return z.pos +} + +// Bytes returns the underlying buffer. +func (z *Lexer) Bytes() []byte { + return z.buf[:len(z.buf)-1] +} diff --git a/vendor/github.com/tdewolff/parse/v2/buffer/reader.go b/vendor/github.com/tdewolff/parse/v2/buffer/reader.go new file mode 100644 index 0000000000000..9926eef66efc2 --- /dev/null +++ b/vendor/github.com/tdewolff/parse/v2/buffer/reader.go @@ -0,0 +1,44 @@ +package buffer + +import "io" + +// Reader implements an io.Reader over a byte slice. +type Reader struct { + buf []byte + pos int +} + +// NewReader returns a new Reader for a given byte slice. +func NewReader(buf []byte) *Reader { + return &Reader{ + buf: buf, + } +} + +// Read reads bytes into the given byte slice and returns the number of bytes read and an error if occurred. +func (r *Reader) Read(b []byte) (n int, err error) { + if len(b) == 0 { + return 0, nil + } + if r.pos >= len(r.buf) { + return 0, io.EOF + } + n = copy(b, r.buf[r.pos:]) + r.pos += n + return +} + +// Bytes returns the underlying byte slice. +func (r *Reader) Bytes() []byte { + return r.buf +} + +// Reset resets the position of the read pointer to the beginning of the underlying byte slice. +func (r *Reader) Reset() { + r.pos = 0 +} + +// Len returns the length of the buffer. +func (r *Reader) Len() int { + return len(r.buf) +} diff --git a/vendor/github.com/tdewolff/parse/v2/buffer/streamlexer.go b/vendor/github.com/tdewolff/parse/v2/buffer/streamlexer.go new file mode 100644 index 0000000000000..5ea2dd58d5e72 --- /dev/null +++ b/vendor/github.com/tdewolff/parse/v2/buffer/streamlexer.go @@ -0,0 +1,223 @@ +package buffer + +import ( + "io" +) + +type block struct { + buf []byte + next int // index in pool plus one + active bool +} + +type bufferPool struct { + pool []block + head int // index in pool plus one + tail int // index in pool plus one + + pos int // byte pos in tail +} + +func (z *bufferPool) swap(oldBuf []byte, size int) []byte { + // find new buffer that can be reused + swap := -1 + for i := 0; i < len(z.pool); i++ { + if !z.pool[i].active && size <= cap(z.pool[i].buf) { + swap = i + break + } + } + if swap == -1 { // no free buffer found for reuse + if z.tail == 0 && z.pos >= len(oldBuf) && size <= cap(oldBuf) { // but we can reuse the current buffer! + z.pos -= len(oldBuf) + return oldBuf[:0] + } + // allocate new + z.pool = append(z.pool, block{make([]byte, 0, size), 0, true}) + swap = len(z.pool) - 1 + } + + newBuf := z.pool[swap].buf + + // put current buffer into pool + z.pool[swap] = block{oldBuf, 0, true} + if z.head != 0 { + z.pool[z.head-1].next = swap + 1 + } + z.head = swap + 1 + if z.tail == 0 { + z.tail = swap + 1 + } + + return newBuf[:0] +} + +func (z *bufferPool) free(n int) { + z.pos += n + // move the tail over to next buffers + for z.tail != 0 && z.pos >= len(z.pool[z.tail-1].buf) { + z.pos -= len(z.pool[z.tail-1].buf) + newTail := z.pool[z.tail-1].next + z.pool[z.tail-1].active = false // after this, any thread may pick up the inactive buffer, so it can't be used anymore + z.tail = newTail + } + if z.tail == 0 { + z.head = 0 + } +} + +// StreamLexer is a buffered reader that allows peeking forward and shifting, taking an io.Reader. +// It keeps data in-memory until Free, taking a byte length, is called to move beyond the data. +type StreamLexer struct { + r io.Reader + err error + + pool bufferPool + + buf []byte + start int // index in buf + pos int // index in buf + prevStart int + + free int +} + +// NewStreamLexer returns a new StreamLexer for a given io.Reader with a 4kB estimated buffer size. +// If the io.Reader implements Bytes, that buffer is used instead. +func NewStreamLexer(r io.Reader) *StreamLexer { + return NewStreamLexerSize(r, defaultBufSize) +} + +// NewStreamLexerSize returns a new StreamLexer for a given io.Reader and estimated required buffer size. +// If the io.Reader implements Bytes, that buffer is used instead. +func NewStreamLexerSize(r io.Reader, size int) *StreamLexer { + // if reader has the bytes in memory already, use that instead + if buffer, ok := r.(interface { + Bytes() []byte + }); ok { + return &StreamLexer{ + err: io.EOF, + buf: buffer.Bytes(), + } + } + return &StreamLexer{ + r: r, + buf: make([]byte, 0, size), + } +} + +func (z *StreamLexer) read(pos int) byte { + if z.err != nil { + return 0 + } + + // free unused bytes + z.pool.free(z.free) + z.free = 0 + + // get new buffer + c := cap(z.buf) + p := pos - z.start + 1 + if 2*p > c { // if the token is larger than half the buffer, increase buffer size + c = 2*c + p + } + d := len(z.buf) - z.start + buf := z.pool.swap(z.buf[:z.start], c) + copy(buf[:d], z.buf[z.start:]) // copy the left-overs (unfinished token) from the old buffer + + // read in new data for the rest of the buffer + var n int + for pos-z.start >= d && z.err == nil { + n, z.err = z.r.Read(buf[d:cap(buf)]) + d += n + } + pos -= z.start + z.pos -= z.start + z.start, z.buf = 0, buf[:d] + if pos >= d { + return 0 + } + return z.buf[pos] +} + +// Err returns the error returned from io.Reader. It may still return valid bytes for a while though. +func (z *StreamLexer) Err() error { + if z.err == io.EOF && z.pos < len(z.buf) { + return nil + } + return z.err +} + +// Free frees up bytes of length n from previously shifted tokens. +// Each call to Shift should at one point be followed by a call to Free with a length returned by ShiftLen. +func (z *StreamLexer) Free(n int) { + z.free += n +} + +// Peek returns the ith byte relative to the end position and possibly does an allocation. +// Peek returns zero when an error has occurred, Err returns the error. +// TODO: inline function +func (z *StreamLexer) Peek(pos int) byte { + pos += z.pos + if uint(pos) < uint(len(z.buf)) { // uint for BCE + return z.buf[pos] + } + return z.read(pos) +} + +// PeekRune returns the rune and rune length of the ith byte relative to the end position. +func (z *StreamLexer) PeekRune(pos int) (rune, int) { + // from unicode/utf8 + c := z.Peek(pos) + if c < 0xC0 { + return rune(c), 1 + } else if c < 0xE0 { + return rune(c&0x1F)<<6 | rune(z.Peek(pos+1)&0x3F), 2 + } else if c < 0xF0 { + return rune(c&0x0F)<<12 | rune(z.Peek(pos+1)&0x3F)<<6 | rune(z.Peek(pos+2)&0x3F), 3 + } + return rune(c&0x07)<<18 | rune(z.Peek(pos+1)&0x3F)<<12 | rune(z.Peek(pos+2)&0x3F)<<6 | rune(z.Peek(pos+3)&0x3F), 4 +} + +// Move advances the position. +func (z *StreamLexer) Move(n int) { + z.pos += n +} + +// Pos returns a mark to which can be rewinded. +func (z *StreamLexer) Pos() int { + return z.pos - z.start +} + +// Rewind rewinds the position to the given position. +func (z *StreamLexer) Rewind(pos int) { + z.pos = z.start + pos +} + +// Lexeme returns the bytes of the current selection. +func (z *StreamLexer) Lexeme() []byte { + return z.buf[z.start:z.pos] +} + +// Skip collapses the position to the end of the selection. +func (z *StreamLexer) Skip() { + z.start = z.pos +} + +// Shift returns the bytes of the current selection and collapses the position to the end of the selection. +// It also returns the number of bytes we moved since the last call to Shift. This can be used in calls to Free. +func (z *StreamLexer) Shift() []byte { + if z.pos > len(z.buf) { // make sure we peeked at least as much as we shift + z.read(z.pos - 1) + } + b := z.buf[z.start:z.pos] + z.start = z.pos + return b +} + +// ShiftLen returns the number of bytes moved since the last call to ShiftLen. This can be used in calls to Free because it takes into account multiple Shifts or Skips. +func (z *StreamLexer) ShiftLen() int { + n := z.start - z.prevStart + z.prevStart = z.start + return n +} diff --git a/vendor/github.com/tdewolff/parse/v2/buffer/writer.go b/vendor/github.com/tdewolff/parse/v2/buffer/writer.go new file mode 100644 index 0000000000000..b3c9990d904a9 --- /dev/null +++ b/vendor/github.com/tdewolff/parse/v2/buffer/writer.go @@ -0,0 +1,41 @@ +package buffer + +// Writer implements an io.Writer over a byte slice. +type Writer struct { + buf []byte +} + +// NewWriter returns a new Writer for a given byte slice. +func NewWriter(buf []byte) *Writer { + return &Writer{ + buf: buf, + } +} + +// Write writes bytes from the given byte slice and returns the number of bytes written and an error if occurred. When err != nil, n == 0. +func (w *Writer) Write(b []byte) (int, error) { + n := len(b) + end := len(w.buf) + if end+n > cap(w.buf) { + buf := make([]byte, end, 2*cap(w.buf)+n) + copy(buf, w.buf) + w.buf = buf + } + w.buf = w.buf[:end+n] + return copy(w.buf[end:], b), nil +} + +// Len returns the length of the underlying byte slice. +func (w *Writer) Len() int { + return len(w.buf) +} + +// Bytes returns the underlying byte slice. +func (w *Writer) Bytes() []byte { + return w.buf +} + +// Reset empties and reuses the current buffer. Subsequent writes will overwrite the buffer, so any reference to the underlying slice is invalidated after this call. +func (w *Writer) Reset() { + w.buf = w.buf[:0] +} diff --git a/vendor/github.com/tdewolff/parse/v2/common.go b/vendor/github.com/tdewolff/parse/v2/common.go new file mode 100644 index 0000000000000..4c4aee9b899a0 --- /dev/null +++ b/vendor/github.com/tdewolff/parse/v2/common.go @@ -0,0 +1,231 @@ +// Package parse contains a collection of parsers for various formats in its subpackages. +package parse + +import ( + "bytes" + "encoding/base64" + "errors" + "net/url" +) + +// ErrBadDataURI is returned by DataURI when the byte slice does not start with 'data:' or is too short. +var ErrBadDataURI = errors.New("not a data URI") + +// Number returns the number of bytes that parse as a number of the regex format (+|-)?([0-9]+(\.[0-9]+)?|\.[0-9]+)((e|E)(+|-)?[0-9]+)?. +func Number(b []byte) int { + if len(b) == 0 { + return 0 + } + i := 0 + if b[i] == '+' || b[i] == '-' { + i++ + if i >= len(b) { + return 0 + } + } + firstDigit := (b[i] >= '0' && b[i] <= '9') + if firstDigit { + i++ + for i < len(b) && b[i] >= '0' && b[i] <= '9' { + i++ + } + } + if i < len(b) && b[i] == '.' { + i++ + if i < len(b) && b[i] >= '0' && b[i] <= '9' { + i++ + for i < len(b) && b[i] >= '0' && b[i] <= '9' { + i++ + } + } else if firstDigit { + // . could belong to the next token + i-- + return i + } else { + return 0 + } + } else if !firstDigit { + return 0 + } + iOld := i + if i < len(b) && (b[i] == 'e' || b[i] == 'E') { + i++ + if i < len(b) && (b[i] == '+' || b[i] == '-') { + i++ + } + if i >= len(b) || b[i] < '0' || b[i] > '9' { + // e could belong to next token + return iOld + } + for i < len(b) && b[i] >= '0' && b[i] <= '9' { + i++ + } + } + return i +} + +// Dimension parses a byte-slice and returns the length of the number and its unit. +func Dimension(b []byte) (int, int) { + num := Number(b) + if num == 0 || num == len(b) { + return num, 0 + } else if b[num] == '%' { + return num, 1 + } else if b[num] >= 'a' && b[num] <= 'z' || b[num] >= 'A' && b[num] <= 'Z' { + i := num + 1 + for i < len(b) && (b[i] >= 'a' && b[i] <= 'z' || b[i] >= 'A' && b[i] <= 'Z') { + i++ + } + return num, i - num + } + return num, 0 +} + +// Mediatype parses a given mediatype and splits the mimetype from the parameters. +// It works similar to mime.ParseMediaType but is faster. +func Mediatype(b []byte) ([]byte, map[string]string) { + i := 0 + for i < len(b) && b[i] == ' ' { + i++ + } + b = b[i:] + n := len(b) + mimetype := b + var params map[string]string + for i := 3; i < n; i++ { // mimetype is at least three characters long + if b[i] == ';' || b[i] == ' ' { + mimetype = b[:i] + if b[i] == ' ' { + i++ + for i < n && b[i] == ' ' { + i++ + } + if i < n && b[i] != ';' { + break + } + } + params = map[string]string{} + s := string(b) + PARAM: + i++ + for i < n && s[i] == ' ' { + i++ + } + start := i + for i < n && s[i] != '=' && s[i] != ';' && s[i] != ' ' { + i++ + } + key := s[start:i] + for i < n && s[i] == ' ' { + i++ + } + if i < n && s[i] == '=' { + i++ + for i < n && s[i] == ' ' { + i++ + } + start = i + for i < n && s[i] != ';' && s[i] != ' ' { + i++ + } + } else { + start = i + } + params[key] = s[start:i] + for i < n && s[i] == ' ' { + i++ + } + if i < n && s[i] == ';' { + goto PARAM + } + break + } + } + return mimetype, params +} + +// DataURI parses the given data URI and returns the mediatype, data and ok. +func DataURI(dataURI []byte) ([]byte, []byte, error) { + if len(dataURI) > 5 && bytes.Equal(dataURI[:5], []byte("data:")) { + dataURI = dataURI[5:] + inBase64 := false + var mediatype []byte + i := 0 + for j := 0; j < len(dataURI); j++ { + c := dataURI[j] + if c == '=' || c == ';' || c == ',' { + if c != '=' && bytes.Equal(TrimWhitespace(dataURI[i:j]), []byte("base64")) { + if len(mediatype) > 0 { + mediatype = mediatype[:len(mediatype)-1] + } + inBase64 = true + i = j + } else if c != ',' { + mediatype = append(append(mediatype, TrimWhitespace(dataURI[i:j])...), c) + i = j + 1 + } else { + mediatype = append(mediatype, TrimWhitespace(dataURI[i:j])...) + } + if c == ',' { + if len(mediatype) == 0 || mediatype[0] == ';' { + mediatype = []byte("text/plain") + } + data := dataURI[j+1:] + if inBase64 { + decoded := make([]byte, base64.StdEncoding.DecodedLen(len(data))) + n, err := base64.StdEncoding.Decode(decoded, data) + if err != nil { + return nil, nil, err + } + data = decoded[:n] + } else if unescaped, err := url.QueryUnescape(string(data)); err == nil { + data = []byte(unescaped) + } + return mediatype, data, nil + } + } + } + } + return nil, nil, ErrBadDataURI +} + +// QuoteEntity parses the given byte slice and returns the quote that got matched (' or ") and its entity length. +func QuoteEntity(b []byte) (quote byte, n int) { + if len(b) < 5 || b[0] != '&' { + return 0, 0 + } + if b[1] == '#' { + if b[2] == 'x' { + i := 3 + for i < len(b) && b[i] == '0' { + i++ + } + if i+2 < len(b) && b[i] == '2' && b[i+2] == ';' { + if b[i+1] == '2' { + return '"', i + 3 // " + } else if b[i+1] == '7' { + return '\'', i + 3 // ' + } + } + } else { + i := 2 + for i < len(b) && b[i] == '0' { + i++ + } + if i+2 < len(b) && b[i] == '3' && b[i+2] == ';' { + if b[i+1] == '4' { + return '"', i + 3 // " + } else if b[i+1] == '9' { + return '\'', i + 3 // ' + } + } + } + } else if len(b) >= 6 && b[5] == ';' { + if EqualFold(b[1:5], []byte{'q', 'u', 'o', 't'}) { + return '"', 6 // " + } else if EqualFold(b[1:5], []byte{'a', 'p', 'o', 's'}) { + return '\'', 6 // ' + } + } + return 0, 0 +} diff --git a/vendor/github.com/tdewolff/parse/v2/css/README.md b/vendor/github.com/tdewolff/parse/v2/css/README.md new file mode 100644 index 0000000000000..11a70cb510fd2 --- /dev/null +++ b/vendor/github.com/tdewolff/parse/v2/css/README.md @@ -0,0 +1,171 @@ +# CSS [![GoDoc](http://godoc.org/github.com/tdewolff/parse/css?status.svg)](http://godoc.org/github.com/tdewolff/parse/css) + +This package is a CSS3 lexer and parser written in [Go][1]. Both follow the specification at [CSS Syntax Module Level 3](http://www.w3.org/TR/css-syntax-3/). The lexer takes an io.Reader and converts it into tokens until the EOF. The parser returns a parse tree of the full io.Reader input stream, but the low-level `Next` function can be used for stream parsing to returns grammar units until the EOF. + +## Installation +Run the following command + + go get -u github.com/tdewolff/parse/v2/css + +or add the following import and run project with `go get` + + import "github.com/tdewolff/parse/v2/css" + +## Lexer +### Usage +The following initializes a new Lexer with io.Reader `r`: +``` go +l := css.NewLexer(r) +``` + +To tokenize until EOF an error, use: +``` go +for { + tt, text := l.Next() + switch tt { + case css.ErrorToken: + // error or EOF set in l.Err() + return + // ... + } +} +``` + +All tokens (see [CSS Syntax Module Level 3](http://www.w3.org/TR/css3-syntax/)): +``` go +ErrorToken // non-official token, returned when errors occur +IdentToken +FunctionToken // rgb( rgba( ... +AtKeywordToken // @abc +HashToken // #abc +StringToken +BadStringToken +UrlToken // url( +BadUrlToken +DelimToken // any unmatched character +NumberToken // 5 +PercentageToken // 5% +DimensionToken // 5em +UnicodeRangeToken +IncludeMatchToken // ~= +DashMatchToken // |= +PrefixMatchToken // ^= +SuffixMatchToken // $= +SubstringMatchToken // *= +ColumnToken // || +WhitespaceToken +CDOToken // +ColonToken +SemicolonToken +CommaToken +BracketToken // ( ) [ ] { }, all bracket tokens use this, Data() can distinguish between the brackets +CommentToken // non-official token +``` + +### Examples +``` go +package main + +import ( + "os" + + "github.com/tdewolff/parse/v2/css" +) + +// Tokenize CSS3 from stdin. +func main() { + l := css.NewLexer(os.Stdin) + for { + tt, text := l.Next() + switch tt { + case css.ErrorToken: + if l.Err() != io.EOF { + fmt.Println("Error on line", l.Line(), ":", l.Err()) + } + return + case css.IdentToken: + fmt.Println("Identifier", string(text)) + case css.NumberToken: + fmt.Println("Number", string(text)) + // ... + } + } +} +``` + +## Parser +### Usage +The following creates a new Parser. +``` go +// true because this is the content of an inline style attribute +p := css.NewParser(bytes.NewBufferString("color: red;"), true) +``` + +To iterate over the stylesheet, use: +``` go +for { + gt, _, data := p.Next() + if gt == css.ErrorGrammar { + break + } + // ... +} +``` + +All grammar units returned by `Next`: +``` go +ErrorGrammar +AtRuleGrammar +EndAtRuleGrammar +RulesetGrammar +EndRulesetGrammar +DeclarationGrammar +TokenGrammar +``` + +### Examples +``` go +package main + +import ( + "bytes" + "fmt" + + "github.com/tdewolff/parse/v2/css" +) + +func main() { + // true because this is the content of an inline style attribute + p := css.NewParser(bytes.NewBufferString("color: red;"), true) + out := "" + for { + gt, _, data := p.Next() + if gt == css.ErrorGrammar { + break + } else if gt == css.AtRuleGrammar || gt == css.BeginAtRuleGrammar || gt == css.BeginRulesetGrammar || gt == css.DeclarationGrammar { + out += string(data) + if gt == css.DeclarationGrammar { + out += ":" + } + for _, val := range p.Values() { + out += string(val.Data) + } + if gt == css.BeginAtRuleGrammar || gt == css.BeginRulesetGrammar { + out += "{" + } else if gt == css.AtRuleGrammar || gt == css.DeclarationGrammar { + out += ";" + } + } else { + out += string(data) + } + } + fmt.Println(out) +} + +``` + +## License +Released under the [MIT license](https://github.com/tdewolff/parse/blob/master/LICENSE.md). + +[1]: http://golang.org/ "Go Language" diff --git a/vendor/github.com/tdewolff/parse/v2/css/hash.go b/vendor/github.com/tdewolff/parse/v2/css/hash.go new file mode 100644 index 0000000000000..e654787f21115 --- /dev/null +++ b/vendor/github.com/tdewolff/parse/v2/css/hash.go @@ -0,0 +1,757 @@ +package css + +// generated by hasher -type=Hash -file=hash.go; DO NOT EDIT, except for adding more constants to the list and rerun go generate + +// uses github.com/tdewolff/hasher +//go:generate hasher -type=Hash -file=hash.go + +// Hash defines perfect hashes for a predefined list of strings +type Hash uint32 + +// Unique hash definitions to be used instead of strings +const ( + Ms_Filter Hash = 0xa // -ms-filter + Accelerator Hash = 0x4b30b // accelerator + Aliceblue Hash = 0x5b109 // aliceblue + Alpha Hash = 0x63605 // alpha + Antiquewhite Hash = 0x4900c // antiquewhite + Aquamarine Hash = 0x7a70a // aquamarine + Azimuth Hash = 0x63a07 // azimuth + Background Hash = 0x2d0a // background + Background_Attachment Hash = 0x4fb15 // background-attachment + Background_Color Hash = 0x17c10 // background-color + Background_Image Hash = 0x61510 // background-image + Background_Position Hash = 0x2d13 // background-position + Background_Position_X Hash = 0x8ac15 // background-position-x + Background_Position_Y Hash = 0x2d15 // background-position-y + Background_Repeat Hash = 0x4211 // background-repeat + Background_Size Hash = 0x660f // background-size + Behavior Hash = 0x7508 // behavior + Black Hash = 0xa505 // black + Blanchedalmond Hash = 0xaa0e // blanchedalmond + Blueviolet Hash = 0x5b60a // blueviolet + Bold Hash = 0xbf04 // bold + Border Hash = 0xca06 // border + Border_Bottom Hash = 0xca0d // border-bottom + Border_Bottom_Color Hash = 0xca13 // border-bottom-color + Border_Bottom_Style Hash = 0xe913 // border-bottom-style + Border_Bottom_Width Hash = 0x11013 // border-bottom-width + Border_Box Hash = 0x1310a // border-box + Border_Collapse Hash = 0x1620f // border-collapse + Border_Color Hash = 0x18c0c // border-color + Border_Left Hash = 0x1980b // border-left + Border_Left_Color Hash = 0x19811 // border-left-color + Border_Left_Style Hash = 0x1a911 // border-left-style + Border_Left_Width Hash = 0x1ba11 // border-left-width + Border_Right Hash = 0x1cb0c // border-right + Border_Right_Color Hash = 0x1cb12 // border-right-color + Border_Right_Style Hash = 0x1dd12 // border-right-style + Border_Right_Width Hash = 0x1ef12 // border-right-width + Border_Spacing Hash = 0x2010e // border-spacing + Border_Style Hash = 0x20f0c // border-style + Border_Top Hash = 0x21b0a // border-top + Border_Top_Color Hash = 0x21b10 // border-top-color + Border_Top_Style Hash = 0x22b10 // border-top-style + Border_Top_Width Hash = 0x23b10 // border-top-width + Border_Width Hash = 0x24b0c // border-width + Bottom Hash = 0xd106 // bottom + Box_Shadow Hash = 0x1380a // box-shadow + Burlywood Hash = 0x25709 // burlywood + Cadetblue Hash = 0x75509 // cadetblue + Calc Hash = 0x75204 // calc + Caption_Side Hash = 0x2730c // caption-side + Caret_Color Hash = 0x2850b // caret-color + Center Hash = 0x10a06 // center + Charset Hash = 0x47607 // charset + Chartreuse Hash = 0x2900a // chartreuse + Chocolate Hash = 0x29a09 // chocolate + Clear Hash = 0x2c805 // clear + Clip Hash = 0x2cd04 // clip + Color Hash = 0xd805 // color + Column_Rule Hash = 0x3220b // column-rule + Column_Rule_Color Hash = 0x32211 // column-rule-color + Content Hash = 0x33307 // content + Cornflowerblue Hash = 0x3430e // cornflowerblue + Cornsilk Hash = 0x35108 // cornsilk + Counter_Increment Hash = 0x35911 // counter-increment + Counter_Reset Hash = 0x3740d // counter-reset + Cue Hash = 0x38103 // cue + Cue_After Hash = 0x38109 // cue-after + Cue_Before Hash = 0x38a0a // cue-before + Currentcolor Hash = 0x39b0c // currentcolor + Cursive Hash = 0x3a707 // cursive + Cursor Hash = 0x3ba06 // cursor + Darkblue Hash = 0xb708 // darkblue + Darkcyan Hash = 0xc208 // darkcyan + Darkgoldenrod Hash = 0x25f0d // darkgoldenrod + Darkgray Hash = 0x26b08 // darkgray + Darkgreen Hash = 0x83709 // darkgreen + Darkkhaki Hash = 0x94e09 // darkkhaki + Darkmagenta Hash = 0x5790b // darkmagenta + Darkolivegreen Hash = 0x7c60e // darkolivegreen + Darkorange Hash = 0x82b0a // darkorange + Darkorchid Hash = 0x9450a // darkorchid + Darksalmon Hash = 0x9890a // darksalmon + Darkseagreen Hash = 0x9ea0c // darkseagreen + Darkslateblue Hash = 0x3c00d // darkslateblue + Darkslategray Hash = 0x3cd0d // darkslategray + Darkturquoise Hash = 0x3da0d // darkturquoise + Darkviolet Hash = 0x3e70a // darkviolet + Deeppink Hash = 0x27d08 // deeppink + Deepskyblue Hash = 0x95c0b // deepskyblue + Default Hash = 0x5ef07 // default + Direction Hash = 0xac109 // direction + Display Hash = 0x3f107 // display + Document Hash = 0x3ff08 // document + Dodgerblue Hash = 0x4070a // dodgerblue + Elevation Hash = 0x4d409 // elevation + Empty_Cells Hash = 0x5200b // empty-cells + Fantasy Hash = 0x56107 // fantasy + Fill Hash = 0x60c04 // fill + Filter Hash = 0x406 // filter + Firebrick Hash = 0x41109 // firebrick + Flex Hash = 0x41a04 // flex + Float Hash = 0x41e05 // float + Floralwhite Hash = 0x4230b // floralwhite + Font Hash = 0x10304 // font + Font_Face Hash = 0x10309 // font-face + Font_Family Hash = 0x44d0b // font-family + Font_Size Hash = 0x45809 // font-size + Font_Size_Adjust Hash = 0x45810 // font-size-adjust + Font_Stretch Hash = 0x46c0c // font-stretch + Font_Style Hash = 0x47d0a // font-style + Font_Variant Hash = 0x4870c // font-variant + Font_Weight Hash = 0x4a20b // font-weight + Forestgreen Hash = 0x3900b // forestgreen + Fuchsia Hash = 0x4ad07 // fuchsia + Gainsboro Hash = 0x8809 // gainsboro + Ghostwhite Hash = 0x14c0a // ghostwhite + Goldenrod Hash = 0x26309 // goldenrod + Greenyellow Hash = 0x83b0b // greenyellow + Grid Hash = 0x5d204 // grid + Height Hash = 0x70906 // height + Honeydew Hash = 0x64008 // honeydew + Hsl Hash = 0x12203 // hsl + Hsla Hash = 0x12204 // hsla + Ime_Mode Hash = 0x95608 // ime-mode + Import Hash = 0x56806 // import + Important Hash = 0x56809 // important + Include_Source Hash = 0x8960e // include-source + Indianred Hash = 0x57109 // indianred + Inherit Hash = 0x5a507 // inherit + Initial Hash = 0x5ac07 // initial + Keyframes Hash = 0x43109 // keyframes + Large Hash = 0x54c05 // large + Larger Hash = 0x54c06 // larger + Lavender Hash = 0x12408 // lavender + Lavenderblush Hash = 0x1240d // lavenderblush + Lawngreen Hash = 0x9c09 // lawngreen + Layer_Background_Color Hash = 0x17616 // layer-background-color + Layer_Background_Image Hash = 0x60f16 // layer-background-image + Layout_Flow Hash = 0x5880b // layout-flow + Layout_Grid Hash = 0x5cb0b // layout-grid + Layout_Grid_Char Hash = 0xa5210 // layout-grid-char + Layout_Grid_Char_Spacing Hash = 0xa5218 // layout-grid-char-spacing + Layout_Grid_Line Hash = 0x5cb10 // layout-grid-line + Layout_Grid_Mode Hash = 0x5e110 // layout-grid-mode + Layout_Grid_Type Hash = 0x5f610 // layout-grid-type + Left Hash = 0x19f04 // left + Lemonchiffon Hash = 0xfa0c // lemonchiffon + Letter_Spacing Hash = 0x5bd0e // letter-spacing + Lightblue Hash = 0x62509 // lightblue + Lightcoral Hash = 0x62e0a // lightcoral + Lightcyan Hash = 0x66c09 // lightcyan + Lightgoldenrodyellow Hash = 0x67514 // lightgoldenrodyellow + Lightgray Hash = 0x69409 // lightgray + Lightgreen Hash = 0x69d0a // lightgreen + Lightpink Hash = 0x6a709 // lightpink + Lightsalmon Hash = 0x6b00b // lightsalmon + Lightseagreen Hash = 0x6bb0d // lightseagreen + Lightskyblue Hash = 0x6c80c // lightskyblue + Lightslateblue Hash = 0x6d40e // lightslateblue + Lightsteelblue Hash = 0x6e20e // lightsteelblue + Lightyellow Hash = 0x6f00b // lightyellow + Limegreen Hash = 0x6fb09 // limegreen + Line_Break Hash = 0x5d70a // line-break + Line_Height Hash = 0x7040b // line-height + Linear_Gradient Hash = 0x70f0f // linear-gradient + List_Style Hash = 0x71e0a // list-style + List_Style_Image Hash = 0x71e10 // list-style-image + List_Style_Position Hash = 0x72e13 // list-style-position + List_Style_Type Hash = 0x7410f // list-style-type + Local Hash = 0x75005 // local + Magenta Hash = 0x57d07 // magenta + Margin Hash = 0x2dd06 // margin + Margin_Bottom Hash = 0x2dd0d // margin-bottom + Margin_Left Hash = 0x2e90b // margin-left + Margin_Right Hash = 0x3000c // margin-right + Margin_Top Hash = 0x8720a // margin-top + Marker_Offset Hash = 0x75e0d // marker-offset + Marks Hash = 0x76b05 // marks + Mask Hash = 0x78a04 // mask + Max_Height Hash = 0x78e0a // max-height + Max_Width Hash = 0x79809 // max-width + Media Hash = 0xae905 // media + Medium Hash = 0x7a106 // medium + Mediumaquamarine Hash = 0x7a110 // mediumaquamarine + Mediumblue Hash = 0x7b10a // mediumblue + Mediumorchid Hash = 0x7bb0c // mediumorchid + Mediumpurple Hash = 0x7d40c // mediumpurple + Mediumseagreen Hash = 0x7e00e // mediumseagreen + Mediumslateblue Hash = 0x7ee0f // mediumslateblue + Mediumspringgreen Hash = 0x7fd11 // mediumspringgreen + Mediumturquoise Hash = 0x80e0f // mediumturquoise + Mediumvioletred Hash = 0x81d0f // mediumvioletred + Midnightblue Hash = 0x84b0c // midnightblue + Min_Height Hash = 0x8570a // min-height + Min_Width Hash = 0x86109 // min-width + Mintcream Hash = 0x86a09 // mintcream + Mistyrose Hash = 0x88709 // mistyrose + Moccasin Hash = 0x89008 // moccasin + Monospace Hash = 0x99009 // monospace + Namespace Hash = 0x4cc09 // namespace + Navajowhite Hash = 0x4dc0b // navajowhite + No_Repeat Hash = 0x53309 // no-repeat + None Hash = 0x8d204 // none + Normal Hash = 0x9706 // normal + Olivedrab Hash = 0x8a409 // olivedrab + Orangered Hash = 0x82f09 // orangered + Orphans Hash = 0x4bc07 // orphans + Outline Hash = 0x8d607 // outline + Outline_Color Hash = 0x8d60d // outline-color + Outline_Style Hash = 0x8e30d // outline-style + Outline_Width Hash = 0x8f00d // outline-width + Overflow Hash = 0x54008 // overflow + Overflow_X Hash = 0x5400a // overflow-x + Overflow_Y Hash = 0x8fd0a // overflow-y + Padding Hash = 0x2d007 // padding + Padding_Bottom Hash = 0x2d00e // padding-bottom + Padding_Box Hash = 0x59a0b // padding-box + Padding_Left Hash = 0x87b0c // padding-left + Padding_Right Hash = 0x9ac0d // padding-right + Padding_Top Hash = 0x9a20b // padding-top + Page Hash = 0x90704 // page + Page_Break_After Hash = 0x90710 // page-break-after + Page_Break_Before Hash = 0x91711 // page-break-before + Page_Break_Inside Hash = 0x92811 // page-break-inside + Palegoldenrod Hash = 0x9390d // palegoldenrod + Palegreen Hash = 0x96709 // palegreen + Paleturquoise Hash = 0x9700d // paleturquoise + Palevioletred Hash = 0x97d0d // palevioletred + Papayawhip Hash = 0x9990a // papayawhip + Pause Hash = 0x9b905 // pause + Pause_After Hash = 0x9b90b // pause-after + Pause_Before Hash = 0x9c40c // pause-before + Peachpuff Hash = 0x60409 // peachpuff + Pitch Hash = 0x9d005 // pitch + Pitch_Range Hash = 0x9d00b // pitch-range + Play_During Hash = 0x3f40b // play-during + Position Hash = 0x3808 // position + Powderblue Hash = 0x9db0a // powderblue + Progid Hash = 0x9e506 // progid + Quotes Hash = 0x9f606 // quotes + Radial_Gradient Hash = 0x90f // radial-gradient + Repeat Hash = 0x4d06 // repeat + Rgb Hash = 0x4f903 // rgb + Rgba Hash = 0x4f904 // rgba + Richness Hash = 0x55108 // richness + Right Hash = 0x1d205 // right + Rosybrown Hash = 0x8f09 // rosybrown + Round Hash = 0x3205 // round + Royalblue Hash = 0x66309 // royalblue + Ruby_Align Hash = 0x8c90a // ruby-align + Ruby_Overhang Hash = 0x7c0d // ruby-overhang + Ruby_Position Hash = 0xdc0d // ruby-position + Saddlebrown Hash = 0x4c20b // saddlebrown + Sandybrown Hash = 0x52a0a // sandybrown + Sans_Serif Hash = 0x5580a // sans-serif + Scroll Hash = 0x2b306 // scroll + Scrollbar_3d_Light_Color Hash = 0x64c18 // scrollbar-3d-light-color + Scrollbar_Arrow_Color Hash = 0x2b315 // scrollbar-arrow-color + Scrollbar_Base_Color Hash = 0x43914 // scrollbar-base-color + Scrollbar_Dark_Shadow_Color Hash = 0x76f1b // scrollbar-dark-shadow-color + Scrollbar_Face_Color Hash = 0x9fb14 // scrollbar-face-color + Scrollbar_Highlight_Color Hash = 0xa9e19 // scrollbar-highlight-color + Scrollbar_Shadow_Color Hash = 0xa0f16 // scrollbar-shadow-color + Scrollbar_Track_Color Hash = 0xa2515 // scrollbar-track-color + Seagreen Hash = 0x6c008 // seagreen + Seashell Hash = 0x16f08 // seashell + Serif Hash = 0x55d05 // serif + Size Hash = 0x7104 // size + Slateblue Hash = 0x3c409 // slateblue + Slategray Hash = 0x3d109 // slategray + Small Hash = 0x8c305 // small + Smaller Hash = 0x8c307 // smaller + Space Hash = 0x15d05 // space + Speak Hash = 0xa3a05 // speak + Speak_Header Hash = 0xa3a0c // speak-header + Speak_Numeral Hash = 0xa460d // speak-numeral + Speak_Punctuation Hash = 0xa6a11 // speak-punctuation + Speech_Rate Hash = 0xa7b0b // speech-rate + Springgreen Hash = 0x8030b // springgreen + Steelblue Hash = 0x6e709 // steelblue + Stress Hash = 0x2ae06 // stress + Stroke Hash = 0x46606 // stroke + Supports Hash = 0xa9708 // supports + Table_Layout Hash = 0x5820c // table-layout + Text_Align Hash = 0x2a10a // text-align + Text_Align_Last Hash = 0x2a10f // text-align-last + Text_Autospace Hash = 0x1540e // text-autospace + Text_Decoration Hash = 0x4e50f // text-decoration + Text_Decoration_Color Hash = 0x4e515 // text-decoration-color + Text_Emphasis Hash = 0xa840d // text-emphasis + Text_Emphasis_Color Hash = 0xa8413 // text-emphasis-color + Text_Indent Hash = 0x170b // text-indent + Text_Justify Hash = 0x210c // text-justify + Text_Kashida_Space Hash = 0x50f12 // text-kashida-space + Text_Overflow Hash = 0x53b0d // text-overflow + Text_Shadow Hash = 0x520b // text-shadow + Text_Transform Hash = 0x2f30e // text-transform + Text_Underline_Position Hash = 0x30b17 // text-underline-position + Top Hash = 0x22203 // top + Transition Hash = 0x3390a // transition + Transparent Hash = 0x3690b // transparent + Turquoise Hash = 0x3de09 // turquoise + Unicode_Bidi Hash = 0xab70c // unicode-bidi + Unset Hash = 0xaca05 // unset + Vertical_Align Hash = 0x3ac0e // vertical-align + Visibility Hash = 0xacf0a // visibility + Voice_Family Hash = 0xad90c // voice-family + Volume Hash = 0xae506 // volume + White Hash = 0x15105 // white + White_Space Hash = 0x4970b // white-space + Whitesmoke Hash = 0x4290a // whitesmoke + Widows Hash = 0x64706 // widows + Width Hash = 0x11e05 // width + Word_Break Hash = 0x5c0a // word-break + Word_Spacing Hash = 0x1410c // word-spacing + Word_Wrap Hash = 0x59209 // word-wrap + Writing_Mode Hash = 0x6880c // writing-mode + X_Large Hash = 0x54a07 // x-large + X_Small Hash = 0x8c107 // x-small + Xx_Large Hash = 0x54908 // xx-large + Xx_Small Hash = 0x8c008 // xx-small + Yellow Hash = 0x68306 // yellow + Yellowgreen Hash = 0x8400b // yellowgreen + Z_Index Hash = 0xaee07 // z-index +) + +// String returns the hash' name. +func (i Hash) String() string { + start := uint32(i >> 8) + n := uint32(i & 0xff) + if start+n > uint32(len(_Hash_text)) { + return "" + } + return _Hash_text[start : start+n] +} + +// ToHash returns the hash whose name is s. It returns zero if there is no +// such hash. It is case sensitive. +func ToHash(s []byte) Hash { + if len(s) == 0 || len(s) > _Hash_maxLen { + return 0 + } + h := uint32(_Hash_hash0) + for i := 0; i < len(s); i++ { + h ^= uint32(s[i]) + h *= 16777619 + } + if i := _Hash_table[h&uint32(len(_Hash_table)-1)]; int(i&0xff) == len(s) { + t := _Hash_text[i>>8 : i>>8+i&0xff] + for i := 0; i < len(s); i++ { + if t[i] != s[i] { + goto NEXT + } + } + return i + } +NEXT: + if i := _Hash_table[(h>>16)&uint32(len(_Hash_table)-1)]; int(i&0xff) == len(s) { + t := _Hash_text[i>>8 : i>>8+i&0xff] + for i := 0; i < len(s); i++ { + if t[i] != s[i] { + return 0 + } + } + return i + } + return 0 +} + +const _Hash_hash0 = 0x4c0d9a56 +const _Hash_maxLen = 27 +const _Hash_text = "-ms-filteradial-gradientext-indentext-justifybackground-posi" + + "tion-ybackground-repeatext-shadoword-breakbackground-sizebeh" + + "avioruby-overhangainsborosybrownormalawngreenblackblanchedal" + + "mondarkblueboldarkcyanborder-bottom-coloruby-positionborder-" + + "bottom-stylemonchiffont-facenterborder-bottom-widthslavender" + + "blushborder-box-shadoword-spacinghostwhitext-autospaceborder" + + "-collapseashellayer-background-colorborder-colorborder-left-" + + "colorborder-left-styleborder-left-widthborder-right-colorbor" + + "der-right-styleborder-right-widthborder-spacingborder-styleb" + + "order-top-colorborder-top-styleborder-top-widthborder-widthb" + + "urlywoodarkgoldenrodarkgraycaption-sideeppinkcaret-colorchar" + + "treusechocolatext-align-lastresscrollbar-arrow-colorclearcli" + + "padding-bottomargin-bottomargin-leftext-transformargin-right" + + "ext-underline-positioncolumn-rule-colorcontentransitioncornf" + + "lowerbluecornsilkcounter-incrementransparentcounter-resetcue" + + "-aftercue-beforestgreencurrentcolorcursivertical-aligncursor" + + "darkslatebluedarkslategraydarkturquoisedarkvioletdisplay-dur" + + "ingdocumentdodgerbluefirebrickflexfloatfloralwhitesmokeyfram" + + "escrollbar-base-colorfont-familyfont-size-adjustrokefont-str" + + "etcharsetfont-stylefont-variantiquewhite-spacefont-weightfuc" + + "hsiacceleratorphansaddlebrownamespacelevationavajowhitext-de" + + "coration-colorgbackground-attachmentext-kashida-spacempty-ce" + + "llsandybrowno-repeatext-overflow-xx-largerichnessans-serifan" + + "tasyimportantindianredarkmagentable-layout-floword-wrapaddin" + + "g-boxinheritinitialicebluevioletter-spacinglayout-grid-line-" + + "breaklayout-grid-modefaultlayout-grid-typeachpuffillayer-bac" + + "kground-imagelightbluelightcoralphazimuthoneydewidowscrollba" + + "r-3d-light-coloroyalbluelightcyanlightgoldenrodyellowriting-" + + "modelightgraylightgreenlightpinklightsalmonlightseagreenligh" + + "tskybluelightslatebluelightsteelbluelightyellowlimegreenline" + + "-heightlinear-gradientlist-style-imagelist-style-positionlis" + + "t-style-typelocalcadetbluemarker-offsetmarkscrollbar-dark-sh" + + "adow-colormaskmax-heightmax-widthmediumaquamarinemediumbluem" + + "ediumorchidarkolivegreenmediumpurplemediumseagreenmediumslat" + + "ebluemediumspringgreenmediumturquoisemediumvioletredarkorang" + + "eredarkgreenyellowgreenmidnightbluemin-heightmin-widthmintcr" + + "eamargin-topadding-leftmistyrosemoccasinclude-sourceolivedra" + + "background-position-xx-smalleruby-alignoneoutline-coloroutli" + + "ne-styleoutline-widthoverflow-ypage-break-afterpage-break-be" + + "forepage-break-insidepalegoldenrodarkorchidarkkhakime-modeep" + + "skybluepalegreenpaleturquoisepalevioletredarksalmonospacepap" + + "ayawhipadding-topadding-rightpause-afterpause-beforepitch-ra" + + "ngepowderblueprogidarkseagreenquotescrollbar-face-colorscrol" + + "lbar-shadow-colorscrollbar-track-colorspeak-headerspeak-nume" + + "ralayout-grid-char-spacingspeak-punctuationspeech-ratext-emp" + + "hasis-colorsupportscrollbar-highlight-colorunicode-bidirecti" + + "onunsetvisibilityvoice-familyvolumediaz-index" + +var _Hash_table = [1 << 9]Hash{ + 0x0: 0xad90c, // voice-family + 0x2: 0x4290a, // whitesmoke + 0x4: 0x9d005, // pitch + 0x6: 0x7c0d, // ruby-overhang + 0x7: 0xaee07, // z-index + 0x8: 0x8a409, // olivedrab + 0x9: 0x3a707, // cursive + 0xb: 0x4a20b, // font-weight + 0xf: 0x81d0f, // mediumvioletred + 0x11: 0x54908, // xx-large + 0x12: 0x1ef12, // border-right-width + 0x14: 0xca0d, // border-bottom + 0x18: 0x660f, // background-size + 0x19: 0x3390a, // transition + 0x1a: 0x44d0b, // font-family + 0x1b: 0xa460d, // speak-numeral + 0x1c: 0xae905, // media + 0x1d: 0x90704, // page + 0x1e: 0x8d60d, // outline-color + 0x1f: 0x3000c, // margin-right + 0x20: 0x1620f, // border-collapse + 0x21: 0x12408, // lavender + 0x22: 0x70f0f, // linear-gradient + 0x23: 0x6e20e, // lightsteelblue + 0x26: 0xa8413, // text-emphasis-color + 0x27: 0x4230b, // floralwhite + 0x28: 0x97d0d, // palevioletred + 0x29: 0x64008, // honeydew + 0x2a: 0x8d204, // none + 0x2b: 0x1dd12, // border-right-style + 0x2c: 0xa2515, // scrollbar-track-color + 0x2e: 0x3205, // round + 0x2f: 0x8f09, // rosybrown + 0x30: 0x2d15, // background-position-y + 0x31: 0x23b10, // border-top-width + 0x32: 0x47d0a, // font-style + 0x33: 0x18c0c, // border-color + 0x34: 0x5a507, // inherit + 0x37: 0x5cb10, // layout-grid-line + 0x38: 0x4f904, // rgba + 0x39: 0x96709, // palegreen + 0x3b: 0x1540e, // text-autospace + 0x3c: 0x76b05, // marks + 0x3d: 0x70906, // height + 0x3e: 0x68306, // yellow + 0x3f: 0x11e05, // width + 0x41: 0x45810, // font-size-adjust + 0x44: 0x9390d, // palegoldenrod + 0x45: 0x5790b, // darkmagenta + 0x47: 0x3c409, // slateblue + 0x48: 0x2b306, // scroll + 0x49: 0xa7b0b, // speech-rate + 0x4d: 0x95c0b, // deepskyblue + 0x4f: 0x9a20b, // padding-top + 0x50: 0x27d08, // deeppink + 0x52: 0x4d06, // repeat + 0x55: 0x35108, // cornsilk + 0x57: 0x7104, // size + 0x59: 0x16f08, // seashell + 0x5a: 0x84b0c, // midnightblue + 0x5c: 0x56809, // important + 0x5d: 0x95608, // ime-mode + 0x5e: 0x71e0a, // list-style + 0x5f: 0x92811, // page-break-inside + 0x60: 0x4c20b, // saddlebrown + 0x61: 0x7410f, // list-style-type + 0x62: 0x5f610, // layout-grid-type + 0x63: 0x75204, // calc + 0x64: 0x3ba06, // cursor + 0x66: 0x5880b, // layout-flow + 0x67: 0x1410c, // word-spacing + 0x68: 0x5e110, // layout-grid-mode + 0x69: 0x1380a, // box-shadow + 0x6b: 0x9f606, // quotes + 0x6c: 0x4fb15, // background-attachment + 0x6d: 0x55108, // richness + 0x6e: 0x22b10, // border-top-style + 0x6f: 0x38a0a, // cue-before + 0x70: 0x15105, // white + 0x71: 0x80e0f, // mediumturquoise + 0x73: 0x87b0c, // padding-left + 0x76: 0x5d70a, // line-break + 0x78: 0x2dd0d, // margin-bottom + 0x7a: 0x7c60e, // darkolivegreen + 0x7c: 0x26309, // goldenrod + 0x7d: 0x6bb0d, // lightseagreen + 0x7e: 0x14c0a, // ghostwhite + 0x7f: 0x3c00d, // darkslateblue + 0x80: 0x2010e, // border-spacing + 0x81: 0x8f00d, // outline-width + 0x83: 0x46c0c, // font-stretch + 0x85: 0x3cd0d, // darkslategray + 0x86: 0x8720a, // margin-top + 0x88: 0x8030b, // springgreen + 0x89: 0x8400b, // yellowgreen + 0x8a: 0x6f00b, // lightyellow + 0x8c: 0x6b00b, // lightsalmon + 0x8d: 0x4b30b, // accelerator + 0x8e: 0x50f12, // text-kashida-space + 0x90: 0x19811, // border-left-color + 0x92: 0xaca05, // unset + 0x95: 0x52a0a, // sandybrown + 0x96: 0x4211, // background-repeat + 0x97: 0x9c40c, // pause-before + 0x98: 0x3d109, // slategray + 0x99: 0x26b08, // darkgray + 0x9b: 0x60c04, // fill + 0x9d: 0x6e709, // steelblue + 0xa1: 0xc208, // darkcyan + 0xa2: 0x9fb14, // scrollbar-face-color + 0xa4: 0xd106, // bottom + 0xa5: 0xa6a11, // speak-punctuation + 0xa6: 0x9700d, // paleturquoise + 0xa7: 0x62e0a, // lightcoral + 0xa8: 0xae506, // volume + 0xaa: 0x6880c, // writing-mode + 0xab: 0x7ee0f, // mediumslateblue + 0xad: 0x8c305, // small + 0xae: 0x53b0d, // text-overflow + 0xb0: 0x5c0a, // word-break + 0xb4: 0x4970b, // white-space + 0xb7: 0x10304, // font + 0xb8: 0x8d607, // outline + 0xb9: 0x3690b, // transparent + 0xba: 0x2900a, // chartreuse + 0xbb: 0x56806, // import + 0xbd: 0x3e70a, // darkviolet + 0xbe: 0x2d13, // background-position + 0xbf: 0x4ad07, // fuchsia + 0xc1: 0x3808, // position + 0xc4: 0x53309, // no-repeat + 0xc6: 0x78a04, // mask + 0xc7: 0x3de09, // turquoise + 0xca: 0xaa0e, // blanchedalmond + 0xcb: 0xac109, // direction + 0xcc: 0x12204, // hsla + 0xcd: 0x520b, // text-shadow + 0xd3: 0x5cb0b, // layout-grid + 0xd5: 0x4cc09, // namespace + 0xd6: 0x8809, // gainsboro + 0xd7: 0x10309, // font-face + 0xd8: 0xb708, // darkblue + 0xda: 0x47607, // charset + 0xdd: 0x88709, // mistyrose + 0xde: 0x170b, // text-indent + 0xe0: 0x17616, // layer-background-color + 0xe2: 0x5ac07, // initial + 0xe5: 0x8960e, // include-source + 0xe6: 0xa5210, // layout-grid-char + 0xe9: 0x5400a, // overflow-x + 0xea: 0x46606, // stroke + 0xeb: 0x41109, // firebrick + 0xed: 0x41e05, // float + 0xef: 0x1cb0c, // border-right + 0xf0: 0x67514, // lightgoldenrodyellow + 0xf1: 0x86a09, // mintcream + 0xf3: 0x82b0a, // darkorange + 0xf4: 0x60409, // peachpuff + 0xf5: 0x7b10a, // mediumblue + 0xf7: 0x8c107, // x-small + 0xf9: 0xa9e19, // scrollbar-highlight-color + 0xfb: 0x10a06, // center + 0xfc: 0x2e90b, // margin-left + 0xfd: 0x9d00b, // pitch-range + 0xfe: 0x6a709, // lightpink + 0x102: 0xa5218, // layout-grid-char-spacing + 0x103: 0x2850b, // caret-color + 0x108: 0x56107, // fantasy + 0x10f: 0x7fd11, // mediumspringgreen + 0x110: 0x210c, // text-justify + 0x111: 0x9450a, // darkorchid + 0x112: 0x9990a, // papayawhip + 0x114: 0x9ea0c, // darkseagreen + 0x115: 0x4d409, // elevation + 0x116: 0x3220b, // column-rule + 0x118: 0x30b17, // text-underline-position + 0x11a: 0xca13, // border-bottom-color + 0x11c: 0x1d205, // right + 0x11d: 0x11013, // border-bottom-width + 0x11e: 0x5bd0e, // letter-spacing + 0x11f: 0x3740d, // counter-reset + 0x121: 0x63605, // alpha + 0x122: 0xa9708, // supports + 0x123: 0x3430e, // cornflowerblue + 0x126: 0xacf0a, // visibility + 0x127: 0x82f09, // orangered + 0x12a: 0x4e515, // text-decoration-color + 0x12b: 0x3da0d, // darkturquoise + 0x12d: 0x6fb09, // limegreen + 0x12e: 0x61510, // background-image + 0x12f: 0x9db0a, // powderblue + 0x130: 0x7508, // behavior + 0x131: 0x66c09, // lightcyan + 0x132: 0x35911, // counter-increment + 0x133: 0x6d40e, // lightslateblue + 0x134: 0x57109, // indianred + 0x136: 0xdc0d, // ruby-position + 0x139: 0x5b60a, // blueviolet + 0x13d: 0x64706, // widows + 0x13e: 0x2d0a, // background + 0x13f: 0x7a110, // mediumaquamarine + 0x140: 0xfa0c, // lemonchiffon + 0x141: 0x3ac0e, // vertical-align + 0x142: 0x2ae06, // stress + 0x145: 0x9706, // normal + 0x146: 0xa840d, // text-emphasis + 0x147: 0x7d40c, // mediumpurple + 0x148: 0x94e09, // darkkhaki + 0x149: 0x1cb12, // border-right-color + 0x14a: 0x4070a, // dodgerblue + 0x14d: 0x83709, // darkgreen + 0x14e: 0x5d204, // grid + 0x14f: 0x75509, // cadetblue + 0x150: 0x2dd06, // margin + 0x151: 0x91711, // page-break-before + 0x152: 0x89008, // moccasin + 0x153: 0x9e506, // progid + 0x156: 0x8fd0a, // overflow-y + 0x157: 0x90f, // radial-gradient + 0x159: 0x1310a, // border-box + 0x15b: 0x5ef07, // default + 0x15c: 0x20f0c, // border-style + 0x15e: 0x38109, // cue-after + 0x15f: 0x9b90b, // pause-after + 0x160: 0xa0f16, // scrollbar-shadow-color + 0x161: 0x22203, // top + 0x162: 0x54c05, // large + 0x164: 0x29a09, // chocolate + 0x165: 0x66309, // royalblue + 0x166: 0x4e50f, // text-decoration + 0x168: 0x4f903, // rgb + 0x16a: 0x75e0d, // marker-offset + 0x16b: 0x3ff08, // document + 0x16d: 0x21b10, // border-top-color + 0x16f: 0x8570a, // min-height + 0x171: 0x79809, // max-width + 0x173: 0x5200b, // empty-cells + 0x175: 0x2d00e, // padding-bottom + 0x17c: 0x9890a, // darksalmon + 0x17d: 0x1240d, // lavenderblush + 0x17e: 0x1a911, // border-left-style + 0x17f: 0x5580a, // sans-serif + 0x180: 0xa3a05, // speak + 0x182: 0x1980b, // border-left + 0x186: 0x2a10f, // text-align-last + 0x187: 0x86109, // min-width + 0x188: 0x33307, // content + 0x189: 0x69409, // lightgray + 0x18a: 0x39b0c, // currentcolor + 0x18b: 0x21b0a, // border-top + 0x18c: 0x90710, // page-break-after + 0x18f: 0x24b0c, // border-width + 0x192: 0x60f16, // layer-background-image + 0x193: 0x19f04, // left + 0x194: 0x7bb0c, // mediumorchid + 0x195: 0x4dc0b, // navajowhite + 0x196: 0x25709, // burlywood + 0x197: 0x2d007, // padding + 0x198: 0x5820c, // table-layout + 0x199: 0x4bc07, // orphans + 0x19a: 0x99009, // monospace + 0x19d: 0x8e30d, // outline-style + 0x19e: 0x59209, // word-wrap + 0x19f: 0x76f1b, // scrollbar-dark-shadow-color + 0x1a0: 0x43914, // scrollbar-base-color + 0x1a1: 0x41a04, // flex + 0x1a3: 0x9c09, // lawngreen + 0x1a4: 0x3f107, // display + 0x1a6: 0x5b109, // aliceblue + 0x1a7: 0x2c805, // clear + 0x1a9: 0x54008, // overflow + 0x1ab: 0x64c18, // scrollbar-3d-light-color + 0x1ac: 0x7040b, // line-height + 0x1ad: 0x83b0b, // greenyellow + 0x1ae: 0x3900b, // forestgreen + 0x1af: 0x45809, // font-size + 0x1b1: 0x7a106, // medium + 0x1b2: 0x8c008, // xx-small + 0x1b3: 0x55d05, // serif + 0x1b4: 0x54a07, // x-large + 0x1b8: 0xa, // -ms-filter + 0x1b9: 0xd805, // color + 0x1ba: 0x2b315, // scrollbar-arrow-color + 0x1bb: 0x54c06, // larger + 0x1bc: 0x4900c, // antiquewhite + 0x1bd: 0x75005, // local + 0x1bf: 0x7e00e, // mediumseagreen + 0x1c0: 0x78e0a, // max-height + 0x1c1: 0xbf04, // bold + 0x1c3: 0x8ac15, // background-position-x + 0x1c5: 0x2a10a, // text-align + 0x1c6: 0x9b905, // pause + 0x1c7: 0x1ba11, // border-left-width + 0x1c8: 0x25f0d, // darkgoldenrod + 0x1cb: 0x57d07, // magenta + 0x1cc: 0xca06, // border + 0x1cd: 0x2f30e, // text-transform + 0x1ce: 0x71e10, // list-style-image + 0x1cf: 0x4870c, // font-variant + 0x1d0: 0x406, // filter + 0x1d1: 0x38103, // cue + 0x1d6: 0x3f40b, // play-during + 0x1d9: 0x8c90a, // ruby-align + 0x1da: 0x2cd04, // clip + 0x1db: 0x17c10, // background-color + 0x1de: 0x63a07, // azimuth + 0x1e2: 0x2730c, // caption-side + 0x1e3: 0x59a0b, // padding-box + 0x1e4: 0x9ac0d, // padding-right + 0x1e5: 0x12203, // hsl + 0x1e6: 0x8c307, // smaller + 0x1e9: 0x72e13, // list-style-position + 0x1ec: 0xab70c, // unicode-bidi + 0x1ef: 0x7a70a, // aquamarine + 0x1f0: 0x15d05, // space + 0x1f1: 0xa505, // black + 0x1f3: 0xa3a0c, // speak-header + 0x1f4: 0x6c008, // seagreen + 0x1f7: 0x32211, // column-rule-color + 0x1fa: 0x62509, // lightblue + 0x1fc: 0xe913, // border-bottom-style + 0x1fd: 0x69d0a, // lightgreen + 0x1fe: 0x43109, // keyframes + 0x1ff: 0x6c80c, // lightskyblue +} diff --git a/vendor/github.com/tdewolff/parse/v2/css/lex.go b/vendor/github.com/tdewolff/parse/v2/css/lex.go new file mode 100644 index 0000000000000..b275bab0a0eb3 --- /dev/null +++ b/vendor/github.com/tdewolff/parse/v2/css/lex.go @@ -0,0 +1,710 @@ +// Package css is a CSS3 lexer and parser following the specifications at http://www.w3.org/TR/css-syntax-3/. +package css + +// TODO: \uFFFD replacement character for NULL bytes in strings for example, or atleast don't end the string early + +import ( + "bytes" + "io" + "strconv" + + "github.com/tdewolff/parse/v2" + "github.com/tdewolff/parse/v2/buffer" +) + +// TokenType determines the type of token, eg. a number or a semicolon. +type TokenType uint32 + +// TokenType values. +const ( + ErrorToken TokenType = iota // extra token when errors occur + IdentToken + FunctionToken // rgb( rgba( ... + AtKeywordToken // @abc + HashToken // #abc + StringToken + BadStringToken + URLToken + BadURLToken + DelimToken // any unmatched character + NumberToken // 5 + PercentageToken // 5% + DimensionToken // 5em + UnicodeRangeToken // U+554A + IncludeMatchToken // ~= + DashMatchToken // |= + PrefixMatchToken // ^= + SuffixMatchToken // $= + SubstringMatchToken // *= + ColumnToken // || + WhitespaceToken // space \t \r \n \f + CDOToken // + ColonToken // : + SemicolonToken // ; + CommaToken // , + LeftBracketToken // [ + RightBracketToken // ] + LeftParenthesisToken // ( + RightParenthesisToken // ) + LeftBraceToken // { + RightBraceToken // } + CommentToken // extra token for comments + EmptyToken + CustomPropertyNameToken + CustomPropertyValueToken +) + +// String returns the string representation of a TokenType. +func (tt TokenType) String() string { + switch tt { + case ErrorToken: + return "Error" + case IdentToken: + return "Ident" + case FunctionToken: + return "Function" + case AtKeywordToken: + return "AtKeyword" + case HashToken: + return "Hash" + case StringToken: + return "String" + case BadStringToken: + return "BadString" + case URLToken: + return "URL" + case BadURLToken: + return "BadURL" + case DelimToken: + return "Delim" + case NumberToken: + return "Number" + case PercentageToken: + return "Percentage" + case DimensionToken: + return "Dimension" + case UnicodeRangeToken: + return "UnicodeRange" + case IncludeMatchToken: + return "IncludeMatch" + case DashMatchToken: + return "DashMatch" + case PrefixMatchToken: + return "PrefixMatch" + case SuffixMatchToken: + return "SuffixMatch" + case SubstringMatchToken: + return "SubstringMatch" + case ColumnToken: + return "Column" + case WhitespaceToken: + return "Whitespace" + case CDOToken: + return "CDO" + case CDCToken: + return "CDC" + case ColonToken: + return "Colon" + case SemicolonToken: + return "Semicolon" + case CommaToken: + return "Comma" + case LeftBracketToken: + return "LeftBracket" + case RightBracketToken: + return "RightBracket" + case LeftParenthesisToken: + return "LeftParenthesis" + case RightParenthesisToken: + return "RightParenthesis" + case LeftBraceToken: + return "LeftBrace" + case RightBraceToken: + return "RightBrace" + case CommentToken: + return "Comment" + case EmptyToken: + return "Empty" + case CustomPropertyNameToken: + return "CustomPropertyName" + case CustomPropertyValueToken: + return "CustomPropertyValue" + } + return "Invalid(" + strconv.Itoa(int(tt)) + ")" +} + +//////////////////////////////////////////////////////////////// + +// Lexer is the state for the lexer. +type Lexer struct { + r *buffer.Lexer +} + +// NewLexer returns a new Lexer for a given io.Reader. +func NewLexer(r io.Reader) *Lexer { + return &Lexer{ + buffer.NewLexer(r), + } +} + +// Err returns the error encountered during lexing, this is often io.EOF but also other errors can be returned. +func (l *Lexer) Err() error { + return l.r.Err() +} + +// Restore restores the NULL byte at the end of the buffer. +func (l *Lexer) Restore() { + l.r.Restore() +} + +// Next returns the next Token. It returns ErrorToken when an error was encountered. Using Err() one can retrieve the error message. +func (l *Lexer) Next() (TokenType, []byte) { + switch l.r.Peek(0) { + case ' ', '\t', '\n', '\r', '\f': + l.r.Move(1) + for l.consumeWhitespace() { + } + return WhitespaceToken, l.r.Shift() + case ':': + l.r.Move(1) + return ColonToken, l.r.Shift() + case ';': + l.r.Move(1) + return SemicolonToken, l.r.Shift() + case ',': + l.r.Move(1) + return CommaToken, l.r.Shift() + case '(', ')', '[', ']', '{', '}': + if t := l.consumeBracket(); t != ErrorToken { + return t, l.r.Shift() + } + case '#': + if l.consumeHashToken() { + return HashToken, l.r.Shift() + } + case '"', '\'': + if t := l.consumeString(); t != ErrorToken { + return t, l.r.Shift() + } + case '.', '+': + if t := l.consumeNumeric(); t != ErrorToken { + return t, l.r.Shift() + } + case '-': + if t := l.consumeNumeric(); t != ErrorToken { + return t, l.r.Shift() + } else if t := l.consumeIdentlike(); t != ErrorToken { + return t, l.r.Shift() + } else if l.consumeCDCToken() { + return CDCToken, l.r.Shift() + } else if l.consumeCustomVariableToken() { + return CustomPropertyNameToken, l.r.Shift() + } + case '@': + if l.consumeAtKeywordToken() { + return AtKeywordToken, l.r.Shift() + } + case '$', '*', '^', '~': + if t := l.consumeMatch(); t != ErrorToken { + return t, l.r.Shift() + } + case '/': + if l.consumeComment() { + return CommentToken, l.r.Shift() + } + case '<': + if l.consumeCDOToken() { + return CDOToken, l.r.Shift() + } + case '\\': + if t := l.consumeIdentlike(); t != ErrorToken { + return t, l.r.Shift() + } + case 'u', 'U': + if l.consumeUnicodeRangeToken() { + return UnicodeRangeToken, l.r.Shift() + } else if t := l.consumeIdentlike(); t != ErrorToken { + return t, l.r.Shift() + } + case '|': + if t := l.consumeMatch(); t != ErrorToken { + return t, l.r.Shift() + } else if l.consumeColumnToken() { + return ColumnToken, l.r.Shift() + } + case 0: + if l.r.Err() != nil { + return ErrorToken, nil + } + default: + if t := l.consumeNumeric(); t != ErrorToken { + return t, l.r.Shift() + } else if t := l.consumeIdentlike(); t != ErrorToken { + return t, l.r.Shift() + } + } + // can't be rune because consumeIdentlike consumes that as an identifier + l.r.Move(1) + return DelimToken, l.r.Shift() +} + +//////////////////////////////////////////////////////////////// + +/* +The following functions follow the railroad diagrams in http://www.w3.org/TR/css3-syntax/ +*/ + +func (l *Lexer) consumeByte(c byte) bool { + if l.r.Peek(0) == c { + l.r.Move(1) + return true + } + return false +} + +func (l *Lexer) consumeComment() bool { + if l.r.Peek(0) != '/' || l.r.Peek(1) != '*' { + return false + } + l.r.Move(2) + for { + c := l.r.Peek(0) + if c == 0 && l.r.Err() != nil { + break + } else if c == '*' && l.r.Peek(1) == '/' { + l.r.Move(2) + return true + } + l.r.Move(1) + } + return true +} + +func (l *Lexer) consumeNewline() bool { + c := l.r.Peek(0) + if c == '\n' || c == '\f' { + l.r.Move(1) + return true + } else if c == '\r' { + if l.r.Peek(1) == '\n' { + l.r.Move(2) + } else { + l.r.Move(1) + } + return true + } + return false +} + +func (l *Lexer) consumeWhitespace() bool { + c := l.r.Peek(0) + if c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '\f' { + l.r.Move(1) + return true + } + return false +} + +func (l *Lexer) consumeDigit() bool { + c := l.r.Peek(0) + if c >= '0' && c <= '9' { + l.r.Move(1) + return true + } + return false +} + +func (l *Lexer) consumeHexDigit() bool { + c := l.r.Peek(0) + if (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F') { + l.r.Move(1) + return true + } + return false +} + +func (l *Lexer) consumeEscape() bool { + if l.r.Peek(0) != '\\' { + return false + } + mark := l.r.Pos() + l.r.Move(1) + if l.consumeNewline() { + l.r.Rewind(mark) + return false + } else if l.consumeHexDigit() { + for k := 1; k < 6; k++ { + if !l.consumeHexDigit() { + break + } + } + l.consumeWhitespace() + return true + } else { + c := l.r.Peek(0) + if c >= 0xC0 { + _, n := l.r.PeekRune(0) + l.r.Move(n) + return true + } else if c == 0 && l.r.Err() != nil { + return true + } + } + l.r.Move(1) + return true +} + +func (l *Lexer) consumeIdentToken() bool { + mark := l.r.Pos() + if l.r.Peek(0) == '-' { + l.r.Move(1) + } + c := l.r.Peek(0) + if !((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_' || c >= 0x80) { + if c != '\\' || !l.consumeEscape() { + l.r.Rewind(mark) + return false + } + } else { + l.r.Move(1) + } + for { + c := l.r.Peek(0) + if !((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_' || c == '-' || c >= 0x80) { + if c != '\\' || !l.consumeEscape() { + break + } + } else { + l.r.Move(1) + } + } + return true +} + +// support custom variables, https://www.w3.org/TR/css-variables-1/ +func (l *Lexer) consumeCustomVariableToken() bool { + // expect to be on a '-' + l.r.Move(1) + if l.r.Peek(0) != '-' { + l.r.Move(-1) + return false + } + if !l.consumeIdentToken() { + l.r.Move(-1) + return false + } + return true +} + +func (l *Lexer) consumeAtKeywordToken() bool { + // expect to be on an '@' + l.r.Move(1) + if !l.consumeIdentToken() { + l.r.Move(-1) + return false + } + return true +} + +func (l *Lexer) consumeHashToken() bool { + // expect to be on a '#' + mark := l.r.Pos() + l.r.Move(1) + c := l.r.Peek(0) + if !((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_' || c == '-' || c >= 0x80) { + if c != '\\' || !l.consumeEscape() { + l.r.Rewind(mark) + return false + } + } else { + l.r.Move(1) + } + for { + c := l.r.Peek(0) + if !((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_' || c == '-' || c >= 0x80) { + if c != '\\' || !l.consumeEscape() { + break + } + } else { + l.r.Move(1) + } + } + return true +} + +func (l *Lexer) consumeNumberToken() bool { + mark := l.r.Pos() + c := l.r.Peek(0) + if c == '+' || c == '-' { + l.r.Move(1) + } + firstDigit := l.consumeDigit() + if firstDigit { + for l.consumeDigit() { + } + } + if l.r.Peek(0) == '.' { + l.r.Move(1) + if l.consumeDigit() { + for l.consumeDigit() { + } + } else if firstDigit { + // . could belong to the next token + l.r.Move(-1) + return true + } else { + l.r.Rewind(mark) + return false + } + } else if !firstDigit { + l.r.Rewind(mark) + return false + } + mark = l.r.Pos() + c = l.r.Peek(0) + if c == 'e' || c == 'E' { + l.r.Move(1) + c = l.r.Peek(0) + if c == '+' || c == '-' { + l.r.Move(1) + } + if !l.consumeDigit() { + // e could belong to next token + l.r.Rewind(mark) + return true + } + for l.consumeDigit() { + } + } + return true +} + +func (l *Lexer) consumeUnicodeRangeToken() bool { + c := l.r.Peek(0) + if (c != 'u' && c != 'U') || l.r.Peek(1) != '+' { + return false + } + mark := l.r.Pos() + l.r.Move(2) + if l.consumeHexDigit() { + // consume up to 6 hexDigits + k := 1 + for ; k < 6; k++ { + if !l.consumeHexDigit() { + break + } + } + + // either a minus or a question mark or the end is expected + if l.consumeByte('-') { + // consume another up to 6 hexDigits + if l.consumeHexDigit() { + for k := 1; k < 6; k++ { + if !l.consumeHexDigit() { + break + } + } + } else { + l.r.Rewind(mark) + return false + } + } else { + // could be filled up to 6 characters with question marks or else regular hexDigits + if l.consumeByte('?') { + k++ + for ; k < 6; k++ { + if !l.consumeByte('?') { + l.r.Rewind(mark) + return false + } + } + } + } + } else { + // consume 6 question marks + for k := 0; k < 6; k++ { + if !l.consumeByte('?') { + l.r.Rewind(mark) + return false + } + } + } + return true +} + +func (l *Lexer) consumeColumnToken() bool { + if l.r.Peek(0) == '|' && l.r.Peek(1) == '|' { + l.r.Move(2) + return true + } + return false +} + +func (l *Lexer) consumeCDOToken() bool { + if l.r.Peek(0) == '<' && l.r.Peek(1) == '!' && l.r.Peek(2) == '-' && l.r.Peek(3) == '-' { + l.r.Move(4) + return true + } + return false +} + +func (l *Lexer) consumeCDCToken() bool { + if l.r.Peek(0) == '-' && l.r.Peek(1) == '-' && l.r.Peek(2) == '>' { + l.r.Move(3) + return true + } + return false +} + +//////////////////////////////////////////////////////////////// + +// consumeMatch consumes any MatchToken. +func (l *Lexer) consumeMatch() TokenType { + if l.r.Peek(1) == '=' { + switch l.r.Peek(0) { + case '~': + l.r.Move(2) + return IncludeMatchToken + case '|': + l.r.Move(2) + return DashMatchToken + case '^': + l.r.Move(2) + return PrefixMatchToken + case '$': + l.r.Move(2) + return SuffixMatchToken + case '*': + l.r.Move(2) + return SubstringMatchToken + } + } + return ErrorToken +} + +// consumeBracket consumes any bracket token. +func (l *Lexer) consumeBracket() TokenType { + switch l.r.Peek(0) { + case '(': + l.r.Move(1) + return LeftParenthesisToken + case ')': + l.r.Move(1) + return RightParenthesisToken + case '[': + l.r.Move(1) + return LeftBracketToken + case ']': + l.r.Move(1) + return RightBracketToken + case '{': + l.r.Move(1) + return LeftBraceToken + case '}': + l.r.Move(1) + return RightBraceToken + } + return ErrorToken +} + +// consumeNumeric consumes NumberToken, PercentageToken or DimensionToken. +func (l *Lexer) consumeNumeric() TokenType { + if l.consumeNumberToken() { + if l.consumeByte('%') { + return PercentageToken + } else if l.consumeIdentToken() { + return DimensionToken + } + return NumberToken + } + return ErrorToken +} + +// consumeString consumes a string and may return BadStringToken when a newline is encountered. +func (l *Lexer) consumeString() TokenType { + // assume to be on " or ' + delim := l.r.Peek(0) + l.r.Move(1) + for { + c := l.r.Peek(0) + if c == 0 && l.r.Err() != nil { + break + } else if c == '\n' || c == '\r' || c == '\f' { + l.r.Move(1) + return BadStringToken + } else if c == delim { + l.r.Move(1) + break + } else if c == '\\' { + if !l.consumeEscape() { + l.r.Move(1) + l.consumeNewline() + } + } else { + l.r.Move(1) + } + } + return StringToken +} + +func (l *Lexer) consumeUnquotedURL() bool { + for { + c := l.r.Peek(0) + if c == 0 && l.r.Err() != nil || c == ')' { + break + } else if c == '"' || c == '\'' || c == '(' || c == '\\' || c == ' ' || c <= 0x1F || c == 0x7F { + if c != '\\' || !l.consumeEscape() { + return false + } + } else { + l.r.Move(1) + } + } + return true +} + +// consumeRemnantsBadUrl consumes bytes of a BadUrlToken so that normal tokenization may continue. +func (l *Lexer) consumeRemnantsBadURL() { + for { + if l.consumeByte(')') || l.r.Err() != nil { + break + } else if !l.consumeEscape() { + l.r.Move(1) + } + } +} + +// consumeIdentlike consumes IdentToken, FunctionToken or UrlToken. +func (l *Lexer) consumeIdentlike() TokenType { + if l.consumeIdentToken() { + if l.r.Peek(0) != '(' { + return IdentToken + } else if !parse.EqualFold(bytes.Replace(l.r.Lexeme(), []byte{'\\'}, nil, -1), []byte{'u', 'r', 'l'}) { + l.r.Move(1) + return FunctionToken + } + l.r.Move(1) + + // consume url + for l.consumeWhitespace() { + } + if c := l.r.Peek(0); c == '"' || c == '\'' { + if l.consumeString() == BadStringToken { + l.consumeRemnantsBadURL() + return BadURLToken + } + } else if !l.consumeUnquotedURL() && !l.consumeWhitespace() { // if unquoted URL fails due to encountering whitespace, continue + l.consumeRemnantsBadURL() + return BadURLToken + } + for l.consumeWhitespace() { + } + if !l.consumeByte(')') && l.r.Err() != io.EOF { + l.consumeRemnantsBadURL() + return BadURLToken + } + return URLToken + } + return ErrorToken +} diff --git a/vendor/github.com/tdewolff/parse/v2/css/parse.go b/vendor/github.com/tdewolff/parse/v2/css/parse.go new file mode 100644 index 0000000000000..5ba769c2513cd --- /dev/null +++ b/vendor/github.com/tdewolff/parse/v2/css/parse.go @@ -0,0 +1,454 @@ +package css + +import ( + "bytes" + "io" + "strconv" + + "github.com/tdewolff/parse/v2" +) + +var wsBytes = []byte(" ") +var endBytes = []byte("}") +var emptyBytes = []byte("") + +// GrammarType determines the type of grammar. +type GrammarType uint32 + +// GrammarType values. +const ( + ErrorGrammar GrammarType = iota // extra token when errors occur + CommentGrammar + AtRuleGrammar + BeginAtRuleGrammar + EndAtRuleGrammar + QualifiedRuleGrammar + BeginRulesetGrammar + EndRulesetGrammar + DeclarationGrammar + TokenGrammar + CustomPropertyGrammar +) + +// String returns the string representation of a GrammarType. +func (tt GrammarType) String() string { + switch tt { + case ErrorGrammar: + return "Error" + case CommentGrammar: + return "Comment" + case AtRuleGrammar: + return "AtRule" + case BeginAtRuleGrammar: + return "BeginAtRule" + case EndAtRuleGrammar: + return "EndAtRule" + case QualifiedRuleGrammar: + return "QualifiedRule" + case BeginRulesetGrammar: + return "BeginRuleset" + case EndRulesetGrammar: + return "EndRuleset" + case DeclarationGrammar: + return "Declaration" + case TokenGrammar: + return "Token" + case CustomPropertyGrammar: + return "CustomProperty" + } + return "Invalid(" + strconv.Itoa(int(tt)) + ")" +} + +//////////////////////////////////////////////////////////////// + +// State is the state function the parser currently is in. +type State func(*Parser) GrammarType + +// Token is a single TokenType and its associated data. +type Token struct { + TokenType + Data []byte +} + +func (t Token) String() string { + return t.TokenType.String() + "('" + string(t.Data) + "')" +} + +// Parser is the state for the parser. +type Parser struct { + l *Lexer + state []State + err error + + buf []Token + level int + + tt TokenType + data []byte + keepWS bool + prevWS bool + prevEnd bool + prevComment bool +} + +// NewParser returns a new CSS parser from an io.Reader. isInline specifies whether this is an inline style attribute. +func NewParser(r io.Reader, isInline bool) *Parser { + l := NewLexer(r) + p := &Parser{ + l: l, + state: make([]State, 0, 4), + } + + if isInline { + p.state = append(p.state, (*Parser).parseDeclarationList) + } else { + p.state = append(p.state, (*Parser).parseStylesheet) + } + return p +} + +// Err returns the error encountered during parsing, this is often io.EOF but also other errors can be returned. +func (p *Parser) Err() error { + if p.err != nil { + return p.err + } + return p.l.Err() +} + +// Restore restores the NULL byte at the end of the buffer. +func (p *Parser) Restore() { + p.l.Restore() +} + +// Next returns the next Grammar. It returns ErrorGrammar when an error was encountered. Using Err() one can retrieve the error message. +func (p *Parser) Next() (GrammarType, TokenType, []byte) { + p.err = nil + + if p.prevEnd { + p.tt, p.data = RightBraceToken, endBytes + p.prevEnd = false + } else { + p.tt, p.data = p.popToken(true) + } + gt := p.state[len(p.state)-1](p) + return gt, p.tt, p.data +} + +// Values returns a slice of Tokens for the last Grammar. Only AtRuleGrammar, BeginAtRuleGrammar, BeginRulesetGrammar and Declaration will return the at-rule components, ruleset selector and declaration values respectively. +func (p *Parser) Values() []Token { + return p.buf +} + +func (p *Parser) popToken(allowComment bool) (TokenType, []byte) { + p.prevWS = false + p.prevComment = false + tt, data := p.l.Next() + for !p.keepWS && tt == WhitespaceToken || tt == CommentToken { + if tt == WhitespaceToken { + p.prevWS = true + } else { + p.prevComment = true + if allowComment && len(p.state) == 1 { + break + } + } + tt, data = p.l.Next() + } + return tt, data +} + +func (p *Parser) initBuf() { + p.buf = p.buf[:0] +} + +func (p *Parser) pushBuf(tt TokenType, data []byte) { + p.buf = append(p.buf, Token{tt, data}) +} + +//////////////////////////////////////////////////////////////// + +func (p *Parser) parseStylesheet() GrammarType { + if p.tt == CDOToken || p.tt == CDCToken { + return TokenGrammar + } else if p.tt == AtKeywordToken { + return p.parseAtRule() + } else if p.tt == CommentToken { + return CommentGrammar + } else if p.tt == ErrorToken { + return ErrorGrammar + } + return p.parseQualifiedRule() +} + +func (p *Parser) parseDeclarationList() GrammarType { + if p.tt == CommentToken { + p.tt, p.data = p.popToken(false) + } + for p.tt == SemicolonToken { + p.tt, p.data = p.popToken(false) + } + + // IE hack: *color:red; + if p.tt == DelimToken && p.data[0] == '*' { + tt, data := p.popToken(false) + p.tt = tt + p.data = append(p.data, data...) + } + + if p.tt == ErrorToken { + return ErrorGrammar + } else if p.tt == AtKeywordToken { + return p.parseAtRule() + } else if p.tt == IdentToken || p.tt == DelimToken { + return p.parseDeclaration() + } else if p.tt == CustomPropertyNameToken { + return p.parseCustomProperty() + } + + // parse error + p.initBuf() + p.l.r.Move(-len(p.data)) + p.err = parse.NewErrorLexer("unexpected token in declaration", p.l.r) + p.l.r.Move(len(p.data)) + + if p.tt == RightBraceToken { + // right brace token will occur when we've had a decl error that ended in a right brace token + // as these are not handled by decl error, we handle it here explictly. Normally its used to end eg. the qual rule. + p.pushBuf(p.tt, p.data) + return ErrorGrammar + } + return p.parseDeclarationError(p.tt, p.data) +} + +//////////////////////////////////////////////////////////////// + +func (p *Parser) parseAtRule() GrammarType { + p.initBuf() + parse.ToLower(p.data) + atRuleName := p.data + if len(atRuleName) > 0 && atRuleName[1] == '-' { + if i := bytes.IndexByte(atRuleName[2:], '-'); i != -1 { + atRuleName = atRuleName[i+2:] // skip vendor specific prefix + } + } + atRule := ToHash(atRuleName[1:]) + + first := true + skipWS := false + for { + tt, data := p.popToken(false) + if tt == LeftBraceToken && p.level == 0 { + if atRule == Font_Face || atRule == Page { + p.state = append(p.state, (*Parser).parseAtRuleDeclarationList) + } else if atRule == Document || atRule == Keyframes || atRule == Media || atRule == Supports { + p.state = append(p.state, (*Parser).parseAtRuleRuleList) + } else { + p.state = append(p.state, (*Parser).parseAtRuleUnknown) + } + return BeginAtRuleGrammar + } else if (tt == SemicolonToken || tt == RightBraceToken) && p.level == 0 || tt == ErrorToken { + p.prevEnd = (tt == RightBraceToken) + return AtRuleGrammar + } else if tt == LeftParenthesisToken || tt == LeftBraceToken || tt == LeftBracketToken || tt == FunctionToken { + p.level++ + } else if tt == RightParenthesisToken || tt == RightBraceToken || tt == RightBracketToken { + p.level-- + } + if first { + if tt == LeftParenthesisToken || tt == LeftBracketToken { + p.prevWS = false + } + first = false + } + if len(data) == 1 && (data[0] == ',' || data[0] == ':') { + skipWS = true + } else if p.prevWS && !skipWS && tt != RightParenthesisToken { + p.pushBuf(WhitespaceToken, wsBytes) + } else { + skipWS = false + } + if tt == LeftParenthesisToken { + skipWS = true + } + p.pushBuf(tt, data) + } +} + +func (p *Parser) parseAtRuleRuleList() GrammarType { + if p.tt == RightBraceToken || p.tt == ErrorToken { + p.state = p.state[:len(p.state)-1] + return EndAtRuleGrammar + } else if p.tt == AtKeywordToken { + return p.parseAtRule() + } else { + return p.parseQualifiedRule() + } +} + +func (p *Parser) parseAtRuleDeclarationList() GrammarType { + for p.tt == SemicolonToken { + p.tt, p.data = p.popToken(false) + } + if p.tt == RightBraceToken || p.tt == ErrorToken { + p.state = p.state[:len(p.state)-1] + return EndAtRuleGrammar + } + return p.parseDeclarationList() +} + +func (p *Parser) parseAtRuleUnknown() GrammarType { + p.keepWS = true + if p.tt == RightBraceToken && p.level == 0 || p.tt == ErrorToken { + p.state = p.state[:len(p.state)-1] + p.keepWS = false + return EndAtRuleGrammar + } + if p.tt == LeftParenthesisToken || p.tt == LeftBraceToken || p.tt == LeftBracketToken || p.tt == FunctionToken { + p.level++ + } else if p.tt == RightParenthesisToken || p.tt == RightBraceToken || p.tt == RightBracketToken { + p.level-- + } + return TokenGrammar +} + +func (p *Parser) parseQualifiedRule() GrammarType { + p.initBuf() + first := true + inAttrSel := false + skipWS := true + var tt TokenType + var data []byte + for { + if first { + tt, data = p.tt, p.data + p.tt = WhitespaceToken + p.data = emptyBytes + first = false + } else { + tt, data = p.popToken(false) + } + if tt == LeftBraceToken && p.level == 0 { + p.state = append(p.state, (*Parser).parseQualifiedRuleDeclarationList) + return BeginRulesetGrammar + } else if tt == ErrorToken { + p.err = parse.NewErrorLexer("unexpected ending in qualified rule", p.l.r) + return ErrorGrammar + } else if tt == LeftParenthesisToken || tt == LeftBraceToken || tt == LeftBracketToken || tt == FunctionToken { + p.level++ + } else if tt == RightParenthesisToken || tt == RightBraceToken || tt == RightBracketToken { + p.level-- + } + if len(data) == 1 && (data[0] == ',' || data[0] == '>' || data[0] == '+' || data[0] == '~') { + if data[0] == ',' { + return QualifiedRuleGrammar + } + skipWS = true + } else if p.prevWS && !skipWS && !inAttrSel { + p.pushBuf(WhitespaceToken, wsBytes) + } else { + skipWS = false + } + if tt == LeftBracketToken { + inAttrSel = true + } else if tt == RightBracketToken { + inAttrSel = false + } + p.pushBuf(tt, data) + } +} + +func (p *Parser) parseQualifiedRuleDeclarationList() GrammarType { + for p.tt == SemicolonToken { + p.tt, p.data = p.popToken(false) + } + if p.tt == RightBraceToken || p.tt == ErrorToken { + p.state = p.state[:len(p.state)-1] + return EndRulesetGrammar + } + return p.parseDeclarationList() +} + +func (p *Parser) parseDeclaration() GrammarType { + p.initBuf() + parse.ToLower(p.data) + + ttName, dataName := p.tt, p.data + tt, data := p.popToken(false) + if tt != ColonToken { + p.l.r.Move(-len(data)) + p.err = parse.NewErrorLexer("expected colon in declaration", p.l.r) + p.l.r.Move(len(data)) + p.pushBuf(ttName, dataName) + return p.parseDeclarationError(tt, data) + } + + skipWS := true + for { + tt, data := p.popToken(false) + if (tt == SemicolonToken || tt == RightBraceToken) && p.level == 0 || tt == ErrorToken { + p.prevEnd = (tt == RightBraceToken) + return DeclarationGrammar + } else if tt == LeftParenthesisToken || tt == LeftBraceToken || tt == LeftBracketToken || tt == FunctionToken { + p.level++ + } else if tt == RightParenthesisToken || tt == RightBraceToken || tt == RightBracketToken { + p.level-- + } + if len(data) == 1 && (data[0] == ',' || data[0] == '/' || data[0] == ':' || data[0] == '!' || data[0] == '=') { + skipWS = true + } else if (p.prevWS || p.prevComment) && !skipWS { + p.pushBuf(WhitespaceToken, wsBytes) + } else { + skipWS = false + } + p.pushBuf(tt, data) + } +} + +func (p *Parser) parseDeclarationError(tt TokenType, data []byte) GrammarType { + // we're on the offending (tt,data), keep popping tokens till we reach ;, }, or EOF + p.tt, p.data = tt, data + for { + if (tt == SemicolonToken || tt == RightBraceToken) && p.level == 0 || tt == ErrorToken { + p.prevEnd = (tt == RightBraceToken) + if tt == SemicolonToken { + p.pushBuf(tt, data) + } + return ErrorGrammar + } else if tt == LeftParenthesisToken || tt == LeftBraceToken || tt == LeftBracketToken || tt == FunctionToken { + p.level++ + } else if tt == RightParenthesisToken || tt == RightBraceToken || tt == RightBracketToken { + p.level-- + } + + if p.prevWS { + p.pushBuf(WhitespaceToken, wsBytes) + } + p.pushBuf(tt, data) + + tt, data = p.popToken(false) + } +} + +func (p *Parser) parseCustomProperty() GrammarType { + p.initBuf() + if tt, data := p.popToken(false); tt != ColonToken { + p.l.r.Move(-len(data)) + p.err = parse.NewErrorLexer("expected colon in custom property", p.l.r) + p.l.r.Move(len(data)) + return ErrorGrammar + } + val := []byte{} + for { + tt, data := p.l.Next() + if (tt == SemicolonToken || tt == RightBraceToken) && p.level == 0 || tt == ErrorToken { + p.prevEnd = (tt == RightBraceToken) + p.pushBuf(CustomPropertyValueToken, val) + return CustomPropertyGrammar + } else if tt == LeftParenthesisToken || tt == LeftBraceToken || tt == LeftBracketToken || tt == FunctionToken { + p.level++ + } else if tt == RightParenthesisToken || tt == RightBraceToken || tt == RightBracketToken { + p.level-- + } + val = append(val, data...) + } +} diff --git a/vendor/github.com/tdewolff/parse/v2/css/util.go b/vendor/github.com/tdewolff/parse/v2/css/util.go new file mode 100644 index 0000000000000..e20c4997911f4 --- /dev/null +++ b/vendor/github.com/tdewolff/parse/v2/css/util.go @@ -0,0 +1,47 @@ +package css + +import "github.com/tdewolff/parse/v2/buffer" + +// IsIdent returns true if the bytes are a valid identifier. +func IsIdent(b []byte) bool { + l := NewLexer(buffer.NewReader(b)) + l.consumeIdentToken() + l.r.Restore() + return l.r.Pos() == len(b) +} + +// IsURLUnquoted returns true if the bytes are a valid unquoted URL. +func IsURLUnquoted(b []byte) bool { + l := NewLexer(buffer.NewReader(b)) + l.consumeUnquotedURL() + l.r.Restore() + return l.r.Pos() == len(b) +} + +// HSL2RGB converts HSL to RGB with all of range [0,1] +// from http://www.w3.org/TR/css3-color/#hsl-color +func HSL2RGB(h, s, l float64) (float64, float64, float64) { + m2 := l * (s + 1) + if l > 0.5 { + m2 = l + s - l*s + } + m1 := l*2 - m2 + return hue2rgb(m1, m2, h+1.0/3.0), hue2rgb(m1, m2, h), hue2rgb(m1, m2, h-1.0/3.0) +} + +func hue2rgb(m1, m2, h float64) float64 { + if h < 0.0 { + h += 1.0 + } + if h > 1.0 { + h -= 1.0 + } + if h*6.0 < 1.0 { + return m1 + (m2-m1)*h*6.0 + } else if h*2.0 < 1.0 { + return m2 + } else if h*3.0 < 2.0 { + return m1 + (m2-m1)*(2.0/3.0-h)*6.0 + } + return m1 +} diff --git a/vendor/github.com/tdewolff/parse/v2/error.go b/vendor/github.com/tdewolff/parse/v2/error.go new file mode 100644 index 0000000000000..28b872179b290 --- /dev/null +++ b/vendor/github.com/tdewolff/parse/v2/error.go @@ -0,0 +1,49 @@ +package parse + +import ( + "fmt" + "io" + + "github.com/tdewolff/parse/v2/buffer" +) + +// Error is a parsing error returned by parser. It contains a message and an offset at which the error occurred. +type Error struct { + Message string + r io.Reader + Offset int + line int + column int + context string +} + +// NewError creates a new error +func NewError(msg string, r io.Reader, offset int) *Error { + return &Error{ + Message: msg, + r: r, + Offset: offset, + } +} + +// NewErrorLexer creates a new error from an active Lexer. +func NewErrorLexer(msg string, l *buffer.Lexer) *Error { + r := buffer.NewReader(l.Bytes()) + offset := l.Offset() + return NewError(msg, r, offset) +} + +// Positions re-parses the file to determine the line, column, and context of the error. +// Context is the entire line at which the error occurred. +func (e *Error) Position() (int, int, string) { + if e.line == 0 { + e.line, e.column, e.context = Position(e.r, e.Offset) + } + return e.line, e.column, e.context +} + +// Error returns the error string, containing the context and line + column number. +func (e *Error) Error() string { + line, column, context := e.Position() + return fmt.Sprintf("parse error:%d:%d: %s\n%s", line, column, e.Message, context) +} diff --git a/vendor/github.com/tdewolff/parse/v2/go.mod b/vendor/github.com/tdewolff/parse/v2/go.mod new file mode 100644 index 0000000000000..d78727b9d1b92 --- /dev/null +++ b/vendor/github.com/tdewolff/parse/v2/go.mod @@ -0,0 +1,3 @@ +module github.com/tdewolff/parse/v2 + +require github.com/tdewolff/test v1.0.0 diff --git a/vendor/github.com/tdewolff/parse/v2/go.sum b/vendor/github.com/tdewolff/parse/v2/go.sum new file mode 100644 index 0000000000000..63216169eb180 --- /dev/null +++ b/vendor/github.com/tdewolff/parse/v2/go.sum @@ -0,0 +1,2 @@ +github.com/tdewolff/test v1.0.0 h1:jOwzqCXr5ePXEPGJaq2ivoR6HOCi+D5TPfpoyg8yvmU= +github.com/tdewolff/test v1.0.0/go.mod h1:DiQUlutnqlEvdvhSn2LPGy4TFwRauAaYDsL+683RNX4= diff --git a/vendor/github.com/tdewolff/parse/v2/position.go b/vendor/github.com/tdewolff/parse/v2/position.go new file mode 100644 index 0000000000000..8a40d677f0b2e --- /dev/null +++ b/vendor/github.com/tdewolff/parse/v2/position.go @@ -0,0 +1,97 @@ +package parse + +import ( + "fmt" + "io" + "strings" + + "github.com/tdewolff/parse/v2/buffer" +) + +// Position returns the line and column number for a certain position in a file. It is useful for recovering the position in a file that caused an error. +// It only treates \n, \r, and \r\n as newlines, which might be different from some languages also recognizing \f, \u2028, and \u2029 to be newlines. +func Position(r io.Reader, offset int) (line, col int, context string) { + l := buffer.NewLexer(r) + + line = 1 + for { + c := l.Peek(0) + if c == 0 && l.Err() != nil || offset == l.Pos() { + col = l.Pos() + 1 + context = positionContext(l, line, col) + return + } + + nNewline := 0 + if c == '\n' { + nNewline = 1 + } else if c == '\r' { + if l.Peek(1) == '\n' { + nNewline = 2 + } else { + nNewline = 1 + } + } else if c >= 0xC0 { + if r, n := l.PeekRune(0); r == '\u2028' || r == '\u2029' { + nNewline = n + } + } else { + l.Move(1) + } + + if nNewline > 0 { + if offset < l.Pos()+nNewline { + // move onto offset position, let next iteration handle it + l.Move(offset - l.Pos()) + continue + } + l.Move(nNewline) + line++ + offset -= l.Pos() + l.Skip() + } + } +} + +func positionContext(l *buffer.Lexer, line, col int) (context string) { + for { + c := l.Peek(0) + if c == 0 && l.Err() != nil || c == '\n' || c == '\r' { + break + } + l.Move(1) + } + + // cut off front or rear of context to stay between 60 characters + b := l.Lexeme() + limit := 60 + offset := 20 + ellipsisFront := "" + ellipsisRear := "" + if limit < len(b) { + if col <= limit-offset { + ellipsisRear = "..." + b = b[:limit-3] + } else if col >= len(b)-offset-3 { + ellipsisFront = "..." + col -= len(b) - offset - offset - 7 + b = b[len(b)-offset-offset-4:] + } else { + ellipsisFront = "..." + ellipsisRear = "..." + b = b[col-offset-1 : col+offset] + col = offset + 4 + } + } + + // replace unprintable characters by a space + for i, c := range b { + if c < 0x20 || c == 0x7F { + b[i] = ' ' + } + } + + context += fmt.Sprintf("%5d: %s%s%s\n", line, ellipsisFront, string(b), ellipsisRear) + context += fmt.Sprintf("%s^", strings.Repeat(" ", col+6)) + return +} diff --git a/vendor/github.com/tdewolff/parse/v2/strconv/float.go b/vendor/github.com/tdewolff/parse/v2/strconv/float.go new file mode 100644 index 0000000000000..ae13975e18dbd --- /dev/null +++ b/vendor/github.com/tdewolff/parse/v2/strconv/float.go @@ -0,0 +1,251 @@ +package strconv + +import "math" + +var float64pow10 = []float64{ + 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, + 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19, + 1e20, 1e21, 1e22, +} + +// Float parses a byte-slice and returns the float it represents. +// If an invalid character is encountered, it will stop there. +func ParseFloat(b []byte) (float64, int) { + i := 0 + neg := false + if i < len(b) && (b[i] == '+' || b[i] == '-') { + neg = b[i] == '-' + i++ + } + + dot := -1 + trunk := -1 + n := uint64(0) + for ; i < len(b); i++ { + c := b[i] + if c >= '0' && c <= '9' { + if trunk == -1 { + if n > math.MaxUint64/10 { + trunk = i + } else { + n *= 10 + n += uint64(c - '0') + } + } + } else if dot == -1 && c == '.' { + dot = i + } else { + break + } + } + + f := float64(n) + if neg { + f = -f + } + + mantExp := int64(0) + if dot != -1 { + if trunk == -1 { + trunk = i + } + mantExp = int64(trunk - dot - 1) + } else if trunk != -1 { + mantExp = int64(trunk - i) + } + expExp := int64(0) + if i < len(b) && (b[i] == 'e' || b[i] == 'E') { + i++ + if e, expLen := ParseInt(b[i:]); expLen > 0 { + expExp = e + i += expLen + } + } + exp := expExp - mantExp + + // copied from strconv/atof.go + if exp == 0 { + return f, i + } else if exp > 0 && exp <= 15+22 { // int * 10^k + // If exponent is big but number of digits is not, + // can move a few zeros into the integer part. + if exp > 22 { + f *= float64pow10[exp-22] + exp = 22 + } + if f <= 1e15 && f >= -1e15 { + return f * float64pow10[exp], i + } + } else if exp < 0 && exp >= -22 { // int / 10^k + return f / float64pow10[-exp], i + } + f *= math.Pow10(int(-mantExp)) + return f * math.Pow10(int(expExp)), i +} + +const log2 = 0.301029995 +const int64maxlen = 18 + +func float64exp(f float64) int { + exp2 := 0 + if f != 0.0 { + x := math.Float64bits(f) + exp2 = int(x>>(64-11-1))&0x7FF - 1023 + 1 + } + + exp10 := float64(exp2) * log2 + if exp10 < 0 { + exp10 -= 1.0 + } + return int(exp10) +} + +func AppendFloat(b []byte, f float64, prec int) ([]byte, bool) { + if math.IsNaN(f) || math.IsInf(f, 0) { + return b, false + } else if prec >= int64maxlen { + return b, false + } + + neg := false + if f < 0.0 { + f = -f + neg = true + } + if prec == -1 { + prec = int64maxlen - 1 + } + prec -= float64exp(f) // number of digits in front of the dot + f *= math.Pow10(prec) + + // calculate mantissa and exponent + mant := int64(f) + mantLen := LenInt(mant) + mantExp := mantLen - prec - 1 + if mant == 0 { + return append(b, '0'), true + } + + // expLen is zero for positive exponents, because positive exponents are determined later on in the big conversion loop + exp := 0 + expLen := 0 + if mantExp > 0 { + // positive exponent is determined in the loop below + // but if we initially decreased the exponent to fit in an integer, we can't set the new exponent in the loop alone, + // since the number of zeros at the end determines the positive exponent in the loop, and we just artificially lost zeros + if prec < 0 { + exp = mantExp + } + expLen = 1 + LenInt(int64(exp)) // e + digits + } else if mantExp < -3 { + exp = mantExp + expLen = 2 + LenInt(int64(exp)) // e + minus + digits + } else if mantExp < -1 { + mantLen += -mantExp - 1 // extra zero between dot and first digit + } + + // reserve space in b + i := len(b) + maxLen := 1 + mantLen + expLen // dot + mantissa digits + exponent + if neg { + maxLen++ + } + if i+maxLen > cap(b) { + b = append(b, make([]byte, maxLen)...) + } else { + b = b[:i+maxLen] + } + + // write to string representation + if neg { + b[i] = '-' + i++ + } + + // big conversion loop, start at the end and move to the front + // initially print trailing zeros and remove them later on + // for example if the first non-zero digit is three positions in front of the dot, it will overwrite the zeros with a positive exponent + zero := true + last := i + mantLen // right-most position of digit that is non-zero + dot + dot := last - prec - exp // position of dot + j := last + for mant > 0 { + if j == dot { + b[j] = '.' + j-- + } + newMant := mant / 10 + digit := mant - 10*newMant + if zero && digit > 0 { + // first non-zero digit, if we are still behind the dot we can trim the end to this position + // otherwise trim to the dot (including the dot) + if j > dot { + i = j + 1 + // decrease negative exponent further to get rid of dot + if exp < 0 { + newExp := exp - (j - dot) + // getting rid of the dot shouldn't lower the exponent to more digits (e.g. -9 -> -10) + if LenInt(int64(newExp)) == LenInt(int64(exp)) { + exp = newExp + dot = j + j-- + i-- + } + } + } else { + i = dot + } + last = j + zero = false + } + b[j] = '0' + byte(digit) + j-- + mant = newMant + } + + if j > dot { + // extra zeros behind the dot + for j > dot { + b[j] = '0' + j-- + } + b[j] = '.' + } else if last+3 < dot { + // add positive exponent because we have 3 or more zeros in front of the dot + i = last + 1 + exp = dot - last - 1 + } else if j == dot { + // handle 0.1 + b[j] = '.' + } + + // exponent + if exp != 0 { + if exp == 1 { + b[i] = '0' + i++ + } else if exp == 2 { + b[i] = '0' + b[i+1] = '0' + i += 2 + } else { + b[i] = 'e' + i++ + if exp < 0 { + b[i] = '-' + i++ + exp = -exp + } + i += LenInt(int64(exp)) + j := i + for exp > 0 { + newExp := exp / 10 + digit := exp - 10*newExp + j-- + b[j] = '0' + byte(digit) + exp = newExp + } + } + } + return b[:i], true +} diff --git a/vendor/github.com/tdewolff/parse/v2/strconv/int.go b/vendor/github.com/tdewolff/parse/v2/strconv/int.go new file mode 100644 index 0000000000000..ed174e023166f --- /dev/null +++ b/vendor/github.com/tdewolff/parse/v2/strconv/int.go @@ -0,0 +1,83 @@ +package strconv + +import ( + "math" +) + +// Int parses a byte-slice and returns the integer it represents. +// If an invalid character is encountered, it will stop there. +func ParseInt(b []byte) (int64, int) { + i := 0 + neg := false + if len(b) > 0 && (b[0] == '+' || b[0] == '-') { + neg = b[0] == '-' + i++ + } + n := uint64(0) + for i < len(b) { + c := b[i] + if n > math.MaxUint64/10 { + return 0, 0 + } else if c >= '0' && c <= '9' { + n *= 10 + n += uint64(c - '0') + } else { + break + } + i++ + } + if !neg && n > uint64(math.MaxInt64) || n > uint64(math.MaxInt64)+1 { + return 0, 0 + } else if neg { + return -int64(n), i + } + return int64(n), i +} + +func LenInt(i int64) int { + if i < 0 { + if i == -9223372036854775808 { + return 19 + } + i = -i + } + switch { + case i < 10: + return 1 + case i < 100: + return 2 + case i < 1000: + return 3 + case i < 10000: + return 4 + case i < 100000: + return 5 + case i < 1000000: + return 6 + case i < 10000000: + return 7 + case i < 100000000: + return 8 + case i < 1000000000: + return 9 + case i < 10000000000: + return 10 + case i < 100000000000: + return 11 + case i < 1000000000000: + return 12 + case i < 10000000000000: + return 13 + case i < 100000000000000: + return 14 + case i < 1000000000000000: + return 15 + case i < 10000000000000000: + return 16 + case i < 100000000000000000: + return 17 + case i < 1000000000000000000: + return 18 + } + return 19 +} diff --git a/vendor/github.com/tdewolff/parse/v2/strconv/price.go b/vendor/github.com/tdewolff/parse/v2/strconv/price.go new file mode 100644 index 0000000000000..94b38343e8cdc --- /dev/null +++ b/vendor/github.com/tdewolff/parse/v2/strconv/price.go @@ -0,0 +1,83 @@ +package strconv + +// AppendPrice will append an int64 formatted as a price, where the int64 is the price in cents. +// It does not display whether a price is negative or not. +func AppendPrice(b []byte, price int64, dec bool, milSeparator byte, decSeparator byte) []byte { + if price < 0 { + if price == -9223372036854775808 { + x := []byte("92 233 720 368 547 758 08") + x[2] = milSeparator + x[6] = milSeparator + x[10] = milSeparator + x[14] = milSeparator + x[18] = milSeparator + x[22] = decSeparator + return append(b, x...) + } + price = -price + } + + // rounding + if !dec { + firstDec := (price / 10) % 10 + if firstDec >= 5 { + price += 100 + } + } + + // calculate size + n := LenInt(price) - 2 + if n > 0 { + n += (n - 1) / 3 // mil separator + } else { + n = 1 + } + if dec { + n += 2 + 1 // decimals + dec separator + } + + // resize byte slice + i := len(b) + if i+n > cap(b) { + b = append(b, make([]byte, n)...) + } else { + b = b[:i+n] + } + + // print fractional-part + i += n - 1 + if dec { + for j := 0; j < 2; j++ { + c := byte(price%10) + '0' + price /= 10 + b[i] = c + i-- + } + b[i] = decSeparator + i-- + } else { + price /= 100 + } + + if price == 0 { + b[i] = '0' + return b + } + + // print integer-part + j := 0 + for price > 0 { + if j == 3 { + b[i] = milSeparator + i-- + j = 0 + } + + c := byte(price%10) + '0' + price /= 10 + b[i] = c + i-- + j++ + } + return b +} diff --git a/vendor/github.com/tdewolff/parse/v2/svg/hash.go b/vendor/github.com/tdewolff/parse/v2/svg/hash.go new file mode 100644 index 0000000000000..58528aa6504df --- /dev/null +++ b/vendor/github.com/tdewolff/parse/v2/svg/hash.go @@ -0,0 +1,295 @@ +package svg + +// generated by hasher -type=Hash -file=hash.go; DO NOT EDIT, except for adding more constants to the list and rerun go generate + +// uses github.com/tdewolff/hasher +//go:generate hasher -type=Hash -file=hash.go + +// Hash defines perfect hashes for a predefined list of strings +type Hash uint32 + +// Unique hash definitions to be used instead of strings +const ( + A Hash = 0x101 // a + Alignment_Baseline Hash = 0x2e12 // alignment-baseline + BaseProfile Hash = 0xb // baseProfile + Baseline_Shift Hash = 0x380e // baseline-shift + Buffered_Rendering Hash = 0x5212 // buffered-rendering + Clip Hash = 0x6404 // clip + Clip_Path Hash = 0x6409 // clip-path + Clip_Rule Hash = 0x8009 // clip-rule + Color Hash = 0xd805 // color + Color_Interpolation Hash = 0xd813 // color-interpolation + Color_Interpolation_Filters Hash = 0xd81b // color-interpolation-filters + Color_Profile Hash = 0x1ea0d // color-profile + Color_Rendering Hash = 0x2250f // color-rendering + ContentScriptType Hash = 0xa011 // contentScriptType + ContentStyleType Hash = 0xb110 // contentStyleType + Cursor Hash = 0xc106 // cursor + D Hash = 0x5901 // d + Defs Hash = 0x35c04 // defs + Direction Hash = 0x2ff09 // direction + Display Hash = 0x9807 // display + Dominant_Baseline Hash = 0x18511 // dominant-baseline + Enable_Background Hash = 0x8811 // enable-background + FeImage Hash = 0x14507 // feImage + Fill Hash = 0xc904 // fill + Fill_Opacity Hash = 0x3300c // fill-opacity + Fill_Rule Hash = 0xc909 // fill-rule + Filter Hash = 0xec06 // filter + Flood_Color Hash = 0xd20b // flood-color + Flood_Opacity Hash = 0x1050d // flood-opacity + Font Hash = 0x11404 // font + Font_Family Hash = 0x1140b // font-family + Font_Size Hash = 0x11f09 // font-size + Font_Size_Adjust Hash = 0x11f10 // font-size-adjust + Font_Stretch Hash = 0x1370c // font-stretch + Font_Style Hash = 0x14c0a // font-style + Font_Variant Hash = 0x1560c // font-variant + Font_Weight Hash = 0x1620b // font-weight + G Hash = 0x1601 // g + Glyph_Orientation_Horizontal Hash = 0x1c61c // glyph-orientation-horizontal + Glyph_Orientation_Vertical Hash = 0x161a // glyph-orientation-vertical + Height Hash = 0x6c06 // height + Href Hash = 0x14204 // href + Image Hash = 0x16d05 // image + Image_Rendering Hash = 0x16d0f // image-rendering + Kerning Hash = 0x1af07 // kerning + Letter_Spacing Hash = 0x90e // letter-spacing + Lighting_Color Hash = 0x1e10e // lighting-color + Line Hash = 0x3c04 // line + Marker Hash = 0x17c06 // marker + Marker_End Hash = 0x17c0a // marker-end + Marker_Mid Hash = 0x1960a // marker-mid + Marker_Start Hash = 0x1a00c // marker-start + Mask Hash = 0x1ac04 // mask + Metadata Hash = 0x1b608 // metadata + Missing_Glyph Hash = 0x1be0d // missing-glyph + Opacity Hash = 0x10b07 // opacity + Overflow Hash = 0x25508 // overflow + Paint_Order Hash = 0x2a10b // paint-order + Path Hash = 0x6904 // path + Pattern Hash = 0x1f707 // pattern + Pointer_Events Hash = 0x1fe0e // pointer-events + Points Hash = 0x21a06 // points + Polygon Hash = 0x23407 // polygon + Polyline Hash = 0x23b08 // polyline + PreserveAspectRatio Hash = 0x24313 // preserveAspectRatio + Rect Hash = 0x30104 // rect + Rx Hash = 0x4f02 // rx + Ry Hash = 0xc602 // ry + Script Hash = 0xf206 // script + Shape_Rendering Hash = 0x20b0f // shape-rendering + Solid_Color Hash = 0x21f0b // solid-color + Solid_Opacity Hash = 0x35f0d // solid-opacity + Stop_Color Hash = 0x12d0a // stop-color + Stop_Opacity Hash = 0x2670c // stop-opacity + Stroke Hash = 0x27306 // stroke + Stroke_Dasharray Hash = 0x27310 // stroke-dasharray + Stroke_Dashoffset Hash = 0x28311 // stroke-dashoffset + Stroke_Linecap Hash = 0x2940e // stroke-linecap + Stroke_Linejoin Hash = 0x2ac0f // stroke-linejoin + Stroke_Miterlimit Hash = 0x2bb11 // stroke-miterlimit + Stroke_Opacity Hash = 0x2cc0e // stroke-opacity + Stroke_Width Hash = 0x2da0c // stroke-width + Style Hash = 0x15105 // style + Svg Hash = 0x2e603 // svg + Switch Hash = 0x2e906 // switch + Symbol Hash = 0x2ef06 // symbol + Text_Anchor Hash = 0x450b // text-anchor + Text_Decoration Hash = 0x710f // text-decoration + Text_Rendering Hash = 0xf70e // text-rendering + Type Hash = 0x11004 // type + Unicode_Bidi Hash = 0x2f50c // unicode-bidi + Use Hash = 0x30803 // use + Vector_Effect Hash = 0x30b0d // vector-effect + Version Hash = 0x31807 // version + ViewBox Hash = 0x31f07 // viewBox + Viewport_Fill Hash = 0x3270d // viewport-fill + Viewport_Fill_Opacity Hash = 0x32715 // viewport-fill-opacity + Visibility Hash = 0x33c0a // visibility + White_Space Hash = 0x25c0b // white-space + Width Hash = 0x2e105 // width + Word_Spacing Hash = 0x3460c // word-spacing + Writing_Mode Hash = 0x3520c // writing-mode + X Hash = 0x4701 // x + X1 Hash = 0x5002 // x1 + X2 Hash = 0x32502 // x2 + Xml_Space Hash = 0x36c09 // xml:space + Y Hash = 0x1801 // y + Y1 Hash = 0x9e02 // y1 + Y2 Hash = 0xc702 // y2 +) + +// String returns the hash' name. +func (i Hash) String() string { + start := uint32(i >> 8) + n := uint32(i & 0xff) + if start+n > uint32(len(_Hash_text)) { + return "" + } + return _Hash_text[start : start+n] +} + +// ToHash returns the hash whose name is s. It returns zero if there is no +// such hash. It is case sensitive. +func ToHash(s []byte) Hash { + if len(s) == 0 || len(s) > _Hash_maxLen { + return 0 + } + h := uint32(_Hash_hash0) + for i := 0; i < len(s); i++ { + h ^= uint32(s[i]) + h *= 16777619 + } + if i := _Hash_table[h&uint32(len(_Hash_table)-1)]; int(i&0xff) == len(s) { + t := _Hash_text[i>>8 : i>>8+i&0xff] + for i := 0; i < len(s); i++ { + if t[i] != s[i] { + goto NEXT + } + } + return i + } +NEXT: + if i := _Hash_table[(h>>16)&uint32(len(_Hash_table)-1)]; int(i&0xff) == len(s) { + t := _Hash_text[i>>8 : i>>8+i&0xff] + for i := 0; i < len(s); i++ { + if t[i] != s[i] { + return 0 + } + } + return i + } + return 0 +} + +const _Hash_hash0 = 0x30372d7b +const _Hash_maxLen = 28 +const _Hash_text = "baseProfiletter-spacinglyph-orientation-verticalignment-base" + + "line-shiftext-anchorx1buffered-renderingclip-patheightext-de" + + "corationclip-rulenable-backgroundisplay1contentScriptTypecon" + + "tentStyleTypecursory2fill-ruleflood-color-interpolation-filt" + + "erscriptext-renderingflood-opacitypefont-familyfont-size-adj" + + "ustop-colorfont-stretchrefeImagefont-stylefont-variantfont-w" + + "eightimage-renderingmarker-endominant-baselinemarker-midmark" + + "er-startmaskerningmetadatamissing-glyph-orientation-horizont" + + "alighting-color-profilepatternpointer-eventshape-renderingpo" + + "intsolid-color-renderingpolygonpolylinepreserveAspectRatiove" + + "rflowhite-spacestop-opacitystroke-dasharraystroke-dashoffset" + + "stroke-linecapaint-orderstroke-linejoinstroke-miterlimitstro" + + "ke-opacitystroke-widthsvgswitchsymbolunicode-bidirectionusev" + + "ector-effectversionviewBox2viewport-fill-opacityvisibilitywo" + + "rd-spacingwriting-modefsolid-opacityxml:space" + +var _Hash_table = [1 << 7]Hash{ + 0x0: 0x2940e, // stroke-linecap + 0x1: 0x1140b, // font-family + 0x2: 0x23b08, // polyline + 0x3: 0x1f707, // pattern + 0x4: 0x30104, // rect + 0x5: 0x5212, // buffered-rendering + 0x7: 0x2f50c, // unicode-bidi + 0x8: 0x450b, // text-anchor + 0x9: 0x2bb11, // stroke-miterlimit + 0xa: 0xc909, // fill-rule + 0xb: 0x27310, // stroke-dasharray + 0xc: 0xc904, // fill + 0xd: 0x1af07, // kerning + 0xe: 0x2670c, // stop-opacity + 0x10: 0x1a00c, // marker-start + 0x11: 0x380e, // baseline-shift + 0x14: 0x17c0a, // marker-end + 0x15: 0x18511, // dominant-baseline + 0x16: 0xc602, // ry + 0x17: 0x161a, // glyph-orientation-vertical + 0x18: 0x5002, // x1 + 0x19: 0x20b0f, // shape-rendering + 0x1a: 0x32502, // x2 + 0x1b: 0x11f10, // font-size-adjust + 0x1c: 0x2250f, // color-rendering + 0x1d: 0x28311, // stroke-dashoffset + 0x1f: 0x3520c, // writing-mode + 0x20: 0x2e906, // switch + 0x21: 0xf70e, // text-rendering + 0x22: 0x23407, // polygon + 0x23: 0x3460c, // word-spacing + 0x24: 0x21f0b, // solid-color + 0x25: 0xec06, // filter + 0x26: 0x1801, // y + 0x27: 0x1be0d, // missing-glyph + 0x29: 0x11404, // font + 0x2a: 0x4f02, // rx + 0x2b: 0x9807, // display + 0x2c: 0x2e603, // svg + 0x2d: 0x1050d, // flood-opacity + 0x2f: 0x14204, // href + 0x30: 0x6404, // clip + 0x31: 0x3c04, // line + 0x32: 0x1620b, // font-weight + 0x33: 0x1c61c, // glyph-orientation-horizontal + 0x34: 0x6c06, // height + 0x35: 0x9e02, // y1 + 0x36: 0x6904, // path + 0x37: 0x31807, // version + 0x38: 0x2ac0f, // stroke-linejoin + 0x39: 0x4701, // x + 0x3a: 0x30803, // use + 0x3b: 0x2cc0e, // stroke-opacity + 0x3c: 0x15105, // style + 0x3d: 0x30b0d, // vector-effect + 0x3e: 0x14c0a, // font-style + 0x40: 0x16d05, // image + 0x41: 0x1e10e, // lighting-color + 0x42: 0xd813, // color-interpolation + 0x43: 0x27306, // stroke + 0x44: 0x2ef06, // symbol + 0x47: 0x8811, // enable-background + 0x48: 0x33c0a, // visibility + 0x49: 0x25508, // overflow + 0x4b: 0x31f07, // viewBox + 0x4c: 0x2e12, // alignment-baseline + 0x4d: 0x5901, // d + 0x4e: 0x1560c, // font-variant + 0x4f: 0x1ac04, // mask + 0x50: 0x21a06, // points + 0x51: 0x1b608, // metadata + 0x52: 0x710f, // text-decoration + 0x53: 0xd81b, // color-interpolation-filters + 0x54: 0x2ff09, // direction + 0x55: 0x6409, // clip-path + 0x56: 0x2da0c, // stroke-width + 0x59: 0x35f0d, // solid-opacity + 0x5a: 0xd805, // color + 0x5b: 0xd20b, // flood-color + 0x5c: 0x1601, // g + 0x5d: 0x2e105, // width + 0x5e: 0x1ea0d, // color-profile + 0x61: 0x35c04, // defs + 0x62: 0x1370c, // font-stretch + 0x63: 0x11004, // type + 0x64: 0x8009, // clip-rule + 0x66: 0x24313, // preserveAspectRatio + 0x67: 0x14507, // feImage + 0x68: 0x36c09, // xml:space + 0x69: 0xc106, // cursor + 0x6a: 0x16d0f, // image-rendering + 0x6b: 0x90e, // letter-spacing + 0x6c: 0xf206, // script + 0x6d: 0x12d0a, // stop-color + 0x6e: 0x101, // a + 0x70: 0x10b07, // opacity + 0x71: 0xb110, // contentStyleType + 0x72: 0x1fe0e, // pointer-events + 0x73: 0xb, // baseProfile + 0x74: 0x11f09, // font-size + 0x75: 0x3270d, // viewport-fill + 0x76: 0x3300c, // fill-opacity + 0x77: 0x25c0b, // white-space + 0x79: 0x17c06, // marker + 0x7b: 0x2a10b, // paint-order + 0x7c: 0xc702, // y2 + 0x7d: 0x32715, // viewport-fill-opacity + 0x7e: 0x1960a, // marker-mid + 0x7f: 0xa011, // contentScriptType +} diff --git a/vendor/github.com/tdewolff/parse/v2/util.go b/vendor/github.com/tdewolff/parse/v2/util.go new file mode 100644 index 0000000000000..8e28c2c865397 --- /dev/null +++ b/vendor/github.com/tdewolff/parse/v2/util.go @@ -0,0 +1,197 @@ +package parse + +// Copy returns a copy of the given byte slice. +func Copy(src []byte) (dst []byte) { + dst = make([]byte, len(src)) + copy(dst, src) + return +} + +// ToLower converts all characters in the byte slice from A-Z to a-z. +func ToLower(src []byte) []byte { + for i, c := range src { + if c >= 'A' && c <= 'Z' { + src[i] = c + ('a' - 'A') + } + } + return src +} + +// EqualFold returns true when s matches case-insensitively the targetLower (which must be lowercase). +func EqualFold(s, targetLower []byte) bool { + if len(s) != len(targetLower) { + return false + } + for i, c := range targetLower { + d := s[i] + if d != c && (d < 'A' || d > 'Z' || d+('a'-'A') != c) { + return false + } + } + return true +} + +var whitespaceTable = [256]bool{ + // ASCII + false, false, false, false, false, false, false, false, + false, true, true, false, true, true, false, false, // tab, new line, form feed, carriage return + false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, + + true, false, false, false, false, false, false, false, // space + false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, + + false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, + + false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, + + // non-ASCII + false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, + + false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, + + false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, + + false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, +} + +// IsWhitespace returns true for space, \n, \r, \t, \f. +func IsWhitespace(c byte) bool { + return whitespaceTable[c] +} + +var newlineTable = [256]bool{ + // ASCII + false, false, false, false, false, false, false, false, + false, false, true, false, false, true, false, false, // new line, carriage return + false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, + + false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, + + false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, + + false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, + + // non-ASCII + false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, + + false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, + + false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, + + false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, +} + +// IsNewline returns true for \n, \r. +func IsNewline(c byte) bool { + return newlineTable[c] +} + +// IsAllWhitespace returns true when the entire byte slice consists of space, \n, \r, \t, \f. +func IsAllWhitespace(b []byte) bool { + for _, c := range b { + if !IsWhitespace(c) { + return false + } + } + return true +} + +// TrimWhitespace removes any leading and trailing whitespace characters. +func TrimWhitespace(b []byte) []byte { + n := len(b) + start := n + for i := 0; i < n; i++ { + if !IsWhitespace(b[i]) { + start = i + break + } + } + end := n + for i := n - 1; i >= start; i-- { + if !IsWhitespace(b[i]) { + end = i + 1 + break + } + } + return b[start:end] +} + +// ReplaceMultipleWhitespace replaces character series of space, \n, \t, \f, \r into a single space or newline (when the serie contained a \n or \r). +func ReplaceMultipleWhitespace(b []byte) []byte { + j := 0 + prevWS := false + hasNewline := false + for i, c := range b { + if IsWhitespace(c) { + prevWS = true + if IsNewline(c) { + hasNewline = true + } + } else { + if prevWS { + prevWS = false + if hasNewline { + hasNewline = false + b[j] = '\n' + } else { + b[j] = ' ' + } + j++ + } + b[j] = b[i] + j++ + } + } + if prevWS { + if hasNewline { + b[j] = '\n' + } else { + b[j] = ' ' + } + j++ + } + return b[:j] +} diff --git a/vendor/github.com/tdewolff/parse/v2/xml/README.md b/vendor/github.com/tdewolff/parse/v2/xml/README.md new file mode 100644 index 0000000000000..60fe3f531024b --- /dev/null +++ b/vendor/github.com/tdewolff/parse/v2/xml/README.md @@ -0,0 +1,101 @@ +# XML [![GoDoc](http://godoc.org/github.com/tdewolff/parse/xml?status.svg)](http://godoc.org/github.com/tdewolff/parse/xml) + +This package is an XML lexer written in [Go][1]. It follows the specification at [Extensible Markup Language (XML) 1.0 (Fifth Edition)](http://www.w3.org/TR/REC-xml/). The lexer takes an io.Reader and converts it into tokens until the EOF. + +## Installation +Run the following command + + go get -u github.com/tdewolff/parse/v2/xml + +or add the following import and run project with `go get` + + import "github.com/tdewolff/parse/v2/xml" + +## Lexer +### Usage +The following initializes a new Lexer with io.Reader `r`: +``` go +l := xml.NewLexer(r) +``` + +To tokenize until EOF an error, use: +``` go +for { + tt, data := l.Next() + switch tt { + case xml.ErrorToken: + // error or EOF set in l.Err() + return + case xml.StartTagToken: + // ... + for { + ttAttr, dataAttr := l.Next() + if ttAttr != xml.AttributeToken { + // handle StartTagCloseToken/StartTagCloseVoidToken/StartTagClosePIToken + break + } + // ... + } + case xml.EndTagToken: + // ... + } +} +``` + +All tokens: +``` go +ErrorToken TokenType = iota // extra token when errors occur +CommentToken +CDATAToken +StartTagToken +StartTagCloseToken +StartTagCloseVoidToken +StartTagClosePIToken +EndTagToken +AttributeToken +TextToken +``` + +### Examples +``` go +package main + +import ( + "os" + + "github.com/tdewolff/parse/v2/xml" +) + +// Tokenize XML from stdin. +func main() { + l := xml.NewLexer(os.Stdin) + for { + tt, data := l.Next() + switch tt { + case xml.ErrorToken: + if l.Err() != io.EOF { + fmt.Println("Error on line", l.Line(), ":", l.Err()) + } + return + case xml.StartTagToken: + fmt.Println("Tag", string(data)) + for { + ttAttr, dataAttr := l.Next() + if ttAttr != xml.AttributeToken { + break + } + + key := dataAttr + val := l.AttrVal() + fmt.Println("Attribute", string(key), "=", string(val)) + } + // ... + } + } +} +``` + +## License +Released under the [MIT license](https://github.com/tdewolff/parse/blob/master/LICENSE.md). + +[1]: http://golang.org/ "Go Language" diff --git a/vendor/github.com/tdewolff/parse/v2/xml/lex.go b/vendor/github.com/tdewolff/parse/v2/xml/lex.go new file mode 100644 index 0000000000000..c225babf9cc0c --- /dev/null +++ b/vendor/github.com/tdewolff/parse/v2/xml/lex.go @@ -0,0 +1,348 @@ +// Package xml is an XML1.0 lexer following the specifications at http://www.w3.org/TR/xml/. +package xml + +import ( + "io" + "strconv" + + "github.com/tdewolff/parse/v2" + "github.com/tdewolff/parse/v2/buffer" +) + +// TokenType determines the type of token, eg. a number or a semicolon. +type TokenType uint32 + +// TokenType values. +const ( + ErrorToken TokenType = iota // extra token when errors occur + CommentToken + DOCTYPEToken + CDATAToken + StartTagToken + StartTagPIToken + StartTagCloseToken + StartTagCloseVoidToken + StartTagClosePIToken + EndTagToken + AttributeToken + TextToken +) + +// String returns the string representation of a TokenType. +func (tt TokenType) String() string { + switch tt { + case ErrorToken: + return "Error" + case CommentToken: + return "Comment" + case DOCTYPEToken: + return "DOCTYPE" + case CDATAToken: + return "CDATA" + case StartTagToken: + return "StartTag" + case StartTagPIToken: + return "StartTagPI" + case StartTagCloseToken: + return "StartTagClose" + case StartTagCloseVoidToken: + return "StartTagCloseVoid" + case StartTagClosePIToken: + return "StartTagClosePI" + case EndTagToken: + return "EndTag" + case AttributeToken: + return "Attribute" + case TextToken: + return "Text" + } + return "Invalid(" + strconv.Itoa(int(tt)) + ")" +} + +//////////////////////////////////////////////////////////////// + +// Lexer is the state for the lexer. +type Lexer struct { + r *buffer.Lexer + err error + + inTag bool + + text []byte + attrVal []byte +} + +// NewLexer returns a new Lexer for a given io.Reader. +func NewLexer(r io.Reader) *Lexer { + return &Lexer{ + r: buffer.NewLexer(r), + } +} + +// Err returns the error encountered during lexing, this is often io.EOF but also other errors can be returned. +func (l *Lexer) Err() error { + if l.err != nil { + return l.err + } + return l.r.Err() +} + +// Restore restores the NULL byte at the end of the buffer. +func (l *Lexer) Restore() { + l.r.Restore() +} + +// Next returns the next Token. It returns ErrorToken when an error was encountered. Using Err() one can retrieve the error message. +func (l *Lexer) Next() (TokenType, []byte) { + l.text = nil + var c byte + if l.inTag { + l.attrVal = nil + for { // before attribute name state + if c = l.r.Peek(0); c == ' ' || c == '\t' || c == '\n' || c == '\r' { + l.r.Move(1) + continue + } + break + } + if c == 0 { + if l.r.Err() == nil { + l.err = parse.NewErrorLexer("unexpected null character", l.r) + } + return ErrorToken, nil + } else if c != '>' && (c != '/' && c != '?' || l.r.Peek(1) != '>') { + return AttributeToken, l.shiftAttribute() + } + start := l.r.Pos() + l.inTag = false + if c == '/' { + l.r.Move(2) + l.text = l.r.Lexeme()[start:] + return StartTagCloseVoidToken, l.r.Shift() + } else if c == '?' { + l.r.Move(2) + l.text = l.r.Lexeme()[start:] + return StartTagClosePIToken, l.r.Shift() + } else { + l.r.Move(1) + l.text = l.r.Lexeme()[start:] + return StartTagCloseToken, l.r.Shift() + } + } + + for { + c = l.r.Peek(0) + if c == '<' { + if l.r.Pos() > 0 { + return TextToken, l.r.Shift() + } + c = l.r.Peek(1) + if c == '/' { + l.r.Move(2) + return EndTagToken, l.shiftEndTag() + } else if c == '!' { + l.r.Move(2) + if l.at('-', '-') { + l.r.Move(2) + return CommentToken, l.shiftCommentText() + } else if l.at('[', 'C', 'D', 'A', 'T', 'A', '[') { + l.r.Move(7) + return CDATAToken, l.shiftCDATAText() + } else if l.at('D', 'O', 'C', 'T', 'Y', 'P', 'E') { + l.r.Move(7) + return DOCTYPEToken, l.shiftDOCTYPEText() + } + l.r.Move(-2) + } else if c == '?' { + l.r.Move(2) + l.inTag = true + return StartTagPIToken, l.shiftStartTag() + } + l.r.Move(1) + l.inTag = true + return StartTagToken, l.shiftStartTag() + } else if c == 0 { + if l.r.Pos() > 0 { + return TextToken, l.r.Shift() + } + if l.r.Err() == nil { + l.err = parse.NewErrorLexer("unexpected null character", l.r) + } + return ErrorToken, nil + } + l.r.Move(1) + } +} + +// Text returns the textual representation of a token. This excludes delimiters and additional leading/trailing characters. +func (l *Lexer) Text() []byte { + return l.text +} + +// AttrVal returns the attribute value when an AttributeToken was returned from Next. +func (l *Lexer) AttrVal() []byte { + return l.attrVal +} + +//////////////////////////////////////////////////////////////// + +// The following functions follow the specifications at http://www.w3.org/html/wg/drafts/html/master/syntax.html + +func (l *Lexer) shiftDOCTYPEText() []byte { + inString := false + inBrackets := false + for { + c := l.r.Peek(0) + if c == '"' { + inString = !inString + } else if (c == '[' || c == ']') && !inString { + inBrackets = (c == '[') + } else if c == '>' && !inString && !inBrackets { + l.text = l.r.Lexeme()[9:] + l.r.Move(1) + return l.r.Shift() + } else if c == 0 { + l.text = l.r.Lexeme()[9:] + return l.r.Shift() + } + l.r.Move(1) + } +} + +func (l *Lexer) shiftCDATAText() []byte { + for { + c := l.r.Peek(0) + if c == ']' && l.r.Peek(1) == ']' && l.r.Peek(2) == '>' { + l.text = l.r.Lexeme()[9:] + l.r.Move(3) + return l.r.Shift() + } else if c == 0 { + l.text = l.r.Lexeme()[9:] + return l.r.Shift() + } + l.r.Move(1) + } +} + +func (l *Lexer) shiftCommentText() []byte { + for { + c := l.r.Peek(0) + if c == '-' && l.r.Peek(1) == '-' && l.r.Peek(2) == '>' { + l.text = l.r.Lexeme()[4:] + l.r.Move(3) + return l.r.Shift() + } else if c == 0 { + return l.r.Shift() + } + l.r.Move(1) + } +} + +func (l *Lexer) shiftStartTag() []byte { + nameStart := l.r.Pos() + for { + if c := l.r.Peek(0); c == ' ' || c == '>' || (c == '/' || c == '?') && l.r.Peek(1) == '>' || c == '\t' || c == '\n' || c == '\r' || c == 0 { + break + } + l.r.Move(1) + } + l.text = l.r.Lexeme()[nameStart:] + return l.r.Shift() +} + +func (l *Lexer) shiftAttribute() []byte { + nameStart := l.r.Pos() + var c byte + for { // attribute name state + if c = l.r.Peek(0); c == ' ' || c == '=' || c == '>' || (c == '/' || c == '?') && l.r.Peek(1) == '>' || c == '\t' || c == '\n' || c == '\r' || c == 0 { + break + } + l.r.Move(1) + } + nameEnd := l.r.Pos() + for { // after attribute name state + if c = l.r.Peek(0); c == ' ' || c == '\t' || c == '\n' || c == '\r' { + l.r.Move(1) + continue + } + break + } + if c == '=' { + l.r.Move(1) + for { // before attribute value state + if c = l.r.Peek(0); c == ' ' || c == '\t' || c == '\n' || c == '\r' { + l.r.Move(1) + continue + } + break + } + attrPos := l.r.Pos() + delim := c + if delim == '"' || delim == '\'' { // attribute value single- and double-quoted state + l.r.Move(1) + for { + c = l.r.Peek(0) + if c == delim { + l.r.Move(1) + break + } else if c == 0 { + break + } + l.r.Move(1) + if c == '\t' || c == '\n' || c == '\r' { + l.r.Lexeme()[l.r.Pos()-1] = ' ' + } + } + } else { // attribute value unquoted state + for { + if c = l.r.Peek(0); c == ' ' || c == '>' || (c == '/' || c == '?') && l.r.Peek(1) == '>' || c == '\t' || c == '\n' || c == '\r' || c == 0 { + break + } + l.r.Move(1) + } + } + l.attrVal = l.r.Lexeme()[attrPos:] + } else { + l.r.Rewind(nameEnd) + l.attrVal = nil + } + l.text = l.r.Lexeme()[nameStart:nameEnd] + return l.r.Shift() +} + +func (l *Lexer) shiftEndTag() []byte { + for { + c := l.r.Peek(0) + if c == '>' { + l.text = l.r.Lexeme()[2:] + l.r.Move(1) + break + } else if c == 0 { + l.text = l.r.Lexeme()[2:] + break + } + l.r.Move(1) + } + + end := len(l.text) + for end > 0 { + if c := l.text[end-1]; c == ' ' || c == '\t' || c == '\n' || c == '\r' { + end-- + continue + } + break + } + l.text = l.text[:end] + return l.r.Shift() +} + +//////////////////////////////////////////////////////////////// + +func (l *Lexer) at(b ...byte) bool { + for i, c := range b { + if l.r.Peek(i) != c { + return false + } + } + return true +} diff --git a/vendor/github.com/tdewolff/parse/v2/xml/util.go b/vendor/github.com/tdewolff/parse/v2/xml/util.go new file mode 100644 index 0000000000000..155f3537e0385 --- /dev/null +++ b/vendor/github.com/tdewolff/parse/v2/xml/util.go @@ -0,0 +1,108 @@ +package xml + +import "github.com/tdewolff/parse/v2" + +var ( + ltEntityBytes = []byte("<") + ampEntityBytes = []byte("&") + singleQuoteEntityBytes = []byte("'") + doubleQuoteEntityBytes = []byte(""") +) + +// EscapeAttrVal returns the escape attribute value bytes without quotes. +func EscapeAttrVal(buf *[]byte, b []byte) []byte { + singles := 0 + doubles := 0 + for i, c := range b { + if c == '&' { + if quote, n := parse.QuoteEntity(b[i:]); n > 0 { + if quote == '"' { + doubles++ + } else { + singles++ + } + } + } else if c == '"' { + doubles++ + } else if c == '\'' { + singles++ + } + } + + n := len(b) + 2 + var quote byte + var escapedQuote []byte + if doubles > singles { + n += singles * 4 + quote = '\'' + escapedQuote = singleQuoteEntityBytes + } else { + n += doubles * 4 + quote = '"' + escapedQuote = doubleQuoteEntityBytes + } + if n > cap(*buf) { + *buf = make([]byte, 0, n) // maximum size, not actual size + } + t := (*buf)[:n] // maximum size, not actual size + t[0] = quote + j := 1 + start := 0 + for i, c := range b { + if c == '&' { + if entityQuote, n := parse.QuoteEntity(b[i:]); n > 0 { + j += copy(t[j:], b[start:i]) + if entityQuote != quote { + t[j] = entityQuote + j++ + } else { + j += copy(t[j:], escapedQuote) + } + start = i + n + } + } else if c == quote { + j += copy(t[j:], b[start:i]) + j += copy(t[j:], escapedQuote) + start = i + 1 + } + } + j += copy(t[j:], b[start:]) + t[j] = quote + return t[:j+1] +} + +// EscapeCDATAVal returns the escaped text bytes. +func EscapeCDATAVal(buf *[]byte, b []byte) ([]byte, bool) { + n := 0 + for _, c := range b { + if c == '<' || c == '&' { + if c == '<' { + n += 3 // < + } else { + n += 4 // & + } + if n > len("") { + return b, false + } + } + } + if len(b)+n > cap(*buf) { + *buf = make([]byte, 0, len(b)+n) + } + t := (*buf)[:len(b)+n] + j := 0 + start := 0 + for i, c := range b { + if c == '<' { + j += copy(t[j:], b[start:i]) + j += copy(t[j:], ltEntityBytes) + start = i + 1 + } else if c == '&' { + j += copy(t[j:], b[start:i]) + j += copy(t[j:], ampEntityBytes) + start = i + 1 + } + } + j += copy(t[j:], b[start:]) + return t[:j], true +} diff --git a/vendor/modules.txt b/vendor/modules.txt index c2cdd4a176f92..3f8d51abec8de 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -502,6 +502,17 @@ github.com/syndtr/goleveldb/leveldb/opt github.com/syndtr/goleveldb/leveldb/storage github.com/syndtr/goleveldb/leveldb/table github.com/syndtr/goleveldb/leveldb/util +# github.com/tdewolff/minify/v2 v2.5.1 +github.com/tdewolff/minify/v2 +github.com/tdewolff/minify/v2/css +github.com/tdewolff/minify/v2/svg +# github.com/tdewolff/parse/v2 v2.3.9 +github.com/tdewolff/parse/v2 +github.com/tdewolff/parse/v2/buffer +github.com/tdewolff/parse/v2/css +github.com/tdewolff/parse/v2/strconv +github.com/tdewolff/parse/v2/svg +github.com/tdewolff/parse/v2/xml # github.com/tinylib/msgp v1.1.1 github.com/tinylib/msgp/msgp # github.com/toqueteos/trie v1.0.0 From 6ee9fe507eac710a102d9ed384923653c1a189eb Mon Sep 17 00:00:00 2001 From: Antoine GIRARD Date: Mon, 2 Sep 2019 19:35:03 +0200 Subject: [PATCH 04/11] backup --- modules/util/svg/svg.go | 9 ++++++- modules/util/svg/svg_test.go | 48 ++++++++++++++++++++++++++++++++++++ 2 files changed, 56 insertions(+), 1 deletion(-) diff --git a/modules/util/svg/svg.go b/modules/util/svg/svg.go index 62b7eb372e46e..5928fd9240ae2 100644 --- a/modules/util/svg/svg.go +++ b/modules/util/svg/svg.go @@ -27,9 +27,16 @@ func MinifySVG(svgData io.Reader) (*bytes.Buffer, error) { func SanitizeSVG(svgData io.Reader) *bytes.Buffer { p := bluemonday.NewPolicy() p.AllowElements("svg", "title", "path", "desc", "g") - p.AllowAttrs("id", "viewbox", "role", "aria-labelledby").OnElements("svg") + p.AllowAttrs("id", "viewbox", "role", "aria-labelledby", "xmlns", "xmlns:xlink", "xml:space").OnElements("svg") p.AllowAttrs("id").OnElements("title", "desc") p.AllowAttrs("id", "data-name", "class", "aria-label").OnElements("g") p.AllowAttrs("id", "data-name", "class", "d", "transform", "aria-haspopup").OnElements("path") + p.AllowAttrs("x", "y", "width", "height").OnElements("rect") + + //var invalidID = regexp.MustCompile(`((http|ftp)s?)|(url *\( *' *//)`) + //var validID = regexp.MustCompile(`(?!((http|ftp)s?)|(url *\( *' *//))`) //not supported + //p.AllowAttrs("fill").Matching(regexp.MustCompile(`((http|ftp)s?)|(url *\( *' *//)`)).OnElements("rect") //TODO match opposite + + p.SkipElementsContent("this", "script") return p.SanitizeReader(svgData) } diff --git a/modules/util/svg/svg_test.go b/modules/util/svg/svg_test.go index 7769d38aa14d9..afd0fb8e148a3 100644 --- a/modules/util/svg/svg_test.go +++ b/modules/util/svg/svg_test.go @@ -132,6 +132,54 @@ func TestSanitizeSVG(t *testing.T) { `, }, + { + name: "badXmlTestOne", + input: ` + + + + + + + + + + shouldn't be here + + + + `, + //want: ``, + want: ``, + }, + { + name: "externalTest", + input: ` + + + + + + + + + + + `, + //want: ``, + want: ` + + + + + + + + + + `, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { From c2577d33dc22b207f7dd9ac658b32e87f62b8651 Mon Sep 17 00:00:00 2001 From: Antoine GIRARD Date: Sun, 19 Apr 2020 02:22:20 +0200 Subject: [PATCH 05/11] refresh --- go.mod | 4 +- go.sum | 6 + modules/{util/svg => image}/svg.go | 16 +- modules/{util/svg => image}/svg_test.go | 133 +- .../tdewolff/minify/v2/.goreleaser.yml | 2 +- .../github.com/tdewolff/minify/v2/.travis.yml | 8 +- .../github.com/tdewolff/minify/v2/README.md | 60 +- .../github.com/tdewolff/minify/v2/common.go | 359 ++-- .../github.com/tdewolff/minify/v2/css/css.go | 1185 +++++++----- .../github.com/tdewolff/minify/v2/css/hash.go | 957 ++++++++++ .../tdewolff/minify/v2/css/table.go | 234 +-- .../github.com/tdewolff/minify/v2/css/util.go | 55 + vendor/github.com/tdewolff/minify/v2/go.mod | 6 +- vendor/github.com/tdewolff/minify/v2/go.sum | 10 +- .../github.com/tdewolff/minify/v2/minify.go | 69 +- .../tdewolff/minify/v2/svg/buffer.go | 18 +- .../github.com/tdewolff/minify/v2/svg/hash.go | 414 +++++ .../tdewolff/minify/v2/svg/pathdata.go | 170 +- .../github.com/tdewolff/minify/v2/svg/svg.go | 270 ++- .../tdewolff/minify/v2/svg/table.go | 16 +- .../tdewolff/minify/v2/xml/buffer.go | 84 + .../tdewolff/minify/v2/xml/table.go | 8 + .../github.com/tdewolff/minify/v2/xml/xml.go | 197 ++ .../github.com/tdewolff/parse/v2/.travis.yml | 2 +- .../tdewolff/parse/v2/buffer/lexer.go | 2 +- vendor/github.com/tdewolff/parse/v2/common.go | 10 +- .../github.com/tdewolff/parse/v2/css/hash.go | 1588 ++++++++++------- .../github.com/tdewolff/parse/v2/css/lex.go | 9 +- .../github.com/tdewolff/parse/v2/css/parse.go | 13 +- .../github.com/tdewolff/parse/v2/css/util.go | 4 +- vendor/github.com/tdewolff/parse/v2/error.go | 35 +- vendor/github.com/tdewolff/parse/v2/go.mod | 4 +- vendor/github.com/tdewolff/parse/v2/go.sum | 4 +- .../github.com/tdewolff/parse/v2/position.go | 32 +- .../tdewolff/parse/v2/strconv/float.go | 14 +- .../github.com/tdewolff/parse/v2/svg/hash.go | 295 --- vendor/github.com/tdewolff/parse/v2/util.go | 274 ++- .../github.com/tdewolff/parse/v2/xml/lex.go | 40 +- .../github.com/tdewolff/parse/v2/xml/util.go | 34 +- vendor/modules.txt | 6 +- 40 files changed, 4499 insertions(+), 2148 deletions(-) rename modules/{util/svg => image}/svg.go (74%) rename modules/{util/svg => image}/svg_test.go (58%) create mode 100644 vendor/github.com/tdewolff/minify/v2/css/hash.go create mode 100644 vendor/github.com/tdewolff/minify/v2/css/util.go create mode 100644 vendor/github.com/tdewolff/minify/v2/svg/hash.go create mode 100644 vendor/github.com/tdewolff/minify/v2/xml/buffer.go create mode 100644 vendor/github.com/tdewolff/minify/v2/xml/table.go create mode 100644 vendor/github.com/tdewolff/minify/v2/xml/xml.go delete mode 100644 vendor/github.com/tdewolff/parse/v2/svg/hash.go diff --git a/go.mod b/go.mod index 9bcda32cb01a8..2cdcdc2881dbc 100644 --- a/go.mod +++ b/go.mod @@ -96,9 +96,7 @@ require ( github.com/shurcooL/vfsgen v0.0.0-20181202132449-6a9ea43bcacd github.com/steveyen/gtreap v0.0.0-20150807155958-0abe01ef9be2 // indirect github.com/stretchr/testify v1.4.0 - github.com/tdewolff/minify/v2 v2.5.1 - github.com/tdewolff/parse/v2 v2.3.9 // indirect - github.com/tdewolff/test v1.0.3 // indirect + github.com/tdewolff/minify/v2 v2.7.3 github.com/tecbot/gorocksdb v0.0.0-20181010114359-8752a9433481 // indirect github.com/tinylib/msgp v1.1.1 // indirect github.com/tstranex/u2f v1.0.0 diff --git a/go.sum b/go.sum index 96e8793cda7b0..3af3a67f3aebf 100644 --- a/go.sum +++ b/go.sum @@ -581,12 +581,18 @@ github.com/syndtr/goleveldb v1.0.0 h1:fBdIW9lB4Iz0n9khmH8w27SJ3QEJ7+IgjPEwGSZiFd github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ= github.com/tdewolff/minify/v2 v2.5.1 h1:5Or+sQBV+qUHDQG45lch0iFjUp1wxW0743nLl3qZDrs= github.com/tdewolff/minify/v2 v2.5.1/go.mod h1:ltNgpU7tnfgNCIHP1D0aS8g9IV0qP7WWP1/HdXIGznE= +github.com/tdewolff/minify/v2 v2.7.3 h1:ngzhF7SaunCtbsBjgm7WJzl9HdiKlA1gYC/Qyx9CVMo= +github.com/tdewolff/minify/v2 v2.7.3/go.mod h1:BkDSm8aMMT0ALGmpt7j3Ra7nLUgZL0qhyrAHXwxcy5w= github.com/tdewolff/parse/v2 v2.3.8/go.mod h1:HansaqmN4I/U7L6/tUp0NcwT2tFO0F4EAWYGSDzkYNk= github.com/tdewolff/parse/v2 v2.3.9 h1:d8/K6XOLy5JVpLTG9Kx+SxA72rlm5OowFmVSVgtOlmM= github.com/tdewolff/parse/v2 v2.3.9/go.mod h1:HansaqmN4I/U7L6/tUp0NcwT2tFO0F4EAWYGSDzkYNk= +github.com/tdewolff/parse/v2 v2.4.2 h1:Bu2Qv6wepkc+Ou7iB/qHjAhEImlAP5vedzlQRUdj3BI= +github.com/tdewolff/parse/v2 v2.4.2/go.mod h1:WzaJpRSbwq++EIQHYIRTpbYKNA3gn9it1Ik++q4zyho= github.com/tdewolff/test v1.0.0/go.mod h1:DiQUlutnqlEvdvhSn2LPGy4TFwRauAaYDsL+683RNX4= github.com/tdewolff/test v1.0.3 h1:oQqvxCCoUexB1bWZzvCzWG2VTqOIvWBV1JVg2OOFQi0= github.com/tdewolff/test v1.0.3/go.mod h1:6DAvZliBAAnD7rhVgwaM7DE5/d9NMOAJ09SqYqeK4QE= +github.com/tdewolff/test v1.0.6 h1:76mzYJQ83Op284kMT+63iCNCI7NEERsIN8dLM+RiKr4= +github.com/tdewolff/test v1.0.6/go.mod h1:6DAvZliBAAnD7rhVgwaM7DE5/d9NMOAJ09SqYqeK4QE= github.com/tecbot/gorocksdb v0.0.0-20181010114359-8752a9433481 h1:HOxvxvnntLiPn123Fk+twfUhCQdMDaqmb0cclArW0T0= github.com/tecbot/gorocksdb v0.0.0-20181010114359-8752a9433481/go.mod h1:ahpPrc7HpcfEWDQRZEmnXMzHY03mLDYMCxeDzy46i+8= github.com/tidwall/pretty v1.0.0 h1:HsD+QiTn7sK6flMKIvNmpqz1qrpP3Ps6jOKIKMooyg4= diff --git a/modules/util/svg/svg.go b/modules/image/svg.go similarity index 74% rename from modules/util/svg/svg.go rename to modules/image/svg.go index 5928fd9240ae2..f440071b7cb74 100644 --- a/modules/util/svg/svg.go +++ b/modules/image/svg.go @@ -1,28 +1,16 @@ -// Copyright 2019 The Gitea Authors. All rights reserved. +// Copyright 2020 The Gitea Authors. All rights reserved. // Use of this source code is governed by a MIT-style // license that can be found in the LICENSE file. -package svg +package image import ( "bytes" "io" "github.com/microcosm-cc/bluemonday" - - minify "github.com/tdewolff/minify/v2" - "github.com/tdewolff/minify/v2/svg" ) -// MinifySVG compact svg strings -func MinifySVG(svgData io.Reader) (*bytes.Buffer, error) { - m := minify.New() - m.AddFunc("image/svg+xml", svg.Minify) - var out bytes.Buffer - err := m.Minify("image/svg+xml", &out, svgData) - return &out, err -} - // SanitizeSVG remove potential malicious dom elements func SanitizeSVG(svgData io.Reader) *bytes.Buffer { p := bluemonday.NewPolicy() diff --git a/modules/util/svg/svg_test.go b/modules/image/svg_test.go similarity index 58% rename from modules/util/svg/svg_test.go rename to modules/image/svg_test.go index afd0fb8e148a3..47618da41ffcf 100644 --- a/modules/util/svg/svg_test.go +++ b/modules/image/svg_test.go @@ -1,13 +1,17 @@ -// Copyright 2019 The Gitea Authors. All rights reserved. +// Copyright 2020 The Gitea Authors. All rights reserved. // Use of this source code is governed by a MIT-style // license that can be found in the LICENSE file. -package svg +package image import ( "bytes" + "io" "testing" + minify "github.com/tdewolff/minify/v2" + "github.com/tdewolff/minify/v2/svg" + "github.com/stretchr/testify/assert" ) @@ -75,62 +79,62 @@ func TestSanitizeSVG(t *testing.T) { `, - want: ` - Pixels, My Super-friendly Cat - An illustrated gray cat with bright green blinking eyes. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + want: ` + Pixels, My Super-friendly Cat + An illustrated gray cat with bright green blinking eyes. + + + + + + + + + + + + - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - `, + `, }, { name: "badXmlTestOne", @@ -150,8 +154,7 @@ func TestSanitizeSVG(t *testing.T) { `, - //want: ``, - want: ``, + want: ``, }, { name: "externalTest", @@ -167,7 +170,6 @@ func TestSanitizeSVG(t *testing.T) { `, - //want: ``, want: ` @@ -183,11 +185,20 @@ func TestSanitizeSVG(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - out, err := MinifySVG(SanitizeSVG(bytes.NewBufferString(tt.input))) + out, err := minifySVG(SanitizeSVG(bytes.NewBufferString(tt.input))) assert.NoError(t, err) - expected, err := MinifySVG(bytes.NewBufferString(tt.want)) //Compressed to limit the way it align text on clean-up + expected, err := minifySVG(bytes.NewBufferString(tt.want)) //Compressed to limit the way it align text on clean-up assert.NoError(t, err) assert.Equal(t, expected.String(), out.String(), "The sanitized svg is not equal") }) } } + +// minifySVG compact svg strings to ease testing (could maybe usefull leter in package) +func minifySVG(svgData io.Reader) (*bytes.Buffer, error) { + m := minify.New() + m.AddFunc("image/svg+xml", svg.Minify) + var out bytes.Buffer + err := m.Minify("image/svg+xml", &out, svgData) + return &out, err +} diff --git a/vendor/github.com/tdewolff/minify/v2/.goreleaser.yml b/vendor/github.com/tdewolff/minify/v2/.goreleaser.yml index 4edcdc20a2941..32de82f413fd3 100644 --- a/vendor/github.com/tdewolff/minify/v2/.goreleaser.yml +++ b/vendor/github.com/tdewolff/minify/v2/.goreleaser.yml @@ -1,7 +1,7 @@ builds: - binary: minify main: ./cmd/minify/ - ldflags: -s -w -X main.Version={{.Version}} -X main.Commit={{.Commit}} -X main.Date={{.Date}} + ldflags: -s -w -X main.Version={{.Version}} env: - CGO_ENABLED=0 - GO111MODULE=on diff --git a/vendor/github.com/tdewolff/minify/v2/.travis.yml b/vendor/github.com/tdewolff/minify/v2/.travis.yml index 9fd1c892dce48..e08fe27a8bd43 100644 --- a/vendor/github.com/tdewolff/minify/v2/.travis.yml +++ b/vendor/github.com/tdewolff/minify/v2/.travis.yml @@ -1,6 +1,10 @@ language: go +go: + - 1.13.x +env: + - GO111MODULE=on before_install: - go get github.com/mattn/goveralls script: - - go test -v -covermode=count -coverprofile=profile.cov . ./css ./html ./js ./json ./svg ./xml - - goveralls -v -coverprofile=profile.cov -service travis-ci -repotoken $COVERALLS_TOKEN + - go test -covermode=count -coverprofile=profile.cov . ./css ./html ./js ./json ./svg ./xml + - goveralls -coverprofile=profile.cov -service travis-ci diff --git a/vendor/github.com/tdewolff/minify/v2/README.md b/vendor/github.com/tdewolff/minify/v2/README.md index 3f32185df6ee6..091e8d216897a 100644 --- a/vendor/github.com/tdewolff/minify/v2/README.md +++ b/vendor/github.com/tdewolff/minify/v2/README.md @@ -1,20 +1,14 @@ -# Minify [![Build Status](https://travis-ci.org/tdewolff/minify.svg?branch=master)](https://travis-ci.org/tdewolff/minify) [![GoDoc](http://godoc.org/github.com/tdewolff/minify?status.svg)](http://godoc.org/github.com/tdewolff/minify) [![Coverage Status](https://coveralls.io/repos/github/tdewolff/minify/badge.svg?branch=master)](https://coveralls.io/github/tdewolff/minify?branch=master) [![Join the chat at https://gitter.im/tdewolff/minify](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/tdewolff/minify?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) - -***BE AWARE: YOU NEED GO 1.9.7+, 1.10.3+, 1.11 to run the latest release!!!*** - -If you cannot upgrade Go, please pin to **minify@v2.3.6** and **parse@v2.3.4** - ---- +# Minify [![Build Status](https://travis-ci.org/tdewolff/minify.svg?branch=master)](https://travis-ci.org/tdewolff/minify) [![GoDoc](http://godoc.org/github.com/tdewolff/minify?status.svg)](http://godoc.org/github.com/tdewolff/minify) [![Coverage Status](https://coveralls.io/repos/github/tdewolff/minify/badge.svg?branch=master)](https://coveralls.io/github/tdewolff/minify?branch=master) **[Online demo](https://go.tacodewolff.nl/minify) if you need to minify files *now*.** **[Command line tool](https://github.com/tdewolff/minify/tree/master/cmd/minify) that minifies concurrently and supports watching file changes.** -**[All releases](https://github.com/tdewolff/minify/releases) for various platforms.** +**[Releases](https://github.com/tdewolff/minify/releases) of CLI for various platforms.** See [CLI](https://github.com/tdewolff/minify/tree/master/cmd/minify) for more installation instructions. --- -*Did you know that the shortest valid piece of HTML5 is `x`? See for yourself at the [W3C Validator](http://validator.w3.org/)!* +*Did you know that the shortest valid piece of HTML5 is `x`? See for yourself at the [W3C Validator](http://validator.w3.org/)!* Minify is a minifier package written in [Go][1]. It provides HTML5, CSS3, JS, JSON, SVG and XML minifiers and an interface to implement any other minifier. Minification is the process of removing bytes from a file (such as whitespace) without changing its output and therefore shrinking its size and speeding up transmission over the internet and possibly parsing. The implemented minifiers are designed for high performance. @@ -47,6 +41,10 @@ The core functionality associates mimetypes with minification functions, allowin - [Mediatypes](#mediatypes) - [Examples](#examples) - [Common minifiers](#common-minifiers) + - [External minifiers](#external-minifiers) + - [Closure Compiler](#closure-compiler) + - [UglifyJS](#uglifyjs) + - [esbuild](#esbuild) - [Custom minifier](#custom-minifier-example) - [ResponseWriter](#responsewriter) - [Templates](#templates) @@ -76,11 +74,7 @@ Minifiers or bindings to minifiers exist in almost all programming languages. So This minifier proves to be that fast and extensive minifier that can handle HTML and any other filetype it may contain (CSS, JS, ...). It is usually orders of magnitude faster than existing minifiers. ## Installation -Run the following command - - go get -u github.com/tdewolff/minify/v2 - -or add the following imports and run the project with `go get` +With modules enabled (`GO111MODULES=auto` or `GO111MODULES=on`), add the following imports and run the project with `go get` ``` go import ( "github.com/tdewolff/minify/v2" @@ -93,6 +87,8 @@ import ( ) ``` +See [CLI tool](https://github.com/tdewolff/minify/tree/master/cmd/minify) for installation instructions of the binary. + ## API stability There is no guarantee for absolute stability, but I take issues and bugs seriously and don't take API changes lightly. The library will be maintained in a compatible way unless vital bugs prevent me from doing so. There has been one API change after v1 which added options support and I took the opportunity to push through some more API clean up as well. There are no plans whatsoever for future API changes. @@ -175,6 +171,7 @@ Options: - `KeepDefaultAttrVals` preserve default attribute values such as ``, want: ` - Pixels, My Super-friendly Cat - An illustrated gray cat with bright green blinking eyes. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - `, + Pixels, My Super-friendly Cat + An illustrated gray cat with bright green blinking eyes. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +`, }, { name: "badXmlTestOne", input: ` - - - - - - - - - - shouldn't be here - - - - `, + + + + + + + + + +shouldn't be here + + +`, want: ``, }, { name: "externalTest", input: ` - - - - - - - - - - - `, + + + + + + + + + +`, want: ` - - - - - - - - - - `, + + + + + + + + +`, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - out, err := minifySVG(SanitizeSVG(bytes.NewBufferString(tt.input))) - assert.NoError(t, err) - expected, err := minifySVG(bytes.NewBufferString(tt.want)) //Compressed to limit the way it align text on clean-up - assert.NoError(t, err) - assert.Equal(t, expected.String(), out.String(), "The sanitized svg is not equal") + out := SanitizeSVG(bytes.NewBufferString(tt.input)) + assert.Equal(t, tt.want, out.String(), "The sanitized svg is not equal") }) } } From 1941e9a83a39dbceabdfadb8ac4d732d8b1ff42e Mon Sep 17 00:00:00 2001 From: Antoine GIRARD Date: Sun, 19 Apr 2020 02:54:26 +0200 Subject: [PATCH 07/11] adjsut tests taht need it --- go.mod | 1 - go.sum | 10 --- modules/image/svg.go | 14 +++- modules/image/svg_test.go | 23 ++++++- vendor/modules.txt | 139 ++++++++++++++++++++++++++++++++++++++ 5 files changed, 170 insertions(+), 17 deletions(-) diff --git a/go.mod b/go.mod index b11e16d66bc95..2cdcdc2881dbc 100644 --- a/go.mod +++ b/go.mod @@ -109,7 +109,6 @@ require ( github.com/yuin/goldmark v1.1.25 github.com/yuin/goldmark-meta v0.0.0-20191126180153-f0638e958b60 go.etcd.io/bbolt v1.3.3 // indirect - golang.org/dl v0.0.0-20200414231856-f86334ee252a // indirect golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073 golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45 diff --git a/go.sum b/go.sum index 0a2b8cd093271..e1fec8dd1d5cd 100644 --- a/go.sum +++ b/go.sum @@ -579,18 +579,10 @@ github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81P github.com/syndtr/goleveldb v0.0.0-20190203031304-2f17a3356c66/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ= github.com/syndtr/goleveldb v1.0.0 h1:fBdIW9lB4Iz0n9khmH8w27SJ3QEJ7+IgjPEwGSZiFdE= github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ= -github.com/tdewolff/minify/v2 v2.5.1 h1:5Or+sQBV+qUHDQG45lch0iFjUp1wxW0743nLl3qZDrs= -github.com/tdewolff/minify/v2 v2.5.1/go.mod h1:ltNgpU7tnfgNCIHP1D0aS8g9IV0qP7WWP1/HdXIGznE= github.com/tdewolff/minify/v2 v2.7.3 h1:ngzhF7SaunCtbsBjgm7WJzl9HdiKlA1gYC/Qyx9CVMo= github.com/tdewolff/minify/v2 v2.7.3/go.mod h1:BkDSm8aMMT0ALGmpt7j3Ra7nLUgZL0qhyrAHXwxcy5w= -github.com/tdewolff/parse/v2 v2.3.8/go.mod h1:HansaqmN4I/U7L6/tUp0NcwT2tFO0F4EAWYGSDzkYNk= -github.com/tdewolff/parse/v2 v2.3.9 h1:d8/K6XOLy5JVpLTG9Kx+SxA72rlm5OowFmVSVgtOlmM= -github.com/tdewolff/parse/v2 v2.3.9/go.mod h1:HansaqmN4I/U7L6/tUp0NcwT2tFO0F4EAWYGSDzkYNk= github.com/tdewolff/parse/v2 v2.4.2 h1:Bu2Qv6wepkc+Ou7iB/qHjAhEImlAP5vedzlQRUdj3BI= github.com/tdewolff/parse/v2 v2.4.2/go.mod h1:WzaJpRSbwq++EIQHYIRTpbYKNA3gn9it1Ik++q4zyho= -github.com/tdewolff/test v1.0.0/go.mod h1:DiQUlutnqlEvdvhSn2LPGy4TFwRauAaYDsL+683RNX4= -github.com/tdewolff/test v1.0.3 h1:oQqvxCCoUexB1bWZzvCzWG2VTqOIvWBV1JVg2OOFQi0= -github.com/tdewolff/test v1.0.3/go.mod h1:6DAvZliBAAnD7rhVgwaM7DE5/d9NMOAJ09SqYqeK4QE= github.com/tdewolff/test v1.0.6 h1:76mzYJQ83Op284kMT+63iCNCI7NEERsIN8dLM+RiKr4= github.com/tdewolff/test v1.0.6/go.mod h1:6DAvZliBAAnD7rhVgwaM7DE5/d9NMOAJ09SqYqeK4QE= github.com/tecbot/gorocksdb v0.0.0-20181010114359-8752a9433481 h1:HOxvxvnntLiPn123Fk+twfUhCQdMDaqmb0cclArW0T0= @@ -650,8 +642,6 @@ go.opencensus.io v0.22.1/go.mod h1:Ap50jQcDJrx6rB6VgeeFPtuPIf3wMRvRfrfYDO6+BmA= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= -golang.org/dl v0.0.0-20200414231856-f86334ee252a h1:44quIll1zKsynBTnvnoAHVuAGmTB9mz9meMnWEAAQ+o= -golang.org/dl v0.0.0-20200414231856-f86334ee252a/go.mod h1:IUMfjQLJQd4UTqG1Z90tenwKoCX93Gn3MAQJMOSBsDQ= golang.org/x/crypto v0.0.0-20180820150726-614d502a4dac/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= diff --git a/modules/image/svg.go b/modules/image/svg.go index f440071b7cb74..1bdab684494ef 100644 --- a/modules/image/svg.go +++ b/modules/image/svg.go @@ -5,14 +5,15 @@ package image import ( - "bytes" "io" + "regexp" + "strings" "github.com/microcosm-cc/bluemonday" ) // SanitizeSVG remove potential malicious dom elements -func SanitizeSVG(svgData io.Reader) *bytes.Buffer { +func SanitizeSVG(svgData io.Reader) string { p := bluemonday.NewPolicy() p.AllowElements("svg", "title", "path", "desc", "g") p.AllowAttrs("id", "viewbox", "role", "aria-labelledby", "xmlns", "xmlns:xlink", "xml:space").OnElements("svg") @@ -26,5 +27,12 @@ func SanitizeSVG(svgData io.Reader) *bytes.Buffer { //p.AllowAttrs("fill").Matching(regexp.MustCompile(`((http|ftp)s?)|(url *\( *' *//)`)).OnElements("rect") //TODO match opposite p.SkipElementsContent("this", "script") - return p.SanitizeReader(svgData) + cleanedSVG := p.SanitizeReader(svgData).String() + + //Remove empty lines + cleanedSVG = strings.TrimSpace(cleanedSVG) + r := regexp.MustCompile("\n+") //TODO move this somewhere else + cleanedSVG = r.ReplaceAllString(cleanedSVG, "\n") + + return cleanedSVG } diff --git a/modules/image/svg_test.go b/modules/image/svg_test.go index cd83735a16392..0cafa2afc551b 100644 --- a/modules/image/svg_test.go +++ b/modules/image/svg_test.go @@ -79,7 +79,15 @@ func TestSanitizeSVG(t *testing.T) { `, - want: ` + /* Adjustemnt from https://github.com/darylldoyle/svg-sanitizer base + Diff: + --- Expected + +++ Actual + @@ -1,2 +1,2 @@ + - + + + */ + want: ` Pixels, My Super-friendly Cat An illustrated gray cat with bright green blinking eyes. @@ -153,7 +161,16 @@ func TestSanitizeSVG(t *testing.T) { `, - want: ``, + /* Adjustemnt from https://github.com/darylldoyle/svg-sanitizer base + --- Expected + +++ Actual + @@ -1 +1,2 @@ + - + + + + + */ + want: ` +`, }, { name: "externalTest", @@ -183,7 +200,7 @@ func TestSanitizeSVG(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { out := SanitizeSVG(bytes.NewBufferString(tt.input)) - assert.Equal(t, tt.want, out.String(), "The sanitized svg is not equal") + assert.Equal(t, tt.want, out, "The sanitized svg is not equal") }) } } diff --git a/vendor/modules.txt b/vendor/modules.txt index 4b0ba011809f3..bf45ee17b4711 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -1,31 +1,44 @@ # cloud.google.com/go v0.45.0 +## explicit cloud.google.com/go/compute/metadata # gitea.com/jolheiser/gitea-vet v0.1.0 +## explicit gitea.com/jolheiser/gitea-vet gitea.com/jolheiser/gitea-vet/checks # gitea.com/lunny/levelqueue v0.2.0 +## explicit gitea.com/lunny/levelqueue # gitea.com/macaron/binding v0.0.0-20190822013154-a5f53841ed2b +## explicit gitea.com/macaron/binding # gitea.com/macaron/cache v0.0.0-20190822004001-a6e7fee4ee76 +## explicit gitea.com/macaron/cache gitea.com/macaron/cache/memcache gitea.com/macaron/cache/redis # gitea.com/macaron/captcha v0.0.0-20190822015246-daa973478bae +## explicit gitea.com/macaron/captcha # gitea.com/macaron/cors v0.0.0-20190826180238-95aec09ea8b4 +## explicit gitea.com/macaron/cors # gitea.com/macaron/csrf v0.0.0-20190822024205-3dc5a4474439 +## explicit gitea.com/macaron/csrf # gitea.com/macaron/gzip v0.0.0-20191118041502-506895b47aae +## explicit gitea.com/macaron/gzip # gitea.com/macaron/i18n v0.0.0-20190822004228-474e714e2223 +## explicit gitea.com/macaron/i18n # gitea.com/macaron/inject v0.0.0-20190805023432-d4c86e31027a +## explicit gitea.com/macaron/inject # gitea.com/macaron/macaron v1.4.0 +## explicit gitea.com/macaron/macaron # gitea.com/macaron/session v0.0.0-20191207215012-613cebf0674d +## explicit gitea.com/macaron/session gitea.com/macaron/session/couchbase gitea.com/macaron/session/memcache @@ -34,16 +47,20 @@ gitea.com/macaron/session/nodb gitea.com/macaron/session/postgres gitea.com/macaron/session/redis # gitea.com/macaron/toolbox v0.0.0-20190822013122-05ff0fc766b7 +## explicit gitea.com/macaron/toolbox # github.com/BurntSushi/toml v0.3.1 +## explicit github.com/BurntSushi/toml # github.com/PuerkitoBio/goquery v1.5.0 +## explicit github.com/PuerkitoBio/goquery # github.com/PuerkitoBio/purell v1.1.1 github.com/PuerkitoBio/purell # github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 github.com/PuerkitoBio/urlesc # github.com/RoaringBitmap/roaring v0.4.21 +## explicit github.com/RoaringBitmap/roaring # github.com/andybalholm/cascadia v1.0.0 github.com/andybalholm/cascadia @@ -55,7 +72,10 @@ github.com/asaskevich/govalidator github.com/aymerick/douceur/css # github.com/beorn7/perks v1.0.1 github.com/beorn7/perks/quantile +# github.com/bgentry/speakeasy v0.1.0 +## explicit # github.com/blevesearch/bleve v0.8.1 +## explicit github.com/blevesearch/bleve github.com/blevesearch/bleve/analysis github.com/blevesearch/bleve/analysis/analyzer/custom @@ -96,11 +116,16 @@ github.com/blevesearch/bleve/search/query github.com/blevesearch/bleve/search/scorer github.com/blevesearch/bleve/search/searcher github.com/blevesearch/bleve/size +# github.com/blevesearch/blevex v0.0.0-20180227211930-4b158bb555a3 +## explicit # github.com/blevesearch/go-porterstemmer v1.0.2 +## explicit github.com/blevesearch/go-porterstemmer # github.com/blevesearch/segment v0.0.0-20160915185041-762005e7a34f +## explicit github.com/blevesearch/segment # github.com/boombuler/barcode v0.0.0-20161226211916-fe0f26ff6d26 +## explicit github.com/boombuler/barcode github.com/boombuler/barcode/qr github.com/boombuler/barcode/utils @@ -109,34 +134,47 @@ github.com/bradfitz/gomemcache/memcache # github.com/chris-ramon/douceur v0.2.0 github.com/chris-ramon/douceur/parser # github.com/couchbase/gomemcached v0.0.0-20191004160342-7b5da2ec40b2 +## explicit github.com/couchbase/gomemcached github.com/couchbase/gomemcached/client # github.com/couchbase/goutils v0.0.0-20191018232750-b49639060d85 github.com/couchbase/goutils/logging github.com/couchbase/goutils/scramsha # github.com/couchbase/vellum v0.0.0-20190829182332-ef2e028c01fd +## explicit github.com/couchbase/vellum github.com/couchbase/vellum/levenshtein github.com/couchbase/vellum/regexp github.com/couchbase/vellum/utf8 # github.com/couchbaselabs/go-couchbase v0.0.0-20190708161019-23e7ca2ce2b7 github.com/couchbaselabs/go-couchbase +# github.com/cznic/b v0.0.0-20181122101859-a26611c4d92d +## explicit +# github.com/cznic/mathutil v0.0.0-20181122101859-297441e03548 +## explicit +# github.com/cznic/strutil v0.0.0-20181122101858-275e90344537 +## explicit # github.com/davecgh/go-spew v1.1.1 github.com/davecgh/go-spew/spew # github.com/denisenkom/go-mssqldb v0.0.0-20191128021309-1d7a30a10f73 +## explicit github.com/denisenkom/go-mssqldb github.com/denisenkom/go-mssqldb/internal/cp github.com/denisenkom/go-mssqldb/internal/decimal github.com/denisenkom/go-mssqldb/internal/querytext # github.com/dgrijalva/jwt-go v3.2.0+incompatible +## explicit github.com/dgrijalva/jwt-go # github.com/dustin/go-humanize v1.0.0 +## explicit github.com/dustin/go-humanize # github.com/editorconfig/editorconfig-core-go/v2 v2.1.1 +## explicit github.com/editorconfig/editorconfig-core-go/v2 # github.com/edsrzf/mmap-go v1.0.0 github.com/edsrzf/mmap-go # github.com/emirpasic/gods v1.12.0 +## explicit github.com/emirpasic/gods/containers github.com/emirpasic/gods/lists github.com/emirpasic/gods/lists/arraylist @@ -144,9 +182,17 @@ github.com/emirpasic/gods/trees github.com/emirpasic/gods/trees/binaryheap github.com/emirpasic/gods/utils # github.com/etcd-io/bbolt v1.3.3 +## explicit github.com/etcd-io/bbolt # github.com/ethantkoenig/rupture v0.0.0-20180203182544-0a76f03a811a +## explicit github.com/ethantkoenig/rupture +# github.com/facebookgo/ensure v0.0.0-20160127193407-b4ab57deab51 +## explicit +# github.com/facebookgo/stack v0.0.0-20160209184415-751773369052 +## explicit +# github.com/facebookgo/subset v0.0.0-20150612182917-8dac2c3c4870 +## explicit # github.com/fatih/color v1.9.0 github.com/fatih/color # github.com/fatih/structtag v1.2.0 @@ -154,10 +200,13 @@ github.com/fatih/structtag # github.com/fsnotify/fsnotify v1.4.7 github.com/fsnotify/fsnotify # github.com/gliderlabs/ssh v0.2.2 +## explicit github.com/gliderlabs/ssh # github.com/glycerine/go-unsnap-stream v0.0.0-20190901134440-81cf024a9e0a +## explicit github.com/glycerine/go-unsnap-stream # github.com/go-enry/go-enry/v2 v2.3.0 +## explicit github.com/go-enry/go-enry/v2 github.com/go-enry/go-enry/v2/data github.com/go-enry/go-enry/v2/data/rule @@ -172,12 +221,14 @@ github.com/go-git/gcfg/scanner github.com/go-git/gcfg/token github.com/go-git/gcfg/types # github.com/go-git/go-billy/v5 v5.0.0 +## explicit github.com/go-git/go-billy/v5 github.com/go-git/go-billy/v5/helper/chroot github.com/go-git/go-billy/v5/helper/polyfill github.com/go-git/go-billy/v5/osfs github.com/go-git/go-billy/v5/util # github.com/go-git/go-git/v5 v5.0.0 +## explicit github.com/go-git/go-git/v5 github.com/go-git/go-git/v5/config github.com/go-git/go-git/v5/internal/revision @@ -231,6 +282,7 @@ github.com/go-openapi/inflect # github.com/go-openapi/jsonpointer v0.19.3 github.com/go-openapi/jsonpointer # github.com/go-openapi/jsonreference v0.19.3 +## explicit github.com/go-openapi/jsonreference # github.com/go-openapi/loads v0.19.3 github.com/go-openapi/loads @@ -252,6 +304,7 @@ github.com/go-openapi/swag # github.com/go-openapi/validate v0.19.3 github.com/go-openapi/validate # github.com/go-redis/redis v6.15.2+incompatible +## explicit github.com/go-redis/redis github.com/go-redis/redis/internal github.com/go-redis/redis/internal/consistenthash @@ -260,10 +313,12 @@ github.com/go-redis/redis/internal/pool github.com/go-redis/redis/internal/proto github.com/go-redis/redis/internal/util # github.com/go-sql-driver/mysql v1.4.1 +## explicit github.com/go-sql-driver/mysql # github.com/go-stack/stack v1.8.0 github.com/go-stack/stack # github.com/go-swagger/go-swagger v0.21.0 +## explicit github.com/go-swagger/go-swagger/cmd/swagger github.com/go-swagger/go-swagger/cmd/swagger/commands github.com/go-swagger/go-swagger/cmd/swagger/commands/diff @@ -273,6 +328,7 @@ github.com/go-swagger/go-swagger/codescan github.com/go-swagger/go-swagger/generator github.com/go-swagger/go-swagger/scan # github.com/gobwas/glob v0.2.3 +## explicit github.com/gobwas/glob github.com/gobwas/glob/compiler github.com/gobwas/glob/match @@ -282,20 +338,25 @@ github.com/gobwas/glob/syntax/lexer github.com/gobwas/glob/util/runes github.com/gobwas/glob/util/strings # github.com/gogs/chardet v0.0.0-20191104214054-4b6791f73a28 +## explicit github.com/gogs/chardet # github.com/gogs/cron v0.0.0-20171120032916-9f6c956d3e14 +## explicit github.com/gogs/cron # github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe github.com/golang-sql/civil # github.com/golang/protobuf v1.3.4 +## explicit github.com/golang/protobuf/proto # github.com/golang/snappy v0.0.1 github.com/golang/snappy # github.com/google/go-github/v24 v24.0.1 +## explicit github.com/google/go-github/v24/github # github.com/google/go-querystring v1.0.0 github.com/google/go-querystring/query # github.com/gorilla/context v1.1.1 +## explicit github.com/gorilla/context # github.com/gorilla/css v1.0.0 github.com/gorilla/css/scanner @@ -319,20 +380,31 @@ github.com/hashicorp/hcl/json/parser github.com/hashicorp/hcl/json/scanner github.com/hashicorp/hcl/json/token # github.com/huandu/xstrings v1.3.0 +## explicit github.com/huandu/xstrings +# github.com/issue9/assert v1.3.2 +## explicit # github.com/issue9/identicon v0.0.0-20160320065130-d36b54562f4c +## explicit github.com/issue9/identicon # github.com/jaytaylor/html2text v0.0.0-20160923191438-8fb95d837f7d +## explicit github.com/jaytaylor/html2text # github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 github.com/jbenet/go-context/io # github.com/jessevdk/go-flags v1.4.0 github.com/jessevdk/go-flags +# github.com/jmhodges/levigo v1.0.0 +## explicit +# github.com/joho/godotenv v1.3.0 +## explicit # github.com/kballard/go-shellquote v0.0.0-20170619183022-cd60e84ee657 +## explicit github.com/kballard/go-shellquote # github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd github.com/kevinburke/ssh_config # github.com/keybase/go-crypto v0.0.0-20200123153347-de78d2cb44f4 +## explicit github.com/keybase/go-crypto/brainpool github.com/keybase/go-crypto/cast5 github.com/keybase/go-crypto/curve25519 @@ -347,6 +419,7 @@ github.com/keybase/go-crypto/openpgp/packet github.com/keybase/go-crypto/openpgp/s2k github.com/keybase/go-crypto/rsa # github.com/klauspost/compress v1.10.2 +## explicit github.com/klauspost/compress/flate github.com/klauspost/compress/gzip # github.com/kr/pretty v0.1.0 @@ -354,13 +427,16 @@ github.com/kr/pretty # github.com/kr/text v0.2.0 github.com/kr/text # github.com/lafriks/xormstore v1.3.2 +## explicit github.com/lafriks/xormstore github.com/lafriks/xormstore/util # github.com/lib/pq v1.2.0 +## explicit github.com/lib/pq github.com/lib/pq/oid github.com/lib/pq/scram # github.com/lunny/dingtalk_webhook v0.0.0-20171025031554-e3534c89ef96 +## explicit github.com/lunny/dingtalk_webhook # github.com/lunny/log v0.0.0-20160921050905-7887c61bf0de github.com/lunny/log @@ -373,11 +449,13 @@ github.com/lunny/nodb/store/goleveldb # github.com/magiconair/properties v1.8.1 github.com/magiconair/properties # github.com/mailru/easyjson v0.7.0 +## explicit github.com/mailru/easyjson github.com/mailru/easyjson/buffer github.com/mailru/easyjson/jlexer github.com/mailru/easyjson/jwriter # github.com/markbates/goth v1.61.2 +## explicit github.com/markbates/goth github.com/markbates/goth/gothic github.com/markbates/goth/providers/bitbucket @@ -395,24 +473,33 @@ github.com/markbates/goth/providers/yandex # github.com/mattn/go-colorable v0.1.4 github.com/mattn/go-colorable # github.com/mattn/go-isatty v0.0.11 +## explicit github.com/mattn/go-isatty +# github.com/mattn/go-oci8 v0.0.0-20190320171441-14ba190cf52d +## explicit # github.com/mattn/go-runewidth v0.0.7 github.com/mattn/go-runewidth # github.com/mattn/go-sqlite3 v1.11.0 +## explicit github.com/mattn/go-sqlite3 # github.com/matttproud/golang_protobuf_extensions v1.0.1 github.com/matttproud/golang_protobuf_extensions/pbutil # github.com/mcuadros/go-version v0.0.0-20190308113854-92cdf37c5b75 +## explicit github.com/mcuadros/go-version # github.com/mgechev/dots v0.0.0-20190921121421-c36f7dcfbb81 +## explicit github.com/mgechev/dots # github.com/mgechev/revive v1.0.2 +## explicit github.com/mgechev/revive/formatter github.com/mgechev/revive/lint github.com/mgechev/revive/rule # github.com/microcosm-cc/bluemonday v1.0.3-0.20191119130333-0a75d7616912 +## explicit github.com/microcosm-cc/bluemonday # github.com/mitchellh/go-homedir v1.1.0 +## explicit github.com/mitchellh/go-homedir # github.com/mitchellh/mapstructure v1.1.2 github.com/mitchellh/mapstructure @@ -421,16 +508,21 @@ github.com/mrjones/oauth # github.com/mschoch/smat v0.0.0-20160514031455-90eadee771ae github.com/mschoch/smat # github.com/msteinert/pam v0.0.0-20151204160544-02ccfbfaf0cc +## explicit github.com/msteinert/pam # github.com/nfnt/resize v0.0.0-20160724205520-891127d8d1b5 +## explicit github.com/nfnt/resize # github.com/niklasfasching/go-org v0.1.9 +## explicit github.com/niklasfasching/go-org/org # github.com/olekukonko/tablewriter v0.0.4 github.com/olekukonko/tablewriter # github.com/oliamb/cutter v0.2.2 +## explicit github.com/oliamb/cutter # github.com/olivere/elastic/v7 v7.0.9 +## explicit github.com/olivere/elastic/v7 github.com/olivere/elastic/v7/config github.com/olivere/elastic/v7/uritemplates @@ -439,37 +531,49 @@ github.com/pelletier/go-toml # github.com/philhofer/fwd v1.0.0 github.com/philhofer/fwd # github.com/pkg/errors v0.9.1 +## explicit github.com/pkg/errors # github.com/pmezard/go-difflib v1.0.0 github.com/pmezard/go-difflib/difflib # github.com/pquerna/otp v0.0.0-20160912161815-54653902c20e +## explicit github.com/pquerna/otp github.com/pquerna/otp/hotp github.com/pquerna/otp/totp # github.com/prometheus/client_golang v1.1.0 +## explicit github.com/prometheus/client_golang/prometheus github.com/prometheus/client_golang/prometheus/internal github.com/prometheus/client_golang/prometheus/promhttp # github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4 +## explicit github.com/prometheus/client_model/go # github.com/prometheus/common v0.6.0 github.com/prometheus/common/expfmt github.com/prometheus/common/internal/bitbucket.org/ww/goautoneg github.com/prometheus/common/model # github.com/prometheus/procfs v0.0.4 +## explicit github.com/prometheus/procfs github.com/prometheus/procfs/internal/fs github.com/prometheus/procfs/internal/util # github.com/quasoft/websspi v1.0.0 +## explicit github.com/quasoft/websspi github.com/quasoft/websspi/secctx +# github.com/remyoudompheng/bigfft v0.0.0-20190321074620-2f0d2b0e0001 +## explicit # github.com/satori/go.uuid v1.2.0 +## explicit github.com/satori/go.uuid # github.com/sergi/go-diff v1.1.0 +## explicit github.com/sergi/go-diff/diffmatchpatch # github.com/shurcooL/httpfs v0.0.0-20190527155220-6a4d4a70508b +## explicit github.com/shurcooL/httpfs/vfsutil # github.com/shurcooL/vfsgen v0.0.0-20181202132449-6a9ea43bcacd +## explicit github.com/shurcooL/vfsgen # github.com/siddontang/go-snappy v0.0.0-20140704025258-d8f7bb82a96d github.com/siddontang/go-snappy/snappy @@ -485,8 +589,10 @@ github.com/spf13/pflag # github.com/spf13/viper v1.4.0 github.com/spf13/viper # github.com/steveyen/gtreap v0.0.0-20150807155958-0abe01ef9be2 +## explicit github.com/steveyen/gtreap # github.com/stretchr/testify v1.4.0 +## explicit github.com/stretchr/testify/assert github.com/stretchr/testify/require # github.com/syndtr/goleveldb v1.0.0 @@ -503,6 +609,7 @@ github.com/syndtr/goleveldb/leveldb/storage github.com/syndtr/goleveldb/leveldb/table github.com/syndtr/goleveldb/leveldb/util # github.com/tdewolff/minify/v2 v2.7.3 +## explicit github.com/tdewolff/minify/v2 github.com/tdewolff/minify/v2/css github.com/tdewolff/minify/v2/svg @@ -513,32 +620,43 @@ github.com/tdewolff/parse/v2/buffer github.com/tdewolff/parse/v2/css github.com/tdewolff/parse/v2/strconv github.com/tdewolff/parse/v2/xml +# github.com/tecbot/gorocksdb v0.0.0-20181010114359-8752a9433481 +## explicit # github.com/tinylib/msgp v1.1.1 +## explicit github.com/tinylib/msgp/msgp # github.com/toqueteos/trie v1.0.0 github.com/toqueteos/trie # github.com/toqueteos/webbrowser v1.2.0 github.com/toqueteos/webbrowser # github.com/tstranex/u2f v1.0.0 +## explicit github.com/tstranex/u2f # github.com/unknwon/cae v1.0.0 +## explicit github.com/unknwon/cae github.com/unknwon/cae/zip # github.com/unknwon/com v1.0.1 +## explicit github.com/unknwon/com # github.com/unknwon/i18n v0.0.0-20190805065654-5c6446a380b6 +## explicit github.com/unknwon/i18n # github.com/unknwon/paginater v0.0.0-20151104151617-7748a72e0141 +## explicit github.com/unknwon/paginater # github.com/urfave/cli v1.20.0 +## explicit github.com/urfave/cli # github.com/willf/bitset v1.1.10 github.com/willf/bitset # github.com/xanzy/ssh-agent v0.2.1 github.com/xanzy/ssh-agent # github.com/yohcop/openid-go v0.0.0-20160914080427-2c050d2dae53 +## explicit github.com/yohcop/openid-go # github.com/yuin/goldmark v1.1.25 +## explicit github.com/yuin/goldmark github.com/yuin/goldmark/ast github.com/yuin/goldmark/extension @@ -549,7 +667,10 @@ github.com/yuin/goldmark/renderer/html github.com/yuin/goldmark/text github.com/yuin/goldmark/util # github.com/yuin/goldmark-meta v0.0.0-20191126180153-f0638e958b60 +## explicit github.com/yuin/goldmark-meta +# go.etcd.io/bbolt v1.3.3 +## explicit # go.mongodb.org/mongo-driver v1.1.1 go.mongodb.org/mongo-driver/bson go.mongodb.org/mongo-driver/bson/bsoncodec @@ -557,7 +678,10 @@ go.mongodb.org/mongo-driver/bson/bsonrw go.mongodb.org/mongo-driver/bson/bsontype go.mongodb.org/mongo-driver/bson/primitive go.mongodb.org/mongo-driver/x/bsonx/bsoncore +# golang.org/dl v0.0.0-20200414231856-f86334ee252a +## explicit # golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073 +## explicit golang.org/x/crypto/acme golang.org/x/crypto/acme/autocert golang.org/x/crypto/argon2 @@ -588,6 +712,7 @@ golang.org/x/crypto/ssh/knownhosts golang.org/x/mod/module golang.org/x/mod/semver # golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e +## explicit golang.org/x/net/context golang.org/x/net/context/ctxhttp golang.org/x/net/html @@ -597,18 +722,21 @@ golang.org/x/net/idna golang.org/x/net/internal/socks golang.org/x/net/proxy # golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45 +## explicit golang.org/x/oauth2 golang.org/x/oauth2/google golang.org/x/oauth2/internal golang.org/x/oauth2/jws golang.org/x/oauth2/jwt # golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd +## explicit golang.org/x/sys/cpu golang.org/x/sys/unix golang.org/x/sys/windows golang.org/x/sys/windows/svc golang.org/x/sys/windows/svc/debug # golang.org/x/text v0.3.2 +## explicit golang.org/x/text/encoding golang.org/x/text/encoding/charmap golang.org/x/text/encoding/htmlindex @@ -631,6 +759,7 @@ golang.org/x/text/unicode/bidi golang.org/x/text/unicode/norm golang.org/x/text/width # golang.org/x/tools v0.0.0-20200325010219-a49f79bcc224 +## explicit golang.org/x/tools/cover golang.org/x/tools/go/analysis golang.org/x/tools/go/analysis/internal/analysisflags @@ -667,16 +796,22 @@ google.golang.org/appengine/internal/remote_api google.golang.org/appengine/internal/urlfetch google.golang.org/appengine/urlfetch # gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc +## explicit gopkg.in/alexcesaro/quotedprintable.v3 # gopkg.in/asn1-ber.v1 v1.0.0-20150924051756-4e86f4367175 +## explicit gopkg.in/asn1-ber.v1 # gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df +## explicit gopkg.in/gomail.v2 # gopkg.in/ini.v1 v1.52.0 +## explicit gopkg.in/ini.v1 # gopkg.in/ldap.v3 v3.0.2 +## explicit gopkg.in/ldap.v3 # gopkg.in/testfixtures.v2 v2.5.0 +## explicit gopkg.in/testfixtures.v2 # gopkg.in/toqueteos/substring.v1 v1.0.2 gopkg.in/toqueteos/substring.v1 @@ -685,12 +820,16 @@ gopkg.in/warnings.v0 # gopkg.in/yaml.v2 v2.2.8 gopkg.in/yaml.v2 # mvdan.cc/xurls/v2 v2.1.0 +## explicit mvdan.cc/xurls/v2 # strk.kbt.io/projects/go/libravatar v0.0.0-20191008002943-06d1c002b251 +## explicit strk.kbt.io/projects/go/libravatar # xorm.io/builder v0.3.7 +## explicit xorm.io/builder # xorm.io/xorm v1.0.1 +## explicit xorm.io/xorm xorm.io/xorm/caches xorm.io/xorm/contexts From d0d6da8c5bf217451b2a35c6d08304eacdbd43eb Mon Sep 17 00:00:00 2001 From: Antoine GIRARD Date: Sun, 19 Apr 2020 03:31:53 +0200 Subject: [PATCH 08/11] add more test --- modules/image/svg.go | 14 +++-- modules/image/svg_test.go | 112 +++++++++++++++++++++++++++++++++----- 2 files changed, 109 insertions(+), 17 deletions(-) diff --git a/modules/image/svg.go b/modules/image/svg.go index 1bdab684494ef..4deef3c9ce377 100644 --- a/modules/image/svg.go +++ b/modules/image/svg.go @@ -15,16 +15,22 @@ import ( // SanitizeSVG remove potential malicious dom elements func SanitizeSVG(svgData io.Reader) string { p := bluemonday.NewPolicy() - p.AllowElements("svg", "title", "path", "desc", "g") - p.AllowAttrs("id", "viewbox", "role", "aria-labelledby", "xmlns", "xmlns:xlink", "xml:space").OnElements("svg") + p.AllowElements("svg", "title", "path", "desc", "g", "a") + p.AllowNoAttrs().OnElements("svg", "title", "desc", "g", "a") + p.AllowAttrs("id", "viewBox", "role", "aria-labelledby", "xmlns", "xmlns:xlink", "xml:space").OnElements("svg") + p.AllowAttrs("version").Matching(regexp.MustCompile(`^\d$`)).OnElements("svg") p.AllowAttrs("id").OnElements("title", "desc") p.AllowAttrs("id", "data-name", "class", "aria-label").OnElements("g") p.AllowAttrs("id", "data-name", "class", "d", "transform", "aria-haspopup").OnElements("path") - p.AllowAttrs("x", "y", "width", "height").OnElements("rect") + p.AllowAttrs("x", "y", "width", "height").OnElements("rect", "svg") + p.AllowAttrs("href", "xlink:href").Matching(regexp.MustCompile(`^#\w+$`)).OnElements("a") + + //TODO find a good way to allow relative url import //var invalidID = regexp.MustCompile(`((http|ftp)s?)|(url *\( *' *//)`) //var validID = regexp.MustCompile(`(?!((http|ftp)s?)|(url *\( *' *//))`) //not supported - //p.AllowAttrs("fill").Matching(regexp.MustCompile(`((http|ftp)s?)|(url *\( *' *//)`)).OnElements("rect") //TODO match opposite + //p.AllowAttrs("fill").Matching(regexp.MustCompile(`^(\w+)|(url\(#\w+\))$`)).OnElements("rect") + p.AllowAttrs("fill").Matching(regexp.MustCompile(`^\w+$`)).OnElements("rect") p.SkipElementsContent("this", "script") cleanedSVG := p.SanitizeReader(svgData).String() diff --git a/modules/image/svg_test.go b/modules/image/svg_test.go index 0cafa2afc551b..7a813089af372 100644 --- a/modules/image/svg_test.go +++ b/modules/image/svg_test.go @@ -79,15 +79,15 @@ func TestSanitizeSVG(t *testing.T) { `, - /* Adjustemnt from https://github.com/darylldoyle/svg-sanitizer base + /* Adjustement from https://github.com/darylldoyle/svg-sanitizer base Diff: --- Expected +++ Actual @@ -1,2 +1,2 @@ - - + + + */ - want: ` + want: ` Pixels, My Super-friendly Cat An illustrated gray cat with bright green blinking eyes. @@ -161,15 +161,14 @@ func TestSanitizeSVG(t *testing.T) { `, - /* Adjustemnt from https://github.com/darylldoyle/svg-sanitizer base + /* Adjustement from https://github.com/darylldoyle/svg-sanitizer base --- Expected +++ Actual - @@ -1 +1,2 @@ - - - + - + + @@ -1,2 +1,2 @@ + - + + */ - want: ` + want: ` `, }, { @@ -185,15 +184,102 @@ func TestSanitizeSVG(t *testing.T) { `, - want: ` - + /* Adjustement from https://github.com/darylldoyle/svg-sanitizer base + --- Expected + +++ Actual + @@ -1,2 +1 @@ + -110 + @@ -6,4 +6,4 @@ + + - + - + + + + + + FIXME: Currently this will block any fill with url. + */ + want: ` - - + + +`, + }, + { + name: "hrefTestOne", + input: ` + test 1 + test 2 + test 3 + test 4 + + test 5 + test 6 + + test 7 + test 8 +`, + /* Adjustement from https://github.com/darylldoyle/svg-sanitizer base + Diff: + --- Expected + +++ Actual + @@ -5,6 +5,4 @@ + test 4 + - + test 5 + test 6 + - + test 7 + */ + want: ` + test 1 + test 2 + test 3 + test 4 + test 5 + test 6 + test 7 + test 8 +`, + }, + { + name: "hrefTestTwo", + input: ` + test 1 + test 2 + test 3 + test 4 + + test 5 + test 6 + + test 7 + test 8 +`, + /* Adjustement from https://github.com/darylldoyle/svg-sanitizer base + Diff: + --- Expected + +++ Actual + @@ -5,6 +5,4 @@ + test 4 + - + test 5 + test 6 + - + test 7 + */ + want: ` + test 1 + test 2 + test 3 + test 4 + test 5 + test 6 + test 7 + test 8 `, }, } From 4fe54face29367247b97406f73798f434ad71f8f Mon Sep 17 00:00:00 2001 From: Antoine GIRARD Date: Sun, 19 Apr 2020 03:33:19 +0200 Subject: [PATCH 09/11] lint: misspell --- modules/image/svg.go | 1 + modules/image/svg_test.go | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/modules/image/svg.go b/modules/image/svg.go index 4deef3c9ce377..bce955fa78f0d 100644 --- a/modules/image/svg.go +++ b/modules/image/svg.go @@ -14,6 +14,7 @@ import ( // SanitizeSVG remove potential malicious dom elements func SanitizeSVG(svgData io.Reader) string { + //TODO init policy at start-up and keep it p := bluemonday.NewPolicy() p.AllowElements("svg", "title", "path", "desc", "g", "a") p.AllowNoAttrs().OnElements("svg", "title", "desc", "g", "a") diff --git a/modules/image/svg_test.go b/modules/image/svg_test.go index 7a813089af372..77254f7d488cf 100644 --- a/modules/image/svg_test.go +++ b/modules/image/svg_test.go @@ -291,7 +291,7 @@ func TestSanitizeSVG(t *testing.T) { } } -// minifySVG compact svg strings to ease testing (could maybe usefull leter in package) +// minifySVG compact svg strings to ease testing (could maybe useful leter in package) func minifySVG(svgData io.Reader) (*bytes.Buffer, error) { m := minify.New() m.AddFunc("image/svg+xml", svg.Minify) From 5b44c1606953e57a5fd21d25d99ce2f623230070 Mon Sep 17 00:00:00 2001 From: Antoine GIRARD Date: Sun, 19 Apr 2020 04:13:56 +0200 Subject: [PATCH 10/11] add mor cases --- modules/image/svg.go | 9 ++--- modules/image/svg_test.go | 75 ++++++++++++++++++++++++++++++++++----- 2 files changed, 71 insertions(+), 13 deletions(-) diff --git a/modules/image/svg.go b/modules/image/svg.go index bce955fa78f0d..b26fe04b45fd4 100644 --- a/modules/image/svg.go +++ b/modules/image/svg.go @@ -16,22 +16,23 @@ import ( func SanitizeSVG(svgData io.Reader) string { //TODO init policy at start-up and keep it p := bluemonday.NewPolicy() - p.AllowElements("svg", "title", "path", "desc", "g", "a") + p.AllowElements("svg", "title", "path", "desc", "g", "a", "line") p.AllowNoAttrs().OnElements("svg", "title", "desc", "g", "a") p.AllowAttrs("id", "viewBox", "role", "aria-labelledby", "xmlns", "xmlns:xlink", "xml:space").OnElements("svg") - p.AllowAttrs("version").Matching(regexp.MustCompile(`^\d$`)).OnElements("svg") + p.AllowAttrs("version").Matching(regexp.MustCompile(`^\d+(\.\d+)?$`)).OnElements("svg") p.AllowAttrs("id").OnElements("title", "desc") p.AllowAttrs("id", "data-name", "class", "aria-label").OnElements("g") p.AllowAttrs("id", "data-name", "class", "d", "transform", "aria-haspopup").OnElements("path") p.AllowAttrs("x", "y", "width", "height").OnElements("rect", "svg") - + p.AllowAttrs("x1", "y1", "x2", "y2").Matching(regexp.MustCompile(`^\d+(\.\d+)?$`)).OnElements("line") + p.AllowAttrs("stroke-miterlimit").Matching(regexp.MustCompile(`^\d+$`)).OnElements("line") + p.AllowAttrs("stroke", "fill").Matching(regexp.MustCompile(`^(#\d+)|(\w+)$`)).OnElements("line", "rect") p.AllowAttrs("href", "xlink:href").Matching(regexp.MustCompile(`^#\w+$`)).OnElements("a") //TODO find a good way to allow relative url import //var invalidID = regexp.MustCompile(`((http|ftp)s?)|(url *\( *' *//)`) //var validID = regexp.MustCompile(`(?!((http|ftp)s?)|(url *\( *' *//))`) //not supported //p.AllowAttrs("fill").Matching(regexp.MustCompile(`^(\w+)|(url\(#\w+\))$`)).OnElements("rect") - p.AllowAttrs("fill").Matching(regexp.MustCompile(`^\w+$`)).OnElements("rect") p.SkipElementsContent("this", "script") cleanedSVG := p.SanitizeReader(svgData).String() diff --git a/modules/image/svg_test.go b/modules/image/svg_test.go index 77254f7d488cf..a2a0fcc17a318 100644 --- a/modules/image/svg_test.go +++ b/modules/image/svg_test.go @@ -162,13 +162,27 @@ func TestSanitizeSVG(t *testing.T) { `, /* Adjustement from https://github.com/darylldoyle/svg-sanitizer base - --- Expected - +++ Actual - @@ -1,2 +1,2 @@ - - - + + --- Expected + +++ Actual + @@ -1,2 +1,9 @@ + - + + + + + + + + + + + + + + + + */ - want: ` + want: ` + + + + + + + `, }, { @@ -187,18 +201,19 @@ func TestSanitizeSVG(t *testing.T) { /* Adjustement from https://github.com/darylldoyle/svg-sanitizer base --- Expected +++ Actual - @@ -1,2 +1 @@ + @@ -1,2 +1,2 @@ -110 + - + + @@ -6,4 +6,4 @@ - - + + - FIXME: Currently this will block any fill with url. */ - want: ` + want: ` @@ -280,6 +295,48 @@ func TestSanitizeSVG(t *testing.T) { test 6 test 7 test 8 +`, + }, + { + name: "svgTestOne", + input: ` + + + + + + + + + +shouldn't be here + + +`, + /* Adjustement from https://github.com/darylldoyle/svg-sanitizer base + Diff: + --- Expected + +++ Actual + @@ -1,3 +1,2 @@ + - + - + + + + @@ -8,4 +7,2 @@ + + - + - + + */ + want: ` + + + + + + + `, }, } From f449f9110d924b3214219caa97192340a96a64b3 Mon Sep 17 00:00:00 2001 From: Antoine GIRARD Date: Sun, 19 Apr 2020 04:17:51 +0200 Subject: [PATCH 11/11] lint: remove unused --- go.mod | 1 - go.sum | 9 - modules/image/svg_test.go | 13 - .../tdewolff/minify/v2/.gitattributes | 1 - .../github.com/tdewolff/minify/v2/.gitignore | 4 - .../tdewolff/minify/v2/.goreleaser.yml | 28 - .../github.com/tdewolff/minify/v2/.travis.yml | 10 - .../github.com/tdewolff/minify/v2/LICENSE.md | 22 - .../github.com/tdewolff/minify/v2/README.md | 617 -------- .../github.com/tdewolff/minify/v2/common.go | 493 ------ .../github.com/tdewolff/minify/v2/css/css.go | 1379 ----------------- .../github.com/tdewolff/minify/v2/css/hash.go | 957 ------------ .../tdewolff/minify/v2/css/table.go | 197 --- .../github.com/tdewolff/minify/v2/css/util.go | 55 - vendor/github.com/tdewolff/minify/v2/go.mod | 14 - vendor/github.com/tdewolff/minify/v2/go.sum | 18 - .../github.com/tdewolff/minify/v2/minify.go | 352 ----- .../tdewolff/minify/v2/svg/buffer.go | 130 -- .../github.com/tdewolff/minify/v2/svg/hash.go | 414 ----- .../tdewolff/minify/v2/svg/pathdata.go | 440 ------ .../github.com/tdewolff/minify/v2/svg/svg.go | 361 ----- .../tdewolff/minify/v2/svg/table.go | 82 - .../tdewolff/minify/v2/xml/buffer.go | 84 - .../tdewolff/minify/v2/xml/table.go | 8 - .../github.com/tdewolff/minify/v2/xml/xml.go | 197 --- .../github.com/tdewolff/parse/v2/.travis.yml | 10 - .../github.com/tdewolff/parse/v2/LICENSE.md | 22 - vendor/github.com/tdewolff/parse/v2/README.md | 70 - .../tdewolff/parse/v2/buffer/buffer.go | 15 - .../tdewolff/parse/v2/buffer/lexer.go | 158 -- .../tdewolff/parse/v2/buffer/reader.go | 44 - .../tdewolff/parse/v2/buffer/streamlexer.go | 223 --- .../tdewolff/parse/v2/buffer/writer.go | 41 - vendor/github.com/tdewolff/parse/v2/common.go | 231 --- .../tdewolff/parse/v2/css/README.md | 171 -- .../github.com/tdewolff/parse/v2/css/hash.go | 957 ------------ .../github.com/tdewolff/parse/v2/css/lex.go | 717 --------- .../github.com/tdewolff/parse/v2/css/parse.go | 459 ------ .../github.com/tdewolff/parse/v2/css/util.go | 49 - vendor/github.com/tdewolff/parse/v2/error.go | 48 - vendor/github.com/tdewolff/parse/v2/go.mod | 5 - vendor/github.com/tdewolff/parse/v2/go.sum | 2 - .../github.com/tdewolff/parse/v2/position.go | 99 -- .../tdewolff/parse/v2/strconv/float.go | 251 --- .../tdewolff/parse/v2/strconv/int.go | 83 - .../tdewolff/parse/v2/strconv/price.go | 83 - vendor/github.com/tdewolff/parse/v2/util.go | 425 ----- .../tdewolff/parse/v2/xml/README.md | 101 -- .../github.com/tdewolff/parse/v2/xml/lex.go | 352 ----- .../github.com/tdewolff/parse/v2/xml/util.go | 94 -- vendor/modules.txt | 14 - 51 files changed, 10610 deletions(-) delete mode 100644 vendor/github.com/tdewolff/minify/v2/.gitattributes delete mode 100644 vendor/github.com/tdewolff/minify/v2/.gitignore delete mode 100644 vendor/github.com/tdewolff/minify/v2/.goreleaser.yml delete mode 100644 vendor/github.com/tdewolff/minify/v2/.travis.yml delete mode 100644 vendor/github.com/tdewolff/minify/v2/LICENSE.md delete mode 100644 vendor/github.com/tdewolff/minify/v2/README.md delete mode 100644 vendor/github.com/tdewolff/minify/v2/common.go delete mode 100644 vendor/github.com/tdewolff/minify/v2/css/css.go delete mode 100644 vendor/github.com/tdewolff/minify/v2/css/hash.go delete mode 100644 vendor/github.com/tdewolff/minify/v2/css/table.go delete mode 100644 vendor/github.com/tdewolff/minify/v2/css/util.go delete mode 100644 vendor/github.com/tdewolff/minify/v2/go.mod delete mode 100644 vendor/github.com/tdewolff/minify/v2/go.sum delete mode 100644 vendor/github.com/tdewolff/minify/v2/minify.go delete mode 100644 vendor/github.com/tdewolff/minify/v2/svg/buffer.go delete mode 100644 vendor/github.com/tdewolff/minify/v2/svg/hash.go delete mode 100644 vendor/github.com/tdewolff/minify/v2/svg/pathdata.go delete mode 100644 vendor/github.com/tdewolff/minify/v2/svg/svg.go delete mode 100644 vendor/github.com/tdewolff/minify/v2/svg/table.go delete mode 100644 vendor/github.com/tdewolff/minify/v2/xml/buffer.go delete mode 100644 vendor/github.com/tdewolff/minify/v2/xml/table.go delete mode 100644 vendor/github.com/tdewolff/minify/v2/xml/xml.go delete mode 100644 vendor/github.com/tdewolff/parse/v2/.travis.yml delete mode 100644 vendor/github.com/tdewolff/parse/v2/LICENSE.md delete mode 100644 vendor/github.com/tdewolff/parse/v2/README.md delete mode 100644 vendor/github.com/tdewolff/parse/v2/buffer/buffer.go delete mode 100644 vendor/github.com/tdewolff/parse/v2/buffer/lexer.go delete mode 100644 vendor/github.com/tdewolff/parse/v2/buffer/reader.go delete mode 100644 vendor/github.com/tdewolff/parse/v2/buffer/streamlexer.go delete mode 100644 vendor/github.com/tdewolff/parse/v2/buffer/writer.go delete mode 100644 vendor/github.com/tdewolff/parse/v2/common.go delete mode 100644 vendor/github.com/tdewolff/parse/v2/css/README.md delete mode 100644 vendor/github.com/tdewolff/parse/v2/css/hash.go delete mode 100644 vendor/github.com/tdewolff/parse/v2/css/lex.go delete mode 100644 vendor/github.com/tdewolff/parse/v2/css/parse.go delete mode 100644 vendor/github.com/tdewolff/parse/v2/css/util.go delete mode 100644 vendor/github.com/tdewolff/parse/v2/error.go delete mode 100644 vendor/github.com/tdewolff/parse/v2/go.mod delete mode 100644 vendor/github.com/tdewolff/parse/v2/go.sum delete mode 100644 vendor/github.com/tdewolff/parse/v2/position.go delete mode 100644 vendor/github.com/tdewolff/parse/v2/strconv/float.go delete mode 100644 vendor/github.com/tdewolff/parse/v2/strconv/int.go delete mode 100644 vendor/github.com/tdewolff/parse/v2/strconv/price.go delete mode 100644 vendor/github.com/tdewolff/parse/v2/util.go delete mode 100644 vendor/github.com/tdewolff/parse/v2/xml/README.md delete mode 100644 vendor/github.com/tdewolff/parse/v2/xml/lex.go delete mode 100644 vendor/github.com/tdewolff/parse/v2/xml/util.go diff --git a/go.mod b/go.mod index 2cdcdc2881dbc..404ca6d5c54df 100644 --- a/go.mod +++ b/go.mod @@ -96,7 +96,6 @@ require ( github.com/shurcooL/vfsgen v0.0.0-20181202132449-6a9ea43bcacd github.com/steveyen/gtreap v0.0.0-20150807155958-0abe01ef9be2 // indirect github.com/stretchr/testify v1.4.0 - github.com/tdewolff/minify/v2 v2.7.3 github.com/tecbot/gorocksdb v0.0.0-20181010114359-8752a9433481 // indirect github.com/tinylib/msgp v1.1.1 // indirect github.com/tstranex/u2f v1.0.0 diff --git a/go.sum b/go.sum index e1fec8dd1d5cd..d904ed86daf6a 100644 --- a/go.sum +++ b/go.sum @@ -96,7 +96,6 @@ github.com/boombuler/barcode v0.0.0-20161226211916-fe0f26ff6d26/go.mod h1:paBWMc github.com/bradfitz/gomemcache v0.0.0-20190329173943-551aad21a668 h1:U/lr3Dgy4WK+hNk4tyD+nuGjpVLPEHuJSFXMw11/HPA= github.com/bradfitz/gomemcache v0.0.0-20190329173943-551aad21a668/go.mod h1:H0wQNHz2YrLsuXOZozoeDmnHXkNCRmMW0gwFWDfEZDA= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= -github.com/cheekybits/is v0.0.0-20150225183255-68e9c0620927/go.mod h1:h/aW8ynjgkuj+NQRlZcDbAbM1ORAbXjXX77sX7T289U= github.com/chris-ramon/douceur v0.2.0 h1:IDMEdxlEUUBYBKE4z/mJnFyVXox+MjuEVDJNN27glkU= github.com/chris-ramon/douceur v0.2.0/go.mod h1:wDW5xjJdeoMm1mRt4sD4c/LbF/mWdEpRXQKjTR8nIBE= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= @@ -417,7 +416,6 @@ github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7 github.com/markbates/going v1.0.0/go.mod h1:I6mnB4BPnEeqo85ynXIx1ZFLLbtiLHNXVgWeFO9OGOA= github.com/markbates/goth v1.61.2 h1:jDowrUH5qw8KGuQdKwFhLzkXkTYCIPfz3LHADJsiPIs= github.com/markbates/goth v1.61.2/go.mod h1:qh2QfwZoWRucQ+DR5KVKC6dUGkNCToWh4vS45GIzFsY= -github.com/matryer/try v0.0.0-20161228173917-9ac251b645a2/go.mod h1:0KeJpeMD6o+O4hW7qJOT7vyQPKrWmj26uf5wMc/IiIs= github.com/mattn/go-colorable v0.1.4 h1:snbPLB8fVfU9iwbbo30TPtbLRzwWu6aJS6Xh4eaaviA= github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= @@ -579,12 +577,6 @@ github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81P github.com/syndtr/goleveldb v0.0.0-20190203031304-2f17a3356c66/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ= github.com/syndtr/goleveldb v1.0.0 h1:fBdIW9lB4Iz0n9khmH8w27SJ3QEJ7+IgjPEwGSZiFdE= github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ= -github.com/tdewolff/minify/v2 v2.7.3 h1:ngzhF7SaunCtbsBjgm7WJzl9HdiKlA1gYC/Qyx9CVMo= -github.com/tdewolff/minify/v2 v2.7.3/go.mod h1:BkDSm8aMMT0ALGmpt7j3Ra7nLUgZL0qhyrAHXwxcy5w= -github.com/tdewolff/parse/v2 v2.4.2 h1:Bu2Qv6wepkc+Ou7iB/qHjAhEImlAP5vedzlQRUdj3BI= -github.com/tdewolff/parse/v2 v2.4.2/go.mod h1:WzaJpRSbwq++EIQHYIRTpbYKNA3gn9it1Ik++q4zyho= -github.com/tdewolff/test v1.0.6 h1:76mzYJQ83Op284kMT+63iCNCI7NEERsIN8dLM+RiKr4= -github.com/tdewolff/test v1.0.6/go.mod h1:6DAvZliBAAnD7rhVgwaM7DE5/d9NMOAJ09SqYqeK4QE= github.com/tecbot/gorocksdb v0.0.0-20181010114359-8752a9433481 h1:HOxvxvnntLiPn123Fk+twfUhCQdMDaqmb0cclArW0T0= github.com/tecbot/gorocksdb v0.0.0-20181010114359-8752a9433481/go.mod h1:ahpPrc7HpcfEWDQRZEmnXMzHY03mLDYMCxeDzy46i+8= github.com/tidwall/pretty v1.0.0 h1:HsD+QiTn7sK6flMKIvNmpqz1qrpP3Ps6jOKIKMooyg4= @@ -713,7 +705,6 @@ golang.org/x/sys v0.0.0-20180824143301-4910a1d54f87/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181031143558-9b800f95dbbc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= diff --git a/modules/image/svg_test.go b/modules/image/svg_test.go index a2a0fcc17a318..29c6b2bcf8058 100644 --- a/modules/image/svg_test.go +++ b/modules/image/svg_test.go @@ -6,12 +6,8 @@ package image import ( "bytes" - "io" "testing" - minify "github.com/tdewolff/minify/v2" - "github.com/tdewolff/minify/v2/svg" - "github.com/stretchr/testify/assert" ) @@ -347,12 +343,3 @@ func TestSanitizeSVG(t *testing.T) { }) } } - -// minifySVG compact svg strings to ease testing (could maybe useful leter in package) -func minifySVG(svgData io.Reader) (*bytes.Buffer, error) { - m := minify.New() - m.AddFunc("image/svg+xml", svg.Minify) - var out bytes.Buffer - err := m.Minify("image/svg+xml", &out, svgData) - return &out, err -} diff --git a/vendor/github.com/tdewolff/minify/v2/.gitattributes b/vendor/github.com/tdewolff/minify/v2/.gitattributes deleted file mode 100644 index 4c50ee14b24e1..0000000000000 --- a/vendor/github.com/tdewolff/minify/v2/.gitattributes +++ /dev/null @@ -1 +0,0 @@ -benchmarks/sample_* linguist-generated=true diff --git a/vendor/github.com/tdewolff/minify/v2/.gitignore b/vendor/github.com/tdewolff/minify/v2/.gitignore deleted file mode 100644 index 3f3e864bfa62c..0000000000000 --- a/vendor/github.com/tdewolff/minify/v2/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -dist/ -benchmarks/* -!benchmarks/*.go -!benchmarks/sample_* diff --git a/vendor/github.com/tdewolff/minify/v2/.goreleaser.yml b/vendor/github.com/tdewolff/minify/v2/.goreleaser.yml deleted file mode 100644 index 32de82f413fd3..0000000000000 --- a/vendor/github.com/tdewolff/minify/v2/.goreleaser.yml +++ /dev/null @@ -1,28 +0,0 @@ -builds: - - binary: minify - main: ./cmd/minify/ - ldflags: -s -w -X main.Version={{.Version}} - env: - - CGO_ENABLED=0 - - GO111MODULE=on - goos: - - linux - - windows - - darwin - - freebsd - - netbsd - - openbsd - goarch: - - amd64 -archives: - - id: minify - format: tar.gz - format_overrides: - - goos: windows - format: zip - name_template: "{{.Binary}}_{{.Version}}_{{.Os}}_{{.Arch}}" - files: - - cmd/minify/README.md - - LICENSE.md -release: - disable: true diff --git a/vendor/github.com/tdewolff/minify/v2/.travis.yml b/vendor/github.com/tdewolff/minify/v2/.travis.yml deleted file mode 100644 index e08fe27a8bd43..0000000000000 --- a/vendor/github.com/tdewolff/minify/v2/.travis.yml +++ /dev/null @@ -1,10 +0,0 @@ -language: go -go: - - 1.13.x -env: - - GO111MODULE=on -before_install: - - go get github.com/mattn/goveralls -script: - - go test -covermode=count -coverprofile=profile.cov . ./css ./html ./js ./json ./svg ./xml - - goveralls -coverprofile=profile.cov -service travis-ci diff --git a/vendor/github.com/tdewolff/minify/v2/LICENSE.md b/vendor/github.com/tdewolff/minify/v2/LICENSE.md deleted file mode 100644 index 41677de41ec1d..0000000000000 --- a/vendor/github.com/tdewolff/minify/v2/LICENSE.md +++ /dev/null @@ -1,22 +0,0 @@ -Copyright (c) 2015 Taco de Wolff - - Permission is hereby granted, free of charge, to any person - obtaining a copy of this software and associated documentation - files (the "Software"), to deal in the Software without - restriction, including without limitation the rights to use, - copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the - Software is furnished to do so, subject to the following - conditions: - - The above copyright notice and this permission notice shall be - included in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES - OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT - HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/vendor/github.com/tdewolff/minify/v2/README.md b/vendor/github.com/tdewolff/minify/v2/README.md deleted file mode 100644 index 091e8d216897a..0000000000000 --- a/vendor/github.com/tdewolff/minify/v2/README.md +++ /dev/null @@ -1,617 +0,0 @@ -# Minify [![Build Status](https://travis-ci.org/tdewolff/minify.svg?branch=master)](https://travis-ci.org/tdewolff/minify) [![GoDoc](http://godoc.org/github.com/tdewolff/minify?status.svg)](http://godoc.org/github.com/tdewolff/minify) [![Coverage Status](https://coveralls.io/repos/github/tdewolff/minify/badge.svg?branch=master)](https://coveralls.io/github/tdewolff/minify?branch=master) - -**[Online demo](https://go.tacodewolff.nl/minify) if you need to minify files *now*.** - -**[Command line tool](https://github.com/tdewolff/minify/tree/master/cmd/minify) that minifies concurrently and supports watching file changes.** - -**[Releases](https://github.com/tdewolff/minify/releases) of CLI for various platforms.** See [CLI](https://github.com/tdewolff/minify/tree/master/cmd/minify) for more installation instructions. - ---- - -*Did you know that the shortest valid piece of HTML5 is `x`? See for yourself at the [W3C Validator](http://validator.w3.org/)!* - -Minify is a minifier package written in [Go][1]. It provides HTML5, CSS3, JS, JSON, SVG and XML minifiers and an interface to implement any other minifier. Minification is the process of removing bytes from a file (such as whitespace) without changing its output and therefore shrinking its size and speeding up transmission over the internet and possibly parsing. The implemented minifiers are designed for high performance. - -The core functionality associates mimetypes with minification functions, allowing embedded resources (like CSS or JS within HTML files) to be minified as well. Users can add new implementations that are triggered based on a mimetype (or pattern), or redirect to an external command (like ClosureCompiler, UglifyCSS, ...). - -#### Table of Contents - -- [Minify](#minify) - - [Prologue](#prologue) - - [Installation](#installation) - - [API stability](#api-stability) - - [Testing](#testing) - - [Performance](#performance) - - [HTML](#html) - - [Whitespace removal](#whitespace-removal) - - [CSS](#css) - - [JS](#js) - - [JSON](#json) - - [SVG](#svg) - - [XML](#xml) - - [Usage](#usage) - - [New](#new) - - [From reader](#from-reader) - - [From bytes](#from-bytes) - - [From string](#from-string) - - [To reader](#to-reader) - - [To writer](#to-writer) - - [Middleware](#middleware) - - [Custom minifier](#custom-minifier) - - [Mediatypes](#mediatypes) - - [Examples](#examples) - - [Common minifiers](#common-minifiers) - - [External minifiers](#external-minifiers) - - [Closure Compiler](#closure-compiler) - - [UglifyJS](#uglifyjs) - - [esbuild](#esbuild) - - [Custom minifier](#custom-minifier-example) - - [ResponseWriter](#responsewriter) - - [Templates](#templates) - - [License](#license) - -### Status - -* CSS: **fully implemented** -* HTML: **fully implemented** -* JS: improved JSmin implementation -* JSON: **fully implemented** -* SVG: partially implemented; in development -* XML: **fully implemented** - -### Roadmap - -- [ ] Use ASM/SSE to further speed-up core parts of the parsers/minifiers -- [ ] Improve JS minifiers by shortening variables and proper semicolon omission -- [ ] Speed-up SVG minifier, it is very slow -- [x] Proper parser error reporting and line number + column information -- [ ] Generation of source maps (uncertain, might slow down parsers too much if it cannot run separately nicely) -- [ ] Create a cmd to pack webfiles (much like webpack), ie. merging CSS and JS files, inlining small external files, minification and gzipping. This would work on HTML files. - -## Prologue -Minifiers or bindings to minifiers exist in almost all programming languages. Some implementations are merely using several regular expressions to trim whitespace and comments (even though regex for parsing HTML/XML is ill-advised, for a good read see [Regular Expressions: Now You Have Two Problems](http://blog.codinghorror.com/regular-expressions-now-you-have-two-problems/)). Some implementations are much more profound, such as the [YUI Compressor](http://yui.github.io/yuicompressor/) and [Google Closure Compiler](https://github.com/google/closure-compiler) for JS. As most existing implementations either use JavaScript, use regexes, and don't focus on performance, they are pretty slow. - -This minifier proves to be that fast and extensive minifier that can handle HTML and any other filetype it may contain (CSS, JS, ...). It is usually orders of magnitude faster than existing minifiers. - -## Installation -With modules enabled (`GO111MODULES=auto` or `GO111MODULES=on`), add the following imports and run the project with `go get` -``` go -import ( - "github.com/tdewolff/minify/v2" - "github.com/tdewolff/minify/v2/css" - "github.com/tdewolff/minify/v2/html" - "github.com/tdewolff/minify/v2/js" - "github.com/tdewolff/minify/v2/json" - "github.com/tdewolff/minify/v2/svg" - "github.com/tdewolff/minify/v2/xml" -) -``` - -See [CLI tool](https://github.com/tdewolff/minify/tree/master/cmd/minify) for installation instructions of the binary. - -## API stability -There is no guarantee for absolute stability, but I take issues and bugs seriously and don't take API changes lightly. The library will be maintained in a compatible way unless vital bugs prevent me from doing so. There has been one API change after v1 which added options support and I took the opportunity to push through some more API clean up as well. There are no plans whatsoever for future API changes. - -## Testing -For all subpackages and the imported `parse` package, test coverage of 100% is pursued. Besides full coverage, the minifiers are [fuzz tested](https://github.com/tdewolff/fuzz) using [github.com/dvyukov/go-fuzz](http://www.github.com/dvyukov/go-fuzz), see [the wiki](https://github.com/tdewolff/minify/wiki) for the most important bugs found by fuzz testing. These tests ensure that everything works as intended and that the code does not crash (whatever the input). If you still encounter a bug, please file a [bug report](https://github.com/tdewolff/minify/issues)! - -## Performance -The benchmarks directory contains a number of standardized samples used to compare performance between changes. To give an indication of the speed of this library, I've ran the tests on my Thinkpad T460 (i5-6300U quad-core 2.4GHz running Arch Linux) using Go 1.9.2. - -``` -name time/op -CSS/sample_bootstrap.css-4 2.26ms ± 0% -CSS/sample_gumby.css-4 2.92ms ± 1% -HTML/sample_amazon.html-4 2.33ms ± 2% -HTML/sample_bbc.html-4 1.02ms ± 1% -HTML/sample_blogpost.html-4 171µs ± 2% -HTML/sample_es6.html-4 14.5ms ± 0% -HTML/sample_stackoverflow.html-4 2.41ms ± 1% -HTML/sample_wikipedia.html-4 4.76ms ± 0% -JS/sample_ace.js-4 7.41ms ± 0% -JS/sample_dot.js-4 63.7µs ± 0% -JS/sample_jquery.js-4 2.99ms ± 0% -JS/sample_jqueryui.js-4 5.92ms ± 2% -JS/sample_moment.js-4 1.09ms ± 1% -JSON/sample_large.json-4 2.95ms ± 0% -JSON/sample_testsuite.json-4 1.51ms ± 1% -JSON/sample_twitter.json-4 6.75µs ± 1% -SVG/sample_arctic.svg-4 62.3ms ± 1% -SVG/sample_gopher.svg-4 218µs ± 0% -SVG/sample_usa.svg-4 33.1ms ± 3% -XML/sample_books.xml-4 36.2µs ± 0% -XML/sample_catalog.xml-4 14.9µs ± 0% -XML/sample_omg.xml-4 6.31ms ± 1% - -name speed -CSS/sample_bootstrap.css-4 60.8MB/s ± 0% -CSS/sample_gumby.css-4 63.9MB/s ± 1% -HTML/sample_amazon.html-4 203MB/s ± 2% -HTML/sample_bbc.html-4 113MB/s ± 1% -HTML/sample_blogpost.html-4 123MB/s ± 2% -HTML/sample_es6.html-4 70.7MB/s ± 0% -HTML/sample_stackoverflow.html-4 85.2MB/s ± 1% -HTML/sample_wikipedia.html-4 93.6MB/s ± 0% -JS/sample_ace.js-4 86.9MB/s ± 0% -JS/sample_dot.js-4 81.0MB/s ± 0% -JS/sample_jquery.js-4 82.8MB/s ± 0% -JS/sample_jqueryui.js-4 79.3MB/s ± 2% -JS/sample_moment.js-4 91.2MB/s ± 1% -JSON/sample_large.json-4 258MB/s ± 0% -JSON/sample_testsuite.json-4 457MB/s ± 1% -JSON/sample_twitter.json-4 226MB/s ± 1% -SVG/sample_arctic.svg-4 23.6MB/s ± 1% -SVG/sample_gopher.svg-4 26.7MB/s ± 0% -SVG/sample_usa.svg-4 30.9MB/s ± 3% -XML/sample_books.xml-4 122MB/s ± 0% -XML/sample_catalog.xml-4 130MB/s ± 0% -XML/sample_omg.xml-4 180MB/s ± 1% -``` - -## HTML - -HTML (with JS and CSS) minification typically shaves off about 10%. - -The HTML5 minifier uses these minifications: - -- strip unnecessary whitespace and otherwise collapse it to one space (or newline if it originally contained a newline) -- strip superfluous quotes, or uses single/double quotes whichever requires fewer escapes -- strip default attribute values and attribute boolean values -- strip some empty attributes -- strip unrequired tags (`html`, `head`, `body`, ...) -- strip unrequired end tags (`tr`, `td`, `li`, ... and often `p`) -- strip default protocols (`http:`, `https:` and `javascript:`) -- strip all comments (including conditional comments, old IE versions are not supported anymore by Microsoft) -- shorten `doctype` and `meta` charset -- lowercase tags, attributes and some values to enhance gzip compression - -Options: - -- `KeepConditionalComments` preserve all IE conditional comments such as `` and ``, see https://msdn.microsoft.com/en-us/library/ms537512(v=vs.85).aspx#syntax -- `KeepDefaultAttrVals` preserve default attribute values such as `

  • ` that have `display:inline-block` applied and have whitespace in between them. It is bad practise to rely on whitespace for element positioning anyways! - -## CSS - -Minification typically shaves off about 10%-15%. This CSS minifier will _not_ do structural changes to your stylesheets. Although this could result in smaller files, the complexity is quite high and the risk of breaking website is high too. - -The CSS minifier will only use safe minifications: - -- remove comments and unnecessary whitespace (but keep `/*! ... */` which usually contains the license) -- remove trailing semicolons -- optimize `margin`, `padding` and `border-width` number of sides -- shorten numbers by removing unnecessary `+` and zeros and rewriting with/without exponent -- remove dimension and percentage for zero values -- remove quotes for URLs -- remove quotes for font families and make lowercase -- rewrite hex colors to/from color names, or to three digit hex -- rewrite `rgb(`, `rgba(`, `hsl(` and `hsla(` colors to hex or name -- use four digit hex for alpha values (`transparent` → `#0000`) -- replace `normal` and `bold` by numbers for `font-weight` and `font` -- replace `none` → `0` for `border`, `background` and `outline` -- lowercase all identifiers except classes, IDs and URLs to enhance gzip compression -- shorten MS alpha function -- rewrite data URIs with base64 or ASCII whichever is shorter -- calls minifier for data URI mediatypes, thus you can compress embedded SVG files if you have that minifier attached -- shorten aggregate declarations such as `background` and `font` - -It does purposely not use the following techniques: - -- (partially) merge rulesets -- (partially) split rulesets -- collapse multiple declarations when main declaration is defined within a ruleset (don't put `font-weight` within an already existing `font`, too complex) -- remove overwritten properties in ruleset (this not always overwrites it, for example with `!important`) -- rewrite properties into one ruleset if possible (like `margin-top`, `margin-right`, `margin-bottom` and `margin-left` → `margin`) -- put nested ID selector at the front (`body > div#elem p` → `#elem p`) -- rewrite attribute selectors for IDs and classes (`div[id=a]` → `div#a`) -- put space after pseudo-selectors (IE6 is old, move on!) - -There are a couple of comparison tables online, such as [CSS Minifier Comparison](http://www.codenothing.com/benchmarks/css-compressor-3.0/full.html), [CSS minifiers comparison](http://www.phpied.com/css-minifiers-comparison/) and [CleanCSS tests](http://goalsmashers.github.io/css-minification-benchmark/). Comparing speed between each, this minifier will usually be between 10x-300x faster than existing implementations, and even rank among the top for minification ratios. It falls short with the purposely not implemented and often unsafe techniques. - -Options: - -- `KeepCSS2` prohibits using CSS3 syntax (such as exponents in numbers, or `rgba(` → `rgb(`), might be incomplete -- `Precision` number of significant digits to preserve for numbers, `0` means no trimming - -## JS - -The JS minifier is pretty basic. It removes comments, whitespace and line breaks whenever it can. It employs all the rules that [JSMin](http://www.crockford.com/javascript/jsmin.html) does too, but has additional improvements. For example the prefix-postfix bug is fixed. - -Common speeds of PHP and JS implementations are about 100-300kB/s (see [Uglify2](http://lisperator.net/uglifyjs/), [Adventures in PHP web asset minimization](https://www.happyassassin.net/2014/12/29/adventures-in-php-web-asset-minimization/)). This implementation or orders of magnitude faster, around ~80MB/s. - -TODO: -- shorten local variables / function parameters names -- precise semicolon and newline omission - -## JSON - -Minification typically shaves off about 15% of filesize for common indented JSON such as generated by [JSON Generator](http://www.json-generator.com/). - -The JSON minifier only removes whitespace, which is the only thing that can be left out. - -## SVG - -The SVG minifier uses these minifications: - -- trim and collapse whitespace between all tags -- strip comments, empty `doctype`, XML prelude, `metadata` -- strip SVG version -- strip CDATA sections wherever possible -- collapse tags with no content to a void tag -- minify style tag and attributes with the CSS minifier -- minify colors -- shorten lengths and numbers and remove default `px` unit -- shorten `path` data -- use relative or absolute positions in path data whichever is shorter - -TODO: -- convert attributes to style attribute whenever shorter -- merge path data? (same style and no intersection -- the latter is difficult) - -Options: - -- `Precision` number of significant digits to preserve for numbers, `0` means no trimming - -## XML - -The XML minifier uses these minifications: - -- strip unnecessary whitespace and otherwise collapse it to one space (or newline if it originally contained a newline) -- strip comments -- collapse tags with no content to a void tag -- strip CDATA sections wherever possible - -Options: - -- `KeepWhitespace` preserve whitespace between inline tags but still collapse multiple whitespace characters into one - -## Usage -Any input stream is being buffered by the minification functions. This is how the underlying buffer package inherently works to ensure high performance. The output stream however is not buffered. It is wise to preallocate a buffer as big as the input to which the output is written, or otherwise use `bufio` to buffer to a streaming writer. - -### New -Retrieve a minifier struct which holds a map of mediatype → minifier functions. -``` go -m := minify.New() -``` - -The following loads all provided minifiers. -``` go -m := minify.New() -m.AddFunc("text/css", css.Minify) -m.AddFunc("text/html", html.Minify) -m.AddFunc("image/svg+xml", svg.Minify) -m.AddFuncRegexp(regexp.MustCompile("^(application|text)/(x-)?(java|ecma)script$"), js.Minify) -m.AddFuncRegexp(regexp.MustCompile("[/+]json$"), json.Minify) -m.AddFuncRegexp(regexp.MustCompile("[/+]xml$"), xml.Minify) -``` - -You can set options to several minifiers. -``` go -m.Add("text/html", &html.Minifier{ - KeepDefaultAttrVals: true, - KeepWhitespace: true, -}) -``` - -### From reader -Minify from an `io.Reader` to an `io.Writer` for a specific mediatype. -``` go -if err := m.Minify(mediatype, w, r); err != nil { - panic(err) -} -``` - -### From bytes -Minify from and to a `[]byte` for a specific mediatype. -``` go -b, err = m.Bytes(mediatype, b) -if err != nil { - panic(err) -} -``` - -### From string -Minify from and to a `string` for a specific mediatype. -``` go -s, err = m.String(mediatype, s) -if err != nil { - panic(err) -} -``` - -### To reader -Get a minifying reader for a specific mediatype. -``` go -mr := m.Reader(mediatype, r) -if _, err := mr.Read(b); err != nil { - panic(err) -} -``` - -### To writer -Get a minifying writer for a specific mediatype. Must be explicitly closed because it uses an `io.Pipe` underneath. -``` go -mw := m.Writer(mediatype, w) -if mw.Write([]byte("input")); err != nil { - panic(err) -} -if err := mw.Close(); err != nil { - panic(err) -} -``` - -### Middleware -Minify resources on the fly using middleware. It passes a wrapped response writer to the handler that removes the Content-Length header. The minifier is chosen based on the Content-Type header or, if the header is empty, by the request URI file extension. This is on-the-fly processing, you should preferably cache the results though! -``` go -fs := http.FileServer(http.Dir("www/")) -http.Handle("/", m.Middleware(fs)) -``` - -### Custom minifier -Add a minifier for a specific mimetype. -``` go -type CustomMinifier struct { - KeepLineBreaks bool -} - -func (c *CustomMinifier) Minify(m *minify.M, w io.Writer, r io.Reader, params map[string]string) error { - // ... - return nil -} - -m.Add(mimetype, &CustomMinifier{KeepLineBreaks: true}) -// or -m.AddRegexp(regexp.MustCompile("/x-custom$"), &CustomMinifier{KeepLineBreaks: true}) -``` - -Add a minify function for a specific mimetype. -``` go -m.AddFunc(mimetype, func(m *minify.M, w io.Writer, r io.Reader, params map[string]string) error { - // ... - return nil -}) -m.AddFuncRegexp(regexp.MustCompile("/x-custom$"), func(m *minify.M, w io.Writer, r io.Reader, params map[string]string) error { - // ... - return nil -}) -``` - -Add a command `cmd` with arguments `args` for a specific mimetype. -``` go -m.AddCmd(mimetype, exec.Command(cmd, args...)) -m.AddCmdRegexp(regexp.MustCompile("/x-custom$"), exec.Command(cmd, args...)) -``` - -### Mediatypes -Using the `params map[string]string` argument one can pass parameters to the minifier such as seen in mediatypes (`type/subtype; key1=val2; key2=val2`). Examples are the encoding or charset of the data. Calling `Minify` will split the mimetype and parameters for the minifiers for you, but `MinifyMimetype` can be used if you already have them split up. - -Minifiers can also be added using a regular expression. For example a minifier with `image/.*` will match any image mime. - -## Examples -### Common minifiers -Basic example that minifies from stdin to stdout and loads the default HTML, CSS and JS minifiers. Optionally, one can enable `java -jar build/compiler.jar` to run for JS (for example the [ClosureCompiler](https://code.google.com/p/closure-compiler/)). Note that reading the file into a buffer first and writing to a pre-allocated buffer would be faster (but would disable streaming). -``` go -package main - -import ( - "log" - "os" - "os/exec" - - "github.com/tdewolff/minify/v2" - "github.com/tdewolff/minify/v2/css" - "github.com/tdewolff/minify/v2/html" - "github.com/tdewolff/minify/v2/js" - "github.com/tdewolff/minify/v2/json" - "github.com/tdewolff/minify/v2/svg" - "github.com/tdewolff/minify/v2/xml" -) - -func main() { - m := minify.New() - m.AddFunc("text/css", css.Minify) - m.AddFunc("text/html", html.Minify) - m.AddFunc("image/svg+xml", svg.Minify) - m.AddFuncRegexp(regexp.MustCompile("^(application|text)/(x-)?(java|ecma)script$"), js.Minify) - m.AddFuncRegexp(regexp.MustCompile("[/+]json$"), json.Minify) - m.AddFuncRegexp(regexp.MustCompile("[/+]xml$"), xml.Minify) - - if err := m.Minify("text/html", os.Stdout, os.Stdin); err != nil { - panic(err) - } -} -``` - -### External minifiers -Below are some examples of using common external minifiers. - -#### Closure Compiler -See [Closure Compiler Application](https://developers.google.com/closure/compiler/docs/gettingstarted_app). Not tested. - -``` go -m.AddCmdRegexp(regexp.MustCompile("^(application|text)/(x-)?(java|ecma)script$"), - exec.Command("java", "-jar", "build/compiler.jar")) -``` - -### UglifyJS -See [UglifyJS](https://github.com/mishoo/UglifyJS2). - -``` go -m.AddCmdRegexp(regexp.MustCompile("^(application|text)/(x-)?(java|ecma)script$"), - exec.Command("uglifyjs")) -``` - -### esbuild -See [esbuild](https://github.com/evanw/esbuild). - -``` go -m.AddCmdRegexp(regexp.MustCompile("^(application|text)/(x-)?(java|ecma)script$"), - exec.Command("esbuild", "$in.js", "--minify", "--outfile=$out.js")) -``` - -### Custom minifier -Custom minifier showing an example that implements the minifier function interface. Within a custom minifier, it is possible to call any minifier function (through `m minify.Minifier`) recursively when dealing with embedded resources. -``` go -package main - -import ( - "bufio" - "fmt" - "io" - "log" - "strings" - - "github.com/tdewolff/minify/v2" -) - -func main() { - m := minify.New() - m.AddFunc("text/plain", func(m *minify.M, w io.Writer, r io.Reader, _ map[string]string) error { - // remove newlines and spaces - rb := bufio.NewReader(r) - for { - line, err := rb.ReadString('\n') - if err != nil && err != io.EOF { - return err - } - if _, errws := io.WriteString(w, strings.Replace(line, " ", "", -1)); errws != nil { - return errws - } - if err == io.EOF { - break - } - } - return nil - }) - - in := "Because my coffee was too cold, I heated it in the microwave." - out, err := m.String("text/plain", in) - if err != nil { - panic(err) - } - fmt.Println(out) - // Output: Becausemycoffeewastoocold,Iheateditinthemicrowave. -} -``` - -### ResponseWriter -#### Middleware -``` go -func main() { - m := minify.New() - m.AddFunc("text/css", css.Minify) - m.AddFunc("text/html", html.Minify) - m.AddFunc("image/svg+xml", svg.Minify) - m.AddFuncRegexp(regexp.MustCompile("^(application|text)/(x-)?(java|ecma)script$"), js.Minify) - m.AddFuncRegexp(regexp.MustCompile("[/+]json$"), json.Minify) - m.AddFuncRegexp(regexp.MustCompile("[/+]xml$"), xml.Minify) - - fs := http.FileServer(http.Dir("www/")) - http.Handle("/", m.Middleware(fs)) -} -``` - -#### ResponseWriter -``` go -func Serve(w http.ResponseWriter, r *http.Request) { - mw := m.ResponseWriter(w, r) - defer mw.Close() - w = mw - - http.ServeFile(w, r, path.Join("www", r.URL.Path)) -} -``` - -#### Custom response writer -ResponseWriter example which returns a ResponseWriter that minifies the content and then writes to the original ResponseWriter. Any write after applying this filter will be minified. -``` go -type MinifyResponseWriter struct { - http.ResponseWriter - io.WriteCloser -} - -func (m MinifyResponseWriter) Write(b []byte) (int, error) { - return m.WriteCloser.Write(b) -} - -// MinifyResponseWriter must be closed explicitly by calling site. -func MinifyFilter(mediatype string, res http.ResponseWriter) MinifyResponseWriter { - m := minify.New() - // add minfiers - - mw := m.Writer(mediatype, res) - return MinifyResponseWriter{res, mw} -} -``` - -``` go -// Usage -func(w http.ResponseWriter, req *http.Request) { - w = MinifyFilter("text/html", w) - if _, err := io.WriteString(w, "

    This HTTP response will be minified.

    "); err != nil { - panic(err) - } - if err := w.Close(); err != nil { - panic(err) - } - // Output:

    This HTTP response will be minified. -} -``` - -### Templates - -Here's an example of a replacement for `template.ParseFiles` from `template/html`, which automatically minifies each template before parsing it. - -Be aware that minifying templates will work in most cases but not all. Because the HTML minifier only works for valid HTML5, your template must be valid HTML5 of itself. Template tags are parsed as regular text by the minifier. - -``` go -func compileTemplates(filenames ...string) (*template.Template, error) { - m := minify.New() - m.AddFunc("text/html", html.Minify) - - var tmpl *template.Template - for _, filename := range filenames { - name := filepath.Base(filename) - if tmpl == nil { - tmpl = template.New(name) - } else { - tmpl = tmpl.New(name) - } - - b, err := ioutil.ReadFile(filename) - if err != nil { - return nil, err - } - - mb, err := m.Bytes("text/html", b) - if err != nil { - return nil, err - } - tmpl.Parse(string(mb)) - } - return tmpl, nil -} -``` - -Example usage: - -``` go -templates := template.Must(compileTemplates("view.html", "home.html")) -``` - -## License -Released under the [MIT license](LICENSE.md). - -[1]: http://golang.org/ "Go Language" diff --git a/vendor/github.com/tdewolff/minify/v2/common.go b/vendor/github.com/tdewolff/minify/v2/common.go deleted file mode 100644 index 17787f08394c2..0000000000000 --- a/vendor/github.com/tdewolff/minify/v2/common.go +++ /dev/null @@ -1,493 +0,0 @@ -package minify - -import ( - "encoding/base64" - - "github.com/tdewolff/parse/v2" - "github.com/tdewolff/parse/v2/strconv" -) - -// Epsilon is the closest number to zero that is not considered to be zero. -var Epsilon = 0.00001 - -// Mediatype minifies a given mediatype by removing all whitespace. -func Mediatype(b []byte) []byte { - j := 0 - start := 0 - inString := false - for i, c := range b { - if !inString && parse.IsWhitespace(c) { - if start != 0 { - j += copy(b[j:], b[start:i]) - } else { - j += i - } - start = i + 1 - } else if c == '"' { - inString = !inString - } - } - if start != 0 { - j += copy(b[j:], b[start:]) - return parse.ToLower(b[:j]) - } - return parse.ToLower(b) -} - -// DataURI minifies a data URI and calls a minifier by the specified mediatype. Specifications: https://www.ietf.org/rfc/rfc2397.txt. -func DataURI(m *M, dataURI []byte) []byte { - origData := parse.Copy(dataURI) - mediatype, data, err := parse.DataURI(dataURI) - if err != nil { - return dataURI - } - - data, _ = m.Bytes(string(mediatype), data) - base64Len := len(";base64") + base64.StdEncoding.EncodedLen(len(data)) - asciiLen := len(data) - for _, c := range data { - if parse.URLEncodingTable[c] { - asciiLen += 2 - } - if asciiLen > base64Len { - break - } - } - if len(origData) < base64Len && len(origData) < asciiLen { - return origData - } - if base64Len < asciiLen { - encoded := make([]byte, base64Len-len(";base64")) - base64.StdEncoding.Encode(encoded, data) - data = encoded - mediatype = append(mediatype, []byte(";base64")...) - } else { - data = parse.EncodeURL(data, parse.URLEncodingTable) - } - if len("text/plain") <= len(mediatype) && parse.EqualFold(mediatype[:len("text/plain")], []byte("text/plain")) { - mediatype = mediatype[len("text/plain"):] - } - for i := 0; i+len(";charset=us-ascii") <= len(mediatype); i++ { - // must start with semicolon and be followed by end of mediatype or semicolon - if mediatype[i] == ';' && parse.EqualFold(mediatype[i+1:i+len(";charset=us-ascii")], []byte("charset=us-ascii")) && (i+len(";charset=us-ascii") >= len(mediatype) || mediatype[i+len(";charset=us-ascii")] == ';') { - mediatype = append(mediatype[:i], mediatype[i+len(";charset=us-ascii"):]...) - break - } - } - return append(append(append([]byte("data:"), mediatype...), ','), data...) -} - -const MaxInt = int(^uint(0) >> 1) -const MinInt = -MaxInt - 1 - -// Decimal minifies a given byte slice containing a number (see parse.Number) and removes superfluous characters. -// It does not parse or output exponents. prec is the number of significant digits. When prec is zero it will keep all digits. Only digits after the dot can be removed to reach the number of significant digits. Very large number may thus have more significant digits. -func Decimal(num []byte, prec int) []byte { - if len(num) <= 1 { - return num - } - - // omit first + and register mantissa start and end, whether it's negative and the exponent - neg := false - start := 0 - dot := -1 - end := len(num) - if 0 < end && (num[0] == '+' || num[0] == '-') { - if num[0] == '-' { - neg = true - } - start++ - } - for i, c := range num[start:] { - if c == '.' { - dot = start + i - break - } - } - if dot == -1 { - dot = end - } - - // trim leading zeros but leave at least one digit - for start < end-1 && num[start] == '0' { - start++ - } - // trim trailing zeros - i := end - 1 - for ; dot < i; i-- { - if num[i] != '0' { - end = i + 1 - break - } - } - if i == dot { - end = dot - if start == end { - num[start] = '0' - return num[start : start+1] - } - } else if start == end-1 && num[start] == '0' { - return num[start:end] - } - - // apply precision - if 0 < prec && dot <= start+prec { - precEnd := start + prec + 1 // include dot - if dot == start { // for numbers like .012 - digit := start + 1 - for digit < end && num[digit] == '0' { - digit++ - } - precEnd = digit + prec - } - if precEnd < end { - end = precEnd - - // process either an increase from a lesser significant decimal (>= 5) - // or remove trailing zeros after the dot, or both - i := end - 1 - inc := '5' <= num[end] - for ; start < i; i-- { - if i == dot { - // no-op - } else if inc && num[i] != '9' { - num[i]++ - inc = false - break - } else if inc && i < dot { // end inc for integer - num[i] = '0' - } else if !inc && (i < dot || num[i] != '0') { - break - } - } - if i < dot { - end = dot - } else { - end = i + 1 - } - - if inc { - if dot == start && end == start+1 { - num[start] = '1' - } else if num[start] == '9' { - num[start] = '1' - num[start+1] = '0' - end++ - } else { - num[start]++ - } - } - } - } - - if neg { - start-- - num[start] = '-' - } - return num[start:end] -} - -// Number minifies a given byte slice containing a number (see parse.Number) and removes superfluous characters. -func Number(num []byte, prec int) []byte { - if len(num) <= 1 { - return num - } - - // omit first + and register mantissa start and end, whether it's negative and the exponent - neg := false - start := 0 - dot := -1 - end := len(num) - origExp := 0 - if num[0] == '+' || num[0] == '-' { - if num[0] == '-' { - neg = true - } - start++ - } - for i, c := range num[start:] { - if c == '.' { - dot = start + i - } else if c == 'e' || c == 'E' { - end = start + i - i += start + 1 - if i < len(num) && num[i] == '+' { - i++ - } - if tmpOrigExp, n := strconv.ParseInt(num[i:]); 0 < n && int64(MinInt) <= tmpOrigExp && tmpOrigExp <= int64(MaxInt) { - // range checks for when int is 32 bit - origExp = int(tmpOrigExp) - } else { - return num - } - break - } - } - if dot == -1 { - dot = end - } - - // trim leading zeros but leave at least one digit - for start < end-1 && num[start] == '0' { - start++ - } - // trim trailing zeros - i := end - 1 - for ; dot < i; i-- { - if num[i] != '0' { - end = i + 1 - break - } - } - if i == dot { - end = dot - if start == end { - num[start] = '0' - return num[start : start+1] - } - } else if start == end-1 && num[start] == '0' { - return num[start:end] - } - - // apply precision - if 0 < prec { //&& (dot <= start+prec || start+prec+1 < dot || 0 < origExp) { // don't minify 9 to 10, but do 999 to 1e3 and 99e1 to 1e3 - precEnd := start + prec - if dot == start { // for numbers like .012 - digit := start + 1 - for digit < end && num[digit] == '0' { - digit++ - } - precEnd = digit + prec - } else if dot < precEnd { // for numbers where precision will include the dot - precEnd++ - } - if precEnd < end && (dot < end || 1 < dot-precEnd+origExp) { // do not minify 9=>10 or 99=>100 or 9e1=>1e2 (but 90), but 999=>1e3 and 99e1=>1e3 - end = precEnd - inc := '5' <= num[end] - if dot == end { - inc = end+1 < len(num) && '5' <= num[end+1] - } - if precEnd < dot { - origExp += dot - precEnd - dot = precEnd - } - // process either an increase from a lesser significant decimal (>= 5) - // and remove trailing zeros - i := end - 1 - for ; start < i; i-- { - if i == dot { - // no-op - } else if inc && num[i] != '9' { - num[i]++ - inc = false - break - } else if !inc && num[i] != '0' { - break - } - } - end = i + 1 - if end < dot { - origExp += dot - end - dot = end - } - if inc { // single digit left - if dot == start { - num[start] = '1' - dot = start + 1 - } else if num[start] == '9' { - num[start] = '1' - origExp++ - } else { - num[start]++ - } - } - } - } - - // n is the number of significant digits - // normExp would be the exponent if it were normalised (0.1 <= f < 1) - n := 0 - normExp := 0 - if dot == start { - for i = dot + 1; i < end; i++ { - if num[i] != '0' { - n = end - i - normExp = dot - i + 1 - break - } - } - } else if dot == end { - normExp = end - start - for i = end - 1; start <= i; i-- { - if num[i] != '0' { - n = i + 1 - start - end = i + 1 - break - } - } - } else { - n = end - start - 1 - normExp = dot - start - } - - if origExp < 0 && (normExp < MinInt-origExp || normExp-n < MinInt-origExp) || 0 < origExp && (MaxInt-origExp < normExp || MaxInt-origExp < normExp-n) { - return num // exponent overflow - } - normExp += origExp - - // intExp would be the exponent if it were an integer - intExp := normExp - n - lenIntExp := strconv.LenInt(int64(intExp)) - lenNormExp := strconv.LenInt(int64(normExp)) - - // there are three cases to consider when printing the number - // case 1: without decimals and with a positive exponent (large numbers: 5e4) - // case 2: with decimals and with a negative exponent (small numbers with many digits: .123456e-4) - // case 3: with decimals and without an exponent (around zero: 5.6) - // case 4: without decimals and with a negative exponent (small numbers: 123456e-9) - if n <= normExp { - // case 1: print number with positive exponent - if dot < end { - // remove dot, either from the front or copy the smallest part - if dot == start { - start = end - n - } else if dot-start < end-dot-1 { - copy(num[start+1:], num[start:dot]) - start++ - } else { - copy(num[dot:], num[dot+1:end]) - end-- - } - } - if n+3 <= normExp { - num[end] = 'e' - end++ - for i := end + lenIntExp - 1; end <= i; i-- { - num[i] = byte(intExp%10) + '0' - intExp /= 10 - } - end += lenIntExp - } else if n+2 == normExp { - num[end] = '0' - num[end+1] = '0' - end += 2 - } else if n+1 == normExp { - num[end] = '0' - end++ - } - } else if normExp < -3 && lenNormExp < lenIntExp { - // case 2: print normalized number (0.1 <= f < 1) - zeroes := -normExp + origExp - if 0 < zeroes { - copy(num[start+1:], num[start+1+zeroes:end]) - end -= zeroes - } else if zeroes < 0 { - copy(num[start+1:], num[start:dot]) - num[start] = '.' - } - num[end] = 'e' - num[end+1] = '-' - end += 2 - for i := end + lenNormExp - 1; end <= i; i-- { - num[i] = -byte(normExp%10) + '0' - normExp /= 10 - } - end += lenNormExp - } else if -lenIntExp-1 <= normExp { - // case 3: print number without exponent - zeroes := -normExp - if 0 < zeroes { - // dot placed at the front and negative exponent, adding zeroes - newDot := end - n - zeroes - 1 - if newDot != dot { - d := start - newDot - if 0 < d { - if dot < end { - // copy original digits after the dot towards the end - copy(num[dot+1+d:], num[dot+1:end]) - if start < dot { - // copy original digits before the dot towards the end - copy(num[start+d+1:], num[start:dot]) - } - } else if start < dot { - // copy original digits before the dot towards the end - copy(num[start+d:], num[start:dot]) - } - newDot = start - end += d - } else { - start += -d - } - num[newDot] = '.' - for i := 0; i < zeroes; i++ { - num[newDot+1+i] = '0' - } - } - } else { - // dot placed in the middle of the number - if dot == start { - // when there are zeroes after the dot - dot = end - n - 1 - start = dot - } else if end <= dot { - // when input has no dot in it - dot = end - end++ - } - newDot := start + normExp - // move digits between dot and newDot towards the end - if dot < newDot { - copy(num[dot:], num[dot+1:newDot+1]) - } else if newDot < dot { - copy(num[newDot+1:], num[newDot:dot]) - } - num[newDot] = '.' - } - } else { - // case 4: print number with negative exponent - // find new end, considering moving numbers to the front, removing the dot and increasing the length of the exponent - newEnd := end - if dot == start { - newEnd = start + n - } else { - newEnd-- - } - newEnd += 2 + lenIntExp - - exp := intExp - lenExp := lenIntExp - if newEnd < len(num) { - // it saves space to convert the decimal to an integer and decrease the exponent - if dot < end { - if dot == start { - copy(num[start:], num[end-n:end]) - end = start + n - } else { - copy(num[dot:], num[dot+1:end]) - end-- - } - } - } else { - // it does not save space and will panic, so we revert to the original representation - exp = origExp - lenExp = 1 - if origExp <= -10 || 10 <= origExp { - lenExp = strconv.LenInt(int64(origExp)) - } - } - num[end] = 'e' - num[end+1] = '-' - end += 2 - for i := end + lenExp - 1; end <= i; i-- { - num[i] = -byte(exp%10) + '0' - exp /= 10 - } - end += lenExp - } - - if neg { - start-- - num[start] = '-' - } - return num[start:end] -} diff --git a/vendor/github.com/tdewolff/minify/v2/css/css.go b/vendor/github.com/tdewolff/minify/v2/css/css.go deleted file mode 100644 index 21998e9607838..0000000000000 --- a/vendor/github.com/tdewolff/minify/v2/css/css.go +++ /dev/null @@ -1,1379 +0,0 @@ -// Package css minifies CSS3 following the specifications at http://www.w3.org/TR/css-syntax-3/. -package css - -import ( - "bytes" - "fmt" - "io" - "math" - "strconv" - - "github.com/tdewolff/minify/v2" - "github.com/tdewolff/parse/v2" - "github.com/tdewolff/parse/v2/css" - strconvParse "github.com/tdewolff/parse/v2/strconv" -) - -var ( - spaceBytes = []byte(" ") - colonBytes = []byte(":") - semicolonBytes = []byte(";") - commaBytes = []byte(",") - leftBracketBytes = []byte("{") - rightBracketBytes = []byte("}") - zeroBytes = []byte("0") - transparentBytes = []byte("transparent") - initialBytes = []byte("initial") - importantBytes = []byte("!important") - dataSchemeBytes = []byte("data:") -) - -type cssMinifier struct { - m *minify.M - w io.Writer - p *css.Parser - o *Minifier - - tokenBuffer []Token -} - -//////////////////////////////////////////////////////////////// - -// DEPRECATED: DefaultMinifier is the default minifier. -var DefaultMinifier = &Minifier{} - -// Minifier is a CSS minifier. -type Minifier struct { - KeepCSS2 bool - Decimals int // DEPRECATED - Precision int // number of significant digits - newPrecision int // precision for new numbers -} - -// Minify minifies CSS data, it reads from r and writes to w. -func Minify(m *minify.M, w io.Writer, r io.Reader, params map[string]string) error { - return (&Minifier{}).Minify(m, w, r, params) -} - -type Token struct { - css.TokenType - Data []byte - Args []Token // only filled for functions - Fun, Ident Hash // only filled for functions and identifiers respectively -} - -func (t Token) String() string { - if len(t.Args) == 0 { - return t.TokenType.String() + "(" + string(t.Data) + ")" - } - return fmt.Sprint(t.Args) -} - -func (a Token) Equal(b Token) bool { - if a.TokenType == b.TokenType && bytes.Equal(a.Data, b.Data) && len(a.Args) == len(b.Args) { - for i := 0; i < len(a.Args); i++ { - if a.Args[i].TokenType != b.Args[i].TokenType || !bytes.Equal(a.Args[i].Data, b.Args[i].Data) { - return false - } - } - return true - } - return false -} - -func (t Token) IsZero() bool { - // as each number is already minified, starting with a zero means it is zero - return (t.TokenType == css.DimensionToken || t.TokenType == css.PercentageToken || t.TokenType == css.NumberToken) && t.Data[0] == '0' -} - -func (t Token) IsLength() bool { - if t.TokenType == css.DimensionToken { - return true - } else if t.TokenType == css.NumberToken && t.Data[0] == '0' { - return true - } else if t.TokenType == css.FunctionToken { - fun := ToHash(t.Data[:len(t.Data)-1]) - if fun == Calc || fun == Min || fun == Max || fun == Clamp || fun == Attr || fun == Var || fun == Env { - return true - } - } - return false -} - -func (t Token) IsLengthPercentage() bool { - return t.TokenType == css.PercentageToken || t.IsLength() -} - -// Minify minifies CSS data, it reads from r and writes to w. -func (o *Minifier) Minify(m *minify.M, w io.Writer, r io.Reader, params map[string]string) error { - if o.Decimals != 0 { - minify.Warning.Println("CSS option `Decimals` is deprecated, using as `Precision` instead. Be aware that `Decimals` meant the number of digits behind the dot while `Precision` means the number of significant digits. Example: 1.23 with `Decimals=1` would give 1.2 but with `Pecision=1` gives 1. The default `Decimals=-1` is now `Precision=0` which prints the whole number.") - } - if o.Precision == 0 { - o.Precision = o.Decimals - } - o.newPrecision = o.Precision - if o.newPrecision <= 0 || 15 < o.newPrecision { - o.newPrecision = 15 // minimum number of digits a double can represent exactly - } - - isInline := params != nil && params["inline"] == "1" - c := &cssMinifier{ - m: m, - w: w, - p: css.NewParser(r, isInline), - o: o, - } - defer c.p.Restore() - - if err := c.minifyGrammar(); err != nil && err != io.EOF { - return err - } - return nil -} - -func (c *cssMinifier) minifyGrammar() error { - semicolonQueued := false - for { - gt, _, data := c.p.Next() - switch gt { - case css.ErrorGrammar: - if _, ok := c.p.Err().(*parse.Error); ok { - if semicolonQueued { - if _, err := c.w.Write(semicolonBytes); err != nil { - return err - } - } - - // write out the offending declaration (but save the semicolon) - vals := c.p.Values() - if len(vals) > 0 && vals[len(vals)-1].TokenType == css.SemicolonToken { - vals = vals[:len(vals)-1] - semicolonQueued = true - } - for _, val := range vals { - if _, err := c.w.Write(val.Data); err != nil { - return err - } - } - continue - } - return c.p.Err() - case css.EndAtRuleGrammar, css.EndRulesetGrammar: - if _, err := c.w.Write(rightBracketBytes); err != nil { - return err - } - semicolonQueued = false - continue - } - - if semicolonQueued { - if _, err := c.w.Write(semicolonBytes); err != nil { - return err - } - semicolonQueued = false - } - - switch gt { - case css.AtRuleGrammar: - if _, err := c.w.Write(data); err != nil { - return err - } - values := c.p.Values() - if ToHash(data[1:]) == Import && len(values) == 2 && values[1].TokenType == css.URLToken { - url := values[1].Data - if url[4] != '"' && url[4] != '\'' { - url = url[3:] - url[0] = '"' - url[len(url)-1] = '"' - } else { - url = url[4 : len(url)-1] - } - values[1].Data = url - } - for _, val := range values { - if _, err := c.w.Write(val.Data); err != nil { - return err - } - } - semicolonQueued = true - case css.BeginAtRuleGrammar: - if _, err := c.w.Write(data); err != nil { - return err - } - for _, val := range c.p.Values() { - if _, err := c.w.Write(val.Data); err != nil { - return err - } - } - if _, err := c.w.Write(leftBracketBytes); err != nil { - return err - } - case css.QualifiedRuleGrammar: - if err := c.minifySelectors(data, c.p.Values()); err != nil { - return err - } - if _, err := c.w.Write(commaBytes); err != nil { - return err - } - case css.BeginRulesetGrammar: - if err := c.minifySelectors(data, c.p.Values()); err != nil { - return err - } - if _, err := c.w.Write(leftBracketBytes); err != nil { - return err - } - case css.DeclarationGrammar: - if err := c.minifyDeclaration(data, c.p.Values()); err != nil { - return err - } - semicolonQueued = true - case css.CustomPropertyGrammar: - if _, err := c.w.Write(data); err != nil { - return err - } - if _, err := c.w.Write(colonBytes); err != nil { - return err - } - if _, err := c.w.Write(c.p.Values()[0].Data); err != nil { - return err - } - semicolonQueued = true - case css.CommentGrammar: - if len(data) > 5 && data[1] == '*' && data[2] == '!' { - if _, err := c.w.Write(data[:3]); err != nil { - return err - } - comment := parse.TrimWhitespace(parse.ReplaceMultipleWhitespace(data[3 : len(data)-2])) - if _, err := c.w.Write(comment); err != nil { - return err - } - if _, err := c.w.Write(data[len(data)-2:]); err != nil { - return err - } - } - default: - if _, err := c.w.Write(data); err != nil { - return err - } - } - } -} - -func (c *cssMinifier) minifySelectors(property []byte, values []css.Token) error { - inAttr := false - isClass := false - for _, val := range c.p.Values() { - if !inAttr { - if val.TokenType == css.IdentToken { - if !isClass { - parse.ToLower(val.Data) - } - isClass = false - } else if val.TokenType == css.DelimToken && val.Data[0] == '.' { - isClass = true - } else if val.TokenType == css.LeftBracketToken { - inAttr = true - } - } else { - if val.TokenType == css.StringToken && len(val.Data) > 2 { - s := val.Data[1 : len(val.Data)-1] - if css.IsIdent(s) { - if _, err := c.w.Write(s); err != nil { - return err - } - continue - } - } else if val.TokenType == css.RightBracketToken { - inAttr = false - } else if val.TokenType == css.IdentToken && len(val.Data) == 1 && (val.Data[0] == 'i' || val.Data[0] == 'I') { - if _, err := c.w.Write(spaceBytes); err != nil { - return err - } - } - } - if _, err := c.w.Write(val.Data); err != nil { - return err - } - } - return nil -} - -func (c *cssMinifier) parseFunction(values []css.Token) ([]Token, int) { - i := 1 - level := 0 - args := []Token{} - for ; i < len(values); i++ { - tt := values[i].TokenType - data := values[i].Data - if tt == css.LeftParenthesisToken { - level++ - } else if tt == css.RightParenthesisToken { - if level == 0 { - i++ - break - } - level-- - } - if tt == css.FunctionToken { - subArgs, di := c.parseFunction(values[i:]) - h := ToHash(parse.ToLower(parse.Copy(data[:len(data)-1]))) // TODO: use ToHashFold - args = append(args, Token{tt, data, subArgs, h, 0}) - i += di - 1 - } else { - var h Hash - if tt == css.IdentToken { - h = ToHash(parse.ToLower(parse.Copy(data))) // TODO: use ToHashFold - } - args = append(args, Token{tt, data, nil, 0, h}) - } - } - return args, i -} - -func (c *cssMinifier) parseDeclaration(values []css.Token) []Token { - // Check if this is a simple list of values separated by whitespace or commas, otherwise we'll not be processing - prevSep := true - tokens := c.tokenBuffer[:0] - for i := 0; i < len(values); i++ { - tt := values[i].TokenType - data := values[i].Data - if tt == css.LeftParenthesisToken || tt == css.LeftBraceToken || tt == css.LeftBracketToken || - tt == css.RightParenthesisToken || tt == css.RightBraceToken || tt == css.RightBracketToken { - return nil - } - - if !prevSep && tt != css.WhitespaceToken && tt != css.CommaToken && (tt != css.DelimToken || values[i].Data[0] != '/') { - return nil - } - - if tt == css.WhitespaceToken || tt == css.CommaToken || tt == css.DelimToken && values[i].Data[0] == '/' { - if tt != css.WhitespaceToken { - tokens = append(tokens, Token{tt, data, nil, 0, 0}) - } - prevSep = true - } else if tt == css.FunctionToken { - args, di := c.parseFunction(values[i:]) - h := ToHash(parse.ToLower(parse.Copy(data[:len(data)-1]))) // TODO: use ToHashFold - tokens = append(tokens, Token{tt, data, args, h, 0}) - prevSep = true - i += di - 1 - } else { - var h Hash - if tt == css.IdentToken { - h = ToHash(parse.ToLower(parse.Copy(data))) // TODO: use ToHashFold - } - tokens = append(tokens, Token{tt, data, nil, 0, h}) - prevSep = tt == css.URLToken - } - } - c.tokenBuffer = tokens // update buffer size for memory reuse - return tokens -} - -func (c *cssMinifier) minifyDeclaration(property []byte, components []css.Token) error { - if _, err := c.w.Write(property); err != nil { - return err - } - if _, err := c.w.Write(colonBytes); err != nil { - return err - } - - if len(components) == 0 { - return nil - } - - // Strip !important from the component list, this will be added later separately - important := false - if len(components) > 2 && components[len(components)-2].TokenType == css.DelimToken && components[len(components)-2].Data[0] == '!' && ToHash(components[len(components)-1].Data) == Important { - components = components[:len(components)-2] - important = true - } - - prop := ToHash(property) - values := c.parseDeclaration(components) - - // Do not process complex values (eg. containing blocks or is not alternated between whitespace/commas and flat values - if values == nil { - if prop == Filter && len(components) == 11 { - if bytes.Equal(components[0].Data, []byte("progid")) && - components[1].TokenType == css.ColonToken && - bytes.Equal(components[2].Data, []byte("DXImageTransform")) && - components[3].Data[0] == '.' && - bytes.Equal(components[4].Data, []byte("Microsoft")) && - components[5].Data[0] == '.' && - bytes.Equal(components[6].Data, []byte("Alpha(")) && - bytes.Equal(parse.ToLower(components[7].Data), []byte("opacity")) && - components[8].Data[0] == '=' && - components[10].Data[0] == ')' { - components = components[6:] - components[0].Data = []byte("alpha(") - } - } - - for _, component := range components { - if _, err := c.w.Write(component.Data); err != nil { - return err - } - } - if important { - if _, err := c.w.Write(importantBytes); err != nil { - return err - } - } - return nil - } - - values = c.minifyTokens(prop, values) - if len(values) > 0 { - values = c.minifyProperty(prop, values) - } - return c.writeDeclaration(values, important) -} - -func (c *cssMinifier) writeFunction(args []Token) error { - for _, arg := range args { - if _, err := c.w.Write(arg.Data); err != nil { - return err - } - if arg.TokenType == css.FunctionToken { - if err := c.writeFunction(arg.Args); err != nil { - return err - } - if _, err := c.w.Write([]byte(")")); err != nil { - return err - } - } - } - return nil -} - -func (c *cssMinifier) writeDeclaration(values []Token, important bool) error { - prevSep := true - for _, value := range values { - if !prevSep && value.TokenType != css.CommaToken && (value.TokenType != css.DelimToken || value.Data[0] != '/') { - if _, err := c.w.Write(spaceBytes); err != nil { - return err - } - } - - if _, err := c.w.Write(value.Data); err != nil { - return err - } - if value.TokenType == css.FunctionToken { - if err := c.writeFunction(value.Args); err != nil { - return err - } - if _, err := c.w.Write([]byte(")")); err != nil { - return err - } - } - - if value.TokenType == css.CommaToken || value.TokenType == css.DelimToken && value.Data[0] == '/' || value.TokenType == css.FunctionToken || value.TokenType == css.URLToken { - prevSep = true - } else { - prevSep = false - } - } - - if important { - if _, err := c.w.Write(importantBytes); err != nil { - return err - } - } - return nil -} - -func (c *cssMinifier) minifyTokens(prop Hash, values []Token) []Token { - for i, value := range values { - tt := value.TokenType - switch tt { - case css.NumberToken: - if prop == Z_Index || prop == Counter_Increment || prop == Counter_Reset || prop == Orphans || prop == Widows { - break // integers - } - if c.o.KeepCSS2 { - values[i].Data = minify.Decimal(values[i].Data, c.o.Precision) // don't use exponents - } else { - values[i].Data = minify.Number(values[i].Data, c.o.Precision) - } - case css.PercentageToken: - n := len(values[i].Data) - 1 - if c.o.KeepCSS2 { - values[i].Data = minify.Decimal(values[i].Data[:n], c.o.Precision) // don't use exponents - } else { - values[i].Data = minify.Number(values[i].Data[:n], c.o.Precision) - } - values[i].Data = append(values[i].Data, '%') - case css.DimensionToken: - var dim []byte - values[i], dim = c.minifyDimension(values[i]) - if 1 < len(values[i].Data) && values[i].Data[0] == '0' && optionalZeroDimension[string(dim)] && prop != Flex { - // cut dimension for zero value, TODO: don't hardcode check for Flex and remove the dimension in minifyDimension - values[i].Data = values[i].Data[:1] - } - case css.StringToken: - values[i].Data = removeMarkupNewlines(values[i].Data) - case css.URLToken: - if 10 < len(values[i].Data) { - uri := parse.TrimWhitespace(values[i].Data[4 : len(values[i].Data)-1]) - delim := byte('"') - if 1 < len(uri) && (uri[0] == '\'' || uri[0] == '"') { - delim = uri[0] - uri = removeMarkupNewlines(uri) - uri = uri[1 : len(uri)-1] - } - if 4 < len(uri) && parse.EqualFold(uri[:5], dataSchemeBytes) { - uri = minify.DataURI(c.m, uri) - } - if css.IsURLUnquoted(uri) { - values[i].Data = append(append([]byte("url("), uri...), ')') - } else { - values[i].Data = append(append(append([]byte("url("), delim), uri...), delim, ')') - } - } - case css.FunctionToken: - values[i].Args = c.minifyTokens(prop, values[i].Args) - - fun := values[i].Fun - args := values[i].Args - if fun == Rgb || fun == Rgba || fun == Hsl || fun == Hsla { - valid := true - vals := []float64{} - for i, arg := range args { - numeric := arg.TokenType == css.NumberToken || arg.TokenType == css.PercentageToken - separator := arg.TokenType == css.CommaToken || i != 5 && arg.TokenType == css.WhitespaceToken || i == 5 && arg.TokenType == css.DelimToken && arg.Data[0] == '/' - if i%2 == 0 && !numeric || i%2 == 1 && !separator { - valid = false - } else if numeric { - var d float64 - if arg.TokenType == css.PercentageToken { - d, _ = strconv.ParseFloat(string(arg.Data[:len(arg.Data)-1]), 32) // can never fail - d /= 100.0 - if d < minify.Epsilon { - d = 0.0 - } else if 1.0-minify.Epsilon < d { - d = 1.0 - } - } else { - d, _ = strconv.ParseFloat(string(arg.Data), 32) // can never fail - } - vals = append(vals, d) - } - } - if !valid { - break - } - - a := 1.0 - if len(vals) == 4 { - if vals[3] < minify.Epsilon { - values[i] = Token{css.IdentToken, transparentBytes, nil, 0, Transparent} - break - } else if 1.0-minify.Epsilon < vals[3] { - vals = vals[:3] - values[i].Args = values[i].Args[:len(values[i].Args)-2] - if fun == Rgba || fun == Hsla { - values[i].Data = values[i].Data[:len(values[i].Data)-1] - values[i].Data[len(values[i].Data)-1] = '(' - } - } else { - a = vals[3] - } - } - - if a == 1.0 && (len(vals) == 3 || len(vals) == 4) { // only minify color if fully opaque - if fun == Rgb || fun == Rgba { - for j := 0; j < 3; j++ { - if args[j*2].TokenType == css.NumberToken { - vals[j] /= 255.0 - if vals[j] < minify.Epsilon { - vals[j] = 0.0 - } else if 1.0-minify.Epsilon < vals[j] { - vals[j] = 1.0 - } - } - } - values[i] = rgbToToken(vals[0], vals[1], vals[2]) - break - } else if fun == Hsl || fun == Hsla && args[0].TokenType == css.NumberToken && args[2].TokenType == css.PercentageToken && args[4].TokenType == css.PercentageToken { - for vals[0] < 0.0 { - vals[0] += 360.0 - } - for 360.0 <= vals[0] { - vals[0] -= 360.0 - } - vals[0] /= 360.0 - - r, g, b := css.HSL2RGB(vals[0], vals[1], vals[2]) - values[i] = rgbToToken(r, g, b) - break - } - } else if len(vals) == 4 { - args[6] = minifyNumberPercentage(args[6]) - } - - if fun == Rgb || fun == Rgba { - // 0%, 20%, 40%, 60%, 80% and 100% can be represented exactly as, 51, 102, 153, 204, and 255 respectively - removePercentage := true - for j := 0; j < 3; j++ { - if args[j*2].TokenType != css.PercentageToken || 2.0*minify.Epsilon <= math.Mod(vals[j]+minify.Epsilon, 0.2) { - removePercentage = false - break - } - } - if removePercentage { - for j := 0; j < 3; j++ { - args[j*2].TokenType = css.NumberToken - if vals[j] < minify.Epsilon { - args[j*2].Data = []byte("0") - } else if math.Abs(vals[j]-0.2) < minify.Epsilon { - args[j*2].Data = []byte("51") - } else if math.Abs(vals[j]-0.4) < minify.Epsilon { - args[j*2].Data = []byte("102") - } else if math.Abs(vals[j]-0.6) < minify.Epsilon { - args[j*2].Data = []byte("153") - } else if math.Abs(vals[j]-0.8) < minify.Epsilon { - args[j*2].Data = []byte("204") - } else if math.Abs(vals[j]-1.0) < minify.Epsilon { - args[j*2].Data = []byte("255") - } - } - } - } - } - } - } - return values -} - -func (c *cssMinifier) minifyProperty(prop Hash, values []Token) []Token { - switch prop { - case Font: - if len(values) > 1 { // must contain atleast font-size and font-family - // the font-families are separated by commas and are at the end of font - // get index for last token before font family names - i := len(values) - 1 - for j, value := range values[2:] { - if value.TokenType == css.CommaToken { - i = 2 + j - 1 // identifier before first comma is a font-family - break - } - } - i-- - - // advance i while still at font-families when they contain spaces but no quotes - for ; i > 0; i-- { // i cannot be 0, font-family must be prepended by font-size - if values[i-1].TokenType == css.DelimToken && values[i-1].Data[0] == '/' { - break - } else if values[i].TokenType != css.IdentToken && values[i].TokenType != css.StringToken { - break - } else if h := values[i].Ident; h == Xx_Small || h == X_Small || h == Small || h == Medium || h == Large || h == X_Large || h == Xx_Large || h == Smaller || h == Larger || h == Inherit || h == Initial || h == Unset { - // inherit, initial and unset are followed by an IdentToken/StringToken, so must be for font-size - break - } - } - - // font-family minified in place - values = append(values[:i+1], c.minifyProperty(Font_Family, values[i+1:])...) - - // fix for IE9, IE10, IE11: font name starting with `-` is not recognized - if values[i+1].Data[0] == '-' { - v := make([]byte, len(values[i+1].Data)+2) - v[0] = '\'' - copy(v[1:], values[i+1].Data) - v[len(v)-1] = '\'' - values[i+1].Data = v - } - - if i > 0 { - // line-height - if i > 1 && values[i-1].TokenType == css.DelimToken && values[i-1].Data[0] == '/' { - if values[i].Ident == Normal { - values = append(values[:i-1], values[i+1:]...) - } - i -= 2 - } - - // font-size - i-- - - for ; i > -1; i-- { - if values[i].Ident == Normal { - values = append(values[:i], values[i+1:]...) - } else if values[i].Ident == Bold { - values[i].TokenType = css.NumberToken - values[i].Data = []byte("700") - } else if values[i].TokenType == css.NumberToken && bytes.Equal(values[i].Data, []byte("400")) { - values = append(values[:i], values[i+1:]...) - } - } - } - } - case Font_Family: - for i, value := range values { - if value.TokenType == css.StringToken && len(value.Data) > 2 { - unquote := true - parse.ToLower(value.Data) - s := value.Data[1 : len(value.Data)-1] - if len(s) > 0 { - for _, split := range bytes.Split(s, spaceBytes) { - // if len is zero, it contains two consecutive spaces - if len(split) == 0 || !css.IsIdent(split) { - unquote = false - break - } - } - } - if unquote { - values[i].Data = s - } - } - } - case Font_Weight: - if values[0].Ident == Normal { - values[0].TokenType = css.NumberToken - values[0].Data = []byte("400") - } else if values[0].Ident == Bold { - values[0].TokenType = css.NumberToken - values[0].Data = []byte("700") - } - case Url: - for i := 0; i < len(values); i++ { - if values[i].TokenType == css.FunctionToken && len(values[i].Args) == 1 { - fun := values[i].Fun - data := values[i].Args[0].Data - if fun == Local && (data[0] == '\'' || data[0] == '"') { - if css.IsURLUnquoted(data[1 : len(data)-1]) { - data = data[1 : len(data)-1] - } - values[i].Args[0].Data = data - } - } - } - case Margin, Padding, Border_Width: - switch len(values) { - case 2: - if values[0].Equal(values[1]) { - values = values[:1] - } - case 3: - if values[0].Equal(values[1]) && values[0].Equal(values[2]) { - values = values[:1] - } else if values[0].Equal(values[2]) { - values = values[:2] - } - case 4: - if values[0].Equal(values[1]) && values[0].Equal(values[2]) && values[0].Equal(values[3]) { - values = values[:1] - } else if values[0].Equal(values[2]) && values[1].Equal(values[3]) { - values = values[:2] - } else if values[1].Equal(values[3]) { - values = values[:3] - } - } - case Border, Border_Bottom, Border_Left, Border_Right, Border_Top: - for i := 0; i < len(values); i++ { - if values[i].Ident == None || values[i].Ident == Currentcolor || values[i].Ident == Medium { - values = append(values[:i], values[i+1:]...) - i-- - } else { - values[i] = minifyColor(values[i]) - } - } - if len(values) == 0 { - values = []Token{{css.IdentToken, []byte("none"), nil, 0, None}} - } - case Outline: - for i := 0; i < len(values); i++ { - if values[i].Ident == Invert || values[i].Ident == None || values[i].Ident == Medium { - values = append(values[:i], values[i+1:]...) - i-- - } else { - values[i] = minifyColor(values[i]) - } - } - if len(values) == 0 { - values = []Token{{css.IdentToken, []byte("none"), nil, 0, None}} - } - case Background: - // minify background-size and lowercase all identifiers - for i := 0; i < len(values); i++ { - if values[i].TokenType == css.DelimToken && values[i].Data[0] == '/' { - // background-size consists of either [ | auto | cover | contain] or [ | auto]{2} - // we can only minify the latter - if i+1 < len(values) && (values[i+1].TokenType == css.NumberToken || values[i+1].IsLengthPercentage() || values[i+1].Ident == Auto) { - if i+2 < len(values) && (values[i+2].TokenType == css.NumberToken || values[i+2].IsLengthPercentage() || values[i+2].Ident == Auto) { - sizeValues := c.minifyProperty(Background_Size, values[i+1:i+3]) - if len(sizeValues) == 1 && sizeValues[0].Ident == Auto { - // remove background-size if it is '/ auto' after minifying the property - values = append(values[:i], values[i+3:]...) - i-- - } else { - values = append(values[:i+1], append(sizeValues, values[i+3:]...)...) - i += len(sizeValues) - 1 - } - } else if values[i+1].Ident == Auto { - // remove background-size if it is '/ auto' - values = append(values[:i], values[i+2:]...) - i-- - } - } - } - } - - // minify all other values - iPaddingBox := -1 // position of background-origin that is padding-box - for i := 0; i < len(values); i++ { - h := values[i].Ident - values[i] = minifyColor(values[i]) - if values[i].TokenType == css.IdentToken { - if i+1 < len(values) && values[i+1].TokenType == css.IdentToken && (h == Space || h == Round || h == Repeat || h == No_Repeat) { - if h2 := values[i+1].Ident; h2 == Space || h2 == Round || h2 == Repeat || h2 == No_Repeat { - repeatValues := c.minifyProperty(Background_Repeat, values[i:i+2]) - if len(repeatValues) == 1 && repeatValues[0].Ident == Repeat { - values = append(values[:i], values[i+2:]...) - i-- - } else { - values = append(values[:i], append(repeatValues, values[i+2:]...)...) - i += len(repeatValues) - 1 - } - continue - } - } else if h == None || h == Scroll || h == Transparent { - values = append(values[:i], values[i+1:]...) - i-- - continue - } else if h == Border_Box || h == Padding_Box { - if iPaddingBox == -1 && h == Padding_Box { // background-origin - iPaddingBox = i - } else if iPaddingBox != -1 && h == Border_Box { // background-clip - values = append(values[:i], values[i+1:]...) - values = append(values[:iPaddingBox], values[iPaddingBox+1:]...) - i -= 2 - } - continue - } - } else if values[i].TokenType == css.HashToken && bytes.Equal(values[i].Data, []byte("#0000")) { - values = append(values[:i], values[i+1:]...) - i-- - continue - } - - // further minify background-position and background-size combination - if values[i].TokenType == css.NumberToken || values[i].IsLengthPercentage() || h == Left || h == Right || h == Top || h == Bottom || h == Center { - j := i + 1 - for ; j < len(values); j++ { - if h := values[j].Ident; h == Left || h == Right || h == Top || h == Bottom || h == Center { - continue - } else if values[j].TokenType == css.NumberToken || values[j].IsLengthPercentage() { - continue - } - break - } - - positionValues := c.minifyProperty(Background_Position, values[i:j]) - hasSize := j < len(values) && values[j].TokenType == css.DelimToken && values[j].Data[0] == '/' - if !hasSize && len(positionValues) == 2 && positionValues[0].IsZero() && positionValues[1].IsZero() { - values = append(values[:i], values[j:]...) - i-- - } else { - values = append(values[:i], append(positionValues, values[j:]...)...) - i += len(positionValues) - 1 - } - } - } - - if len(values) == 0 { - values = []Token{{css.NumberToken, []byte("0"), nil, 0, 0}, {css.NumberToken, []byte("0"), nil, 0, 0}} - } - case Background_Size: - if len(values) == 2 && values[1].Ident == Auto { - values = values[:1] - } - case Background_Repeat: - if len(values) == 2 && values[0].TokenType == css.IdentToken && values[1].TokenType == css.IdentToken { - if values[0].Ident == values[1].Ident { - values = values[:1] - } else if values[0].Ident == Repeat && values[1].Ident == No_Repeat { - values = values[:1] - values[0].Data = []byte("repeat-x") - values[0].Ident = Repeat_X - } else if values[0].Ident == No_Repeat && values[1].Ident == Repeat { - values = values[:1] - values[0].Data = []byte("repeat-y") - values[0].Ident = Repeat_Y - } - } - case Background_Position: - if len(values) == 3 || len(values) == 4 { - // remove zero offsets - for _, i := range []int{len(values) - 1, 1} { - if 2 < len(values) && values[i].IsZero() { - values = append(values[:i], values[i+1:]...) - } - } - - j := 1 // position of second set of horizontal/vertical values - if 2 < len(values) && values[2].TokenType == css.IdentToken { - j = 2 - } - - b := make([]byte, 0, 4) - offsets := make([]Token, 2) - for _, i := range []int{j, 0} { - if i+1 < len(values) && i+1 != j { - if values[i+1].TokenType == css.PercentageToken { - // change right or bottom with percentage offset to left or top respectively - if values[i].Ident == Right || values[i].Ident == Bottom { - n, _ := strconvParse.ParseInt(values[i+1].Data[:len(values[i+1].Data)-1]) - b = strconv.AppendInt(b[:0], 100-n, 10) - b = append(b, '%') - values[i+1].Data = b - if values[i].Ident == Right { - values[i].Data = []byte("left") - values[i].Ident = Left - } else { - values[i].Data = []byte("top") - values[i].Ident = Top - } - } - } - if values[i].Ident == Left { - offsets[0] = values[i+1] - } else if values[i].Ident == Top { - offsets[1] = values[i+1] - } - } else if values[i].Ident == Left { - offsets[0] = Token{css.NumberToken, []byte("0"), nil, 0, 0} - } else if values[i].Ident == Top { - offsets[1] = Token{css.NumberToken, []byte("0"), nil, 0, 0} - } else if values[i].Ident == Right { - offsets[0] = Token{css.PercentageToken, []byte("100%"), nil, 0, 0} - values[i].Ident = Left - } else if values[i].Ident == Bottom { - offsets[1] = Token{css.PercentageToken, []byte("100%"), nil, 0, 0} - values[i].Ident = Top - } - } - - if values[0].Ident == Center || values[j].Ident == Center { - if values[0].Ident == Left || values[j].Ident == Left { - offsets = offsets[:1] - } else if values[0].Ident == Top || values[j].Ident == Top { - offsets[0] = Token{css.NumberToken, []byte("50%"), nil, 0, 0} - } - } - - if offsets[0].Data != nil && (len(offsets) == 1 || offsets[1].Data != nil) { - values = offsets - } - } - // removing zero offsets in the previous loop might make it eligible for the next loop - if len(values) == 1 || len(values) == 2 { - if values[0].Ident == Top || values[0].Ident == Bottom { - if len(values) == 1 { - // we can't make this smaller, and converting to a number will break it - // (https://github.com/tdewolff/minify/issues/221#issuecomment-415419918) - break - } - // if it's a vertical position keyword, swap it with the next element - // since otherwise converted number positions won't be valid anymore - // (https://github.com/tdewolff/minify/issues/221#issue-353067229) - values[0], values[1] = values[1], values[0] - } - // transform keywords to lengths|percentages - for i := 0; i < len(values); i++ { - if values[i].TokenType == css.IdentToken { - if values[i].Ident == Left || values[i].Ident == Top { - values[i].TokenType = css.NumberToken - values[i].Data = []byte("0") - values[i].Ident = 0 - } else if values[i].Ident == Right || values[i].Ident == Bottom { - values[i].TokenType = css.PercentageToken - values[i].Data = []byte("100%") - values[i].Ident = 0 - } else if values[i].Ident == Center { - if i == 0 { - values[i].TokenType = css.PercentageToken - values[i].Data = []byte("50%") - values[i].Ident = 0 - } else { - values = values[:1] - } - } - } else if i == 1 && values[i].TokenType == css.PercentageToken && bytes.Equal(values[i].Data, []byte("50%")) { - values = values[:1] - } else if values[i].TokenType == css.PercentageToken && values[i].Data[0] == '0' { - values[i].TokenType = css.NumberToken - values[i].Data = []byte("0") - values[i].Ident = 0 - } - } - } - case Box_Shadow: - if len(values) == 1 && (values[0].Ident == None || values[0].Ident == Initial) { - values = []Token{{css.NumberToken, []byte("0"), nil, 0, 0}, {css.NumberToken, []byte("0"), nil, 0, 0}} - } else { - numbers := []int{} - for i := 0; i < len(values); i++ { - if values[i].IsLength() { - numbers = append(numbers, i) - } - } - if len(numbers) == 4 && values[numbers[3]].IsZero() { - values = append(values[:numbers[3]], values[numbers[3]+1:]...) - numbers = numbers[:3] - } - if len(numbers) == 3 && values[numbers[2]].IsZero() { - values = append(values[:numbers[2]], values[numbers[2]+1:]...) - } - } - case Ms_Filter: - alpha := []byte("progid:DXImageTransform.Microsoft.Alpha(Opacity=") - if values[0].TokenType == css.StringToken && 2 < len(values[0].Data) && bytes.HasPrefix(values[0].Data[1:len(values[0].Data)-1], alpha) { - values[0].Data = append(append([]byte{values[0].Data[0]}, []byte("alpha(opacity=")...), values[0].Data[1+len(alpha):]...) - } - case Color: - values[0] = minifyColor(values[0]) - case Background_Color: - values[0] = minifyColor(values[0]) - if values[0].Ident == Transparent { - values[0].Data = initialBytes - values[0].Ident = Initial - } - case Border_Color: - sameValues := true - for i := range values { - if values[i].Ident == Currentcolor { - values[i].Data = initialBytes - values[i].Ident = Initial - } else { - values[i] = minifyColor(values[i]) - } - if 0 < i && sameValues && !bytes.Equal(values[0].Data, values[i].Data) { - sameValues = false - } - } - if sameValues { - values = values[:1] - } - case Border_Left_Color, Border_Right_Color, Border_Top_Color, Border_Bottom_Color, Text_Decoration_Color, Text_Emphasis_Color: - if values[0].Ident == Currentcolor { - values[0].Data = initialBytes - values[0].Ident = Initial - } else { - values[0] = minifyColor(values[0]) - } - case Caret_Color, Outline_Color, Fill, Stroke: - values[0] = minifyColor(values[0]) - case Column_Rule: - for i := 0; i < len(values); i++ { - if values[i].Ident == Currentcolor || values[i].Ident == None || values[i].Ident == Medium { - values = append(values[:i], values[i+1:]...) - i-- - } else { - values[i] = minifyColor(values[i]) - } - } - if len(values) == 0 { - values = []Token{{css.IdentToken, []byte("none"), nil, 0, None}} - } - case Text_Shadow: - for i := 0; i < len(values); i++ { - values[i] = minifyColor(values[i]) - } - case Text_Decoration: - for i := 0; i < len(values); i++ { - if values[i].Ident == Currentcolor || values[i].Ident == None || values[i].Ident == Solid { - values = append(values[:i], values[i+1:]...) - i-- - } else { - values[i] = minifyColor(values[i]) - } - } - if len(values) == 0 { - values = []Token{{css.IdentToken, []byte("none"), nil, 0, None}} - } - case Text_Emphasis: - for i := 0; i < len(values); i++ { - if values[i].Ident == Currentcolor || values[i].Ident == None { - values = append(values[:i], values[i+1:]...) - i-- - } else { - values[i] = minifyColor(values[i]) - } - } - if len(values) == 0 { - values = []Token{{css.IdentToken, []byte("none"), nil, 0, None}} - } - case Flex: - if len(values) == 1 && values[0].TokenType == css.IdentToken { - if values[0].Ident == None { - values = []Token{{css.NumberToken, []byte("0"), nil, 0, 0}, {css.NumberToken, []byte("0"), nil, 0, 0}} - } else if values[0].Ident == Auto { - values = []Token{{css.NumberToken, []byte("1"), nil, 0, 0}, {css.NumberToken, []byte("1"), nil, 0, 0}} - } else if values[0].Ident == Initial { - values = []Token{{css.NumberToken, []byte("0"), nil, 0, 0}, {css.NumberToken, []byte("1"), nil, 0, 0}} - } - } else if len(values) == 2 && values[0].TokenType == css.NumberToken { - if values[1].TokenType != css.NumberToken && values[1].IsZero() { - values = values[:1] // remove if it is zero - } else if values[1].Ident == Auto { - values[1].TokenType = css.NumberToken - values[1].Data = []byte("1") // replace if it is auto by - values[1].Ident = 0 - } - } else if len(values) == 3 && values[0].TokenType == css.NumberToken && values[1].TokenType == css.NumberToken { - if len(values[1].Data) == 1 && values[1].Data[0] == '1' && values[2].IsZero() { - values = values[:1] // remove and if they are 1 and 0 respectively - } else if values[2].Ident == Auto { - values = values[:2] // remove auto to write 2-value syntax of - } else { - values[2] = minifyLengthPercentage(values[2]) - } - } - case Flex_Basis: - if values[0].Ident == Initial { - values[0].Data = []byte("auto") - values[0].Ident = Auto - } else { - values[0] = minifyLengthPercentage(values[0]) - } - case Order, Flex_Grow: - if values[0].Ident == Initial { - values[0].TokenType = css.NumberToken - values[0].Data = []byte("0") - values[0].Ident = 0 - } - case Flex_Shrink: - if values[0].Ident == Initial { - values[0].TokenType = css.NumberToken - values[0].Data = []byte("1") - values[0].Ident = 0 - } - } - return values -} - -func minifyColor(value Token) Token { - data := value.Data - if value.TokenType == css.IdentToken { - if hexValue, ok := ShortenColorName[value.Ident]; ok { - value.TokenType = css.HashToken - value.Data = hexValue - } - } else if value.TokenType == css.HashToken { - parse.ToLower(data[1:]) - if len(data) == 9 && data[7] == data[8] { - if data[7] == 'f' { - data = data[:7] - } else if data[7] == '0' { - data = []byte("#0000") - } - } - if ident, ok := ShortenColorHex[string(data)]; ok { - value.TokenType = css.IdentToken - data = ident - } else if len(data) == 7 && data[1] == data[2] && data[3] == data[4] && data[5] == data[6] { - value.TokenType = css.HashToken - data[2] = data[3] - data[3] = data[5] - data = data[:4] - } else if len(data) == 9 && data[1] == data[2] && data[3] == data[4] && data[5] == data[6] && data[7] == data[8] { - // from working draft Color Module Level 4 - value.TokenType = css.HashToken - data[2] = data[3] - data[3] = data[5] - data[4] = data[7] - data = data[:5] - } - value.Data = data - } - return value -} - -func minifyNumberPercentage(value Token) Token { - // assumes input already minified - if value.TokenType == css.PercentageToken && 2 < len(value.Data) && value.Data[len(value.Data)-2] == '0' { - if len(value.Data) == 4 && (value.Data[3] == '.' || value.Data[3] == '%') { - value.Data[0] = '1' - value.Data = value.Data[:1] - } else { - value.Data[1] = value.Data[0] - value.Data[0] = '.' - value.Data = value.Data[:2] - } - value.TokenType = css.NumberToken - } else if value.TokenType == css.NumberToken && 2 < len(value.Data) && value.Data[0] == '.' && value.Data[1] == '0' { - if value.Data[2] == '0' { - value.Data[0] = '.' - copy(value.Data[1:], value.Data[3:]) - value.Data[len(value.Data)-2] = '%' - value.Data = value.Data[:len(value.Data)-1] - value.TokenType = css.PercentageToken - } else if len(value.Data) == 3 { - value.Data[0] = value.Data[2] - value.Data[1] = '%' - value.Data = value.Data[:2] - value.TokenType = css.PercentageToken - } - } - return value -} - -func minifyLengthPercentage(value Token) Token { - if value.TokenType != css.NumberToken && value.IsZero() { - value.TokenType = css.NumberToken - value.Data = value.Data[:1] // remove dimension for zero value - } - return value -} - -func (c *cssMinifier) minifyDimension(value Token) (Token, []byte) { - // TODO: add check for zero value - var dim []byte - if value.TokenType == css.DimensionToken { - n := len(value.Data) - for 0 < n { - lower := 'a' <= value.Data[n-1] && value.Data[n-1] <= 'z' - upper := 'A' <= value.Data[n-1] && value.Data[n-1] <= 'Z' - if !lower && !upper { - break - } else if upper { - value.Data[n-1] = value.Data[n-1] + ('a' - 'A') - } - n-- - } - - num := value.Data[:n] - if c.o.KeepCSS2 { - num = minify.Decimal(num, c.o.Precision) // don't use exponents - } else { - num = minify.Number(num, c.o.Precision) - } - dim = value.Data[n:] - value.Data = append(num, dim...) - } - return value, dim - - // TODO: optimize - //if value.TokenType == css.DimensionToken { - // // TODO: reverse; parse dim not number - // n := parse.Number(value.Data) - // num := value.Data[:n] - // dim = value.Data[n:] - // parse.ToLower(dim) - - // if c.o.KeepCSS2 { - // num = minify.Decimal(num, c.o.Precision) // don't use exponents - // } else { - // num = minify.Number(num, c.o.Precision) - // } - - // // change dimension to compress number - // h := ToHash(dim) - // if h == Px || h == Pt || h == Pc || h == In || h == Mm || h == Cm || h == Q || h == Deg || h == Grad || h == Rad || h == Turn || h == S || h == Ms || h == Hz || h == Khz || h == Dpi || h == Dpcm || h == Dppx { - // d, _ := strconv.ParseFloat(string(num), 64) // can never fail - // var dimensions []Hash - // var multipliers []float64 - // switch h { - // case Px: - // //dimensions = []Hash{In, Cm, Pc, Mm, Pt, Q} - // //multipliers = []float64{0.010416666666666667, 0.026458333333333333, 0.0625, 0.26458333333333333, 0.75, 1.0583333333333333} - // dimensions = []Hash{In, Pc, Pt} - // multipliers = []float64{0.010416666666666667, 0.0625, 0.75} - // case Pt: - // //dimensions = []Hash{In, Cm, Pc, Mm, Px, Q} - // //multipliers = []float64{0.013888888888888889, 0.035277777777777778, 0.083333333333333333, 0.35277777777777778, 1.3333333333333333, 1.4111111111111111} - // dimensions = []Hash{In, Pc, Px} - // multipliers = []float64{0.013888888888888889, 0.083333333333333333, 1.3333333333333333} - // case Pc: - // //dimensions = []Hash{In, Cm, Mm, Pt, Px, Q} - // //multipliers = []float64{0.16666666666666667, 0.42333333333333333, 4.2333333333333333, 12.0, 16.0, 16.933333333333333} - // dimensions = []Hash{In, Pt, Px} - // multipliers = []float64{0.16666666666666667, 12.0, 16.0} - // case In: - // //dimensions = []Hash{Cm, Pc, Mm, Pt, Px, Q} - // //multipliers = []float64{2.54, 6.0, 25.4, 72.0, 96.0, 101.6} - // dimensions = []Hash{Pc, Pt, Px} - // multipliers = []float64{6.0, 72.0, 96.0} - // case Cm: - // //dimensions = []Hash{In, Pc, Mm, Pt, Px, Q} - // //multipliers = []float64{0.39370078740157480, 2.3622047244094488, 10.0, 28.346456692913386, 37.795275590551181, 40.0} - // dimensions = []Hash{Mm, Q} - // multipliers = []float64{10.0, 40.0} - // case Mm: - // //dimensions = []Hash{In, Cm, Pc, Pt, Px, Q} - // //multipliers = []float64{0.039370078740157480, 0.1, 0.23622047244094488, 2.8346456692913386, 3.7795275590551181, 4.0} - // dimensions = []Hash{Cm, Q} - // multipliers = []float64{0.1, 4.0} - // case Q: - // //dimensions = []Hash{In, Cm, Pc, Pt, Px} // Q to mm is never smaller - // //multipliers = []float64{0.0098425196850393701, 0.025, 0.059055118110236220, 0.70866141732283465, 0.94488188976377953} - // dimensions = []Hash{Cm} // Q to mm is never smaller - // multipliers = []float64{0.025} - // case Deg: - // //dimensions = []Hash{Turn, Rad, Grad} - // //multipliers = []float64{0.0027777777777777778, 0.017453292519943296, 1.1111111111111111} - // dimensions = []Hash{Turn, Grad} - // multipliers = []float64{0.0027777777777777778, 1.1111111111111111} - // case Grad: - // //dimensions = []Hash{Turn, Rad, Deg} - // //multipliers = []float64{0.0025, 0.015707963267948966, 0.9} - // dimensions = []Hash{Turn, Deg} - // multipliers = []float64{0.0025, 0.9} - // case Turn: - // //dimensions = []Hash{Rad, Deg, Grad} - // //multipliers = []float64{6.2831853071795865, 360.0, 400.0} - // dimensions = []Hash{Deg, Grad} - // multipliers = []float64{360.0, 400.0} - // case Rad: - // //dimensions = []Hash{Turn, Deg, Grad} - // //multipliers = []float64{0.15915494309189534, 57.295779513082321, 63.661977236758134} - // case S: - // dimensions = []Hash{Ms} - // multipliers = []float64{1000.0} - // case Ms: - // dimensions = []Hash{S} - // multipliers = []float64{0.001} - // case Hz: - // dimensions = []Hash{Khz} - // multipliers = []float64{0.001} - // case Khz: - // dimensions = []Hash{Hz} - // multipliers = []float64{1000.0} - // case Dpi: - // dimensions = []Hash{Dppx, Dpcm} - // multipliers = []float64{0.010416666666666667, 0.39370078740157480} - // case Dpcm: - // //dimensions = []Hash{Dppx, Dpi} - // //multipliers = []float64{0.026458333333333333, 2.54} - // dimensions = []Hash{Dpi} - // multipliers = []float64{2.54} - // case Dppx: - // //dimensions = []Hash{Dpcm, Dpi} - // //multipliers = []float64{37.795275590551181, 96.0} - // dimensions = []Hash{Dpi} - // multipliers = []float64{96.0} - // } - // for i := range dimensions { - // if dimensions[i] != h { //&& (d < 1.0) == (multipliers[i] > 1.0) { - // b, _ := strconvParse.AppendFloat([]byte{}, d*multipliers[i], -1) - // if c.o.KeepCSS2 { - // b = minify.Decimal(b, c.o.newPrecision) // don't use exponents - // } else { - // b = minify.Number(b, c.o.newPrecision) - // } - // newDim := []byte(dimensions[i].String()) - // if len(b)+len(newDim) < len(num)+len(dim) { - // num = b - // dim = newDim - // } - // } - // } - // } - // value.Data = append(num, dim...) - //} - return value, dim -} diff --git a/vendor/github.com/tdewolff/minify/v2/css/hash.go b/vendor/github.com/tdewolff/minify/v2/css/hash.go deleted file mode 100644 index e2ca12796a06d..0000000000000 --- a/vendor/github.com/tdewolff/minify/v2/css/hash.go +++ /dev/null @@ -1,957 +0,0 @@ -package css - -// generated by hasher -type=Hash -file=hash.go; DO NOT EDIT, except for adding more constants to the list and rerun go generate - -// uses github.com/tdewolff/hasher -//go:generate hasher -type=Hash -file=hash.go - -// Hash defines perfect hashes for a predefined list of strings -type Hash uint32 - -// Unique hash definitions to be used instead of strings -const ( - Ms_Filter Hash = 0xa // -ms-filter - Accelerator Hash = 0x3760b // accelerator - Aliceblue Hash = 0x7a209 // aliceblue - Align_Content Hash = 0xd8b0d // align-content - Align_Items Hash = 0x7ef0b // align-items - Align_Self Hash = 0x8cb0a // align-self - All Hash = 0x69103 // all - Alpha Hash = 0x37205 // alpha - Animation Hash = 0xca09 // animation - Animation_Delay Hash = 0x2050f // animation-delay - Animation_Direction Hash = 0x8e913 // animation-direction - Animation_Duration Hash = 0x35d12 // animation-duration - Animation_Fill_Mode Hash = 0x66c13 // animation-fill-mode - Animation_Iteration_Count Hash = 0xd3c19 // animation-iteration-count - Animation_Name Hash = 0xca0e // animation-name - Animation_Play_State Hash = 0xfc14 // animation-play-state - Animation_Timing_Function Hash = 0x14119 // animation-timing-function - Antiquewhite Hash = 0x6490c // antiquewhite - Aquamarine Hash = 0x9ec0a // aquamarine - Attr Hash = 0x59804 // attr - Auto Hash = 0x44504 // auto - Azimuth Hash = 0x15a07 // azimuth - Background Hash = 0x2b0a // background - Background_Attachment Hash = 0x2b15 // background-attachment - Background_Clip Hash = 0xb6e0f // background-clip - Background_Color Hash = 0x21710 // background-color - Background_Image Hash = 0x5ad10 // background-image - Background_Origin Hash = 0x17111 // background-origin - Background_Position Hash = 0x18e13 // background-position - Background_Position_X Hash = 0x18e15 // background-position-x - Background_Position_Y Hash = 0x1a315 // background-position-y - Background_Repeat Hash = 0x1b811 // background-repeat - Background_Size Hash = 0x1cb0f // background-size - Behavior Hash = 0x1da08 // behavior - Black Hash = 0x1e205 // black - Blanchedalmond Hash = 0x1e70e // blanchedalmond - Blueviolet Hash = 0x7a70a // blueviolet - Bold Hash = 0x1fc04 // bold - Border Hash = 0x22706 // border - Border_Bottom Hash = 0x2270d // border-bottom - Border_Bottom_Color Hash = 0x22713 // border-bottom-color - Border_Bottom_Style Hash = 0x23a13 // border-bottom-style - Border_Bottom_Width Hash = 0x25d13 // border-bottom-width - Border_Box Hash = 0x27e0a // border-box - Border_Collapse Hash = 0x2b60f // border-collapse - Border_Color Hash = 0x2d30c // border-color - Border_Left Hash = 0x2df0b // border-left - Border_Left_Color Hash = 0x2df11 // border-left-color - Border_Left_Style Hash = 0x2f011 // border-left-style - Border_Left_Width Hash = 0x30111 // border-left-width - Border_Right Hash = 0x3120c // border-right - Border_Right_Color Hash = 0x31212 // border-right-color - Border_Right_Style Hash = 0x32412 // border-right-style - Border_Right_Width Hash = 0x33612 // border-right-width - Border_Spacing Hash = 0x3480e // border-spacing - Border_Style Hash = 0x3ab0c // border-style - Border_Top Hash = 0x3b70a // border-top - Border_Top_Color Hash = 0x3b710 // border-top-color - Border_Top_Style Hash = 0x3c710 // border-top-style - Border_Top_Width Hash = 0x3d710 // border-top-width - Border_Width Hash = 0x3e70c // border-width - Bottom Hash = 0x22e06 // bottom - Box_Shadow Hash = 0x2850a // box-shadow - Burlywood Hash = 0x3f309 // burlywood - Cadetblue Hash = 0x9c609 // cadetblue - Calc Hash = 0x9c304 // calc - Caption_Side Hash = 0x40f0c // caption-side - Caret_Color Hash = 0x4240b // caret-color - Center Hash = 0xdb06 // center - Charset Hash = 0x62f07 // charset - Chartreuse Hash = 0x42f0a // chartreuse - Chocolate Hash = 0x43909 // chocolate - Clamp Hash = 0x44e05 // clamp - Clear Hash = 0x45d05 // clear - Clip Hash = 0xb7904 // clip - Cm Hash = 0x53802 // cm - Color Hash = 0x2505 // color - Column_Count Hash = 0x4620c // column-count - Column_Gap Hash = 0x6a30a // column-gap - Column_Rule Hash = 0x4880b // column-rule - Column_Rule_Color Hash = 0x48811 // column-rule-color - Column_Rule_Style Hash = 0x49911 // column-rule-style - Column_Rule_Width Hash = 0x4aa11 // column-rule-width - Column_Width Hash = 0x4bb0c // column-width - Columns Hash = 0x74607 // columns - Content Hash = 0x5607 // content - Cornflowerblue Hash = 0x4c70e // cornflowerblue - Cornsilk Hash = 0x4d508 // cornsilk - Counter_Increment Hash = 0xd5011 // counter-increment - Counter_Reset Hash = 0x4690d // counter-reset - Cue Hash = 0x4dd03 // cue - Cue_After Hash = 0x4dd09 // cue-after - Cue_Before Hash = 0x4e60a // cue-before - Currentcolor Hash = 0x5010c // currentcolor - Cursive Hash = 0x50d07 // cursive - Cursor Hash = 0x51406 // cursor - Darkblue Hash = 0x1f408 // darkblue - Darkcyan Hash = 0x1ff08 // darkcyan - Darkgoldenrod Hash = 0x3fb0d // darkgoldenrod - Darkgray Hash = 0x40708 // darkgray - Darkgreen Hash = 0x75c09 // darkgreen - Darkkhaki Hash = 0xa1409 // darkkhaki - Darkmagenta Hash = 0xce90b // darkmagenta - Darkolivegreen Hash = 0x6d90e // darkolivegreen - Darkorange Hash = 0x7500a // darkorange - Darkorchid Hash = 0xa0b0a // darkorchid - Darksalmon Hash = 0xa990a // darksalmon - Darkseagreen Hash = 0xb110c // darkseagreen - Darkslateblue Hash = 0xc1c0d // darkslateblue - Darkslategray Hash = 0xbfa0d // darkslategray - Darkturquoise Hash = 0xcaa0d // darkturquoise - Darkviolet Hash = 0x51a0a // darkviolet - Deeppink Hash = 0x67d08 // deeppink - Deepskyblue Hash = 0x4190b // deepskyblue - Default Hash = 0xa2207 // default - Deg Hash = 0x70103 // deg - Direction Hash = 0x8d909 // direction - Display Hash = 0xcce07 // display - Document Hash = 0x52408 // document - Dodgerblue Hash = 0x52c0a // dodgerblue - Dpcm Hash = 0x53604 // dpcm - Dpi Hash = 0x54f03 // dpi - Dppx Hash = 0x55b04 // dppx - Elevation Hash = 0x6d09 // elevation - Empty_Cells Hash = 0x3910b // empty-cells - Env Hash = 0x4f503 // env - Fantasy Hash = 0x3a407 // fantasy - Fill Hash = 0x67604 // fill - Filter Hash = 0x406 // filter - Firebrick Hash = 0x83509 // firebrick - Flex Hash = 0x55f04 // flex - Flex_Basis Hash = 0x89d0a // flex-basis - Flex_Direction Hash = 0x8d40e // flex-direction - Flex_Flow Hash = 0xc8709 // flex-flow - Flex_Grow Hash = 0x55f09 // flex-grow - Flex_Shrink Hash = 0x5680b // flex-shrink - Flex_Wrap Hash = 0x57309 // flex-wrap - Float Hash = 0x59505 // float - Floralwhite Hash = 0x5bd0b // floralwhite - Font Hash = 0x25404 // font - Font_Face Hash = 0x25409 // font-face - Font_Family Hash = 0x5ee0b // font-family - Font_Size Hash = 0x5f909 // font-size - Font_Size_Adjust Hash = 0x5f910 // font-size-adjust - Font_Stretch Hash = 0x6250c // font-stretch - Font_Style Hash = 0x6360a // font-style - Font_Variant Hash = 0x6400c // font-variant - Font_Weight Hash = 0x65b0b // font-weight - Forestgreen Hash = 0x4ec0b // forestgreen - Fuchsia Hash = 0x66607 // fuchsia - Gainsboro Hash = 0xec09 // gainsboro - Ghostwhite Hash = 0x2990a // ghostwhite - Goldenrod Hash = 0x3ff09 // goldenrod - Grad Hash = 0x1004 // grad - Greenyellow Hash = 0x7600b // greenyellow - Grid Hash = 0x35504 // grid - Grid_Area Hash = 0x35509 // grid-area - Grid_Auto_Columns Hash = 0x7bb11 // grid-auto-columns - Grid_Auto_Flow Hash = 0x81c0e // grid-auto-flow - Grid_Auto_Rows Hash = 0x8640e // grid-auto-rows - Grid_Column Hash = 0x69e0b // grid-column - Grid_Column_End Hash = 0xcdb0f // grid-column-end - Grid_Column_Gap Hash = 0x69e0f // grid-column-gap - Grid_Column_Start Hash = 0x6bd11 // grid-column-start - Grid_Row Hash = 0x6ce08 // grid-row - Grid_Row_End Hash = 0x6ce0c // grid-row-end - Grid_Row_Gap Hash = 0x6e70c // grid-row-gap - Grid_Row_Start Hash = 0x7030e // grid-row-start - Grid_Template Hash = 0x7110d // grid-template - Grid_Template_Areas Hash = 0x71113 // grid-template-areas - Grid_Template_Columns Hash = 0x73815 // grid-template-columns - Grid_Template_Rows Hash = 0x77012 // grid-template-rows - Height Hash = 0x9306 // height - Honeydew Hash = 0x16008 // honeydew - Hsl Hash = 0x26f03 // hsl - Hsla Hash = 0x26f04 // hsla - Hz Hash = 0x68502 // hz - Ime_Mode Hash = 0xa1c08 // ime-mode - Import Hash = 0x78d06 // import - Important Hash = 0x78d09 // important - In Hash = 0x4402 // in - Include_Source Hash = 0x1800e // include-source - Indianred Hash = 0xb0909 // indianred - Inherit Hash = 0x79607 // inherit - Initial Hash = 0x79d07 // initial - Invert Hash = 0x7e406 // invert - Justify_Content Hash = 0x4e0f // justify-content - Justify_Items Hash = 0x6050d // justify-items - Justify_Self Hash = 0x82a0c // justify-self - Keyframes Hash = 0x5cb09 // keyframes - Khz Hash = 0x68403 // khz - Large Hash = 0xa905 // large - Larger Hash = 0xa906 // larger - Lavender Hash = 0x27108 // lavender - Lavenderblush Hash = 0x2710d // lavenderblush - Lawngreen Hash = 0x2ca09 // lawngreen - Layer_Background_Color Hash = 0x21116 // layer-background-color - Layer_Background_Image Hash = 0x5a716 // layer-background-image - Layout_Flow Hash = 0xcf80b // layout-flow - Layout_Grid Hash = 0x8050b // layout-grid - Layout_Grid_Char Hash = 0x80510 // layout-grid-char - Layout_Grid_Char_Spacing Hash = 0x80518 // layout-grid-char-spacing - Layout_Grid_Line Hash = 0x83e10 // layout-grid-line - Layout_Grid_Mode Hash = 0x85410 // layout-grid-mode - Layout_Grid_Type Hash = 0x88710 // layout-grid-type - Left Hash = 0x2e604 // left - Lemonchiffon Hash = 0x24b0c // lemonchiffon - Letter_Spacing Hash = 0x7ae0e // letter-spacing - Lightblue Hash = 0x8ba09 // lightblue - Lightcoral Hash = 0x8c30a // lightcoral - Lightcyan Hash = 0x8e209 // lightcyan - Lightgoldenrodyellow Hash = 0x8fc14 // lightgoldenrodyellow - Lightgray Hash = 0x91009 // lightgray - Lightgreen Hash = 0x9190a // lightgreen - Lightpink Hash = 0x92309 // lightpink - Lightsalmon Hash = 0x92c0b // lightsalmon - Lightseagreen Hash = 0x9370d // lightseagreen - Lightskyblue Hash = 0x9440c // lightskyblue - Lightslateblue Hash = 0x9500e // lightslateblue - Lightsteelblue Hash = 0x95e0e // lightsteelblue - Lightyellow Hash = 0x96c0b // lightyellow - Limegreen Hash = 0x97709 // limegreen - Line_Break Hash = 0x84a0a // line-break - Line_Height Hash = 0x8e0b // line-height - Linear_Gradient Hash = 0x9800f // linear-gradient - List_Style Hash = 0x98f0a // list-style - List_Style_Image Hash = 0x98f10 // list-style-image - List_Style_Position Hash = 0x99f13 // list-style-position - List_Style_Type Hash = 0x9b20f // list-style-type - Local Hash = 0x9c105 // local - Magenta Hash = 0xced07 // magenta - Margin Hash = 0x53906 // margin - Margin_Bottom Hash = 0xda40d // margin-bottom - Margin_Left Hash = 0xdb00b // margin-left - Margin_Right Hash = 0xb890c // margin-right - Margin_Top Hash = 0x5390a // margin-top - Marker_Offset Hash = 0xad00d // marker-offset - Marks Hash = 0xaee05 // marks - Mask Hash = 0x9cf04 // mask - Max Hash = 0x9d303 // max - Max_Height Hash = 0x9d30a // max-height - Max_Width Hash = 0x9dd09 // max-width - Media Hash = 0xd3805 // media - Medium Hash = 0x9e606 // medium - Mediumaquamarine Hash = 0x9e610 // mediumaquamarine - Mediumblue Hash = 0x9f60a // mediumblue - Mediumorchid Hash = 0xa000c // mediumorchid - Mediumpurple Hash = 0xa420c // mediumpurple - Mediumseagreen Hash = 0xa4e0e // mediumseagreen - Mediumslateblue Hash = 0xa5c0f // mediumslateblue - Mediumspringgreen Hash = 0xa6b11 // mediumspringgreen - Mediumturquoise Hash = 0xa7c0f // mediumturquoise - Mediumvioletred Hash = 0xa8b0f // mediumvioletred - Midnightblue Hash = 0xaa90c // midnightblue - Min Hash = 0x14d03 // min - Min_Height Hash = 0xab50a // min-height - Min_Width Hash = 0xabf09 // min-width - Mintcream Hash = 0xac809 // mintcream - Mistyrose Hash = 0xae409 // mistyrose - Mm Hash = 0xaed02 // mm - Moccasin Hash = 0xb0308 // moccasin - Monospace Hash = 0xaa009 // monospace - Ms Hash = 0x102 // ms - Namespace Hash = 0xd409 // namespace - Navajowhite Hash = 0x750b // navajowhite - No_Repeat Hash = 0xbf09 // no-repeat - None Hash = 0x38e04 // none - Normal Hash = 0x36e06 // normal - Offset Hash = 0xad706 // offset - Offset_Anchor Hash = 0xad70d // offset-anchor - Offset_Distance Hash = 0xb1d0f // offset-distance - Offset_Path Hash = 0xb2c0b // offset-path - Offset_Position Hash = 0xb370f // offset-position - Offset_Rotate Hash = 0xb460d // offset-rotate - Olivedrab Hash = 0xb6609 // olivedrab - Orangered Hash = 0x75409 // orangered - Order Hash = 0x22805 // order - Orphans Hash = 0x37f07 // orphans - Outline Hash = 0xba707 // outline - Outline_Color Hash = 0xba70d // outline-color - Outline_Style Hash = 0xbb40d // outline-style - Outline_Width Hash = 0xbc10d // outline-width - Overflow Hash = 0x9d08 // overflow - Overflow_X Hash = 0x9d0a // overflow-x - Overflow_Y Hash = 0xbce0a // overflow-y - Padding Hash = 0x45207 // padding - Padding_Bottom Hash = 0xb7c0e // padding-bottom - Padding_Box Hash = 0x4520b // padding-box - Padding_Left Hash = 0xd0a0c // padding-left - Padding_Right Hash = 0x5420d // padding-right - Padding_Top Hash = 0x57b0b // padding-top - Page Hash = 0x58504 // page - Page_Break_After Hash = 0x58510 // page-break-after - Page_Break_Before Hash = 0x6ac11 // page-break-before - Page_Break_Inside Hash = 0x6f211 // page-break-inside - Palegoldenrod Hash = 0xc100d // palegoldenrod - Palegreen Hash = 0xbd809 // palegreen - Paleturquoise Hash = 0xbe10d // paleturquoise - Palevioletred Hash = 0xbee0d // palevioletred - Papayawhip Hash = 0xc070a // papayawhip - Pause Hash = 0xc2905 // pause - Pause_After Hash = 0xc290b // pause-after - Pause_Before Hash = 0xc340c // pause-before - Pc Hash = 0x53702 // pc - Peachpuff Hash = 0x89509 // peachpuff - Pitch Hash = 0x55005 // pitch - Pitch_Range Hash = 0x5500b // pitch-range - Place_Content Hash = 0xc400d // place-content - Place_Items Hash = 0xc4d0b // place-items - Place_Self Hash = 0xc7e0a // place-self - Play_During Hash = 0xcd10b // play-during - Position Hash = 0x13908 // position - Powderblue Hash = 0xc9b0a // powderblue - Progid Hash = 0xca506 // progid - Pt Hash = 0x39302 // pt - Px Hash = 0x55d02 // px - Q Hash = 0x64d01 // q - Quotes Hash = 0xcb706 // quotes - Rad Hash = 0x903 // rad - Radial_Gradient Hash = 0x90f // radial-gradient - Repeat Hash = 0xc206 // repeat - Repeat_X Hash = 0x1c308 // repeat-x - Repeat_Y Hash = 0xc208 // repeat-y - Rgb Hash = 0x2903 // rgb - Rgba Hash = 0x2904 // rgba - Richness Hash = 0xae08 // richness - Right Hash = 0x31905 // right - Rosybrown Hash = 0xf309 // rosybrown - Round Hash = 0x3005 // round - Row_Gap Hash = 0x6ec07 // row-gap - Royalblue Hash = 0x69509 // royalblue - Ruby_Align Hash = 0xd860a // ruby-align - Ruby_Overhang Hash = 0xe00d // ruby-overhang - Ruby_Position Hash = 0x1340d // ruby-position - S Hash = 0x201 // s - Saddlebrown Hash = 0xb50b // saddlebrown - Sandybrown Hash = 0x3850a // sandybrown - Sans_Serif Hash = 0x39b0a // sans-serif - Scroll Hash = 0x12006 // scroll - Scrollbar_3d_Light_Color Hash = 0xd6f18 // scrollbar-3d-light-color - Scrollbar_Arrow_Color Hash = 0x12015 // scrollbar-arrow-color - Scrollbar_Base_Color Hash = 0x8a614 // scrollbar-base-color - Scrollbar_Dark_Shadow_Color Hash = 0x5d31b // scrollbar-dark-shadow-color - Scrollbar_Face_Color Hash = 0x61114 // scrollbar-face-color - Scrollbar_Highlight_Color Hash = 0x7cb19 // scrollbar-highlight-color - Scrollbar_Shadow_Color Hash = 0x87116 // scrollbar-shadow-color - Scrollbar_Track_Color Hash = 0x72315 // scrollbar-track-color - Seagreen Hash = 0x93c08 // seagreen - Seashell Hash = 0x2c308 // seashell - Serif Hash = 0x3a005 // serif - Size Hash = 0x1d604 // size - Slateblue Hash = 0x95509 // slateblue - Slategray Hash = 0xbfe09 // slategray - Small Hash = 0x68f05 // small - Smaller Hash = 0x68f07 // smaller - Solid Hash = 0x74c05 // solid - Space Hash = 0x6905 // space - Speak Hash = 0x78105 // speak - Speak_Header Hash = 0x7810c // speak-header - Speak_Numeral Hash = 0x7f90d // speak-numeral - Speak_Punctuation Hash = 0xaf211 // speak-punctuation - Speech_Rate Hash = 0xc570b // speech-rate - Springgreen Hash = 0xa710b // springgreen - Steelblue Hash = 0x96309 // steelblue - Stress Hash = 0x11b06 // stress - Stroke Hash = 0xc7806 // stroke - Supports Hash = 0xcbc08 // supports - Table_Layout Hash = 0xcf20c // table-layout - Text_Align Hash = 0x10e0a // text-align - Text_Align_Last Hash = 0x10e0f // text-align-last - Text_Autospace Hash = 0x4400e // text-autospace - Text_Decoration Hash = 0x7e0f // text-decoration - Text_Decoration_Color Hash = 0x2a115 // text-decoration-color - Text_Decoration_Line Hash = 0x7e14 // text-decoration-line - Text_Decoration_Style Hash = 0xb5115 // text-decoration-style - Text_Decoration_Thickness Hash = 0xc6019 // text-decoration-thickness - Text_Emphasis Hash = 0x170d // text-emphasis - Text_Emphasis_Color Hash = 0x1713 // text-emphasis-color - Text_Indent Hash = 0x3f0b // text-indent - Text_Justify Hash = 0x490c // text-justify - Text_Kashida_Space Hash = 0x5c12 // text-kashida-space - Text_Overflow Hash = 0x980d // text-overflow - Text_Shadow Hash = 0xd600b // text-shadow - Text_Transform Hash = 0xd970e // text-transform - Text_Underline_Position Hash = 0xdba17 // text-underline-position - Top Hash = 0x3be03 // top - Transition Hash = 0x4750a // transition - Transition_Delay Hash = 0x59a10 // transition-delay - Transition_Duration Hash = 0xb9413 // transition-duration - Transition_Property Hash = 0x47513 // transition-property - Transition_Timing_Function Hash = 0xa281a // transition-timing-function - Transparent Hash = 0xd150b // transparent - Turn Hash = 0xd1f04 // turn - Turquoise Hash = 0xa8209 // turquoise - Unicode_Bidi Hash = 0xcc40c // unicode-bidi - Unset Hash = 0xd2305 // unset - Url Hash = 0x3f403 // url - Var Hash = 0x64503 // var - Vertical_Align Hash = 0x7e60e // vertical-align - Visibility Hash = 0x4f70a // visibility - Voice_Family Hash = 0xd280c // voice-family - Volume Hash = 0xd3406 // volume - White Hash = 0x7b05 // white - White_Space Hash = 0x6500b // white-space - Whitesmoke Hash = 0x5c30a // whitesmoke - Widows Hash = 0xd6a06 // widows - Width Hash = 0x26b05 // width - Word_Break Hash = 0x1670a // word-break - Word_Spacing Hash = 0x28e0c // word-spacing - Word_Wrap Hash = 0xd0209 // word-wrap - Writing_Mode Hash = 0xc8f0c // writing-mode - X_Large Hash = 0xa707 // x-large - X_Small Hash = 0x68d07 // x-small - Xx_Large Hash = 0xa608 // xx-large - Xx_Small Hash = 0x68c08 // xx-small - Yellow Hash = 0x76506 // yellow - Yellowgreen Hash = 0x7650b // yellowgreen - Z_Index Hash = 0x68607 // z-index -) - -// String returns the hash' name. -func (i Hash) String() string { - start := uint32(i >> 8) - n := uint32(i & 0xff) - if start+n > uint32(len(_Hash_text)) { - return "" - } - return _Hash_text[start : start+n] -} - -// ToHash returns the hash whose name is s. It returns zero if there is no -// such hash. It is case sensitive. -func ToHash(s []byte) Hash { - if len(s) == 0 || len(s) > _Hash_maxLen { - return 0 - } - h := uint32(_Hash_hash0) - for i := 0; i < len(s); i++ { - h ^= uint32(s[i]) - h *= 16777619 - } - if i := _Hash_table[h&uint32(len(_Hash_table)-1)]; int(i&0xff) == len(s) { - t := _Hash_text[i>>8 : i>>8+i&0xff] - for i := 0; i < len(s); i++ { - if t[i] != s[i] { - goto NEXT - } - } - return i - } -NEXT: - if i := _Hash_table[(h>>16)&uint32(len(_Hash_table)-1)]; int(i&0xff) == len(s) { - t := _Hash_text[i>>8 : i>>8+i&0xff] - for i := 0; i < len(s); i++ { - if t[i] != s[i] { - return 0 - } - } - return i - } - return 0 -} - -const _Hash_hash0 = 0x9acb0442 -const _Hash_maxLen = 27 -const _Hash_text = "-ms-filteradial-gradientext-emphasis-colorgbackground-attach" + - "mentext-indentext-justify-contentext-kashida-spacelevationav" + - "ajowhitext-decoration-line-heightext-overflow-xx-largerichne" + - "ssaddlebrowno-repeat-yanimation-namespacenteruby-overhangain" + - "sborosybrownanimation-play-statext-align-lastresscrollbar-ar" + - "row-coloruby-positionanimation-timing-functionazimuthoneydew" + - "ord-breakbackground-originclude-sourcebackground-position-xb" + - "ackground-position-ybackground-repeat-xbackground-sizebehavi" + - "orblackblanchedalmondarkblueboldarkcyanimation-delayer-backg" + - "round-colorborder-bottom-colorborder-bottom-stylemonchiffont" + - "-faceborder-bottom-widthslavenderblushborder-box-shadoword-s" + - "pacinghostwhitext-decoration-colorborder-collapseashellawngr" + - "eenborder-colorborder-left-colorborder-left-styleborder-left" + - "-widthborder-right-colorborder-right-styleborder-right-width" + - "border-spacingrid-areanimation-durationormalphacceleratorpha" + - "nsandybrownonempty-cellsans-serifantasyborder-styleborder-to" + - "p-colorborder-top-styleborder-top-widthborder-widthburlywood" + - "arkgoldenrodarkgraycaption-sideepskybluecaret-colorchartreus" + - "echocolatext-autospaceclampadding-boxclearcolumn-counter-res" + - "etransition-propertycolumn-rule-colorcolumn-rule-stylecolumn" + - "-rule-widthcolumn-widthcornflowerbluecornsilkcue-aftercue-be" + - "forestgreenvisibilitycurrentcolorcursivecursordarkvioletdocu" + - "mentdodgerbluedpcmargin-topadding-rightdpitch-rangedppxflex-" + - "growflex-shrinkflex-wrapadding-topage-break-afterfloattransi" + - "tion-delayer-background-imagefloralwhitesmokeyframescrollbar" + - "-dark-shadow-colorfont-familyfont-size-adjustify-itemscrollb" + - "ar-face-colorfont-stretcharsetfont-stylefont-variantiquewhit" + - "e-spacefont-weightfuchsianimation-fill-modeeppinkhz-indexx-s" + - "malleroyalbluegrid-column-gapage-break-beforegrid-column-sta" + - "rtgrid-row-endarkolivegreengrid-row-gapage-break-insidegrid-" + - "row-startgrid-template-areascrollbar-track-colorgrid-templat" + - "e-columnsolidarkorangeredarkgreenyellowgreengrid-template-ro" + - "wspeak-headerimportantinheritinitialicebluevioletter-spacing" + - "rid-auto-columnscrollbar-highlight-colorinvertical-align-ite" + - "mspeak-numeralayout-grid-char-spacingrid-auto-flowjustify-se" + - "lfirebricklayout-grid-line-breaklayout-grid-modegrid-auto-ro" + - "wscrollbar-shadow-colorlayout-grid-typeachpufflex-basiscroll" + - "bar-base-colorlightbluelightcoralign-selflex-directionlightc" + - "yanimation-directionlightgoldenrodyellowlightgraylightgreenl" + - "ightpinklightsalmonlightseagreenlightskybluelightslateblueli" + - "ghtsteelbluelightyellowlimegreenlinear-gradientlist-style-im" + - "agelist-style-positionlist-style-typelocalcadetbluemaskmax-h" + - "eightmax-widthmediumaquamarinemediumbluemediumorchidarkorchi" + - "darkkhakime-modefaultransition-timing-functionmediumpurpleme" + - "diumseagreenmediumslatebluemediumspringgreenmediumturquoisem" + - "ediumvioletredarksalmonospacemidnightbluemin-heightmin-width" + - "mintcreamarker-offset-anchormistyrosemmarkspeak-punctuationm" + - "occasindianredarkseagreenoffset-distanceoffset-pathoffset-po" + - "sitionoffset-rotatext-decoration-styleolivedrabackground-cli" + - "padding-bottomargin-rightransition-durationoutline-coloroutl" + - "ine-styleoutline-widthoverflow-ypalegreenpaleturquoisepalevi" + - "oletredarkslategraypapayawhipalegoldenrodarkslatebluepause-a" + - "fterpause-beforeplace-contentplace-itemspeech-ratext-decorat" + - "ion-thicknesstrokeplace-selflex-flowriting-modepowderbluepro" + - "gidarkturquoisequotesupportsunicode-bidisplay-duringrid-colu" + - "mn-endarkmagentable-layout-floword-wrapadding-leftransparent" + - "urnunsetvoice-familyvolumedianimation-iteration-counter-incr" + - "ementext-shadowidowscrollbar-3d-light-coloruby-align-content" + - "ext-transformargin-bottomargin-leftext-underline-position" - -var _Hash_table = [1 << 10]Hash{ - 0x3: 0xc290b, // pause-after - 0x6: 0xd5011, // counter-increment - 0x8: 0xcce07, // display - 0x9: 0x51a0a, // darkviolet - 0xb: 0xbf09, // no-repeat - 0xd: 0x4402, // in - 0x14: 0x6f211, // page-break-inside - 0x15: 0x6250c, // font-stretch - 0x19: 0x5f910, // font-size-adjust - 0x1a: 0x47513, // transition-property - 0x1c: 0x78105, // speak - 0x1f: 0x82a0c, // justify-self - 0x20: 0x61114, // scrollbar-face-color - 0x24: 0x2b60f, // border-collapse - 0x25: 0x68607, // z-index - 0x27: 0xd8b0d, // align-content - 0x2a: 0x99f13, // list-style-position - 0x2b: 0xcdb0f, // grid-column-end - 0x2c: 0x14119, // animation-timing-function - 0x30: 0xb0909, // indianred - 0x34: 0x97709, // limegreen - 0x35: 0xbc10d, // outline-width - 0x3f: 0x15a07, // azimuth - 0x40: 0x1e70e, // blanchedalmond - 0x41: 0x84a0a, // line-break - 0x42: 0x7a209, // aliceblue - 0x43: 0xf309, // rosybrown - 0x46: 0xa7c0f, // mediumturquoise - 0x49: 0xd6a06, // widows - 0x4b: 0xb370f, // offset-position - 0x4d: 0xd150b, // transparent - 0x4e: 0x79d07, // initial - 0x52: 0x1cb0f, // background-size - 0x55: 0x2505, // color - 0x56: 0x59a10, // transition-delay - 0x5a: 0x750b, // navajowhite - 0x5b: 0x7110d, // grid-template - 0x5c: 0x3b710, // border-top-color - 0x62: 0xbce0a, // overflow-y - 0x64: 0x9370d, // lightseagreen - 0x6c: 0x10e0f, // text-align-last - 0x6f: 0x8050b, // layout-grid - 0x70: 0xca09, // animation - 0x71: 0x1da08, // behavior - 0x72: 0x5390a, // margin-top - 0x74: 0x3ab0c, // border-style - 0x78: 0x5d31b, // scrollbar-dark-shadow-color - 0x79: 0x69103, // all - 0x7a: 0x3f0b, // text-indent - 0x7b: 0xbe10d, // paleturquoise - 0x7e: 0x58510, // page-break-after - 0x80: 0x5420d, // padding-right - 0x84: 0x7e60e, // vertical-align - 0x85: 0x50d07, // cursive - 0x8a: 0x7030e, // grid-row-start - 0x8c: 0xae08, // richness - 0x8e: 0x3b70a, // border-top - 0x94: 0x35509, // grid-area - 0x95: 0x85410, // layout-grid-mode - 0x96: 0xaee05, // marks - 0x97: 0x64d01, // q - 0x98: 0x78d09, // important - 0x9c: 0x406, // filter - 0x9d: 0xa8b0f, // mediumvioletred - 0xa5: 0xc570b, // speech-rate - 0xa8: 0x53702, // pc - 0xab: 0x90f, // radial-gradient - 0xae: 0x11b06, // stress - 0xb4: 0x6050d, // justify-items - 0xb7: 0x9500e, // lightslateblue - 0xba: 0x35504, // grid - 0xbb: 0xb0308, // moccasin - 0xbe: 0xd0209, // word-wrap - 0xc0: 0x6d90e, // darkolivegreen - 0xc5: 0xc6019, // text-decoration-thickness - 0xc7: 0xdb06, // center - 0xc8: 0x2a115, // text-decoration-color - 0xcb: 0xabf09, // min-width - 0xce: 0x5ee0b, // font-family - 0xd1: 0xa1c08, // ime-mode - 0xd3: 0x3d710, // border-top-width - 0xd4: 0x53906, // margin - 0xd9: 0x4880b, // column-rule - 0xda: 0x98f0a, // list-style - 0xdf: 0x6ce0c, // grid-row-end - 0xe4: 0x2050f, // animation-delay - 0xe8: 0x4aa11, // column-rule-width - 0xec: 0x57309, // flex-wrap - 0xed: 0xced07, // magenta - 0xee: 0x88710, // layout-grid-type - 0xef: 0x4520b, // padding-box - 0xf0: 0x7e14, // text-decoration-line - 0xf2: 0x4dd09, // cue-after - 0xf4: 0x8640e, // grid-auto-rows - 0xf5: 0x7650b, // yellowgreen - 0xf8: 0x89509, // peachpuff - 0xf9: 0x74607, // columns - 0xfa: 0x22805, // order - 0xfb: 0x3120c, // border-right - 0x100: 0x1800e, // include-source - 0x104: 0xc2905, // pause - 0x105: 0x1fc04, // bold - 0x106: 0xcc40c, // unicode-bidi - 0x108: 0x67604, // fill - 0x109: 0x75c09, // darkgreen - 0x10b: 0x45d05, // clear - 0x10c: 0x67d08, // deeppink - 0x110: 0x8e913, // animation-direction - 0x112: 0x1b811, // background-repeat - 0x117: 0xca506, // progid - 0x11d: 0x8a614, // scrollbar-base-color - 0x11e: 0xa, // -ms-filter - 0x11f: 0x2ca09, // lawngreen - 0x120: 0x51406, // cursor - 0x121: 0x44e05, // clamp - 0x123: 0x48811, // column-rule-color - 0x128: 0x40f0c, // caption-side - 0x12a: 0xc9b0a, // powderblue - 0x12b: 0xdba17, // text-underline-position - 0x12d: 0x72315, // scrollbar-track-color - 0x131: 0x81c0e, // grid-auto-flow - 0x132: 0x7810c, // speak-header - 0x133: 0x25409, // font-face - 0x136: 0xa710b, // springgreen - 0x13a: 0xc7e0a, // place-self - 0x13d: 0xc206, // repeat - 0x13e: 0x9800f, // linear-gradient - 0x142: 0x5010c, // currentcolor - 0x145: 0xad706, // offset - 0x14a: 0x69e0f, // grid-column-gap - 0x14c: 0x6905, // space - 0x14e: 0x39b0a, // sans-serif - 0x14f: 0x6360a, // font-style - 0x153: 0x66607, // fuchsia - 0x154: 0xb7904, // clip - 0x155: 0xae409, // mistyrose - 0x158: 0x9d08, // overflow - 0x15d: 0xc7806, // stroke - 0x162: 0x80510, // layout-grid-char - 0x163: 0xa420c, // mediumpurple - 0x165: 0x4f503, // env - 0x168: 0x4690d, // counter-reset - 0x16b: 0x5cb09, // keyframes - 0x16f: 0x7b05, // white - 0x172: 0x1004, // grad - 0x174: 0xda40d, // margin-bottom - 0x175: 0x31212, // border-right-color - 0x177: 0x25404, // font - 0x178: 0xc100d, // palegoldenrod - 0x179: 0x73815, // grid-template-columns - 0x17a: 0x7e0f, // text-decoration - 0x17e: 0x89d0a, // flex-basis - 0x186: 0x7ef0b, // align-items - 0x189: 0x4bb0c, // column-width - 0x18a: 0x3c710, // border-top-style - 0x18b: 0x1d604, // size - 0x18c: 0xd3805, // media - 0x191: 0xb7c0e, // padding-bottom - 0x194: 0x2df11, // border-left-color - 0x195: 0x7a70a, // blueviolet - 0x198: 0x92c0b, // lightsalmon - 0x19d: 0x27108, // lavender - 0x19e: 0x5a716, // layer-background-image - 0x1a0: 0x6500b, // white-space - 0x1a3: 0xe00d, // ruby-overhang - 0x1a4: 0x24b0c, // lemonchiffon - 0x1a5: 0x3be03, // top - 0x1a9: 0x2c308, // seashell - 0x1aa: 0x7ae0e, // letter-spacing - 0x1ac: 0x2b0a, // background - 0x1af: 0x64503, // var - 0x1b0: 0xaed02, // mm - 0x1b6: 0x12015, // scrollbar-arrow-color - 0x1b8: 0xd970e, // text-transform - 0x1b9: 0x65b0b, // font-weight - 0x1ba: 0x53802, // cm - 0x1bb: 0x12006, // scroll - 0x1c0: 0x21710, // background-color - 0x1c1: 0x2710d, // lavenderblush - 0x1c6: 0xb5115, // text-decoration-style - 0x1c9: 0x79607, // inherit - 0x1cf: 0x2e604, // left - 0x1d0: 0x6490c, // antiquewhite - 0x1d4: 0xb6609, // olivedrab - 0x1da: 0x2990a, // ghostwhite - 0x1dd: 0x91009, // lightgray - 0x1e2: 0x26f04, // hsla - 0x1e3: 0x26f03, // hsl - 0x1e4: 0xbd809, // palegreen - 0x1e5: 0x4190b, // deepskyblue - 0x1e8: 0xac809, // mintcream - 0x1ea: 0x7e406, // invert - 0x1eb: 0x6400c, // font-variant - 0x1ec: 0x8fc14, // lightgoldenrodyellow - 0x1ee: 0x62f07, // charset - 0x1ef: 0xc8f0c, // writing-mode - 0x1f0: 0x5c30a, // whitesmoke - 0x1f5: 0x9d0a, // overflow-x - 0x1f6: 0xaa90c, // midnightblue - 0x1f7: 0xcb706, // quotes - 0x1f8: 0x22706, // border - 0x1fa: 0x42f0a, // chartreuse - 0x1fc: 0xba707, // outline - 0x1fd: 0xa281a, // transition-timing-function - 0x1fe: 0xcbc08, // supports - 0x204: 0x1670a, // word-break - 0x205: 0xaa009, // monospace - 0x206: 0x2850a, // box-shadow - 0x209: 0x5680b, // flex-shrink - 0x20f: 0xd0a0c, // padding-left - 0x214: 0xc4d0b, // place-items - 0x216: 0xc070a, // papayawhip - 0x217: 0x17111, // background-origin - 0x218: 0x52408, // document - 0x219: 0x52c0a, // dodgerblue - 0x21c: 0x9440c, // lightskyblue - 0x21e: 0x6bd11, // grid-column-start - 0x221: 0x30111, // border-left-width - 0x224: 0x68c08, // xx-small - 0x226: 0x1f408, // darkblue - 0x229: 0x25d13, // border-bottom-width - 0x22a: 0x98f10, // list-style-image - 0x22d: 0x44504, // auto - 0x230: 0x1e205, // black - 0x231: 0xaf211, // speak-punctuation - 0x232: 0x13908, // position - 0x234: 0xc340c, // pause-before - 0x236: 0x95e0e, // lightsteelblue - 0x23a: 0xcd10b, // play-during - 0x23f: 0x83509, // firebrick - 0x249: 0x6ce08, // grid-row - 0x24a: 0x55d02, // px - 0x24c: 0x1a315, // background-position-y - 0x251: 0xd1f04, // turn - 0x256: 0xba70d, // outline-color - 0x257: 0x9c304, // calc - 0x258: 0xd3c19, // animation-iteration-count - 0x259: 0xad70d, // offset-anchor - 0x25b: 0xa4e0e, // mediumseagreen - 0x25e: 0x4620c, // column-count - 0x263: 0x10e0a, // text-align - 0x266: 0x66c13, // animation-fill-mode - 0x267: 0x32412, // border-right-style - 0x268: 0xa707, // x-large - 0x269: 0x8d40e, // flex-direction - 0x26a: 0x4f70a, // visibility - 0x26f: 0xb2c0b, // offset-path - 0x270: 0x27e0a, // border-box - 0x276: 0x70103, // deg - 0x278: 0x1713, // text-emphasis-color - 0x27f: 0xc1c0d, // darkslateblue - 0x283: 0x55f09, // flex-grow - 0x285: 0x8e209, // lightcyan - 0x28a: 0x102, // ms - 0x28d: 0xa906, // larger - 0x28e: 0xa990a, // darksalmon - 0x292: 0x2f011, // border-left-style - 0x293: 0xa8209, // turquoise - 0x294: 0x3a407, // fantasy - 0x296: 0xec09, // gainsboro - 0x297: 0x201, // s - 0x298: 0x23a13, // border-bottom-style - 0x299: 0xce90b, // darkmagenta - 0x29b: 0xb50b, // saddlebrown - 0x2a0: 0x59505, // float - 0x2a3: 0x6ec07, // row-gap - 0x2a5: 0xd3406, // volume - 0x2a6: 0xab50a, // min-height - 0x2a7: 0x77012, // grid-template-rows - 0x2a9: 0x3760b, // accelerator - 0x2b0: 0x68f05, // small - 0x2b1: 0x59804, // attr - 0x2b2: 0x28e0c, // word-spacing - 0x2b3: 0x35d12, // animation-duration - 0x2b5: 0x4dd03, // cue - 0x2b6: 0x95509, // slateblue - 0x2b8: 0x38e04, // none - 0x2b9: 0x6a30a, // column-gap - 0x2ba: 0x4e0f, // justify-content - 0x2bb: 0x5607, // content - 0x2bd: 0x54f03, // dpi - 0x2be: 0x87116, // scrollbar-shadow-color - 0x2bf: 0x78d06, // import - 0x2c0: 0xc8709, // flex-flow - 0x2c1: 0x69509, // royalblue - 0x2c3: 0x9c609, // cadetblue - 0x2c4: 0x490c, // text-justify - 0x2cb: 0x8c30a, // lightcoral - 0x2cf: 0xb890c, // margin-right - 0x2d2: 0x76506, // yellow - 0x2d3: 0x26b05, // width - 0x2d6: 0x14d03, // min - 0x2da: 0x1340d, // ruby-position - 0x2dc: 0x40708, // darkgray - 0x2e2: 0x69e0b, // grid-column - 0x2e4: 0xa1409, // darkkhaki - 0x2e5: 0xc400d, // place-content - 0x2e7: 0xbee0d, // palevioletred - 0x2ea: 0x5bd0b, // floralwhite - 0x2eb: 0xc208, // repeat-y - 0x2ee: 0x980d, // text-overflow - 0x2f1: 0xca0e, // animation-name - 0x2fb: 0x7cb19, // scrollbar-highlight-color - 0x2fe: 0x5500b, // pitch-range - 0x302: 0x3005, // round - 0x305: 0x4c70e, // cornflowerblue - 0x307: 0x7f90d, // speak-numeral - 0x308: 0x9e606, // medium - 0x30a: 0x170d, // text-emphasis - 0x30d: 0x9dd09, // max-width - 0x311: 0x36e06, // normal - 0x312: 0x68403, // khz - 0x315: 0x2903, // rgb - 0x316: 0x8ba09, // lightblue - 0x317: 0x8d909, // direction - 0x31a: 0xd280c, // voice-family - 0x31c: 0x3480e, // border-spacing - 0x321: 0x6d09, // elevation - 0x323: 0x1c308, // repeat-x - 0x324: 0x83e10, // layout-grid-line - 0x326: 0xa000c, // mediumorchid - 0x32b: 0xa6b11, // mediumspringgreen - 0x32d: 0xa905, // large - 0x32e: 0xd860a, // ruby-align - 0x330: 0xbfa0d, // darkslategray - 0x332: 0x5c12, // text-kashida-space - 0x334: 0xbb40d, // outline-style - 0x336: 0x3a005, // serif - 0x337: 0x4240b, // caret-color - 0x33a: 0x37205, // alpha - 0x33c: 0x71113, // grid-template-areas - 0x33d: 0x49911, // column-rule-style - 0x33f: 0xcf80b, // layout-flow - 0x340: 0x31905, // right - 0x341: 0x3e70c, // border-width - 0x343: 0xb6e0f, // background-clip - 0x345: 0x74c05, // solid - 0x346: 0x2df0b, // border-left - 0x348: 0x9ec0a, // aquamarine - 0x349: 0x3850a, // sandybrown - 0x34a: 0x16008, // honeydew - 0x34b: 0x75409, // orangered - 0x34c: 0xb110c, // darkseagreen - 0x34d: 0x37f07, // orphans - 0x34e: 0x6e70c, // grid-row-gap - 0x351: 0x22e06, // bottom - 0x359: 0x9c105, // local - 0x35c: 0x8cb0a, // align-self - 0x35e: 0x33612, // border-right-width - 0x360: 0x2b15, // background-attachment - 0x364: 0x9190a, // lightgreen - 0x366: 0x39302, // pt - 0x368: 0x4400e, // text-autospace - 0x36b: 0x3f403, // url - 0x36c: 0x68502, // hz - 0x371: 0x9306, // height - 0x372: 0x5ad10, // background-image - 0x377: 0x903, // rad - 0x37c: 0x21116, // layer-background-color - 0x37d: 0x1ff08, // darkcyan - 0x382: 0x18e13, // background-position - 0x384: 0x9d303, // max - 0x38c: 0xa608, // xx-large - 0x38d: 0x3f309, // burlywood - 0x38f: 0xd6f18, // scrollbar-3d-light-color - 0x390: 0x3ff09, // goldenrod - 0x392: 0x92309, // lightpink - 0x393: 0x8e0b, // line-height - 0x396: 0x22713, // border-bottom-color - 0x398: 0x80518, // layout-grid-char-spacing - 0x39c: 0x2904, // rgba - 0x3a1: 0x9f60a, // mediumblue - 0x3a3: 0x9d30a, // max-height - 0x3a4: 0x7bb11, // grid-auto-columns - 0x3a5: 0xa0b0a, // darkorchid - 0x3a9: 0x7600b, // greenyellow - 0x3ae: 0x96c0b, // lightyellow - 0x3b1: 0x4750a, // transition - 0x3b3: 0x4e60a, // cue-before - 0x3b9: 0x96309, // steelblue - 0x3be: 0xa5c0f, // mediumslateblue - 0x3bf: 0xcaa0d, // darkturquoise - 0x3c0: 0x43909, // chocolate - 0x3c3: 0x5f909, // font-size - 0x3c5: 0x55f04, // flex - 0x3c7: 0xd2305, // unset - 0x3c8: 0xd600b, // text-shadow - 0x3ca: 0x4ec0b, // forestgreen - 0x3cc: 0xbfe09, // slategray - 0x3cd: 0x6ac11, // page-break-before - 0x3ce: 0x55b04, // dppx - 0x3d0: 0x2270d, // border-bottom - 0x3d3: 0xb1d0f, // offset-distance - 0x3d4: 0x3fb0d, // darkgoldenrod - 0x3d6: 0x53604, // dpcm - 0x3d8: 0x7500a, // darkorange - 0x3dc: 0xb9413, // transition-duration - 0x3de: 0x2d30c, // border-color - 0x3df: 0x18e15, // background-position-x - 0x3e0: 0x55005, // pitch - 0x3e2: 0xdb00b, // margin-left - 0x3e3: 0x58504, // page - 0x3e5: 0x57b0b, // padding-top - 0x3e7: 0xb460d, // offset-rotate - 0x3e8: 0x93c08, // seagreen - 0x3e9: 0x4d508, // cornsilk - 0x3ea: 0x68f07, // smaller - 0x3ec: 0xcf20c, // table-layout - 0x3ed: 0xfc14, // animation-play-state - 0x3ef: 0xa2207, // default - 0x3f0: 0x68d07, // x-small - 0x3f3: 0x9e610, // mediumaquamarine - 0x3f4: 0xad00d, // marker-offset - 0x3f9: 0xd409, // namespace - 0x3fa: 0x9cf04, // mask - 0x3fb: 0x45207, // padding - 0x3fd: 0x9b20f, // list-style-type - 0x3ff: 0x3910b, // empty-cells -} diff --git a/vendor/github.com/tdewolff/minify/v2/css/table.go b/vendor/github.com/tdewolff/minify/v2/css/table.go deleted file mode 100644 index 1e36259a7e1f5..0000000000000 --- a/vendor/github.com/tdewolff/minify/v2/css/table.go +++ /dev/null @@ -1,197 +0,0 @@ -package css - -var optionalZeroDimension = map[string]bool{ - "px": true, - "mm": true, - "q": true, - "cm": true, - "in": true, - "pt": true, - "pc": true, - "ch": true, - "em": true, - "ex": true, - "rem": true, - "vh": true, - "vw": true, - "vmin": true, - "vmax": true, - "deg": true, - "grad": true, - "rad": true, - "turn": true, -} - -// Uses http://www.w3.org/TR/2010/PR-css3-color-20101028/ for colors - -// ShortenColorHex maps a color hexcode to its shorter name -var ShortenColorHex = map[string][]byte{ - "#000080": []byte("navy"), - "#008000": []byte("green"), - "#008080": []byte("teal"), - "#4b0082": []byte("indigo"), - "#800000": []byte("maroon"), - "#800080": []byte("purple"), - "#808000": []byte("olive"), - "#808080": []byte("gray"), - "#a0522d": []byte("sienna"), - "#a52a2a": []byte("brown"), - "#c0c0c0": []byte("silver"), - "#cd853f": []byte("peru"), - "#d2b48c": []byte("tan"), - "#da70d6": []byte("orchid"), - "#dda0dd": []byte("plum"), - "#ee82ee": []byte("violet"), - "#f0e68c": []byte("khaki"), - "#f0ffff": []byte("azure"), - "#f5deb3": []byte("wheat"), - "#f5f5dc": []byte("beige"), - "#fa8072": []byte("salmon"), - "#faf0e6": []byte("linen"), - "#ff6347": []byte("tomato"), - "#ff7f50": []byte("coral"), - "#ffa500": []byte("orange"), - "#ffc0cb": []byte("pink"), - "#ffd700": []byte("gold"), - "#ffe4c4": []byte("bisque"), - "#fffafa": []byte("snow"), - "#fffff0": []byte("ivory"), - "#ff0000": []byte("red"), - "#f00": []byte("red"), -} - -// ShortenColorName maps a color name to its shorter hexcode -var ShortenColorName = map[Hash][]byte{ - Black: []byte("#000"), - Darkblue: []byte("#00008b"), - Mediumblue: []byte("#0000cd"), - Darkgreen: []byte("#006400"), - Darkcyan: []byte("#008b8b"), - Deepskyblue: []byte("#00bfff"), - Darkturquoise: []byte("#00ced1"), - Mediumspringgreen: []byte("#00fa9a"), - Springgreen: []byte("#00ff7f"), - Midnightblue: []byte("#191970"), - Dodgerblue: []byte("#1e90ff"), - Lightseagreen: []byte("#20b2aa"), - Forestgreen: []byte("#228b22"), - Seagreen: []byte("#2e8b57"), - Darkslategray: []byte("#2f4f4f"), - Limegreen: []byte("#32cd32"), - Mediumseagreen: []byte("#3cb371"), - Turquoise: []byte("#40e0d0"), - Royalblue: []byte("#4169e1"), - Steelblue: []byte("#4682b4"), - Darkslateblue: []byte("#483d8b"), - Mediumturquoise: []byte("#48d1cc"), - Darkolivegreen: []byte("#556b2f"), - Cadetblue: []byte("#5f9ea0"), - Cornflowerblue: []byte("#6495ed"), - Mediumaquamarine: []byte("#66cdaa"), - Slateblue: []byte("#6a5acd"), - Olivedrab: []byte("#6b8e23"), - Slategray: []byte("#708090"), - Lightslateblue: []byte("#789"), - Mediumslateblue: []byte("#7b68ee"), - Lawngreen: []byte("#7cfc00"), - Chartreuse: []byte("#7fff00"), - Aquamarine: []byte("#7fffd4"), - Lightskyblue: []byte("#87cefa"), - Blueviolet: []byte("#8a2be2"), - Darkmagenta: []byte("#8b008b"), - Saddlebrown: []byte("#8b4513"), - Darkseagreen: []byte("#8fbc8f"), - Lightgreen: []byte("#90ee90"), - Mediumpurple: []byte("#9370db"), - Darkviolet: []byte("#9400d3"), - Palegreen: []byte("#98fb98"), - Darkorchid: []byte("#9932cc"), - Yellowgreen: []byte("#9acd32"), - Darkgray: []byte("#a9a9a9"), - Lightblue: []byte("#add8e6"), - Greenyellow: []byte("#adff2f"), - Paleturquoise: []byte("#afeeee"), - Lightsteelblue: []byte("#b0c4de"), - Powderblue: []byte("#b0e0e6"), - Firebrick: []byte("#b22222"), - Darkgoldenrod: []byte("#b8860b"), - Mediumorchid: []byte("#ba55d3"), - Rosybrown: []byte("#bc8f8f"), - Darkkhaki: []byte("#bdb76b"), - Mediumvioletred: []byte("#c71585"), - Indianred: []byte("#cd5c5c"), - Chocolate: []byte("#d2691e"), - Lightgray: []byte("#d3d3d3"), - Goldenrod: []byte("#daa520"), - Palevioletred: []byte("#db7093"), - Gainsboro: []byte("#dcdcdc"), - Burlywood: []byte("#deb887"), - Lightcyan: []byte("#e0ffff"), - Lavender: []byte("#e6e6fa"), - Darksalmon: []byte("#e9967a"), - Palegoldenrod: []byte("#eee8aa"), - Lightcoral: []byte("#f08080"), - Aliceblue: []byte("#f0f8ff"), - Honeydew: []byte("#f0fff0"), - Sandybrown: []byte("#f4a460"), - Whitesmoke: []byte("#f5f5f5"), - Mintcream: []byte("#f5fffa"), - Ghostwhite: []byte("#f8f8ff"), - Antiquewhite: []byte("#faebd7"), - Lightgoldenrodyellow: []byte("#fafad2"), - Fuchsia: []byte("#f0f"), - Magenta: []byte("#f0f"), - Deeppink: []byte("#ff1493"), - Orangered: []byte("#ff4500"), - Darkorange: []byte("#ff8c00"), - Lightsalmon: []byte("#ffa07a"), - Lightpink: []byte("#ffb6c1"), - Peachpuff: []byte("#ffdab9"), - Navajowhite: []byte("#ffdead"), - Moccasin: []byte("#ffe4b5"), - Mistyrose: []byte("#ffe4e1"), - Blanchedalmond: []byte("#ffebcd"), - Papayawhip: []byte("#ffefd5"), - Lavenderblush: []byte("#fff0f5"), - Seashell: []byte("#fff5ee"), - Cornsilk: []byte("#fff8dc"), - Lemonchiffon: []byte("#fffacd"), - Floralwhite: []byte("#fffaf0"), - Yellow: []byte("#ff0"), - Lightyellow: []byte("#ffffe0"), - White: []byte("#fff"), -} - -var PropertyOverrides = map[Hash][]Hash{ - Background: []Hash{Background, Background_Image, Background_Position, Background_Size, Background_Repeat, Background_Origin, Background_Clip, Background_Attachment, Background_Color}, - Font: []Hash{Font, Font_Style, Font_Variant, Font_Weight, Font_Stretch, Font_Size, Font_Family, Line_Height}, - Border: []Hash{Border, Border_Width, Border_Top_Width, Border_Right_Width, Border_Bottom_Width, Border_Left_Width, Border_Style, Border_Top_Style, Border_Right_Style, Border_Bottom_Style, Border_Left_Style, Border_Color, Border_Top_Color, Border_Right_Color, Border_Bottom_Color, Border_Left_Color}, - Border_Width: []Hash{Border_Width, Border_Top_Width, Border_Right_Width, Border_Bottom_Width, Border_Left_Width}, - Border_Style: []Hash{Border_Style, Border_Top_Style, Border_Right_Style, Border_Bottom_Style, Border_Left_Style}, - Border_Color: []Hash{Border_Color, Border_Top_Color, Border_Right_Color, Border_Bottom_Color, Border_Left_Color}, - Border_Top: []Hash{Border_Top, Border_Top_Width, Border_Top_Style, Border_Top_Color}, - Border_Right: []Hash{Border_Right, Border_Right_Width, Border_Right_Style, Border_Right_Color}, - Border_Bottom: []Hash{Border_Bottom, Border_Bottom_Width, Border_Bottom_Style, Border_Bottom_Color}, - Border_Left: []Hash{Border_Left, Border_Left_Width, Border_Left_Style, Border_Left_Color}, - Margin: []Hash{Margin, Margin_Top, Margin_Right, Margin_Bottom, Margin_Left}, - Padding: []Hash{Padding, Padding_Top, Padding_Right, Padding_Bottom, Padding_Left}, - Column_Rule: []Hash{Column_Rule, Column_Rule_Width, Column_Rule_Style, Column_Rule_Color}, - Animation: []Hash{Animation, Animation_Name, Animation_Duration, Animation_Timing_Function, Animation_Delay, Animation_Iteration_Count, Animation_Direction, Animation_Fill_Mode, Animation_Play_State}, - Columns: []Hash{Columns, Column_Width, Column_Count}, - Flex: []Hash{Flex, Flex_Basis, Flex_Grow, Flex_Shrink}, - Flex_Flow: []Hash{Flex_Flow, Flex_Direction, Flex_Wrap}, - Grid: []Hash{Grid, Grid_Template_Rows, Grid_Template_Columns, Grid_Template_Areas, Grid_Auto_Rows, Grid_Auto_Columns, Grid_Auto_Flow, Grid_Column_Gap, Grid_Row_Gap, Column_Gap, Row_Gap}, - Grid_Area: []Hash{Grid_Area, Grid_Row_Start, Grid_Column_Start, Grid_Row_End, Grid_Column_End}, - Grid_Row: []Hash{Grid_Row, Grid_Row_Start, Grid_Row_End}, - Grid_Column: []Hash{Grid_Column, Grid_Column_Start, Grid_Column_End}, - Grid_Template: []Hash{Grid_Template, Grid_Template_Rows, Grid_Template_Columns, Grid_Template_Areas}, - List_Style: []Hash{List_Style, List_Style_Image, List_Style_Position, List_Style_Type}, - Offset: []Hash{Offset, Offset_Position, Offset_Path, Offset_Distance, Offset_Anchor, Offset_Rotate}, - Outline: []Hash{Outline, Outline_Width, Outline_Style, Outline_Color}, - Overflow: []Hash{Overflow, Overflow_X, Overflow_Y}, - Place_Content: []Hash{Place_Content, Align_Content, Justify_Content}, - Place_Items: []Hash{Place_Items, Align_Items, Justify_Items}, - Place_Self: []Hash{Place_Self, Align_Self, Justify_Self}, - Text_Decoration: []Hash{Text_Decoration, Text_Decoration_Color, Text_Decoration_Color, Text_Decoration_Line, Text_Decoration_Thickness}, - Transition: []Hash{Transition, Transition_Property, Transition_Duration, Transition_Timing_Function, Transition_Delay}, -} diff --git a/vendor/github.com/tdewolff/minify/v2/css/util.go b/vendor/github.com/tdewolff/minify/v2/css/util.go deleted file mode 100644 index 7325aca99c7b0..0000000000000 --- a/vendor/github.com/tdewolff/minify/v2/css/util.go +++ /dev/null @@ -1,55 +0,0 @@ -package css - -import ( - "encoding/hex" - - "github.com/tdewolff/parse/v2" - "github.com/tdewolff/parse/v2/css" -) - -func removeMarkupNewlines(data []byte) []byte { - // remove any \\\r\n \\\r \\\n - for i := 1; i < len(data)-2; i++ { - if data[i] == '\\' && (data[i+1] == '\n' || data[i+1] == '\r') { - // encountered first replacee, now start to move bytes to the front - j := i + 2 - if data[i+1] == '\r' && len(data) > i+2 && data[i+2] == '\n' { - j++ - } - for ; j < len(data); j++ { - if data[j] == '\\' && len(data) > j+1 && (data[j+1] == '\n' || data[j+1] == '\r') { - if data[j+1] == '\r' && len(data) > j+2 && data[j+2] == '\n' { - j++ - } - j++ - } else { - data[i] = data[j] - i++ - } - } - data = data[:i] - break - } - } - return data -} - -func rgbToToken(r, g, b float64) Token { - // r, g, b are in interval [0.0, 1.0] - rgb := []byte{byte((r * 255.0) + 0.5), byte((g * 255.0) + 0.5), byte((b * 255.0) + 0.5)} - - val := make([]byte, 7) - val[0] = '#' - hex.Encode(val[1:], rgb) - parse.ToLower(val) - if s, ok := ShortenColorHex[string(val[:7])]; ok { - return Token{css.IdentToken, s, nil, 0, 0} - } else if val[1] == val[2] && val[3] == val[4] && val[5] == val[6] { - val[2] = val[3] - val[3] = val[5] - val = val[:4] - } else { - val = val[:7] - } - return Token{css.HashToken, val, nil, 0, 0} -} diff --git a/vendor/github.com/tdewolff/minify/v2/go.mod b/vendor/github.com/tdewolff/minify/v2/go.mod deleted file mode 100644 index d0f9355088ea5..0000000000000 --- a/vendor/github.com/tdewolff/minify/v2/go.mod +++ /dev/null @@ -1,14 +0,0 @@ -module github.com/tdewolff/minify/v2 - -go 1.13 - -require ( - github.com/cheekybits/is v0.0.0-20150225183255-68e9c0620927 // indirect - github.com/dustin/go-humanize v1.0.0 - github.com/fsnotify/fsnotify v1.4.7 - github.com/matryer/try v0.0.0-20161228173917-9ac251b645a2 - github.com/spf13/pflag v1.0.3 - github.com/tdewolff/parse/v2 v2.4.2 - github.com/tdewolff/test v1.0.6 - golang.org/x/sys v0.0.0-20181031143558-9b800f95dbbc // indirect -) diff --git a/vendor/github.com/tdewolff/minify/v2/go.sum b/vendor/github.com/tdewolff/minify/v2/go.sum deleted file mode 100644 index bdab7a51bb6b0..0000000000000 --- a/vendor/github.com/tdewolff/minify/v2/go.sum +++ /dev/null @@ -1,18 +0,0 @@ -github.com/cheekybits/is v0.0.0-20150225183255-68e9c0620927 h1:SKI1/fuSdodxmNNyVBR8d7X/HuLnRpvvFO0AgyQk764= -github.com/cheekybits/is v0.0.0-20150225183255-68e9c0620927/go.mod h1:h/aW8ynjgkuj+NQRlZcDbAbM1ORAbXjXX77sX7T289U= -github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo= -github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= -github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= -github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= -github.com/matryer/try v0.0.0-20161228173917-9ac251b645a2 h1:JAEbJn3j/FrhdWA9jW8B5ajsLIjeuEHLi8xE4fk997o= -github.com/matryer/try v0.0.0-20161228173917-9ac251b645a2/go.mod h1:0KeJpeMD6o+O4hW7qJOT7vyQPKrWmj26uf5wMc/IiIs= -github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg= -github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= -github.com/tdewolff/parse/v2 v2.4.2-0.20191217133525-7b246f800500 h1:FlcpXrF3rpbZ8lxK0BcPnl3NEDuebxk+A9Wwm/tjDH4= -github.com/tdewolff/parse/v2 v2.4.2-0.20191217133525-7b246f800500/go.mod h1:WzaJpRSbwq++EIQHYIRTpbYKNA3gn9it1Ik++q4zyho= -github.com/tdewolff/parse/v2 v2.4.2 h1:Bu2Qv6wepkc+Ou7iB/qHjAhEImlAP5vedzlQRUdj3BI= -github.com/tdewolff/parse/v2 v2.4.2/go.mod h1:WzaJpRSbwq++EIQHYIRTpbYKNA3gn9it1Ik++q4zyho= -github.com/tdewolff/test v1.0.6 h1:76mzYJQ83Op284kMT+63iCNCI7NEERsIN8dLM+RiKr4= -github.com/tdewolff/test v1.0.6/go.mod h1:6DAvZliBAAnD7rhVgwaM7DE5/d9NMOAJ09SqYqeK4QE= -golang.org/x/sys v0.0.0-20181031143558-9b800f95dbbc h1:SdCq5U4J+PpbSDIl9bM0V1e1Ug1jsnBkAFvTs1htn7U= -golang.org/x/sys v0.0.0-20181031143558-9b800f95dbbc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= diff --git a/vendor/github.com/tdewolff/minify/v2/minify.go b/vendor/github.com/tdewolff/minify/v2/minify.go deleted file mode 100644 index b12a5a35d7338..0000000000000 --- a/vendor/github.com/tdewolff/minify/v2/minify.go +++ /dev/null @@ -1,352 +0,0 @@ -// Package minify relates MIME type to minifiers. Several minifiers are provided in the subpackages. -package minify - -import ( - "bytes" - "errors" - "fmt" - "io" - "io/ioutil" - "log" - "mime" - "net/http" - "net/url" - "os" - "os/exec" - "path" - "regexp" - "strings" - "sync" - - "github.com/tdewolff/parse/v2" - "github.com/tdewolff/parse/v2/buffer" -) - -// Warning is used to report usage warnings such as using a deprecated feature -var Warning = log.New(os.Stderr, "WARNING: ", 0) - -// ErrNotExist is returned when no minifier exists for a given mimetype. -var ErrNotExist = errors.New("minifier does not exist for mimetype") - -//////////////////////////////////////////////////////////////// - -// MinifierFunc is a function that implements Minifer. -type MinifierFunc func(*M, io.Writer, io.Reader, map[string]string) error - -// Minify calls f(m, w, r, params) -func (f MinifierFunc) Minify(m *M, w io.Writer, r io.Reader, params map[string]string) error { - return f(m, w, r, params) -} - -// Minifier is the interface for minifiers. -// The *M parameter is used for minifying embedded resources, such as JS within HTML. -type Minifier interface { - Minify(*M, io.Writer, io.Reader, map[string]string) error -} - -//////////////////////////////////////////////////////////////// - -type patternMinifier struct { - pattern *regexp.Regexp - Minifier -} - -type cmdMinifier struct { - cmd *exec.Cmd -} - -func (c *cmdMinifier) Minify(_ *M, w io.Writer, r io.Reader, _ map[string]string) error { - cmd := &exec.Cmd{} - *cmd = *c.cmd // concurrency safety - - var in, out *os.File - for i, arg := range cmd.Args { - if j := strings.Index(arg, "$in"); j != -1 { - k := strings.IndexAny(arg[j+3:], " \r\n\t!\"#$&'()*;<=>?[\\]^`{|}") - if k == -1 { - k = len(arg) - } - - var err error - if in, err = ioutil.TempFile("", "minify-in-*"+arg[j+3:k]); err != nil { - return err - } - cmd.Args[i] = arg[:j] + in.Name() + arg[k:] - } else if j := strings.Index(arg, "$out"); j != -1 { - k := strings.IndexAny(arg[j+4:], " \r\n\t!\"#$&'()*;<=>?[\\]^`{|}") - if k == -1 { - k = len(arg) - } - - var err error - if out, err = ioutil.TempFile("", "minify-out-*"+arg[j+4:k]); err != nil { - return err - } - cmd.Args[i] = arg[:j] + out.Name() + arg[k:] - } - } - - if in == nil { - cmd.Stdin = r - } else if _, err := io.Copy(in, r); err != nil { - return err - } - if out == nil { - cmd.Stdout = w - } else { - defer io.Copy(w, out) - } - stderr := &bytes.Buffer{} - cmd.Stderr = stderr - - err := cmd.Run() - if _, ok := err.(*exec.ExitError); ok { - if stderr.Len() != 0 { - err = fmt.Errorf("%s", stderr.String()) - } - err = fmt.Errorf("command %s failed:\n%w", cmd.Path, err) - } - return err -} - -//////////////////////////////////////////////////////////////// - -// M holds a map of mimetype => function to allow recursive minifier calls of the minifier functions. -type M struct { - mutex sync.RWMutex - literal map[string]Minifier - pattern []patternMinifier - - URL *url.URL -} - -// New returns a new M. -func New() *M { - return &M{ - sync.RWMutex{}, - map[string]Minifier{}, - []patternMinifier{}, - nil, - } -} - -// Add adds a minifier to the mimetype => function map (unsafe for concurrent use). -func (m *M) Add(mimetype string, minifier Minifier) { - m.mutex.Lock() - m.literal[mimetype] = minifier - m.mutex.Unlock() -} - -// AddFunc adds a minify function to the mimetype => function map (unsafe for concurrent use). -func (m *M) AddFunc(mimetype string, minifier MinifierFunc) { - m.mutex.Lock() - m.literal[mimetype] = minifier - m.mutex.Unlock() -} - -// AddRegexp adds a minifier to the mimetype => function map (unsafe for concurrent use). -func (m *M) AddRegexp(pattern *regexp.Regexp, minifier Minifier) { - m.mutex.Lock() - m.pattern = append(m.pattern, patternMinifier{pattern, minifier}) - m.mutex.Unlock() -} - -// AddFuncRegexp adds a minify function to the mimetype => function map (unsafe for concurrent use). -func (m *M) AddFuncRegexp(pattern *regexp.Regexp, minifier MinifierFunc) { - m.mutex.Lock() - m.pattern = append(m.pattern, patternMinifier{pattern, minifier}) - m.mutex.Unlock() -} - -// AddCmd adds a minify function to the mimetype => function map (unsafe for concurrent use) that executes a command to process the minification. -// It allows the use of external tools like ClosureCompiler, UglifyCSS, etc. for a specific mimetype. -func (m *M) AddCmd(mimetype string, cmd *exec.Cmd) { - m.mutex.Lock() - m.literal[mimetype] = &cmdMinifier{cmd} - m.mutex.Unlock() -} - -// AddCmdRegexp adds a minify function to the mimetype => function map (unsafe for concurrent use) that executes a command to process the minification. -// It allows the use of external tools like ClosureCompiler, UglifyCSS, etc. for a specific mimetype regular expression. -func (m *M) AddCmdRegexp(pattern *regexp.Regexp, cmd *exec.Cmd) { - m.mutex.Lock() - m.pattern = append(m.pattern, patternMinifier{pattern, &cmdMinifier{cmd}}) - m.mutex.Unlock() -} - -// Match returns the pattern and minifier that gets matched with the mediatype. -// It returns nil when no matching minifier exists. -// It has the same matching algorithm as Minify. -func (m *M) Match(mediatype string) (string, map[string]string, MinifierFunc) { - m.mutex.RLock() - defer m.mutex.RUnlock() - - mimetype, params := parse.Mediatype([]byte(mediatype)) - if minifier, ok := m.literal[string(mimetype)]; ok { // string conversion is optimized away - return string(mimetype), params, minifier.Minify - } - - for _, minifier := range m.pattern { - if minifier.pattern.Match(mimetype) { - return minifier.pattern.String(), params, minifier.Minify - } - } - return string(mimetype), params, nil -} - -// Minify minifies the content of a Reader and writes it to a Writer (safe for concurrent use). -// An error is returned when no such mimetype exists (ErrNotExist) or when an error occurred in the minifier function. -// Mediatype may take the form of 'text/plain', 'text/*', '*/*' or 'text/plain; charset=UTF-8; version=2.0'. -func (m *M) Minify(mediatype string, w io.Writer, r io.Reader) error { - mimetype, params := parse.Mediatype([]byte(mediatype)) - return m.MinifyMimetype(mimetype, w, r, params) -} - -// MinifyMimetype minifies the content of a Reader and writes it to a Writer (safe for concurrent use). -// It is a lower level version of Minify and requires the mediatype to be split up into mimetype and parameters. -// It is mostly used internally by minifiers because it is faster (no need to convert a byte-slice to string and vice versa). -func (m *M) MinifyMimetype(mimetype []byte, w io.Writer, r io.Reader, params map[string]string) error { - m.mutex.RLock() - defer m.mutex.RUnlock() - - if minifier, ok := m.literal[string(mimetype)]; ok { // string conversion is optimized away - return minifier.Minify(m, w, r, params) - } else { - for _, minifier := range m.pattern { - if minifier.pattern.Match(mimetype) { - return minifier.Minify(m, w, r, params) - } - } - } - return ErrNotExist -} - -// Bytes minifies an array of bytes (safe for concurrent use). When an error occurs it return the original array and the error. -// It returns an error when no such mimetype exists (ErrNotExist) or any error occurred in the minifier function. -func (m *M) Bytes(mediatype string, v []byte) ([]byte, error) { - out := buffer.NewWriter(make([]byte, 0, len(v))) - if err := m.Minify(mediatype, out, buffer.NewReader(v)); err != nil { - return v, err - } - return out.Bytes(), nil -} - -// String minifies a string (safe for concurrent use). When an error occurs it return the original string and the error. -// It returns an error when no such mimetype exists (ErrNotExist) or any error occurred in the minifier function. -func (m *M) String(mediatype string, v string) (string, error) { - out := buffer.NewWriter(make([]byte, 0, len(v))) - if err := m.Minify(mediatype, out, buffer.NewReader([]byte(v))); err != nil { - return v, err - } - return string(out.Bytes()), nil -} - -// Reader wraps a Reader interface and minifies the stream. -// Errors from the minifier are returned by the reader. -func (m *M) Reader(mediatype string, r io.Reader) io.Reader { - pr, pw := io.Pipe() - go func() { - if err := m.Minify(mediatype, pw, r); err != nil { - pw.CloseWithError(err) - } else { - pw.Close() - } - }() - return pr -} - -// minifyWriter makes sure that errors from the minifier are passed down through Close (can be blocking). -type minifyWriter struct { - pw *io.PipeWriter - wg sync.WaitGroup - err error -} - -// Write intercepts any writes to the writer. -func (w *minifyWriter) Write(b []byte) (int, error) { - return w.pw.Write(b) -} - -// Close must be called when writing has finished. It returns the error from the minifier. -func (w *minifyWriter) Close() error { - w.pw.Close() - w.wg.Wait() - return w.err -} - -// Writer wraps a Writer interface and minifies the stream. -// Errors from the minifier are returned by Close on the writer. -// The writer must be closed explicitly. -func (m *M) Writer(mediatype string, w io.Writer) *minifyWriter { - pr, pw := io.Pipe() - mw := &minifyWriter{pw, sync.WaitGroup{}, nil} - mw.wg.Add(1) - go func() { - defer mw.wg.Done() - - if err := m.Minify(mediatype, w, pr); err != nil { - io.Copy(w, pr) - mw.err = err - } - pr.Close() - }() - return mw -} - -// minifyResponseWriter wraps an http.ResponseWriter and makes sure that errors from the minifier are passed down through Close (can be blocking). -// All writes to the response writer are intercepted and minified on the fly. -// http.ResponseWriter loses all functionality such as Pusher, Hijacker, Flusher, ... -type minifyResponseWriter struct { - http.ResponseWriter - - writer *minifyWriter - m *M - mediatype string -} - -// WriteHeader intercepts any header writes and removes the Content-Length header. -func (w *minifyResponseWriter) WriteHeader(status int) { - w.ResponseWriter.Header().Del("Content-Length") - w.ResponseWriter.WriteHeader(status) -} - -// Write intercepts any writes to the response writer. -// The first write will extract the Content-Type as the mediatype. Otherwise it falls back to the RequestURI extension. -func (w *minifyResponseWriter) Write(b []byte) (int, error) { - if w.writer == nil { - // first write - if mediatype := w.ResponseWriter.Header().Get("Content-Type"); mediatype != "" { - w.mediatype = mediatype - } - w.writer = w.m.Writer(w.mediatype, w.ResponseWriter) - } - return w.writer.Write(b) -} - -// Close must be called when writing has finished. It returns the error from the minifier. -func (w *minifyResponseWriter) Close() error { - if w.writer != nil { - return w.writer.Close() - } - return nil -} - -// ResponseWriter minifies any writes to the http.ResponseWriter. -// http.ResponseWriter loses all functionality such as Pusher, Hijacker, Flusher, ... -// Minification might be slower than just sending the original file! Caching is advised. -func (m *M) ResponseWriter(w http.ResponseWriter, r *http.Request) *minifyResponseWriter { - mediatype := mime.TypeByExtension(path.Ext(r.RequestURI)) - return &minifyResponseWriter{w, nil, m, mediatype} -} - -// Middleware provides a middleware function that minifies content on the fly by intercepting writes to http.ResponseWriter. -// http.ResponseWriter loses all functionality such as Pusher, Hijacker, Flusher, ... -// Minification might be slower than just sending the original file! Caching is advised. -func (m *M) Middleware(next http.Handler) http.Handler { - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - mw := m.ResponseWriter(w, r) - defer mw.Close() - - next.ServeHTTP(mw, r) - }) -} diff --git a/vendor/github.com/tdewolff/minify/v2/svg/buffer.go b/vendor/github.com/tdewolff/minify/v2/svg/buffer.go deleted file mode 100644 index d0b44f5c6eb42..0000000000000 --- a/vendor/github.com/tdewolff/minify/v2/svg/buffer.go +++ /dev/null @@ -1,130 +0,0 @@ -package svg - -import ( - minifyXML "github.com/tdewolff/minify/v2/xml" - "github.com/tdewolff/parse/v2" - "github.com/tdewolff/parse/v2/xml" -) - -// Token is a single token unit with an attribute value (if given) and hash of the data. -type Token struct { - xml.TokenType - Hash Hash - Data []byte - Text []byte - AttrVal []byte -} - -// TokenBuffer is a buffer that allows for token look-ahead. -type TokenBuffer struct { - l *xml.Lexer - - buf []Token - pos int - - attrBuffer []*Token -} - -// NewTokenBuffer returns a new TokenBuffer. -func NewTokenBuffer(l *xml.Lexer) *TokenBuffer { - return &TokenBuffer{ - l: l, - buf: make([]Token, 0, 8), - } -} - -func (z *TokenBuffer) read(t *Token) { - t.TokenType, t.Data = z.l.Next() - t.Text = z.l.Text() - if t.TokenType == xml.AttributeToken { - t.AttrVal = z.l.AttrVal() - if len(t.AttrVal) > 1 && (t.AttrVal[0] == '"' || t.AttrVal[0] == '\'') { - t.AttrVal = t.AttrVal[1 : len(t.AttrVal)-1] // quotes will be readded in attribute loop if necessary - t.AttrVal = parse.ReplaceMultipleWhitespaceAndEntities(t.AttrVal, minifyXML.EntitiesMap, nil) - t.AttrVal = parse.TrimWhitespace(t.AttrVal) - } - t.Hash = ToHash(t.Text) - } else if t.TokenType == xml.StartTagToken || t.TokenType == xml.EndTagToken { - t.AttrVal = nil - t.Hash = ToHash(t.Text) - } else { - t.AttrVal = nil - t.Hash = 0 - } -} - -// Peek returns the ith element and possibly does an allocation. -// Peeking past an error will panic. -func (z *TokenBuffer) Peek(pos int) *Token { - pos += z.pos - if pos >= len(z.buf) { - if len(z.buf) > 0 && z.buf[len(z.buf)-1].TokenType == xml.ErrorToken { - return &z.buf[len(z.buf)-1] - } - - c := cap(z.buf) - d := len(z.buf) - z.pos - p := pos - z.pos + 1 // required peek length - var buf []Token - if 2*p > c { - buf = make([]Token, 0, 2*c+p) - } else { - buf = z.buf - } - copy(buf[:d], z.buf[z.pos:]) - - buf = buf[:p] - pos -= z.pos - for i := d; i < p; i++ { - z.read(&buf[i]) - if buf[i].TokenType == xml.ErrorToken { - buf = buf[:i+1] - pos = i - break - } - } - z.pos, z.buf = 0, buf - } - return &z.buf[pos] -} - -// Shift returns the first element and advances position. -func (z *TokenBuffer) Shift() *Token { - if z.pos >= len(z.buf) { - t := &z.buf[:1][0] - z.read(t) - return t - } - t := &z.buf[z.pos] - z.pos++ - return t -} - -// Attributes extracts the gives attribute hashes from a tag. -// It returns in the same order pointers to the requested token data or nil. -func (z *TokenBuffer) Attributes(hashes ...Hash) []*Token { - n := 0 - for { - if t := z.Peek(n); t.TokenType != xml.AttributeToken { - break - } - n++ - } - if len(hashes) > cap(z.attrBuffer) { - z.attrBuffer = make([]*Token, len(hashes)) - } else { - z.attrBuffer = z.attrBuffer[:len(hashes)] - for i := range z.attrBuffer { - z.attrBuffer[i] = nil - } - } - for i := z.pos; i < z.pos+n; i++ { - attr := &z.buf[i] - for j, hash := range hashes { - if hash == attr.Hash { - z.attrBuffer[j] = attr - } - } - } - return z.attrBuffer -} diff --git a/vendor/github.com/tdewolff/minify/v2/svg/hash.go b/vendor/github.com/tdewolff/minify/v2/svg/hash.go deleted file mode 100644 index b40c117f2ddba..0000000000000 --- a/vendor/github.com/tdewolff/minify/v2/svg/hash.go +++ /dev/null @@ -1,414 +0,0 @@ -package svg - -// uses github.com/tdewolff/hasher -//go:generate hasher -type=Hash -file=hash.go - -// Hash defines perfect hashes for a predefined list of strings -type Hash uint32 - -// Identifiers for the hashes associated with the text in the comments. -const ( - A Hash = 0x101 // a - Alignment_Baseline Hash = 0x2e12 // alignment-baseline - BaseProfile Hash = 0xb // baseProfile - Baseline_Shift Hash = 0x380e // baseline-shift - Buffered_Rendering Hash = 0x5212 // buffered-rendering - Clip Hash = 0x6404 // clip - Clip_Path Hash = 0x6409 // clip-path - Clip_Rule Hash = 0x8009 // clip-rule - Color Hash = 0xd805 // color - Color_Interpolation Hash = 0xd813 // color-interpolation - Color_Interpolation_Filters Hash = 0xd81b // color-interpolation-filters - Color_Profile Hash = 0x1f70d // color-profile - Color_Rendering Hash = 0x2320f // color-rendering - ContentScriptType Hash = 0xa011 // contentScriptType - ContentStyleType Hash = 0xb110 // contentStyleType - Cursor Hash = 0xc106 // cursor - D Hash = 0x5901 // d - Defs Hash = 0x36904 // defs - Direction Hash = 0x30c09 // direction - Display Hash = 0x9807 // display - Dominant_Baseline Hash = 0x19211 // dominant-baseline - Enable_Background Hash = 0x8811 // enable-background - FeImage Hash = 0x14507 // feImage - Fill Hash = 0xc904 // fill - Fill_Opacity Hash = 0x33d0c // fill-opacity - Fill_Rule Hash = 0xc909 // fill-rule - Filter Hash = 0xec06 // filter - Flood_Color Hash = 0xd20b // flood-color - Flood_Opacity Hash = 0x1050d // flood-opacity - Font Hash = 0x11404 // font - Font_Family Hash = 0x1140b // font-family - Font_Size Hash = 0x11f09 // font-size - Font_Size_Adjust Hash = 0x11f10 // font-size-adjust - Font_Stretch Hash = 0x1370c // font-stretch - Font_Style Hash = 0x14c0a // font-style - Font_Variant Hash = 0x1560c // font-variant - Font_Weight Hash = 0x1620b // font-weight - ForeignObject Hash = 0x16d0d // foreignObject - G Hash = 0x1601 // g - Glyph_Orientation_Horizontal Hash = 0x1d31c // glyph-orientation-horizontal - Glyph_Orientation_Vertical Hash = 0x161a // glyph-orientation-vertical - Height Hash = 0x6c06 // height - Href Hash = 0x14204 // href - Image Hash = 0x17a05 // image - Image_Rendering Hash = 0x17a0f // image-rendering - Kerning Hash = 0x1bc07 // kerning - Letter_Spacing Hash = 0x90e // letter-spacing - Lighting_Color Hash = 0x1ee0e // lighting-color - Line Hash = 0x3c04 // line - Marker Hash = 0x18906 // marker - Marker_End Hash = 0x1890a // marker-end - Marker_Mid Hash = 0x1a30a // marker-mid - Marker_Start Hash = 0x1ad0c // marker-start - Mask Hash = 0x1b904 // mask - Metadata Hash = 0x1c308 // metadata - Missing_Glyph Hash = 0x1cb0d // missing-glyph - Opacity Hash = 0x10b07 // opacity - Overflow Hash = 0x26208 // overflow - Paint_Order Hash = 0x2ae0b // paint-order - Path Hash = 0x6904 // path - Pattern Hash = 0x20407 // pattern - Pointer_Events Hash = 0x20b0e // pointer-events - Points Hash = 0x22706 // points - Polygon Hash = 0x24107 // polygon - Polyline Hash = 0x24808 // polyline - PreserveAspectRatio Hash = 0x25013 // preserveAspectRatio - Rect Hash = 0x30e04 // rect - Rx Hash = 0x4f02 // rx - Ry Hash = 0xc602 // ry - Script Hash = 0xf206 // script - Shape_Rendering Hash = 0x2180f // shape-rendering - Solid_Color Hash = 0x22c0b // solid-color - Solid_Opacity Hash = 0x36c0d // solid-opacity - Stop_Color Hash = 0x12d0a // stop-color - Stop_Opacity Hash = 0x2740c // stop-opacity - Stroke Hash = 0x28006 // stroke - Stroke_Dasharray Hash = 0x28010 // stroke-dasharray - Stroke_Dashoffset Hash = 0x29011 // stroke-dashoffset - Stroke_Linecap Hash = 0x2a10e // stroke-linecap - Stroke_Linejoin Hash = 0x2b90f // stroke-linejoin - Stroke_Miterlimit Hash = 0x2c811 // stroke-miterlimit - Stroke_Opacity Hash = 0x2d90e // stroke-opacity - Stroke_Width Hash = 0x2e70c // stroke-width - Style Hash = 0x15105 // style - Svg Hash = 0x2f303 // svg - Switch Hash = 0x2f606 // switch - Symbol Hash = 0x2fc06 // symbol - Text_Anchor Hash = 0x450b // text-anchor - Text_Decoration Hash = 0x710f // text-decoration - Text_Rendering Hash = 0xf70e // text-rendering - Type Hash = 0x11004 // type - Unicode_Bidi Hash = 0x3020c // unicode-bidi - Use Hash = 0x31503 // use - Vector_Effect Hash = 0x3180d // vector-effect - Version Hash = 0x32507 // version - ViewBox Hash = 0x32c07 // viewBox - Viewport_Fill Hash = 0x3340d // viewport-fill - Viewport_Fill_Opacity Hash = 0x33415 // viewport-fill-opacity - Visibility Hash = 0x3490a // visibility - White_Space Hash = 0x2690b // white-space - Width Hash = 0x2ee05 // width - Word_Spacing Hash = 0x3530c // word-spacing - Writing_Mode Hash = 0x35f0c // writing-mode - X Hash = 0x4701 // x - X1 Hash = 0x5002 // x1 - X2 Hash = 0x33202 // x2 - Xml_Space Hash = 0x37909 // xml:space - Y Hash = 0x1801 // y - Y1 Hash = 0x9e02 // y1 - Y2 Hash = 0xc702 // y2 -) - -var HashMap = map[string]Hash{ - "a": A, - "alignment-baseline": Alignment_Baseline, - "baseProfile": BaseProfile, - "baseline-shift": Baseline_Shift, - "buffered-rendering": Buffered_Rendering, - "clip": Clip, - "clip-path": Clip_Path, - "clip-rule": Clip_Rule, - "color": Color, - "color-interpolation": Color_Interpolation, - "color-interpolation-filters": Color_Interpolation_Filters, - "color-profile": Color_Profile, - "color-rendering": Color_Rendering, - "contentScriptType": ContentScriptType, - "contentStyleType": ContentStyleType, - "cursor": Cursor, - "d": D, - "defs": Defs, - "direction": Direction, - "display": Display, - "dominant-baseline": Dominant_Baseline, - "enable-background": Enable_Background, - "feImage": FeImage, - "fill": Fill, - "fill-opacity": Fill_Opacity, - "fill-rule": Fill_Rule, - "filter": Filter, - "flood-color": Flood_Color, - "flood-opacity": Flood_Opacity, - "font": Font, - "font-family": Font_Family, - "font-size": Font_Size, - "font-size-adjust": Font_Size_Adjust, - "font-stretch": Font_Stretch, - "font-style": Font_Style, - "font-variant": Font_Variant, - "font-weight": Font_Weight, - "foreignObject": ForeignObject, - "g": G, - "glyph-orientation-horizontal": Glyph_Orientation_Horizontal, - "glyph-orientation-vertical": Glyph_Orientation_Vertical, - "height": Height, - "href": Href, - "image": Image, - "image-rendering": Image_Rendering, - "kerning": Kerning, - "letter-spacing": Letter_Spacing, - "lighting-color": Lighting_Color, - "line": Line, - "marker": Marker, - "marker-end": Marker_End, - "marker-mid": Marker_Mid, - "marker-start": Marker_Start, - "mask": Mask, - "metadata": Metadata, - "missing-glyph": Missing_Glyph, - "opacity": Opacity, - "overflow": Overflow, - "paint-order": Paint_Order, - "path": Path, - "pattern": Pattern, - "pointer-events": Pointer_Events, - "points": Points, - "polygon": Polygon, - "polyline": Polyline, - "preserveAspectRatio": PreserveAspectRatio, - "rect": Rect, - "rx": Rx, - "ry": Ry, - "script": Script, - "shape-rendering": Shape_Rendering, - "solid-color": Solid_Color, - "solid-opacity": Solid_Opacity, - "stop-color": Stop_Color, - "stop-opacity": Stop_Opacity, - "stroke": Stroke, - "stroke-dasharray": Stroke_Dasharray, - "stroke-dashoffset": Stroke_Dashoffset, - "stroke-linecap": Stroke_Linecap, - "stroke-linejoin": Stroke_Linejoin, - "stroke-miterlimit": Stroke_Miterlimit, - "stroke-opacity": Stroke_Opacity, - "stroke-width": Stroke_Width, - "style": Style, - "svg": Svg, - "switch": Switch, - "symbol": Symbol, - "text-anchor": Text_Anchor, - "text-decoration": Text_Decoration, - "text-rendering": Text_Rendering, - "type": Type, - "unicode-bidi": Unicode_Bidi, - "use": Use, - "vector-effect": Vector_Effect, - "version": Version, - "viewBox": ViewBox, - "viewport-fill": Viewport_Fill, - "viewport-fill-opacity": Viewport_Fill_Opacity, - "visibility": Visibility, - "white-space": White_Space, - "width": Width, - "word-spacing": Word_Spacing, - "writing-mode": Writing_Mode, - "x": X, - "x1": X1, - "x2": X2, - "xml:space": Xml_Space, - "y": Y, - "y1": Y1, - "y2": Y2, -} - -// String returns the text associated with the hash. -func (i Hash) String() string { - return string(i.Bytes()) -} - -// Bytes returns the text associated with the hash. -func (i Hash) Bytes() []byte { - start := uint32(i >> 8) - n := uint32(i & 0xff) - if start+n > uint32(len(_Hash_text)) { - return []byte{} - } - return _Hash_text[start : start+n] -} - -// ToHash returns a hash Hash for a given []byte. Hash is a uint32 that is associated with the text in []byte. It returns zero if no match found. -func ToHash(s []byte) Hash { - if 3 < len(s) { - return HashMap[string(s)] - } - h := uint32(_Hash_hash0) - for i := 0; i < len(s); i++ { - h ^= uint32(s[i]) - h *= 16777619 - } - if i := _Hash_table[h&uint32(len(_Hash_table)-1)]; int(i&0xff) == len(s) { - t := _Hash_text[i>>8 : i>>8+i&0xff] - for i := 0; i < len(s); i++ { - if t[i] != s[i] { - goto NEXT - } - } - return i - } -NEXT: - if i := _Hash_table[(h>>16)&uint32(len(_Hash_table)-1)]; int(i&0xff) == len(s) { - t := _Hash_text[i>>8 : i>>8+i&0xff] - for i := 0; i < len(s); i++ { - if t[i] != s[i] { - return 0 - } - } - return i - } - return 0 -} - -const _Hash_hash0 = 0x2d0dfdc1 -const _Hash_maxLen = 28 - -var _Hash_text = []byte("" + - "baseProfiletter-spacinglyph-orientation-verticalignment-base" + - "line-shiftext-anchorx1buffered-renderingclip-patheightext-de" + - "corationclip-rulenable-backgroundisplay1contentScriptTypecon" + - "tentStyleTypecursory2fill-ruleflood-color-interpolation-filt" + - "erscriptext-renderingflood-opacitypefont-familyfont-size-adj" + - "ustop-colorfont-stretchrefeImagefont-stylefont-variantfont-w" + - "eightforeignObjectimage-renderingmarker-endominant-baselinem" + - "arker-midmarker-startmaskerningmetadatamissing-glyph-orienta" + - "tion-horizontalighting-color-profilepatternpointer-eventshap" + - "e-renderingpointsolid-color-renderingpolygonpolylinepreserve" + - "AspectRatioverflowhite-spacestop-opacitystroke-dasharraystro" + - "ke-dashoffsetstroke-linecapaint-orderstroke-linejoinstroke-m" + - "iterlimitstroke-opacitystroke-widthsvgswitchsymbolunicode-bi" + - "directionusevector-effectversionviewBox2viewport-fill-opacit" + - "yvisibilityword-spacingwriting-modefsolid-opacityxml:space") - -var _Hash_table = [1 << 7]Hash{ - 0x1: 0x2f303, // svg - 0x2: 0x2f606, // switch - 0x3: 0x18906, // marker - 0x5: 0x1620b, // font-weight - 0x6: 0x1801, // y - 0x7: 0x33d0c, // fill-opacity - 0x8: 0x2e70c, // stroke-width - 0x9: 0x33415, // viewport-fill-opacity - 0xa: 0x9807, // display - 0xb: 0xb110, // contentStyleType - 0xc: 0x30c09, // direction - 0xd: 0x20407, // pattern - 0xf: 0x1f70d, // color-profile - 0x10: 0xc602, // ry - 0x12: 0x1ad0c, // marker-start - 0x13: 0x1050d, // flood-opacity - 0x14: 0x36c0d, // solid-opacity - 0x15: 0x90e, // letter-spacing - 0x16: 0x17a05, // image - 0x17: 0x1890a, // marker-end - 0x18: 0x2c811, // stroke-miterlimit - 0x19: 0x20b0e, // pointer-events - 0x1a: 0x12d0a, // stop-color - 0x1b: 0x1b904, // mask - 0x1c: 0xc904, // fill - 0x1d: 0xc909, // fill-rule - 0x1f: 0x26208, // overflow - 0x20: 0x1a30a, // marker-mid - 0x21: 0x1bc07, // kerning - 0x22: 0xa011, // contentScriptType - 0x23: 0x4f02, // rx - 0x24: 0x1560c, // font-variant - 0x25: 0x3020c, // unicode-bidi - 0x26: 0x2a10e, // stroke-linecap - 0x27: 0xc106, // cursor - 0x28: 0x25013, // preserveAspectRatio - 0x29: 0x14507, // feImage - 0x2a: 0x2e12, // alignment-baseline - 0x2b: 0x33202, // x2 - 0x2c: 0x450b, // text-anchor - 0x2d: 0x1d31c, // glyph-orientation-horizontal - 0x2e: 0xf206, // script - 0x2f: 0x3180d, // vector-effect - 0x30: 0x1370c, // font-stretch - 0x31: 0x36904, // defs - 0x32: 0x29011, // stroke-dashoffset - 0x33: 0x6c06, // height - 0x34: 0xd81b, // color-interpolation-filters - 0x36: 0x2ae0b, // paint-order - 0x37: 0x19211, // dominant-baseline - 0x38: 0x11404, // font - 0x39: 0x24808, // polyline - 0x3a: 0x32c07, // viewBox - 0x3b: 0x4701, // x - 0x3c: 0x11004, // type - 0x3d: 0x28010, // stroke-dasharray - 0x3e: 0x5002, // x1 - 0x3f: 0x5901, // d - 0x42: 0x8811, // enable-background - 0x43: 0x30e04, // rect - 0x44: 0x2180f, // shape-rendering - 0x46: 0x37909, // xml:space - 0x47: 0x161a, // glyph-orientation-vertical - 0x48: 0x31503, // use - 0x49: 0x3490a, // visibility - 0x4a: 0x16d0d, // foreignObject - 0x4b: 0x710f, // text-decoration - 0x4c: 0x15105, // style - 0x4f: 0x17a0f, // image-rendering - 0x50: 0x24107, // polygon - 0x51: 0x5212, // buffered-rendering - 0x52: 0x1601, // g - 0x53: 0x1140b, // font-family - 0x54: 0x14204, // href - 0x55: 0xec06, // filter - 0x56: 0x1c308, // metadata - 0x57: 0x1ee0e, // lighting-color - 0x58: 0xf70e, // text-rendering - 0x59: 0x35f0c, // writing-mode - 0x5a: 0x10b07, // opacity - 0x5b: 0x9e02, // y1 - 0x5c: 0xd20b, // flood-color - 0x5d: 0x2690b, // white-space - 0x60: 0x101, // a - 0x61: 0xb, // baseProfile - 0x62: 0x14c0a, // font-style - 0x63: 0x3340d, // viewport-fill - 0x65: 0x8009, // clip-rule - 0x67: 0x6904, // path - 0x68: 0xd813, // color-interpolation - 0x69: 0x2d90e, // stroke-opacity - 0x6a: 0x2b90f, // stroke-linejoin - 0x6b: 0x2ee05, // width - 0x6d: 0x2320f, // color-rendering - 0x6e: 0xc702, // y2 - 0x6f: 0x3c04, // line - 0x70: 0x1cb0d, // missing-glyph - 0x71: 0x2740c, // stop-opacity - 0x72: 0x11f09, // font-size - 0x73: 0x380e, // baseline-shift - 0x74: 0x3530c, // word-spacing - 0x75: 0x2fc06, // symbol - 0x76: 0x11f10, // font-size-adjust - 0x77: 0xd805, // color - 0x79: 0x28006, // stroke - 0x7b: 0x22706, // points - 0x7c: 0x32507, // version - 0x7d: 0x6409, // clip-path - 0x7e: 0x22c0b, // solid-color - 0x7f: 0x6404, // clip -} diff --git a/vendor/github.com/tdewolff/minify/v2/svg/pathdata.go b/vendor/github.com/tdewolff/minify/v2/svg/pathdata.go deleted file mode 100644 index 01a84447792db..0000000000000 --- a/vendor/github.com/tdewolff/minify/v2/svg/pathdata.go +++ /dev/null @@ -1,440 +0,0 @@ -package svg - -import ( - "math" - strconvStdlib "strconv" - - "github.com/tdewolff/minify/v2" - "github.com/tdewolff/parse/v2" - "github.com/tdewolff/parse/v2/strconv" -) - -type PathData struct { - o *Minifier - - x, y float64 - x0, y0 float64 - coords [][]byte - coordFloats []float64 - cx, cy float64 // last control point for cubic bezier - qx, qy float64 // last control point for quadratic bezier - - state PathDataState - curBuffer []byte - altBuffer []byte - coordBuffer []byte -} - -type PathDataState struct { - cmd byte - prevDigit bool - prevDigitIsInt bool - prevFlag bool -} - -func NewPathData(o *Minifier) *PathData { - return &PathData{ - o: o, - cx: math.NaN(), - cy: math.NaN(), - qx: math.NaN(), - qy: math.NaN(), - } -} - -var pathCmds = map[byte]bool{ - 'M': true, - 'm': true, - 'L': true, - 'l': true, - 'H': true, - 'h': true, - 'V': true, - 'v': true, - 'Q': true, - 'q': true, - 'T': true, - 't': true, - 'C': true, - 'c': true, - 'S': true, - 's': true, - 'A': true, - 'a': true, - 'Z': true, - 'z': true, -} - -// ShortenPathData takes a full pathdata string and returns a shortened version. The original string is overwritten. -// It parses all commands (M, A, Z, ...) and coordinates (numbers) and calls copyInstruction for each command. -func (p *PathData) ShortenPathData(b []byte) []byte { - var cmd byte - - p.x, p.y = 0.0, 0.0 - p.coords = p.coords[:0] - p.coordFloats = p.coordFloats[:0] - p.state = PathDataState{} - - j := 0 - for i := 0; i < len(b); i++ { - c := b[i] - if c == ' ' || c == ',' || c == '\n' || c == '\r' || c == '\t' { - continue - } else if pathCmds[c] && (cmd == 0 || cmd != c || c == 'M' || c == 'm') { // any command - if cmd != 0 { - j += p.copyInstruction(b[j:], cmd) - } - cmd = c - p.coords = p.coords[:0] - p.coordFloats = p.coordFloats[:0] - } else if (cmd == 'A' || cmd == 'a') && (len(p.coordFloats)%7 == 3 || len(p.coordFloats)%7 == 4) { - // boolean flags for arc command - if c == '1' { - p.coords = append(p.coords, b[i:i+1]) - p.coordFloats = append(p.coordFloats, 1.0) - } else if c == '0' { - p.coords = append(p.coords, b[i:i+1]) - p.coordFloats = append(p.coordFloats, 0.0) - } else { - cmd = 0 // bad format, don't minify - } - } else if n := parse.Number(b[i:]); n > 0 { - f, _ := strconv.ParseFloat(b[i : i+n]) - p.coords = append(p.coords, b[i:i+n]) - p.coordFloats = append(p.coordFloats, f) - i += n - 1 - } - } - if cmd == 0 { - return b - } - j += p.copyInstruction(b[j:], cmd) - return b[:j] -} - -// copyInstruction copies pathdata of a single command, but may be comprised of multiple sets for that command. For example, L takes two coordinates, but this function may process 2*N coordinates. Lowercase commands are relative commands, where the coordinates are relative to the previous point. Uppercase commands have absolute coordinates. -// We update p.x and p.y (the current coordinates) according to the commands given. For each set of coordinates we call shortenCurPosInstruction and shortenAltPosInstruction. The former just minifies the coordinates, the latter will inverse the lowercase/uppercase of the command, and see if the coordinates get smaller due to that. The shortest is chosen and copied to `b`. -func (p *PathData) copyInstruction(b []byte, cmd byte) int { - n := len(p.coords) - if n == 0 { - if cmd == 'Z' || cmd == 'z' { - p.x = p.x0 - p.y = p.y0 - b[0] = 'z' - return 1 - } - return 0 - } - isRelCmd := cmd >= 'a' - - // get new cursor coordinates - di := 0 - if (cmd == 'M' || cmd == 'm' || cmd == 'L' || cmd == 'l' || cmd == 'T' || cmd == 't') && n%2 == 0 { - di = 2 - // reprint M always, as the first pair is a move but subsequent pairs are L - if cmd == 'M' || cmd == 'm' { - p.state.cmd = byte(0) - } - } else if cmd == 'H' || cmd == 'h' || cmd == 'V' || cmd == 'v' { - di = 1 - } else if (cmd == 'S' || cmd == 's' || cmd == 'Q' || cmd == 'q') && n%4 == 0 { - di = 4 - } else if (cmd == 'C' || cmd == 'c') && n%6 == 0 { - di = 6 - } else if (cmd == 'A' || cmd == 'a') && n%7 == 0 { - di = 7 - } else { - return 0 - } - - j := 0 - origCmd := cmd - for i := 0; i < n; i += di { - // subsequent coordinate pairs for M are really L - if i > 0 && (origCmd == 'M' || origCmd == 'm') { - origCmd = 'L' + (origCmd - 'M') - } - - cmd = origCmd - coords := p.coords[i : i+di] - coordFloats := p.coordFloats[i : i+di] - - // set next coordinate - var ax, ay float64 - if cmd == 'H' || cmd == 'h' { - ax = coordFloats[di-1] - if isRelCmd { - ax += p.x - } - ay = p.y - } else if cmd == 'V' || cmd == 'v' { - ax = p.x - ay = coordFloats[di-1] - if isRelCmd { - ay += p.y - } - } else { - ax = coordFloats[di-2] - ay = coordFloats[di-1] - if isRelCmd { - ax += p.x - ay += p.y - } - } - - // switch from C to S whenever possible - if cmd == 'C' || cmd == 'c' || cmd == 'S' || cmd == 's' { - if math.IsNaN(p.cx) { - p.cx, p.cy = p.x, p.y - } else { - p.cx, p.cy = 2*p.x-p.cx, 2*p.y-p.cy - } - - var cp1x, cp1y float64 - cp2x, cp2y := coordFloats[di-4], coordFloats[di-3] - if isRelCmd { - cp2x += p.x - cp2y += p.y - } - if cmd == 'C' || cmd == 'c' { - cp1x, cp1y = coordFloats[di-6], coordFloats[di-5] - if isRelCmd { - cp1x += p.x - cp1y += p.y - } - if cp1x == p.cx && cp1y == p.cy { - if isRelCmd { - cmd = 's' - } else { - cmd = 'S' - } - coords = coords[2:] - coordFloats = coordFloats[2:] - } - } else { - cp1x, cp1y = p.cx, p.cy - } - - // if control points overlap begin/end points, this is a straight line - // even though if the control points would be along the straight line, we won't minify that as the control points influence the speed along the curve (important for dashes for example) - // only change to a lines if we are sure no 'S' or 's' follows - if (cmd == 'C' || cmd == 'c' || i+di >= n) && (cp1x == p.x && cp1y == p.y || cp1x == ax && cp1y == ay) && (cp2x == p.x && cp2y == p.y || cp2x == ax && cp2y == ay) { - if isRelCmd { - cmd = 'l' - } else { - cmd = 'L' - } - coords = coords[len(coords)-2:] - coordFloats = coordFloats[len(coordFloats)-2:] - cp2x, cp2y = math.NaN(), math.NaN() - } - p.cx, p.cy = cp2x, cp2y - } else { - p.cx, p.cy = math.NaN(), math.NaN() - } - - // switch from Q to T whenever possible - if cmd == 'Q' || cmd == 'q' || cmd == 'T' || cmd == 't' { - if math.IsNaN(p.qx) { - p.qx, p.qy = p.x, p.y - } else { - p.qx, p.qy = 2*p.x-p.qx, 2*p.y-p.qy - } - - var cpx, cpy float64 - if cmd == 'Q' || cmd == 'q' { - cpx, cpy = coordFloats[di-4], coordFloats[di-3] - if isRelCmd { - cpx += p.x - cpy += p.y - } - if cpx == p.qx && cpy == p.qy { - if isRelCmd { - cmd = 't' - } else { - cmd = 'T' - } - coords = coords[2:] - coordFloats = coordFloats[2:] - } - } else { - cpx, cpy = p.qx, p.qy - } - - // if control point overlaps begin/end points, this is a straight line - // even though if the control point would be along the straight line, we won't minify that as the control point influences the speed along the curve (important for dashes for example) - // only change to a lines if we are sure no 'T' or 't' follows - if (cmd == 'Q' || cmd == 'q' || i+di >= n) && (cpx == p.x && cpy == p.y || cpx == ax && cpy == ay) { - if isRelCmd { - cmd = 'l' - } else { - cmd = 'L' - } - coords = coords[len(coords)-2:] - coordFloats = coordFloats[len(coordFloats)-2:] - cpx, cpy = math.NaN(), math.NaN() - } - p.qx, p.qy = cpx, cpy - } else { - p.qx, p.qy = math.NaN(), math.NaN() - } - - // switch from L to H or V whenever possible - if cmd == 'L' || cmd == 'l' { - if ax == p.x && ay == p.y { - continue - } else if ax == p.x { - if isRelCmd { - cmd = 'v' - } else { - cmd = 'V' - } - coords = coords[1:] - coordFloats = coordFloats[1:] - } else if ay == p.y { - if isRelCmd { - cmd = 'h' - } else { - cmd = 'H' - } - coords = coords[:1] - coordFloats = coordFloats[:1] - } - } - - // make a current and alternated path with absolute/relative altered - var curState, altState PathDataState - curState = p.shortenCurPosInstruction(cmd, coords) - if isRelCmd { - altState = p.shortenAltPosInstruction(cmd-'a'+'A', coordFloats, p.x, p.y) - } else { - altState = p.shortenAltPosInstruction(cmd-'A'+'a', coordFloats, -p.x, -p.y) - } - - // choose shortest, relative or absolute path? - if len(p.altBuffer) < len(p.curBuffer) { - j += copy(b[j:], p.altBuffer) - p.state = altState - } else { - j += copy(b[j:], p.curBuffer) - p.state = curState - } - - p.x = ax - p.y = ay - if i == 0 && (origCmd == 'M' || origCmd == 'm') { - p.x0 = p.x - p.y0 = p.y - } - } - return j -} - -// shortenCurPosInstruction only minifies the coordinates. -func (p *PathData) shortenCurPosInstruction(cmd byte, coords [][]byte) PathDataState { - state := p.state - p.curBuffer = p.curBuffer[:0] - if cmd != state.cmd && !(state.cmd == 'M' && cmd == 'L' || state.cmd == 'm' && cmd == 'l') { - p.curBuffer = append(p.curBuffer, cmd) - state.cmd = cmd - state.prevDigit = false - state.prevDigitIsInt = false - } - for i, coord := range coords { - // Arc has boolean flags that can only be 0 or 1. copyFlag prevents from adding a dot before a zero (instead of a space). However, when the dot already was there, the command is malformed and could make the path longer than before, introducing bugs. - if (cmd == 'A' || cmd == 'a') && (i%7 == 3 || i%7 == 4) { - state.copyFlag(&p.curBuffer, coord[0] == '1') - continue - } - - coord = minify.Number(coord, p.o.Precision) - state.copyNumber(&p.curBuffer, coord) - } - return state -} - -// shortenAltPosInstruction toggles the command between absolute / relative coordinates and minifies the coordinates. -func (p *PathData) shortenAltPosInstruction(cmd byte, coordFloats []float64, x, y float64) PathDataState { - state := p.state - p.altBuffer = p.altBuffer[:0] - if cmd != state.cmd && !(state.cmd == 'M' && cmd == 'L' || state.cmd == 'm' && cmd == 'l') { - p.altBuffer = append(p.altBuffer, cmd) - state.cmd = cmd - state.prevDigit = false - state.prevDigitIsInt = false - } - for i, f := range coordFloats { - if cmd == 'L' || cmd == 'l' || cmd == 'C' || cmd == 'c' || cmd == 'S' || cmd == 's' || cmd == 'Q' || cmd == 'q' || cmd == 'T' || cmd == 't' || cmd == 'M' || cmd == 'm' { - if i%2 == 0 { - f += x - } else { - f += y - } - } else if cmd == 'H' || cmd == 'h' { - f += x - } else if cmd == 'V' || cmd == 'v' { - f += y - } else if cmd == 'A' || cmd == 'a' { - if i%7 == 5 { - f += x - } else if i%7 == 6 { - f += y - } else if i%7 == 3 || i%7 == 4 { - state.copyFlag(&p.altBuffer, f == 1.0) - continue - } - } - - p.coordBuffer = strconvStdlib.AppendFloat(p.coordBuffer[:0], f, 'g', -1, 64) - coord := minify.Number(p.coordBuffer, p.o.newPrecision) - state.copyNumber(&p.altBuffer, coord) - } - return state -} - -// copyNumber will copy a number to the destination buffer, taking into account space or dot insertion to guarantee the shortest pathdata. -func (state *PathDataState) copyNumber(buffer *[]byte, coord []byte) { - if state.prevDigit && (coord[0] >= '0' && coord[0] <= '9' || coord[0] == '.' && state.prevDigitIsInt) { - if coord[0] == '0' && !state.prevDigitIsInt { - *buffer = append(*buffer, '.', '0') // aggresively add dot so subsequent numbers could drop leading space - // prevDigit stays true and prevDigitIsInt stays false - return - } - *buffer = append(*buffer, ' ') - } - state.prevDigit = true - state.prevDigitIsInt = true - if len(coord) > 2 && coord[len(coord)-2] == '0' && coord[len(coord)-1] == '0' { - coord[len(coord)-2] = 'e' - coord[len(coord)-1] = '2' - state.prevDigitIsInt = false - } else { - for _, c := range coord { - if c == '.' || c == 'e' || c == 'E' { - state.prevDigitIsInt = false - break - } - } - } - *buffer = append(*buffer, coord...) - state.prevFlag = false -} - -func (state *PathDataState) copyFlag(buffer *[]byte, flag bool) { - if !state.prevFlag { - if flag { - *buffer = append(*buffer, ' ', '1') - } else { - *buffer = append(*buffer, ' ', '0') - } - } else { - if flag { - *buffer = append(*buffer, '1') - } else { - *buffer = append(*buffer, '0') - } - } - state.prevFlag = true - state.prevDigit = false - state.prevDigitIsInt = false -} diff --git a/vendor/github.com/tdewolff/minify/v2/svg/svg.go b/vendor/github.com/tdewolff/minify/v2/svg/svg.go deleted file mode 100644 index aeface1ba3ae1..0000000000000 --- a/vendor/github.com/tdewolff/minify/v2/svg/svg.go +++ /dev/null @@ -1,361 +0,0 @@ -// Package svg minifies SVG1.1 following the specifications at http://www.w3.org/TR/SVG11/. -package svg - -import ( - "bytes" - "io" - - "github.com/tdewolff/minify/v2" - "github.com/tdewolff/minify/v2/css" - minifyXML "github.com/tdewolff/minify/v2/xml" - "github.com/tdewolff/parse/v2" - "github.com/tdewolff/parse/v2/buffer" - "github.com/tdewolff/parse/v2/xml" -) - -var ( - voidBytes = []byte("/>") - isBytes = []byte("=") - spaceBytes = []byte(" ") - cdataEndBytes = []byte("]]>") - pathBytes = []byte(" 0 && t.Text[len(t.Text)-1] == ']' { - if _, err := w.Write(t.Data); err != nil { - return err - } - } - case xml.TextToken: - t.Data = parse.ReplaceMultipleWhitespaceAndEntities(t.Data, minifyXML.EntitiesMap, nil) - t.Data = parse.TrimWhitespace(t.Data) - - if tag == Style && len(t.Data) > 0 { - if err := m.MinifyMimetype(defaultStyleType, w, buffer.NewReader(t.Data), defaultStyleParams); err != nil { - if err != minify.ErrNotExist { - return err - } else if _, err := w.Write(t.Data); err != nil { - return err - } - } - } else if _, err := w.Write(t.Data); err != nil { - return err - } - case xml.CDATAToken: - if tag == Style { - minifyBuffer.Reset() - if err := m.MinifyMimetype(defaultStyleType, minifyBuffer, buffer.NewReader(t.Text), defaultStyleParams); err == nil { - t.Data = append(t.Data[:9], minifyBuffer.Bytes()...) - t.Text = t.Data[9:] - t.Data = append(t.Data, cdataEndBytes...) - } else if err != minify.ErrNotExist { - return err - } - } - var useText bool - if t.Text, useText = xml.EscapeCDATAVal(&attrByteBuffer, t.Text); useText { - t.Text = parse.ReplaceMultipleWhitespace(t.Text) - t.Text = parse.TrimWhitespace(t.Text) - - if _, err := w.Write(t.Text); err != nil { - return err - } - } else if _, err := w.Write(t.Data); err != nil { - return err - } - case xml.StartTagPIToken: - for { - if t := *tb.Shift(); t.TokenType == xml.StartTagClosePIToken || t.TokenType == xml.ErrorToken { - break - } - } - case xml.StartTagToken: - tag = t.Hash - if tag == Metadata { - t.Data = nil - } else if tag == Rect { - o.shortenRect(tb, &t) - } - - if t.Data == nil { - skipTag(tb) - } else if _, err := w.Write(t.Data); err != nil { - return err - } - case xml.AttributeToken: - if len(t.AttrVal) == 0 || t.Text == nil { // data is nil when attribute has been removed - continue - } - - attr := t.Hash - val := t.AttrVal - if n, m := parse.Dimension(val); n+m == len(val) && attr != Version { // TODO: inefficient, temporary measure - val, _ = o.shortenDimension(val) - } - if attr == Xml_Space && bytes.Equal(val, []byte("preserve")) || - tag == Svg && (attr == Version && bytes.Equal(val, []byte("1.1")) || - attr == X && bytes.Equal(val, []byte("0")) || - attr == Y && bytes.Equal(val, []byte("0")) || - attr == Width && bytes.Equal(val, []byte("100%")) || - attr == Height && bytes.Equal(val, []byte("100%")) || - attr == PreserveAspectRatio && bytes.Equal(val, []byte("xMidYMid meet")) || - attr == BaseProfile && bytes.Equal(val, []byte("none")) || - attr == ContentScriptType && bytes.Equal(val, []byte("application/ecmascript")) || - attr == ContentStyleType && bytes.Equal(val, []byte("text/css"))) || - tag == Style && attr == Type && bytes.Equal(val, []byte("text/css")) { - continue - } - - if _, err := w.Write(spaceBytes); err != nil { - return err - } - if _, err := w.Write(t.Text); err != nil { - return err - } - if _, err := w.Write(isBytes); err != nil { - return err - } - - if tag == Svg && attr == ContentStyleType { - val = minify.Mediatype(val) - defaultStyleType = val - } else if attr == Style { - minifyBuffer.Reset() - if err := m.MinifyMimetype(defaultStyleType, minifyBuffer, buffer.NewReader(val), defaultInlineStyleParams); err == nil { - val = minifyBuffer.Bytes() - } else if err != minify.ErrNotExist { - return err - } - } else if attr == D { - val = p.ShortenPathData(val) - } else if attr == ViewBox { - j := 0 - newVal := val[:0] - for i := 0; i < 4; i++ { - if i != 0 { - if j >= len(val) || val[j] != ' ' && val[j] != ',' { - newVal = append(newVal, val[j:]...) - break - } - newVal = append(newVal, ' ') - j++ - } - if dim, n := o.shortenDimension(val[j:]); n > 0 { - newVal = append(newVal, dim...) - j += n - } else { - newVal = append(newVal, val[j:]...) - break - } - } - val = newVal - } else if colorAttrMap[attr] && len(val) > 0 && (len(val) < 5 || !parse.EqualFold(val[:4], urlBytes)) { - parse.ToLower(val) - if val[0] == '#' { - if name, ok := css.ShortenColorHex[string(val)]; ok { - val = name - } else if len(val) == 7 && val[1] == val[2] && val[3] == val[4] && val[5] == val[6] { - val[2] = val[3] - val[3] = val[5] - val = val[:4] - } - } else if hex, ok := css.ShortenColorName[css.ToHash(val)]; ok { - val = hex - // } else if len(val) > 5 && bytes.Equal(val[:4], []byte("rgb(")) && val[len(val)-1] == ')' { - // TODO: handle rgb(x, y, z) and hsl(x, y, z) - } - } - - // prefer single or double quotes depending on what occurs more often in value - val = xml.EscapeAttrVal(&attrByteBuffer, val) - if _, err := w.Write(val); err != nil { - return err - } - case xml.StartTagCloseToken: - next := tb.Peek(0) - skipExtra := false - if next.TokenType == xml.TextToken && parse.IsAllWhitespace(next.Data) { - next = tb.Peek(1) - skipExtra = true - } - if next.TokenType == xml.EndTagToken { - // collapse empty tags to single void tag - tb.Shift() - if skipExtra { - tb.Shift() - } - if _, err := w.Write(voidBytes); err != nil { - return err - } - } else { - if _, err := w.Write(t.Data); err != nil { - return err - } - } - - if tag == ForeignObject { - if err := printTag(w, tb, tag); err != nil { - return err - } - } - case xml.StartTagCloseVoidToken: - tag = 0 - if _, err := w.Write(t.Data); err != nil { - return err - } - case xml.EndTagToken: - tag = 0 - if len(t.Data) > 3+len(t.Text) { - t.Data[2+len(t.Text)] = '>' - t.Data = t.Data[:3+len(t.Text)] - } - if _, err := w.Write(t.Data); err != nil { - return err - } - } - } -} - -func (o *Minifier) shortenDimension(b []byte) ([]byte, int) { - if n, m := parse.Dimension(b); n > 0 { - unit := b[n : n+m] - b = minify.Number(b[:n], o.Precision) - if len(b) != 1 || b[0] != '0' { - if m == 2 && unit[0] == 'p' && unit[1] == 'x' { - unit = nil - } else if m > 1 { // only percentage is length 1 - parse.ToLower(unit) - } - b = append(b, unit...) - } - return b, n + m - } - return b, 0 -} - -func (o *Minifier) shortenRect(tb *TokenBuffer, t *Token) { - w, h := zeroBytes, zeroBytes - attrs := tb.Attributes(Width, Height) - if attrs[0] != nil { - n, _ := parse.Dimension(attrs[0].AttrVal) - w = minify.Number(attrs[0].AttrVal[:n], o.Precision) - } - if attrs[1] != nil { - n, _ := parse.Dimension(attrs[1].AttrVal) - h = minify.Number(attrs[1].AttrVal[:n], o.Precision) - } - if len(w) == 0 || w[0] == '0' || len(h) == 0 || h[0] == '0' { - t.Data = nil - } -} - -//////////////////////////////////////////////////////////////// - -func printTag(w io.Writer, tb *TokenBuffer, tag Hash) error { - level := 0 - for { - t := *tb.Peek(0) - if level == 0 && t.Hash == tag && (t.TokenType == xml.EndTagToken || t.TokenType == xml.StartTagCloseVoidToken) { - break - } - switch t.TokenType { - case xml.ErrorToken: - break - case xml.StartTagToken: - if t.Hash == tag { - level++ - } - case xml.StartTagCloseVoidToken: - if t.Hash == tag { - if level == 0 { - break - } - level-- - } - case xml.EndTagToken: - if t.Hash == tag { - if level == 0 { - break - } - level-- - } - } - if _, err := w.Write(t.Data); err != nil { - return err - } - tb.Shift() - } - return nil -} - -func skipTag(tb *TokenBuffer) { - level := 0 - for { - if t := *tb.Shift(); t.TokenType == xml.ErrorToken { - break - } else if t.TokenType == xml.EndTagToken || t.TokenType == xml.StartTagCloseVoidToken { - if level == 0 { - break - } - level-- - } else if t.TokenType == xml.StartTagToken { - level++ - } - } -} diff --git a/vendor/github.com/tdewolff/minify/v2/svg/table.go b/vendor/github.com/tdewolff/minify/v2/svg/table.go deleted file mode 100644 index 82db6b5f5a932..0000000000000 --- a/vendor/github.com/tdewolff/minify/v2/svg/table.go +++ /dev/null @@ -1,82 +0,0 @@ -package svg - -var colorAttrMap = map[Hash]bool{ - Color: true, - Fill: true, - Stroke: true, - Stop_Color: true, - Flood_Color: true, - Lighting_Color: true, -} - -// var styleAttrMap = map[svg.Hash]bool{ -// svg.Font: true, -// svg.Font_Family: true, -// svg.Font_Size: true, -// svg.Font_Size_Adjust: true, -// svg.Font_Stretch: true, -// svg.Font_Style: true, -// svg.Font_Variant: true, -// svg.Font_Weight: true, -// svg.Direction: true, -// svg.Letter_Spacing: true, -// svg.Text_Decoration: true, -// svg.Unicode_Bidi: true, -// svg.White_Space: true, -// svg.Word_Spacing: true, -// svg.Clip: true, -// svg.Color: true, -// svg.Cursor: true, -// svg.Display: true, -// svg.Overflow: true, -// svg.Visibility: true, -// svg.Clip_Path: true, -// svg.Clip_Rule: true, -// svg.Mask: true, -// svg.Opacity: true, -// svg.Enable_Background: true, -// svg.Filter: true, -// svg.Flood_Color: true, -// svg.Flood_Opacity: true, -// svg.Lighting_Color: true, -// svg.Solid_Color: true, -// svg.Solid_Opacity: true, -// svg.Stop_Color: true, -// svg.Stop_Opacity: true, -// svg.Pointer_Events: true, -// svg.Buffered_Rendering: true, -// svg.Color_Interpolation: true, -// svg.Color_Interpolation_Filters: true, -// svg.Color_Profile: true, -// svg.Color_Rendering: true, -// svg.Fill: true, -// svg.Fill_Opacity: true, -// svg.Fill_Rule: true, -// svg.Image_Rendering: true, -// svg.Marker: true, -// svg.Marker_End: true, -// svg.Marker_Mid: true, -// svg.Marker_Start: true, -// svg.Shape_Rendering: true, -// svg.Stroke: true, -// svg.Stroke_Dasharray: true, -// svg.Stroke_Dashoffset: true, -// svg.Stroke_Linecap: true, -// svg.Stroke_Linejoin: true, -// svg.Stroke_Miterlimit: true, -// svg.Stroke_Opacity: true, -// svg.Stroke_Width: true, -// svg.Paint_Order: true, -// svg.Vector_Effect: true, -// svg.Viewport_Fill: true, -// svg.Viewport_Fill_Opacity: true, -// svg.Text_Rendering: true, -// svg.Alignment_Baseline: true, -// svg.Baseline_Shift: true, -// svg.Dominant_Baseline: true, -// svg.Glyph_Orientation_Horizontal: true, -// svg.Glyph_Orientation_Vertical: true, -// svg.Kerning: true, -// svg.Text_Anchor: true, -// svg.Writing_Mode: true, -// } diff --git a/vendor/github.com/tdewolff/minify/v2/xml/buffer.go b/vendor/github.com/tdewolff/minify/v2/xml/buffer.go deleted file mode 100644 index f6b06c0a05681..0000000000000 --- a/vendor/github.com/tdewolff/minify/v2/xml/buffer.go +++ /dev/null @@ -1,84 +0,0 @@ -package xml - -import "github.com/tdewolff/parse/v2/xml" - -// Token is a single token unit with an attribute value (if given) and hash of the data. -type Token struct { - xml.TokenType - Data []byte - Text []byte - AttrVal []byte -} - -// TokenBuffer is a buffer that allows for token look-ahead. -type TokenBuffer struct { - l *xml.Lexer - - buf []Token - pos int -} - -// NewTokenBuffer returns a new TokenBuffer. -func NewTokenBuffer(l *xml.Lexer) *TokenBuffer { - return &TokenBuffer{ - l: l, - buf: make([]Token, 0, 8), - } -} - -func (z *TokenBuffer) read(t *Token) { - t.TokenType, t.Data = z.l.Next() - t.Text = z.l.Text() - if t.TokenType == xml.AttributeToken { - t.AttrVal = z.l.AttrVal() - } else { - t.AttrVal = nil - } -} - -// Peek returns the ith element and possibly does an allocation. -// Peeking past an error will panic. -func (z *TokenBuffer) Peek(pos int) *Token { - pos += z.pos - if pos >= len(z.buf) { - if len(z.buf) > 0 && z.buf[len(z.buf)-1].TokenType == xml.ErrorToken { - return &z.buf[len(z.buf)-1] - } - - c := cap(z.buf) - d := len(z.buf) - z.pos - p := pos - z.pos + 1 // required peek length - var buf []Token - if 2*p > c { - buf = make([]Token, 0, 2*c+p) - } else { - buf = z.buf - } - copy(buf[:d], z.buf[z.pos:]) - - buf = buf[:p] - pos -= z.pos - for i := d; i < p; i++ { - z.read(&buf[i]) - if buf[i].TokenType == xml.ErrorToken { - buf = buf[:i+1] - pos = i - break - } - } - z.pos, z.buf = 0, buf - } - return &z.buf[pos] -} - -// Shift returns the first element and advances position. -func (z *TokenBuffer) Shift() *Token { - if z.pos >= len(z.buf) { - t := &z.buf[:1][0] - z.read(t) - return t - } - t := &z.buf[z.pos] - z.pos++ - return t -} diff --git a/vendor/github.com/tdewolff/minify/v2/xml/table.go b/vendor/github.com/tdewolff/minify/v2/xml/table.go deleted file mode 100644 index 25ec910a8f93e..0000000000000 --- a/vendor/github.com/tdewolff/minify/v2/xml/table.go +++ /dev/null @@ -1,8 +0,0 @@ -package xml - -// Entities are all named character entities. -var EntitiesMap = map[string][]byte{ - "apos": []byte("'"), - "gt": []byte(">"), - "quot": []byte("\""), -} diff --git a/vendor/github.com/tdewolff/minify/v2/xml/xml.go b/vendor/github.com/tdewolff/minify/v2/xml/xml.go deleted file mode 100644 index 9895f2090bebf..0000000000000 --- a/vendor/github.com/tdewolff/minify/v2/xml/xml.go +++ /dev/null @@ -1,197 +0,0 @@ -// Package xml minifies XML1.0 following the specifications at http://www.w3.org/TR/xml/. -package xml - -import ( - "io" - - "github.com/tdewolff/minify/v2" - "github.com/tdewolff/parse/v2" - "github.com/tdewolff/parse/v2/xml" -) - -var ( - isBytes = []byte("=") - spaceBytes = []byte(" ") - voidBytes = []byte("/>") -) - -//////////////////////////////////////////////////////////////// - -// DefaultMinifier is the default minifier. -var DefaultMinifier = &Minifier{} - -// Minifier is an XML minifier. -type Minifier struct { - KeepWhitespace bool -} - -// Minify minifies XML data, it reads from r and writes to w. -func Minify(m *minify.M, w io.Writer, r io.Reader, params map[string]string) error { - return DefaultMinifier.Minify(m, w, r, params) -} - -// Minify minifies XML data, it reads from r and writes to w. -func (o *Minifier) Minify(m *minify.M, w io.Writer, r io.Reader, _ map[string]string) error { - omitSpace := true // on true the next text token must not start with a space - - attrByteBuffer := make([]byte, 0, 64) - - l := xml.NewLexer(r) - defer l.Restore() - - tb := NewTokenBuffer(l) - for { - t := *tb.Shift() - if t.TokenType == xml.CDATAToken { - if len(t.Text) == 0 { - continue - } - if text, useText := xml.EscapeCDATAVal(&attrByteBuffer, t.Text); useText { - t.TokenType = xml.TextToken - t.Data = text - } - } - switch t.TokenType { - case xml.ErrorToken: - if l.Err() == io.EOF { - return nil - } - return l.Err() - case xml.DOCTYPEToken: - if _, err := w.Write(t.Data); err != nil { - return err - } - case xml.CDATAToken: - if _, err := w.Write(t.Data); err != nil { - return err - } - if len(t.Text) > 0 && parse.IsWhitespace(t.Text[len(t.Text)-1]) { - omitSpace = true - } - case xml.TextToken: - t.Data = parse.ReplaceMultipleWhitespaceAndEntities(t.Data, EntitiesMap, nil) - - // whitespace removal; trim left - if omitSpace && parse.IsWhitespace(t.Data[0]) { - t.Data = t.Data[1:] - } - - // whitespace removal; trim right - omitSpace = false - if len(t.Data) == 0 { - omitSpace = true - } else if parse.IsWhitespace(t.Data[len(t.Data)-1]) { - omitSpace = true - i := 0 - for { - next := tb.Peek(i) - // trim if EOF, text token with whitespace begin or block token - if next.TokenType == xml.ErrorToken { - t.Data = t.Data[:len(t.Data)-1] - omitSpace = false - break - } else if next.TokenType == xml.TextToken { - // this only happens when a comment, doctype, cdata startpi tag was in between - // remove if the text token starts with a whitespace - if len(next.Data) > 0 && parse.IsWhitespace(next.Data[0]) { - t.Data = t.Data[:len(t.Data)-1] - omitSpace = false - } - break - } else if next.TokenType == xml.CDATAToken { - if len(next.Text) > 0 && parse.IsWhitespace(next.Text[0]) { - t.Data = t.Data[:len(t.Data)-1] - omitSpace = false - } - break - } else if next.TokenType == xml.StartTagToken || next.TokenType == xml.EndTagToken { - if !o.KeepWhitespace { - t.Data = t.Data[:len(t.Data)-1] - omitSpace = false - } - break - } - i++ - } - } - - if _, err := w.Write(t.Data); err != nil { - return err - } - case xml.StartTagToken: - if o.KeepWhitespace { - omitSpace = false - } - if _, err := w.Write(t.Data); err != nil { - return err - } - case xml.StartTagPIToken: - if _, err := w.Write(t.Data); err != nil { - return err - } - case xml.AttributeToken: - if _, err := w.Write(spaceBytes); err != nil { - return err - } - if _, err := w.Write(t.Text); err != nil { - return err - } - if _, err := w.Write(isBytes); err != nil { - return err - } - - if len(t.AttrVal) < 2 { - if _, err := w.Write(t.AttrVal); err != nil { - return err - } - } else { - val := t.AttrVal[1 : len(t.AttrVal)-1] - val = parse.ReplaceEntities(val, EntitiesMap, nil) - val = xml.EscapeAttrVal(&attrByteBuffer, val) // prefer single or double quotes depending on what occurs more often in value - if _, err := w.Write(val); err != nil { - return err - } - } - case xml.StartTagCloseToken: - next := tb.Peek(0) - skipExtra := false - if next.TokenType == xml.TextToken && parse.IsAllWhitespace(next.Data) { - next = tb.Peek(1) - skipExtra = true - } - if next.TokenType == xml.EndTagToken { - // collapse empty tags to single void tag - tb.Shift() - if skipExtra { - tb.Shift() - } - if _, err := w.Write(voidBytes); err != nil { - return err - } - } else { - if _, err := w.Write(t.Data); err != nil { - return err - } - } - case xml.StartTagCloseVoidToken: - if _, err := w.Write(t.Data); err != nil { - return err - } - case xml.StartTagClosePIToken: - if _, err := w.Write(t.Data); err != nil { - return err - } - case xml.EndTagToken: - if o.KeepWhitespace { - omitSpace = false - } - if len(t.Data) > 3+len(t.Text) { - t.Data[2+len(t.Text)] = '>' - t.Data = t.Data[:3+len(t.Text)] - } - if _, err := w.Write(t.Data); err != nil { - return err - } - } - } -} diff --git a/vendor/github.com/tdewolff/parse/v2/.travis.yml b/vendor/github.com/tdewolff/parse/v2/.travis.yml deleted file mode 100644 index 9267c26c6a35d..0000000000000 --- a/vendor/github.com/tdewolff/parse/v2/.travis.yml +++ /dev/null @@ -1,10 +0,0 @@ -language: go -go: - - 1.13.x -env: - - GO111MODULE=on -before_install: - - go get github.com/mattn/goveralls -script: - - go test -covermode=count -coverprofile=profile.cov . ./buffer ./css ./html ./js ./json ./strconv ./svg ./xml - - goveralls -coverprofile=profile.cov -service travis-ci diff --git a/vendor/github.com/tdewolff/parse/v2/LICENSE.md b/vendor/github.com/tdewolff/parse/v2/LICENSE.md deleted file mode 100644 index 41677de41ec1d..0000000000000 --- a/vendor/github.com/tdewolff/parse/v2/LICENSE.md +++ /dev/null @@ -1,22 +0,0 @@ -Copyright (c) 2015 Taco de Wolff - - Permission is hereby granted, free of charge, to any person - obtaining a copy of this software and associated documentation - files (the "Software"), to deal in the Software without - restriction, including without limitation the rights to use, - copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the - Software is furnished to do so, subject to the following - conditions: - - The above copyright notice and this permission notice shall be - included in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES - OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT - HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/vendor/github.com/tdewolff/parse/v2/README.md b/vendor/github.com/tdewolff/parse/v2/README.md deleted file mode 100644 index 865ae57ddefda..0000000000000 --- a/vendor/github.com/tdewolff/parse/v2/README.md +++ /dev/null @@ -1,70 +0,0 @@ -# Parse [![Build Status](https://travis-ci.org/tdewolff/parse.svg?branch=master)](https://travis-ci.org/tdewolff/parse) [![GoDoc](http://godoc.org/github.com/tdewolff/parse?status.svg)](http://godoc.org/github.com/tdewolff/parse) [![Coverage Status](https://coveralls.io/repos/github/tdewolff/parse/badge.svg?branch=master)](https://coveralls.io/github/tdewolff/parse?branch=master) - -***BE AWARE: YOU NEED GO 1.9.7+, 1.10.3+, 1.11 to run the latest release!!!*** - -If you cannot upgrade Go, please pin to **parse@v2.3.4** - ---- - -This package contains several lexers and parsers written in [Go][1]. All subpackages are built to be streaming, high performance and to be in accordance with the official (latest) specifications. - -The lexers are implemented using `buffer.Lexer` in https://github.com/tdewolff/parse/buffer and the parsers work on top of the lexers. Some subpackages have hashes defined (using [Hasher](https://github.com/tdewolff/hasher)) that speed up common byte-slice comparisons. - -## Buffer -### Reader -Reader is a wrapper around a `[]byte` that implements the `io.Reader` interface. It is comparable to `bytes.Reader` but has slightly different semantics (and a slightly smaller memory footprint). - -### Writer -Writer is a buffer that implements the `io.Writer` interface and expands the buffer as needed. The reset functionality allows for better memory reuse. After calling `Reset`, it will overwrite the current buffer and thus reduce allocations. - -### Lexer -Lexer is a read buffer specifically designed for building lexers. It keeps track of two positions: a start and end position. The start position is the beginning of the current token being parsed, the end position is being moved forward until a valid token is found. Calling `Shift` will collapse the positions to the end and return the parsed `[]byte`. - -Moving the end position can go through `Move(int)` which also accepts negative integers. One can also use `Pos() int` to try and parse a token, and if it fails rewind with `Rewind(int)`, passing the previously saved position. - -`Peek(int) byte` will peek forward (relative to the end position) and return the byte at that location. `PeekRune(int) (rune, int)` returns UTF-8 runes and its length at the given **byte** position. Upon an error `Peek` will return `0`, the **user must peek at every character** and not skip any, otherwise it may skip a `0` and panic on out-of-bounds indexing. - -`Lexeme() []byte` will return the currently selected bytes, `Skip()` will collapse the selection. `Shift() []byte` is a combination of `Lexeme() []byte` and `Skip()`. - -When the passed `io.Reader` returned an error, `Err() error` will return that error even if not at the end of the buffer. - -### StreamLexer -StreamLexer behaves like Lexer but uses a buffer pool to read in chunks from `io.Reader`, retaining old buffers in memory that are still in use, and re-using old buffers otherwise. Calling `Free(n int)` frees up `n` bytes from the internal buffer(s). It holds an array of buffers to accommodate for keeping everything in-memory. Calling `ShiftLen() int` returns the number of bytes that have been shifted since the previous call to `ShiftLen`, which can be used to specify how many bytes need to be freed up from the buffer. If you don't need to keep returned byte slices around, call `Free(ShiftLen())` after every `Shift` call. - -## Strconv -This package contains string conversion function much like the standard library's `strconv` package, but it is specifically tailored for the performance needs within the `minify` package. - -For example, the floating-point to string conversion function is approximately twice as fast as the standard library, but it is not as precise. - -## CSS -This package is a CSS3 lexer and parser. Both follow the specification at [CSS Syntax Module Level 3](http://www.w3.org/TR/css-syntax-3/). The lexer takes an io.Reader and converts it into tokens until the EOF. The parser returns a parse tree of the full io.Reader input stream, but the low-level `Next` function can be used for stream parsing to returns grammar units until the EOF. - -[See README here](https://github.com/tdewolff/parse/tree/master/css). - -## HTML -This package is an HTML5 lexer. It follows the specification at [The HTML syntax](http://www.w3.org/TR/html5/syntax.html). The lexer takes an io.Reader and converts it into tokens until the EOF. - -[See README here](https://github.com/tdewolff/parse/tree/master/html). - -## JS -This package is a JS lexer (ECMA-262, edition 6.0). It follows the specification at [ECMAScript Language Specification](http://www.ecma-international.org/ecma-262/6.0/). The lexer takes an io.Reader and converts it into tokens until the EOF. - -[See README here](https://github.com/tdewolff/parse/tree/master/js). - -## JSON -This package is a JSON parser (ECMA-404). It follows the specification at [JSON](http://json.org/). The parser takes an io.Reader and converts it into tokens until the EOF. - -[See README here](https://github.com/tdewolff/parse/tree/master/json). - -## SVG -This package contains common hashes for SVG1.1 tags and attributes. - -## XML -This package is an XML1.0 lexer. It follows the specification at [Extensible Markup Language (XML) 1.0 (Fifth Edition)](http://www.w3.org/TR/xml/). The lexer takes an io.Reader and converts it into tokens until the EOF. - -[See README here](https://github.com/tdewolff/parse/tree/master/xml). - -## License -Released under the [MIT license](LICENSE.md). - -[1]: http://golang.org/ "Go Language" diff --git a/vendor/github.com/tdewolff/parse/v2/buffer/buffer.go b/vendor/github.com/tdewolff/parse/v2/buffer/buffer.go deleted file mode 100644 index d9e14d14800e2..0000000000000 --- a/vendor/github.com/tdewolff/parse/v2/buffer/buffer.go +++ /dev/null @@ -1,15 +0,0 @@ -/* -Package buffer contains buffer and wrapper types for byte slices. It is useful for writing lexers or other high-performance byte slice handling. - -The `Reader` and `Writer` types implement the `io.Reader` and `io.Writer` respectively and provide a thinner and faster interface than `bytes.Buffer`. -The `Lexer` type is useful for building lexers because it keeps track of the start and end position of a byte selection, and shifts the bytes whenever a valid token is found. -The `StreamLexer` does the same, but keeps a buffer pool so that it reads a limited amount at a time, allowing to parse from streaming sources. -*/ -package buffer - -// defaultBufSize specifies the default initial length of internal buffers. -var defaultBufSize = 4096 - -// MinBuf specifies the default initial length of internal buffers. -// Solely here to support old versions of parse. -var MinBuf = defaultBufSize diff --git a/vendor/github.com/tdewolff/parse/v2/buffer/lexer.go b/vendor/github.com/tdewolff/parse/v2/buffer/lexer.go deleted file mode 100644 index 7ed7ae202989c..0000000000000 --- a/vendor/github.com/tdewolff/parse/v2/buffer/lexer.go +++ /dev/null @@ -1,158 +0,0 @@ -package buffer - -import ( - "io" - "io/ioutil" -) - -var nullBuffer = []byte{0} - -// Lexer is a buffered reader that allows peeking forward and shifting, taking an io.Reader. -// It keeps data in-memory until Free, taking a byte length, is called to move beyond the data. -type Lexer struct { - buf []byte - pos int // index in buf - start int // index in buf - err error - - restore func() -} - -// NewLexerBytes returns a new Lexer for a given io.Reader, and uses ioutil.ReadAll to read it into a byte slice. -// If the io.Reader implements Bytes, that is used instead. -// It will append a NULL at the end of the buffer. -func NewLexer(r io.Reader) *Lexer { - var b []byte - if r != nil { - if buffer, ok := r.(interface { - Bytes() []byte - }); ok { - b = buffer.Bytes() - } else { - var err error - b, err = ioutil.ReadAll(r) - if err != nil { - return &Lexer{ - buf: []byte{0}, - err: err, - } - } - } - } - return NewLexerBytes(b) -} - -// NewLexerBytes returns a new Lexer for a given byte slice, and appends NULL at the end. -// To avoid reallocation, make sure the capacity has room for one more byte. -func NewLexerBytes(b []byte) *Lexer { - z := &Lexer{ - buf: b, - } - - n := len(b) - if n == 0 { - z.buf = nullBuffer - } else { - // Append NULL to buffer, but try to avoid reallocation - if cap(b) > n { - // Overwrite next byte but restore when done - b = b[:n+1] - c := b[n] - b[n] = 0 - - z.buf = b - z.restore = func() { - b[n] = c - } - } else { - z.buf = append(b, 0) - } - } - return z -} - -// Restore restores the replaced byte past the end of the buffer by NULL. -func (z *Lexer) Restore() { - if z.restore != nil { - z.restore() - z.restore = nil - } -} - -// Err returns the error returned from io.Reader or io.EOF when the end has been reached. -func (z *Lexer) Err() error { - return z.PeekErr(0) -} - -// PeekErr returns the error at position pos. When pos is zero, this is the same as calling Err(). -func (z *Lexer) PeekErr(pos int) error { - if z.err != nil { - return z.err - } else if z.pos+pos >= len(z.buf)-1 { - return io.EOF - } - return nil -} - -// Peek returns the ith byte relative to the end position. -// Peek returns 0 when an error has occurred, Err returns the error. -func (z *Lexer) Peek(pos int) byte { - pos += z.pos - return z.buf[pos] -} - -// PeekRune returns the rune and rune length of the ith byte relative to the end position. -func (z *Lexer) PeekRune(pos int) (rune, int) { - // from unicode/utf8 - c := z.Peek(pos) - if c < 0xC0 || z.Peek(pos+1) == 0 { - return rune(c), 1 - } else if c < 0xE0 || z.Peek(pos+2) == 0 { - return rune(c&0x1F)<<6 | rune(z.Peek(pos+1)&0x3F), 2 - } else if c < 0xF0 || z.Peek(pos+3) == 0 { - return rune(c&0x0F)<<12 | rune(z.Peek(pos+1)&0x3F)<<6 | rune(z.Peek(pos+2)&0x3F), 3 - } - return rune(c&0x07)<<18 | rune(z.Peek(pos+1)&0x3F)<<12 | rune(z.Peek(pos+2)&0x3F)<<6 | rune(z.Peek(pos+3)&0x3F), 4 -} - -// Move advances the position. -func (z *Lexer) Move(n int) { - z.pos += n -} - -// Pos returns a mark to which can be rewinded. -func (z *Lexer) Pos() int { - return z.pos - z.start -} - -// Rewind rewinds the position to the given position. -func (z *Lexer) Rewind(pos int) { - z.pos = z.start + pos -} - -// Lexeme returns the bytes of the current selection. -func (z *Lexer) Lexeme() []byte { - return z.buf[z.start:z.pos] -} - -// Skip collapses the position to the end of the selection. -func (z *Lexer) Skip() { - z.start = z.pos -} - -// Shift returns the bytes of the current selection and collapses the position to the end of the selection. -func (z *Lexer) Shift() []byte { - b := z.buf[z.start:z.pos] - z.start = z.pos - return b -} - -// Offset returns the character position in the buffer. -func (z *Lexer) Offset() int { - return z.pos -} - -// Bytes returns the underlying buffer. -func (z *Lexer) Bytes() []byte { - return z.buf[:len(z.buf)-1] -} diff --git a/vendor/github.com/tdewolff/parse/v2/buffer/reader.go b/vendor/github.com/tdewolff/parse/v2/buffer/reader.go deleted file mode 100644 index 9926eef66efc2..0000000000000 --- a/vendor/github.com/tdewolff/parse/v2/buffer/reader.go +++ /dev/null @@ -1,44 +0,0 @@ -package buffer - -import "io" - -// Reader implements an io.Reader over a byte slice. -type Reader struct { - buf []byte - pos int -} - -// NewReader returns a new Reader for a given byte slice. -func NewReader(buf []byte) *Reader { - return &Reader{ - buf: buf, - } -} - -// Read reads bytes into the given byte slice and returns the number of bytes read and an error if occurred. -func (r *Reader) Read(b []byte) (n int, err error) { - if len(b) == 0 { - return 0, nil - } - if r.pos >= len(r.buf) { - return 0, io.EOF - } - n = copy(b, r.buf[r.pos:]) - r.pos += n - return -} - -// Bytes returns the underlying byte slice. -func (r *Reader) Bytes() []byte { - return r.buf -} - -// Reset resets the position of the read pointer to the beginning of the underlying byte slice. -func (r *Reader) Reset() { - r.pos = 0 -} - -// Len returns the length of the buffer. -func (r *Reader) Len() int { - return len(r.buf) -} diff --git a/vendor/github.com/tdewolff/parse/v2/buffer/streamlexer.go b/vendor/github.com/tdewolff/parse/v2/buffer/streamlexer.go deleted file mode 100644 index 5ea2dd58d5e72..0000000000000 --- a/vendor/github.com/tdewolff/parse/v2/buffer/streamlexer.go +++ /dev/null @@ -1,223 +0,0 @@ -package buffer - -import ( - "io" -) - -type block struct { - buf []byte - next int // index in pool plus one - active bool -} - -type bufferPool struct { - pool []block - head int // index in pool plus one - tail int // index in pool plus one - - pos int // byte pos in tail -} - -func (z *bufferPool) swap(oldBuf []byte, size int) []byte { - // find new buffer that can be reused - swap := -1 - for i := 0; i < len(z.pool); i++ { - if !z.pool[i].active && size <= cap(z.pool[i].buf) { - swap = i - break - } - } - if swap == -1 { // no free buffer found for reuse - if z.tail == 0 && z.pos >= len(oldBuf) && size <= cap(oldBuf) { // but we can reuse the current buffer! - z.pos -= len(oldBuf) - return oldBuf[:0] - } - // allocate new - z.pool = append(z.pool, block{make([]byte, 0, size), 0, true}) - swap = len(z.pool) - 1 - } - - newBuf := z.pool[swap].buf - - // put current buffer into pool - z.pool[swap] = block{oldBuf, 0, true} - if z.head != 0 { - z.pool[z.head-1].next = swap + 1 - } - z.head = swap + 1 - if z.tail == 0 { - z.tail = swap + 1 - } - - return newBuf[:0] -} - -func (z *bufferPool) free(n int) { - z.pos += n - // move the tail over to next buffers - for z.tail != 0 && z.pos >= len(z.pool[z.tail-1].buf) { - z.pos -= len(z.pool[z.tail-1].buf) - newTail := z.pool[z.tail-1].next - z.pool[z.tail-1].active = false // after this, any thread may pick up the inactive buffer, so it can't be used anymore - z.tail = newTail - } - if z.tail == 0 { - z.head = 0 - } -} - -// StreamLexer is a buffered reader that allows peeking forward and shifting, taking an io.Reader. -// It keeps data in-memory until Free, taking a byte length, is called to move beyond the data. -type StreamLexer struct { - r io.Reader - err error - - pool bufferPool - - buf []byte - start int // index in buf - pos int // index in buf - prevStart int - - free int -} - -// NewStreamLexer returns a new StreamLexer for a given io.Reader with a 4kB estimated buffer size. -// If the io.Reader implements Bytes, that buffer is used instead. -func NewStreamLexer(r io.Reader) *StreamLexer { - return NewStreamLexerSize(r, defaultBufSize) -} - -// NewStreamLexerSize returns a new StreamLexer for a given io.Reader and estimated required buffer size. -// If the io.Reader implements Bytes, that buffer is used instead. -func NewStreamLexerSize(r io.Reader, size int) *StreamLexer { - // if reader has the bytes in memory already, use that instead - if buffer, ok := r.(interface { - Bytes() []byte - }); ok { - return &StreamLexer{ - err: io.EOF, - buf: buffer.Bytes(), - } - } - return &StreamLexer{ - r: r, - buf: make([]byte, 0, size), - } -} - -func (z *StreamLexer) read(pos int) byte { - if z.err != nil { - return 0 - } - - // free unused bytes - z.pool.free(z.free) - z.free = 0 - - // get new buffer - c := cap(z.buf) - p := pos - z.start + 1 - if 2*p > c { // if the token is larger than half the buffer, increase buffer size - c = 2*c + p - } - d := len(z.buf) - z.start - buf := z.pool.swap(z.buf[:z.start], c) - copy(buf[:d], z.buf[z.start:]) // copy the left-overs (unfinished token) from the old buffer - - // read in new data for the rest of the buffer - var n int - for pos-z.start >= d && z.err == nil { - n, z.err = z.r.Read(buf[d:cap(buf)]) - d += n - } - pos -= z.start - z.pos -= z.start - z.start, z.buf = 0, buf[:d] - if pos >= d { - return 0 - } - return z.buf[pos] -} - -// Err returns the error returned from io.Reader. It may still return valid bytes for a while though. -func (z *StreamLexer) Err() error { - if z.err == io.EOF && z.pos < len(z.buf) { - return nil - } - return z.err -} - -// Free frees up bytes of length n from previously shifted tokens. -// Each call to Shift should at one point be followed by a call to Free with a length returned by ShiftLen. -func (z *StreamLexer) Free(n int) { - z.free += n -} - -// Peek returns the ith byte relative to the end position and possibly does an allocation. -// Peek returns zero when an error has occurred, Err returns the error. -// TODO: inline function -func (z *StreamLexer) Peek(pos int) byte { - pos += z.pos - if uint(pos) < uint(len(z.buf)) { // uint for BCE - return z.buf[pos] - } - return z.read(pos) -} - -// PeekRune returns the rune and rune length of the ith byte relative to the end position. -func (z *StreamLexer) PeekRune(pos int) (rune, int) { - // from unicode/utf8 - c := z.Peek(pos) - if c < 0xC0 { - return rune(c), 1 - } else if c < 0xE0 { - return rune(c&0x1F)<<6 | rune(z.Peek(pos+1)&0x3F), 2 - } else if c < 0xF0 { - return rune(c&0x0F)<<12 | rune(z.Peek(pos+1)&0x3F)<<6 | rune(z.Peek(pos+2)&0x3F), 3 - } - return rune(c&0x07)<<18 | rune(z.Peek(pos+1)&0x3F)<<12 | rune(z.Peek(pos+2)&0x3F)<<6 | rune(z.Peek(pos+3)&0x3F), 4 -} - -// Move advances the position. -func (z *StreamLexer) Move(n int) { - z.pos += n -} - -// Pos returns a mark to which can be rewinded. -func (z *StreamLexer) Pos() int { - return z.pos - z.start -} - -// Rewind rewinds the position to the given position. -func (z *StreamLexer) Rewind(pos int) { - z.pos = z.start + pos -} - -// Lexeme returns the bytes of the current selection. -func (z *StreamLexer) Lexeme() []byte { - return z.buf[z.start:z.pos] -} - -// Skip collapses the position to the end of the selection. -func (z *StreamLexer) Skip() { - z.start = z.pos -} - -// Shift returns the bytes of the current selection and collapses the position to the end of the selection. -// It also returns the number of bytes we moved since the last call to Shift. This can be used in calls to Free. -func (z *StreamLexer) Shift() []byte { - if z.pos > len(z.buf) { // make sure we peeked at least as much as we shift - z.read(z.pos - 1) - } - b := z.buf[z.start:z.pos] - z.start = z.pos - return b -} - -// ShiftLen returns the number of bytes moved since the last call to ShiftLen. This can be used in calls to Free because it takes into account multiple Shifts or Skips. -func (z *StreamLexer) ShiftLen() int { - n := z.start - z.prevStart - z.prevStart = z.start - return n -} diff --git a/vendor/github.com/tdewolff/parse/v2/buffer/writer.go b/vendor/github.com/tdewolff/parse/v2/buffer/writer.go deleted file mode 100644 index b3c9990d904a9..0000000000000 --- a/vendor/github.com/tdewolff/parse/v2/buffer/writer.go +++ /dev/null @@ -1,41 +0,0 @@ -package buffer - -// Writer implements an io.Writer over a byte slice. -type Writer struct { - buf []byte -} - -// NewWriter returns a new Writer for a given byte slice. -func NewWriter(buf []byte) *Writer { - return &Writer{ - buf: buf, - } -} - -// Write writes bytes from the given byte slice and returns the number of bytes written and an error if occurred. When err != nil, n == 0. -func (w *Writer) Write(b []byte) (int, error) { - n := len(b) - end := len(w.buf) - if end+n > cap(w.buf) { - buf := make([]byte, end, 2*cap(w.buf)+n) - copy(buf, w.buf) - w.buf = buf - } - w.buf = w.buf[:end+n] - return copy(w.buf[end:], b), nil -} - -// Len returns the length of the underlying byte slice. -func (w *Writer) Len() int { - return len(w.buf) -} - -// Bytes returns the underlying byte slice. -func (w *Writer) Bytes() []byte { - return w.buf -} - -// Reset empties and reuses the current buffer. Subsequent writes will overwrite the buffer, so any reference to the underlying slice is invalidated after this call. -func (w *Writer) Reset() { - w.buf = w.buf[:0] -} diff --git a/vendor/github.com/tdewolff/parse/v2/common.go b/vendor/github.com/tdewolff/parse/v2/common.go deleted file mode 100644 index 0b59e00674cc3..0000000000000 --- a/vendor/github.com/tdewolff/parse/v2/common.go +++ /dev/null @@ -1,231 +0,0 @@ -// Package parse contains a collection of parsers for various formats in its subpackages. -package parse - -import ( - "bytes" - "encoding/base64" - "errors" -) - -// ErrBadDataURI is returned by DataURI when the byte slice does not start with 'data:' or is too short. -var ErrBadDataURI = errors.New("not a data URI") - -// Number returns the number of bytes that parse as a number of the regex format (+|-)?([0-9]+(\.[0-9]+)?|\.[0-9]+)((e|E)(+|-)?[0-9]+)?. -func Number(b []byte) int { - if len(b) == 0 { - return 0 - } - i := 0 - if b[i] == '+' || b[i] == '-' { - i++ - if i >= len(b) { - return 0 - } - } - firstDigit := (b[i] >= '0' && b[i] <= '9') - if firstDigit { - i++ - for i < len(b) && b[i] >= '0' && b[i] <= '9' { - i++ - } - } - if i < len(b) && b[i] == '.' { - i++ - if i < len(b) && b[i] >= '0' && b[i] <= '9' { - i++ - for i < len(b) && b[i] >= '0' && b[i] <= '9' { - i++ - } - } else if firstDigit { - // . could belong to the next token - i-- - return i - } else { - return 0 - } - } else if !firstDigit { - return 0 - } - iOld := i - if i < len(b) && (b[i] == 'e' || b[i] == 'E') { - i++ - if i < len(b) && (b[i] == '+' || b[i] == '-') { - i++ - } - if i >= len(b) || b[i] < '0' || b[i] > '9' { - // e could belong to next token - return iOld - } - for i < len(b) && b[i] >= '0' && b[i] <= '9' { - i++ - } - } - return i -} - -// Dimension parses a byte-slice and returns the length of the number and its unit. -func Dimension(b []byte) (int, int) { - num := Number(b) - if num == 0 || num == len(b) { - return num, 0 - } else if b[num] == '%' { - return num, 1 - } else if b[num] >= 'a' && b[num] <= 'z' || b[num] >= 'A' && b[num] <= 'Z' { - i := num + 1 - for i < len(b) && (b[i] >= 'a' && b[i] <= 'z' || b[i] >= 'A' && b[i] <= 'Z') { - i++ - } - return num, i - num - } - return num, 0 -} - -// Mediatype parses a given mediatype and splits the mimetype from the parameters. -// It works similar to mime.ParseMediaType but is faster. -func Mediatype(b []byte) ([]byte, map[string]string) { - i := 0 - for i < len(b) && b[i] == ' ' { - i++ - } - b = b[i:] - n := len(b) - mimetype := b - var params map[string]string - for i := 3; i < n; i++ { // mimetype is at least three characters long - if b[i] == ';' || b[i] == ' ' { - mimetype = b[:i] - if b[i] == ' ' { - i++ - for i < n && b[i] == ' ' { - i++ - } - if i < n && b[i] != ';' { - break - } - } - params = map[string]string{} - s := string(b) - PARAM: - i++ - for i < n && s[i] == ' ' { - i++ - } - start := i - for i < n && s[i] != '=' && s[i] != ';' && s[i] != ' ' { - i++ - } - key := s[start:i] - for i < n && s[i] == ' ' { - i++ - } - if i < n && s[i] == '=' { - i++ - for i < n && s[i] == ' ' { - i++ - } - start = i - for i < n && s[i] != ';' && s[i] != ' ' { - i++ - } - } else { - start = i - } - params[key] = s[start:i] - for i < n && s[i] == ' ' { - i++ - } - if i < n && s[i] == ';' { - goto PARAM - } - break - } - } - return mimetype, params -} - -// DataURI parses the given data URI and returns the mediatype, data and ok. -func DataURI(dataURI []byte) ([]byte, []byte, error) { - if len(dataURI) > 5 && bytes.Equal(dataURI[:5], []byte("data:")) { - dataURI = dataURI[5:] - inBase64 := false - var mediatype []byte - i := 0 - for j := 0; j < len(dataURI); j++ { - c := dataURI[j] - if c == '=' || c == ';' || c == ',' { - if c != '=' && bytes.Equal(TrimWhitespace(dataURI[i:j]), []byte("base64")) { - if len(mediatype) > 0 { - mediatype = mediatype[:len(mediatype)-1] - } - inBase64 = true - i = j - } else if c != ',' { - mediatype = append(append(mediatype, TrimWhitespace(dataURI[i:j])...), c) - i = j + 1 - } else { - mediatype = append(mediatype, TrimWhitespace(dataURI[i:j])...) - } - if c == ',' { - if len(mediatype) == 0 || mediatype[0] == ';' { - mediatype = []byte("text/plain") - } - data := dataURI[j+1:] - if inBase64 { - decoded := make([]byte, base64.StdEncoding.DecodedLen(len(data))) - n, err := base64.StdEncoding.Decode(decoded, data) - if err != nil { - return nil, nil, err - } - data = decoded[:n] - } else { - data = DecodeURL(data) - } - return mediatype, data, nil - } - } - } - } - return nil, nil, ErrBadDataURI -} - -// QuoteEntity parses the given byte slice and returns the quote that got matched (' or ") and its entity length. -// TODO: deprecated -func QuoteEntity(b []byte) (quote byte, n int) { - if len(b) < 5 || b[0] != '&' { - return 0, 0 - } - if b[1] == '#' { - if b[2] == 'x' { - i := 3 - for i < len(b) && b[i] == '0' { - i++ - } - if i+2 < len(b) && b[i] == '2' && b[i+2] == ';' { - if b[i+1] == '2' { - return '"', i + 3 // " - } else if b[i+1] == '7' { - return '\'', i + 3 // ' - } - } - } else { - i := 2 - for i < len(b) && b[i] == '0' { - i++ - } - if i+2 < len(b) && b[i] == '3' && b[i+2] == ';' { - if b[i+1] == '4' { - return '"', i + 3 // " - } else if b[i+1] == '9' { - return '\'', i + 3 // ' - } - } - } - } else if len(b) >= 6 && b[5] == ';' { - if bytes.Equal(b[1:5], []byte{'q', 'u', 'o', 't'}) { - return '"', 6 // " - } else if bytes.Equal(b[1:5], []byte{'a', 'p', 'o', 's'}) { - return '\'', 6 // ' - } - } - return 0, 0 -} diff --git a/vendor/github.com/tdewolff/parse/v2/css/README.md b/vendor/github.com/tdewolff/parse/v2/css/README.md deleted file mode 100644 index 11a70cb510fd2..0000000000000 --- a/vendor/github.com/tdewolff/parse/v2/css/README.md +++ /dev/null @@ -1,171 +0,0 @@ -# CSS [![GoDoc](http://godoc.org/github.com/tdewolff/parse/css?status.svg)](http://godoc.org/github.com/tdewolff/parse/css) - -This package is a CSS3 lexer and parser written in [Go][1]. Both follow the specification at [CSS Syntax Module Level 3](http://www.w3.org/TR/css-syntax-3/). The lexer takes an io.Reader and converts it into tokens until the EOF. The parser returns a parse tree of the full io.Reader input stream, but the low-level `Next` function can be used for stream parsing to returns grammar units until the EOF. - -## Installation -Run the following command - - go get -u github.com/tdewolff/parse/v2/css - -or add the following import and run project with `go get` - - import "github.com/tdewolff/parse/v2/css" - -## Lexer -### Usage -The following initializes a new Lexer with io.Reader `r`: -``` go -l := css.NewLexer(r) -``` - -To tokenize until EOF an error, use: -``` go -for { - tt, text := l.Next() - switch tt { - case css.ErrorToken: - // error or EOF set in l.Err() - return - // ... - } -} -``` - -All tokens (see [CSS Syntax Module Level 3](http://www.w3.org/TR/css3-syntax/)): -``` go -ErrorToken // non-official token, returned when errors occur -IdentToken -FunctionToken // rgb( rgba( ... -AtKeywordToken // @abc -HashToken // #abc -StringToken -BadStringToken -UrlToken // url( -BadUrlToken -DelimToken // any unmatched character -NumberToken // 5 -PercentageToken // 5% -DimensionToken // 5em -UnicodeRangeToken -IncludeMatchToken // ~= -DashMatchToken // |= -PrefixMatchToken // ^= -SuffixMatchToken // $= -SubstringMatchToken // *= -ColumnToken // || -WhitespaceToken -CDOToken // -ColonToken -SemicolonToken -CommaToken -BracketToken // ( ) [ ] { }, all bracket tokens use this, Data() can distinguish between the brackets -CommentToken // non-official token -``` - -### Examples -``` go -package main - -import ( - "os" - - "github.com/tdewolff/parse/v2/css" -) - -// Tokenize CSS3 from stdin. -func main() { - l := css.NewLexer(os.Stdin) - for { - tt, text := l.Next() - switch tt { - case css.ErrorToken: - if l.Err() != io.EOF { - fmt.Println("Error on line", l.Line(), ":", l.Err()) - } - return - case css.IdentToken: - fmt.Println("Identifier", string(text)) - case css.NumberToken: - fmt.Println("Number", string(text)) - // ... - } - } -} -``` - -## Parser -### Usage -The following creates a new Parser. -``` go -// true because this is the content of an inline style attribute -p := css.NewParser(bytes.NewBufferString("color: red;"), true) -``` - -To iterate over the stylesheet, use: -``` go -for { - gt, _, data := p.Next() - if gt == css.ErrorGrammar { - break - } - // ... -} -``` - -All grammar units returned by `Next`: -``` go -ErrorGrammar -AtRuleGrammar -EndAtRuleGrammar -RulesetGrammar -EndRulesetGrammar -DeclarationGrammar -TokenGrammar -``` - -### Examples -``` go -package main - -import ( - "bytes" - "fmt" - - "github.com/tdewolff/parse/v2/css" -) - -func main() { - // true because this is the content of an inline style attribute - p := css.NewParser(bytes.NewBufferString("color: red;"), true) - out := "" - for { - gt, _, data := p.Next() - if gt == css.ErrorGrammar { - break - } else if gt == css.AtRuleGrammar || gt == css.BeginAtRuleGrammar || gt == css.BeginRulesetGrammar || gt == css.DeclarationGrammar { - out += string(data) - if gt == css.DeclarationGrammar { - out += ":" - } - for _, val := range p.Values() { - out += string(val.Data) - } - if gt == css.BeginAtRuleGrammar || gt == css.BeginRulesetGrammar { - out += "{" - } else if gt == css.AtRuleGrammar || gt == css.DeclarationGrammar { - out += ";" - } - } else { - out += string(data) - } - } - fmt.Println(out) -} - -``` - -## License -Released under the [MIT license](https://github.com/tdewolff/parse/blob/master/LICENSE.md). - -[1]: http://golang.org/ "Go Language" diff --git a/vendor/github.com/tdewolff/parse/v2/css/hash.go b/vendor/github.com/tdewolff/parse/v2/css/hash.go deleted file mode 100644 index e2ca12796a06d..0000000000000 --- a/vendor/github.com/tdewolff/parse/v2/css/hash.go +++ /dev/null @@ -1,957 +0,0 @@ -package css - -// generated by hasher -type=Hash -file=hash.go; DO NOT EDIT, except for adding more constants to the list and rerun go generate - -// uses github.com/tdewolff/hasher -//go:generate hasher -type=Hash -file=hash.go - -// Hash defines perfect hashes for a predefined list of strings -type Hash uint32 - -// Unique hash definitions to be used instead of strings -const ( - Ms_Filter Hash = 0xa // -ms-filter - Accelerator Hash = 0x3760b // accelerator - Aliceblue Hash = 0x7a209 // aliceblue - Align_Content Hash = 0xd8b0d // align-content - Align_Items Hash = 0x7ef0b // align-items - Align_Self Hash = 0x8cb0a // align-self - All Hash = 0x69103 // all - Alpha Hash = 0x37205 // alpha - Animation Hash = 0xca09 // animation - Animation_Delay Hash = 0x2050f // animation-delay - Animation_Direction Hash = 0x8e913 // animation-direction - Animation_Duration Hash = 0x35d12 // animation-duration - Animation_Fill_Mode Hash = 0x66c13 // animation-fill-mode - Animation_Iteration_Count Hash = 0xd3c19 // animation-iteration-count - Animation_Name Hash = 0xca0e // animation-name - Animation_Play_State Hash = 0xfc14 // animation-play-state - Animation_Timing_Function Hash = 0x14119 // animation-timing-function - Antiquewhite Hash = 0x6490c // antiquewhite - Aquamarine Hash = 0x9ec0a // aquamarine - Attr Hash = 0x59804 // attr - Auto Hash = 0x44504 // auto - Azimuth Hash = 0x15a07 // azimuth - Background Hash = 0x2b0a // background - Background_Attachment Hash = 0x2b15 // background-attachment - Background_Clip Hash = 0xb6e0f // background-clip - Background_Color Hash = 0x21710 // background-color - Background_Image Hash = 0x5ad10 // background-image - Background_Origin Hash = 0x17111 // background-origin - Background_Position Hash = 0x18e13 // background-position - Background_Position_X Hash = 0x18e15 // background-position-x - Background_Position_Y Hash = 0x1a315 // background-position-y - Background_Repeat Hash = 0x1b811 // background-repeat - Background_Size Hash = 0x1cb0f // background-size - Behavior Hash = 0x1da08 // behavior - Black Hash = 0x1e205 // black - Blanchedalmond Hash = 0x1e70e // blanchedalmond - Blueviolet Hash = 0x7a70a // blueviolet - Bold Hash = 0x1fc04 // bold - Border Hash = 0x22706 // border - Border_Bottom Hash = 0x2270d // border-bottom - Border_Bottom_Color Hash = 0x22713 // border-bottom-color - Border_Bottom_Style Hash = 0x23a13 // border-bottom-style - Border_Bottom_Width Hash = 0x25d13 // border-bottom-width - Border_Box Hash = 0x27e0a // border-box - Border_Collapse Hash = 0x2b60f // border-collapse - Border_Color Hash = 0x2d30c // border-color - Border_Left Hash = 0x2df0b // border-left - Border_Left_Color Hash = 0x2df11 // border-left-color - Border_Left_Style Hash = 0x2f011 // border-left-style - Border_Left_Width Hash = 0x30111 // border-left-width - Border_Right Hash = 0x3120c // border-right - Border_Right_Color Hash = 0x31212 // border-right-color - Border_Right_Style Hash = 0x32412 // border-right-style - Border_Right_Width Hash = 0x33612 // border-right-width - Border_Spacing Hash = 0x3480e // border-spacing - Border_Style Hash = 0x3ab0c // border-style - Border_Top Hash = 0x3b70a // border-top - Border_Top_Color Hash = 0x3b710 // border-top-color - Border_Top_Style Hash = 0x3c710 // border-top-style - Border_Top_Width Hash = 0x3d710 // border-top-width - Border_Width Hash = 0x3e70c // border-width - Bottom Hash = 0x22e06 // bottom - Box_Shadow Hash = 0x2850a // box-shadow - Burlywood Hash = 0x3f309 // burlywood - Cadetblue Hash = 0x9c609 // cadetblue - Calc Hash = 0x9c304 // calc - Caption_Side Hash = 0x40f0c // caption-side - Caret_Color Hash = 0x4240b // caret-color - Center Hash = 0xdb06 // center - Charset Hash = 0x62f07 // charset - Chartreuse Hash = 0x42f0a // chartreuse - Chocolate Hash = 0x43909 // chocolate - Clamp Hash = 0x44e05 // clamp - Clear Hash = 0x45d05 // clear - Clip Hash = 0xb7904 // clip - Cm Hash = 0x53802 // cm - Color Hash = 0x2505 // color - Column_Count Hash = 0x4620c // column-count - Column_Gap Hash = 0x6a30a // column-gap - Column_Rule Hash = 0x4880b // column-rule - Column_Rule_Color Hash = 0x48811 // column-rule-color - Column_Rule_Style Hash = 0x49911 // column-rule-style - Column_Rule_Width Hash = 0x4aa11 // column-rule-width - Column_Width Hash = 0x4bb0c // column-width - Columns Hash = 0x74607 // columns - Content Hash = 0x5607 // content - Cornflowerblue Hash = 0x4c70e // cornflowerblue - Cornsilk Hash = 0x4d508 // cornsilk - Counter_Increment Hash = 0xd5011 // counter-increment - Counter_Reset Hash = 0x4690d // counter-reset - Cue Hash = 0x4dd03 // cue - Cue_After Hash = 0x4dd09 // cue-after - Cue_Before Hash = 0x4e60a // cue-before - Currentcolor Hash = 0x5010c // currentcolor - Cursive Hash = 0x50d07 // cursive - Cursor Hash = 0x51406 // cursor - Darkblue Hash = 0x1f408 // darkblue - Darkcyan Hash = 0x1ff08 // darkcyan - Darkgoldenrod Hash = 0x3fb0d // darkgoldenrod - Darkgray Hash = 0x40708 // darkgray - Darkgreen Hash = 0x75c09 // darkgreen - Darkkhaki Hash = 0xa1409 // darkkhaki - Darkmagenta Hash = 0xce90b // darkmagenta - Darkolivegreen Hash = 0x6d90e // darkolivegreen - Darkorange Hash = 0x7500a // darkorange - Darkorchid Hash = 0xa0b0a // darkorchid - Darksalmon Hash = 0xa990a // darksalmon - Darkseagreen Hash = 0xb110c // darkseagreen - Darkslateblue Hash = 0xc1c0d // darkslateblue - Darkslategray Hash = 0xbfa0d // darkslategray - Darkturquoise Hash = 0xcaa0d // darkturquoise - Darkviolet Hash = 0x51a0a // darkviolet - Deeppink Hash = 0x67d08 // deeppink - Deepskyblue Hash = 0x4190b // deepskyblue - Default Hash = 0xa2207 // default - Deg Hash = 0x70103 // deg - Direction Hash = 0x8d909 // direction - Display Hash = 0xcce07 // display - Document Hash = 0x52408 // document - Dodgerblue Hash = 0x52c0a // dodgerblue - Dpcm Hash = 0x53604 // dpcm - Dpi Hash = 0x54f03 // dpi - Dppx Hash = 0x55b04 // dppx - Elevation Hash = 0x6d09 // elevation - Empty_Cells Hash = 0x3910b // empty-cells - Env Hash = 0x4f503 // env - Fantasy Hash = 0x3a407 // fantasy - Fill Hash = 0x67604 // fill - Filter Hash = 0x406 // filter - Firebrick Hash = 0x83509 // firebrick - Flex Hash = 0x55f04 // flex - Flex_Basis Hash = 0x89d0a // flex-basis - Flex_Direction Hash = 0x8d40e // flex-direction - Flex_Flow Hash = 0xc8709 // flex-flow - Flex_Grow Hash = 0x55f09 // flex-grow - Flex_Shrink Hash = 0x5680b // flex-shrink - Flex_Wrap Hash = 0x57309 // flex-wrap - Float Hash = 0x59505 // float - Floralwhite Hash = 0x5bd0b // floralwhite - Font Hash = 0x25404 // font - Font_Face Hash = 0x25409 // font-face - Font_Family Hash = 0x5ee0b // font-family - Font_Size Hash = 0x5f909 // font-size - Font_Size_Adjust Hash = 0x5f910 // font-size-adjust - Font_Stretch Hash = 0x6250c // font-stretch - Font_Style Hash = 0x6360a // font-style - Font_Variant Hash = 0x6400c // font-variant - Font_Weight Hash = 0x65b0b // font-weight - Forestgreen Hash = 0x4ec0b // forestgreen - Fuchsia Hash = 0x66607 // fuchsia - Gainsboro Hash = 0xec09 // gainsboro - Ghostwhite Hash = 0x2990a // ghostwhite - Goldenrod Hash = 0x3ff09 // goldenrod - Grad Hash = 0x1004 // grad - Greenyellow Hash = 0x7600b // greenyellow - Grid Hash = 0x35504 // grid - Grid_Area Hash = 0x35509 // grid-area - Grid_Auto_Columns Hash = 0x7bb11 // grid-auto-columns - Grid_Auto_Flow Hash = 0x81c0e // grid-auto-flow - Grid_Auto_Rows Hash = 0x8640e // grid-auto-rows - Grid_Column Hash = 0x69e0b // grid-column - Grid_Column_End Hash = 0xcdb0f // grid-column-end - Grid_Column_Gap Hash = 0x69e0f // grid-column-gap - Grid_Column_Start Hash = 0x6bd11 // grid-column-start - Grid_Row Hash = 0x6ce08 // grid-row - Grid_Row_End Hash = 0x6ce0c // grid-row-end - Grid_Row_Gap Hash = 0x6e70c // grid-row-gap - Grid_Row_Start Hash = 0x7030e // grid-row-start - Grid_Template Hash = 0x7110d // grid-template - Grid_Template_Areas Hash = 0x71113 // grid-template-areas - Grid_Template_Columns Hash = 0x73815 // grid-template-columns - Grid_Template_Rows Hash = 0x77012 // grid-template-rows - Height Hash = 0x9306 // height - Honeydew Hash = 0x16008 // honeydew - Hsl Hash = 0x26f03 // hsl - Hsla Hash = 0x26f04 // hsla - Hz Hash = 0x68502 // hz - Ime_Mode Hash = 0xa1c08 // ime-mode - Import Hash = 0x78d06 // import - Important Hash = 0x78d09 // important - In Hash = 0x4402 // in - Include_Source Hash = 0x1800e // include-source - Indianred Hash = 0xb0909 // indianred - Inherit Hash = 0x79607 // inherit - Initial Hash = 0x79d07 // initial - Invert Hash = 0x7e406 // invert - Justify_Content Hash = 0x4e0f // justify-content - Justify_Items Hash = 0x6050d // justify-items - Justify_Self Hash = 0x82a0c // justify-self - Keyframes Hash = 0x5cb09 // keyframes - Khz Hash = 0x68403 // khz - Large Hash = 0xa905 // large - Larger Hash = 0xa906 // larger - Lavender Hash = 0x27108 // lavender - Lavenderblush Hash = 0x2710d // lavenderblush - Lawngreen Hash = 0x2ca09 // lawngreen - Layer_Background_Color Hash = 0x21116 // layer-background-color - Layer_Background_Image Hash = 0x5a716 // layer-background-image - Layout_Flow Hash = 0xcf80b // layout-flow - Layout_Grid Hash = 0x8050b // layout-grid - Layout_Grid_Char Hash = 0x80510 // layout-grid-char - Layout_Grid_Char_Spacing Hash = 0x80518 // layout-grid-char-spacing - Layout_Grid_Line Hash = 0x83e10 // layout-grid-line - Layout_Grid_Mode Hash = 0x85410 // layout-grid-mode - Layout_Grid_Type Hash = 0x88710 // layout-grid-type - Left Hash = 0x2e604 // left - Lemonchiffon Hash = 0x24b0c // lemonchiffon - Letter_Spacing Hash = 0x7ae0e // letter-spacing - Lightblue Hash = 0x8ba09 // lightblue - Lightcoral Hash = 0x8c30a // lightcoral - Lightcyan Hash = 0x8e209 // lightcyan - Lightgoldenrodyellow Hash = 0x8fc14 // lightgoldenrodyellow - Lightgray Hash = 0x91009 // lightgray - Lightgreen Hash = 0x9190a // lightgreen - Lightpink Hash = 0x92309 // lightpink - Lightsalmon Hash = 0x92c0b // lightsalmon - Lightseagreen Hash = 0x9370d // lightseagreen - Lightskyblue Hash = 0x9440c // lightskyblue - Lightslateblue Hash = 0x9500e // lightslateblue - Lightsteelblue Hash = 0x95e0e // lightsteelblue - Lightyellow Hash = 0x96c0b // lightyellow - Limegreen Hash = 0x97709 // limegreen - Line_Break Hash = 0x84a0a // line-break - Line_Height Hash = 0x8e0b // line-height - Linear_Gradient Hash = 0x9800f // linear-gradient - List_Style Hash = 0x98f0a // list-style - List_Style_Image Hash = 0x98f10 // list-style-image - List_Style_Position Hash = 0x99f13 // list-style-position - List_Style_Type Hash = 0x9b20f // list-style-type - Local Hash = 0x9c105 // local - Magenta Hash = 0xced07 // magenta - Margin Hash = 0x53906 // margin - Margin_Bottom Hash = 0xda40d // margin-bottom - Margin_Left Hash = 0xdb00b // margin-left - Margin_Right Hash = 0xb890c // margin-right - Margin_Top Hash = 0x5390a // margin-top - Marker_Offset Hash = 0xad00d // marker-offset - Marks Hash = 0xaee05 // marks - Mask Hash = 0x9cf04 // mask - Max Hash = 0x9d303 // max - Max_Height Hash = 0x9d30a // max-height - Max_Width Hash = 0x9dd09 // max-width - Media Hash = 0xd3805 // media - Medium Hash = 0x9e606 // medium - Mediumaquamarine Hash = 0x9e610 // mediumaquamarine - Mediumblue Hash = 0x9f60a // mediumblue - Mediumorchid Hash = 0xa000c // mediumorchid - Mediumpurple Hash = 0xa420c // mediumpurple - Mediumseagreen Hash = 0xa4e0e // mediumseagreen - Mediumslateblue Hash = 0xa5c0f // mediumslateblue - Mediumspringgreen Hash = 0xa6b11 // mediumspringgreen - Mediumturquoise Hash = 0xa7c0f // mediumturquoise - Mediumvioletred Hash = 0xa8b0f // mediumvioletred - Midnightblue Hash = 0xaa90c // midnightblue - Min Hash = 0x14d03 // min - Min_Height Hash = 0xab50a // min-height - Min_Width Hash = 0xabf09 // min-width - Mintcream Hash = 0xac809 // mintcream - Mistyrose Hash = 0xae409 // mistyrose - Mm Hash = 0xaed02 // mm - Moccasin Hash = 0xb0308 // moccasin - Monospace Hash = 0xaa009 // monospace - Ms Hash = 0x102 // ms - Namespace Hash = 0xd409 // namespace - Navajowhite Hash = 0x750b // navajowhite - No_Repeat Hash = 0xbf09 // no-repeat - None Hash = 0x38e04 // none - Normal Hash = 0x36e06 // normal - Offset Hash = 0xad706 // offset - Offset_Anchor Hash = 0xad70d // offset-anchor - Offset_Distance Hash = 0xb1d0f // offset-distance - Offset_Path Hash = 0xb2c0b // offset-path - Offset_Position Hash = 0xb370f // offset-position - Offset_Rotate Hash = 0xb460d // offset-rotate - Olivedrab Hash = 0xb6609 // olivedrab - Orangered Hash = 0x75409 // orangered - Order Hash = 0x22805 // order - Orphans Hash = 0x37f07 // orphans - Outline Hash = 0xba707 // outline - Outline_Color Hash = 0xba70d // outline-color - Outline_Style Hash = 0xbb40d // outline-style - Outline_Width Hash = 0xbc10d // outline-width - Overflow Hash = 0x9d08 // overflow - Overflow_X Hash = 0x9d0a // overflow-x - Overflow_Y Hash = 0xbce0a // overflow-y - Padding Hash = 0x45207 // padding - Padding_Bottom Hash = 0xb7c0e // padding-bottom - Padding_Box Hash = 0x4520b // padding-box - Padding_Left Hash = 0xd0a0c // padding-left - Padding_Right Hash = 0x5420d // padding-right - Padding_Top Hash = 0x57b0b // padding-top - Page Hash = 0x58504 // page - Page_Break_After Hash = 0x58510 // page-break-after - Page_Break_Before Hash = 0x6ac11 // page-break-before - Page_Break_Inside Hash = 0x6f211 // page-break-inside - Palegoldenrod Hash = 0xc100d // palegoldenrod - Palegreen Hash = 0xbd809 // palegreen - Paleturquoise Hash = 0xbe10d // paleturquoise - Palevioletred Hash = 0xbee0d // palevioletred - Papayawhip Hash = 0xc070a // papayawhip - Pause Hash = 0xc2905 // pause - Pause_After Hash = 0xc290b // pause-after - Pause_Before Hash = 0xc340c // pause-before - Pc Hash = 0x53702 // pc - Peachpuff Hash = 0x89509 // peachpuff - Pitch Hash = 0x55005 // pitch - Pitch_Range Hash = 0x5500b // pitch-range - Place_Content Hash = 0xc400d // place-content - Place_Items Hash = 0xc4d0b // place-items - Place_Self Hash = 0xc7e0a // place-self - Play_During Hash = 0xcd10b // play-during - Position Hash = 0x13908 // position - Powderblue Hash = 0xc9b0a // powderblue - Progid Hash = 0xca506 // progid - Pt Hash = 0x39302 // pt - Px Hash = 0x55d02 // px - Q Hash = 0x64d01 // q - Quotes Hash = 0xcb706 // quotes - Rad Hash = 0x903 // rad - Radial_Gradient Hash = 0x90f // radial-gradient - Repeat Hash = 0xc206 // repeat - Repeat_X Hash = 0x1c308 // repeat-x - Repeat_Y Hash = 0xc208 // repeat-y - Rgb Hash = 0x2903 // rgb - Rgba Hash = 0x2904 // rgba - Richness Hash = 0xae08 // richness - Right Hash = 0x31905 // right - Rosybrown Hash = 0xf309 // rosybrown - Round Hash = 0x3005 // round - Row_Gap Hash = 0x6ec07 // row-gap - Royalblue Hash = 0x69509 // royalblue - Ruby_Align Hash = 0xd860a // ruby-align - Ruby_Overhang Hash = 0xe00d // ruby-overhang - Ruby_Position Hash = 0x1340d // ruby-position - S Hash = 0x201 // s - Saddlebrown Hash = 0xb50b // saddlebrown - Sandybrown Hash = 0x3850a // sandybrown - Sans_Serif Hash = 0x39b0a // sans-serif - Scroll Hash = 0x12006 // scroll - Scrollbar_3d_Light_Color Hash = 0xd6f18 // scrollbar-3d-light-color - Scrollbar_Arrow_Color Hash = 0x12015 // scrollbar-arrow-color - Scrollbar_Base_Color Hash = 0x8a614 // scrollbar-base-color - Scrollbar_Dark_Shadow_Color Hash = 0x5d31b // scrollbar-dark-shadow-color - Scrollbar_Face_Color Hash = 0x61114 // scrollbar-face-color - Scrollbar_Highlight_Color Hash = 0x7cb19 // scrollbar-highlight-color - Scrollbar_Shadow_Color Hash = 0x87116 // scrollbar-shadow-color - Scrollbar_Track_Color Hash = 0x72315 // scrollbar-track-color - Seagreen Hash = 0x93c08 // seagreen - Seashell Hash = 0x2c308 // seashell - Serif Hash = 0x3a005 // serif - Size Hash = 0x1d604 // size - Slateblue Hash = 0x95509 // slateblue - Slategray Hash = 0xbfe09 // slategray - Small Hash = 0x68f05 // small - Smaller Hash = 0x68f07 // smaller - Solid Hash = 0x74c05 // solid - Space Hash = 0x6905 // space - Speak Hash = 0x78105 // speak - Speak_Header Hash = 0x7810c // speak-header - Speak_Numeral Hash = 0x7f90d // speak-numeral - Speak_Punctuation Hash = 0xaf211 // speak-punctuation - Speech_Rate Hash = 0xc570b // speech-rate - Springgreen Hash = 0xa710b // springgreen - Steelblue Hash = 0x96309 // steelblue - Stress Hash = 0x11b06 // stress - Stroke Hash = 0xc7806 // stroke - Supports Hash = 0xcbc08 // supports - Table_Layout Hash = 0xcf20c // table-layout - Text_Align Hash = 0x10e0a // text-align - Text_Align_Last Hash = 0x10e0f // text-align-last - Text_Autospace Hash = 0x4400e // text-autospace - Text_Decoration Hash = 0x7e0f // text-decoration - Text_Decoration_Color Hash = 0x2a115 // text-decoration-color - Text_Decoration_Line Hash = 0x7e14 // text-decoration-line - Text_Decoration_Style Hash = 0xb5115 // text-decoration-style - Text_Decoration_Thickness Hash = 0xc6019 // text-decoration-thickness - Text_Emphasis Hash = 0x170d // text-emphasis - Text_Emphasis_Color Hash = 0x1713 // text-emphasis-color - Text_Indent Hash = 0x3f0b // text-indent - Text_Justify Hash = 0x490c // text-justify - Text_Kashida_Space Hash = 0x5c12 // text-kashida-space - Text_Overflow Hash = 0x980d // text-overflow - Text_Shadow Hash = 0xd600b // text-shadow - Text_Transform Hash = 0xd970e // text-transform - Text_Underline_Position Hash = 0xdba17 // text-underline-position - Top Hash = 0x3be03 // top - Transition Hash = 0x4750a // transition - Transition_Delay Hash = 0x59a10 // transition-delay - Transition_Duration Hash = 0xb9413 // transition-duration - Transition_Property Hash = 0x47513 // transition-property - Transition_Timing_Function Hash = 0xa281a // transition-timing-function - Transparent Hash = 0xd150b // transparent - Turn Hash = 0xd1f04 // turn - Turquoise Hash = 0xa8209 // turquoise - Unicode_Bidi Hash = 0xcc40c // unicode-bidi - Unset Hash = 0xd2305 // unset - Url Hash = 0x3f403 // url - Var Hash = 0x64503 // var - Vertical_Align Hash = 0x7e60e // vertical-align - Visibility Hash = 0x4f70a // visibility - Voice_Family Hash = 0xd280c // voice-family - Volume Hash = 0xd3406 // volume - White Hash = 0x7b05 // white - White_Space Hash = 0x6500b // white-space - Whitesmoke Hash = 0x5c30a // whitesmoke - Widows Hash = 0xd6a06 // widows - Width Hash = 0x26b05 // width - Word_Break Hash = 0x1670a // word-break - Word_Spacing Hash = 0x28e0c // word-spacing - Word_Wrap Hash = 0xd0209 // word-wrap - Writing_Mode Hash = 0xc8f0c // writing-mode - X_Large Hash = 0xa707 // x-large - X_Small Hash = 0x68d07 // x-small - Xx_Large Hash = 0xa608 // xx-large - Xx_Small Hash = 0x68c08 // xx-small - Yellow Hash = 0x76506 // yellow - Yellowgreen Hash = 0x7650b // yellowgreen - Z_Index Hash = 0x68607 // z-index -) - -// String returns the hash' name. -func (i Hash) String() string { - start := uint32(i >> 8) - n := uint32(i & 0xff) - if start+n > uint32(len(_Hash_text)) { - return "" - } - return _Hash_text[start : start+n] -} - -// ToHash returns the hash whose name is s. It returns zero if there is no -// such hash. It is case sensitive. -func ToHash(s []byte) Hash { - if len(s) == 0 || len(s) > _Hash_maxLen { - return 0 - } - h := uint32(_Hash_hash0) - for i := 0; i < len(s); i++ { - h ^= uint32(s[i]) - h *= 16777619 - } - if i := _Hash_table[h&uint32(len(_Hash_table)-1)]; int(i&0xff) == len(s) { - t := _Hash_text[i>>8 : i>>8+i&0xff] - for i := 0; i < len(s); i++ { - if t[i] != s[i] { - goto NEXT - } - } - return i - } -NEXT: - if i := _Hash_table[(h>>16)&uint32(len(_Hash_table)-1)]; int(i&0xff) == len(s) { - t := _Hash_text[i>>8 : i>>8+i&0xff] - for i := 0; i < len(s); i++ { - if t[i] != s[i] { - return 0 - } - } - return i - } - return 0 -} - -const _Hash_hash0 = 0x9acb0442 -const _Hash_maxLen = 27 -const _Hash_text = "-ms-filteradial-gradientext-emphasis-colorgbackground-attach" + - "mentext-indentext-justify-contentext-kashida-spacelevationav" + - "ajowhitext-decoration-line-heightext-overflow-xx-largerichne" + - "ssaddlebrowno-repeat-yanimation-namespacenteruby-overhangain" + - "sborosybrownanimation-play-statext-align-lastresscrollbar-ar" + - "row-coloruby-positionanimation-timing-functionazimuthoneydew" + - "ord-breakbackground-originclude-sourcebackground-position-xb" + - "ackground-position-ybackground-repeat-xbackground-sizebehavi" + - "orblackblanchedalmondarkblueboldarkcyanimation-delayer-backg" + - "round-colorborder-bottom-colorborder-bottom-stylemonchiffont" + - "-faceborder-bottom-widthslavenderblushborder-box-shadoword-s" + - "pacinghostwhitext-decoration-colorborder-collapseashellawngr" + - "eenborder-colorborder-left-colorborder-left-styleborder-left" + - "-widthborder-right-colorborder-right-styleborder-right-width" + - "border-spacingrid-areanimation-durationormalphacceleratorpha" + - "nsandybrownonempty-cellsans-serifantasyborder-styleborder-to" + - "p-colorborder-top-styleborder-top-widthborder-widthburlywood" + - "arkgoldenrodarkgraycaption-sideepskybluecaret-colorchartreus" + - "echocolatext-autospaceclampadding-boxclearcolumn-counter-res" + - "etransition-propertycolumn-rule-colorcolumn-rule-stylecolumn" + - "-rule-widthcolumn-widthcornflowerbluecornsilkcue-aftercue-be" + - "forestgreenvisibilitycurrentcolorcursivecursordarkvioletdocu" + - "mentdodgerbluedpcmargin-topadding-rightdpitch-rangedppxflex-" + - "growflex-shrinkflex-wrapadding-topage-break-afterfloattransi" + - "tion-delayer-background-imagefloralwhitesmokeyframescrollbar" + - "-dark-shadow-colorfont-familyfont-size-adjustify-itemscrollb" + - "ar-face-colorfont-stretcharsetfont-stylefont-variantiquewhit" + - "e-spacefont-weightfuchsianimation-fill-modeeppinkhz-indexx-s" + - "malleroyalbluegrid-column-gapage-break-beforegrid-column-sta" + - "rtgrid-row-endarkolivegreengrid-row-gapage-break-insidegrid-" + - "row-startgrid-template-areascrollbar-track-colorgrid-templat" + - "e-columnsolidarkorangeredarkgreenyellowgreengrid-template-ro" + - "wspeak-headerimportantinheritinitialicebluevioletter-spacing" + - "rid-auto-columnscrollbar-highlight-colorinvertical-align-ite" + - "mspeak-numeralayout-grid-char-spacingrid-auto-flowjustify-se" + - "lfirebricklayout-grid-line-breaklayout-grid-modegrid-auto-ro" + - "wscrollbar-shadow-colorlayout-grid-typeachpufflex-basiscroll" + - "bar-base-colorlightbluelightcoralign-selflex-directionlightc" + - "yanimation-directionlightgoldenrodyellowlightgraylightgreenl" + - "ightpinklightsalmonlightseagreenlightskybluelightslateblueli" + - "ghtsteelbluelightyellowlimegreenlinear-gradientlist-style-im" + - "agelist-style-positionlist-style-typelocalcadetbluemaskmax-h" + - "eightmax-widthmediumaquamarinemediumbluemediumorchidarkorchi" + - "darkkhakime-modefaultransition-timing-functionmediumpurpleme" + - "diumseagreenmediumslatebluemediumspringgreenmediumturquoisem" + - "ediumvioletredarksalmonospacemidnightbluemin-heightmin-width" + - "mintcreamarker-offset-anchormistyrosemmarkspeak-punctuationm" + - "occasindianredarkseagreenoffset-distanceoffset-pathoffset-po" + - "sitionoffset-rotatext-decoration-styleolivedrabackground-cli" + - "padding-bottomargin-rightransition-durationoutline-coloroutl" + - "ine-styleoutline-widthoverflow-ypalegreenpaleturquoisepalevi" + - "oletredarkslategraypapayawhipalegoldenrodarkslatebluepause-a" + - "fterpause-beforeplace-contentplace-itemspeech-ratext-decorat" + - "ion-thicknesstrokeplace-selflex-flowriting-modepowderbluepro" + - "gidarkturquoisequotesupportsunicode-bidisplay-duringrid-colu" + - "mn-endarkmagentable-layout-floword-wrapadding-leftransparent" + - "urnunsetvoice-familyvolumedianimation-iteration-counter-incr" + - "ementext-shadowidowscrollbar-3d-light-coloruby-align-content" + - "ext-transformargin-bottomargin-leftext-underline-position" - -var _Hash_table = [1 << 10]Hash{ - 0x3: 0xc290b, // pause-after - 0x6: 0xd5011, // counter-increment - 0x8: 0xcce07, // display - 0x9: 0x51a0a, // darkviolet - 0xb: 0xbf09, // no-repeat - 0xd: 0x4402, // in - 0x14: 0x6f211, // page-break-inside - 0x15: 0x6250c, // font-stretch - 0x19: 0x5f910, // font-size-adjust - 0x1a: 0x47513, // transition-property - 0x1c: 0x78105, // speak - 0x1f: 0x82a0c, // justify-self - 0x20: 0x61114, // scrollbar-face-color - 0x24: 0x2b60f, // border-collapse - 0x25: 0x68607, // z-index - 0x27: 0xd8b0d, // align-content - 0x2a: 0x99f13, // list-style-position - 0x2b: 0xcdb0f, // grid-column-end - 0x2c: 0x14119, // animation-timing-function - 0x30: 0xb0909, // indianred - 0x34: 0x97709, // limegreen - 0x35: 0xbc10d, // outline-width - 0x3f: 0x15a07, // azimuth - 0x40: 0x1e70e, // blanchedalmond - 0x41: 0x84a0a, // line-break - 0x42: 0x7a209, // aliceblue - 0x43: 0xf309, // rosybrown - 0x46: 0xa7c0f, // mediumturquoise - 0x49: 0xd6a06, // widows - 0x4b: 0xb370f, // offset-position - 0x4d: 0xd150b, // transparent - 0x4e: 0x79d07, // initial - 0x52: 0x1cb0f, // background-size - 0x55: 0x2505, // color - 0x56: 0x59a10, // transition-delay - 0x5a: 0x750b, // navajowhite - 0x5b: 0x7110d, // grid-template - 0x5c: 0x3b710, // border-top-color - 0x62: 0xbce0a, // overflow-y - 0x64: 0x9370d, // lightseagreen - 0x6c: 0x10e0f, // text-align-last - 0x6f: 0x8050b, // layout-grid - 0x70: 0xca09, // animation - 0x71: 0x1da08, // behavior - 0x72: 0x5390a, // margin-top - 0x74: 0x3ab0c, // border-style - 0x78: 0x5d31b, // scrollbar-dark-shadow-color - 0x79: 0x69103, // all - 0x7a: 0x3f0b, // text-indent - 0x7b: 0xbe10d, // paleturquoise - 0x7e: 0x58510, // page-break-after - 0x80: 0x5420d, // padding-right - 0x84: 0x7e60e, // vertical-align - 0x85: 0x50d07, // cursive - 0x8a: 0x7030e, // grid-row-start - 0x8c: 0xae08, // richness - 0x8e: 0x3b70a, // border-top - 0x94: 0x35509, // grid-area - 0x95: 0x85410, // layout-grid-mode - 0x96: 0xaee05, // marks - 0x97: 0x64d01, // q - 0x98: 0x78d09, // important - 0x9c: 0x406, // filter - 0x9d: 0xa8b0f, // mediumvioletred - 0xa5: 0xc570b, // speech-rate - 0xa8: 0x53702, // pc - 0xab: 0x90f, // radial-gradient - 0xae: 0x11b06, // stress - 0xb4: 0x6050d, // justify-items - 0xb7: 0x9500e, // lightslateblue - 0xba: 0x35504, // grid - 0xbb: 0xb0308, // moccasin - 0xbe: 0xd0209, // word-wrap - 0xc0: 0x6d90e, // darkolivegreen - 0xc5: 0xc6019, // text-decoration-thickness - 0xc7: 0xdb06, // center - 0xc8: 0x2a115, // text-decoration-color - 0xcb: 0xabf09, // min-width - 0xce: 0x5ee0b, // font-family - 0xd1: 0xa1c08, // ime-mode - 0xd3: 0x3d710, // border-top-width - 0xd4: 0x53906, // margin - 0xd9: 0x4880b, // column-rule - 0xda: 0x98f0a, // list-style - 0xdf: 0x6ce0c, // grid-row-end - 0xe4: 0x2050f, // animation-delay - 0xe8: 0x4aa11, // column-rule-width - 0xec: 0x57309, // flex-wrap - 0xed: 0xced07, // magenta - 0xee: 0x88710, // layout-grid-type - 0xef: 0x4520b, // padding-box - 0xf0: 0x7e14, // text-decoration-line - 0xf2: 0x4dd09, // cue-after - 0xf4: 0x8640e, // grid-auto-rows - 0xf5: 0x7650b, // yellowgreen - 0xf8: 0x89509, // peachpuff - 0xf9: 0x74607, // columns - 0xfa: 0x22805, // order - 0xfb: 0x3120c, // border-right - 0x100: 0x1800e, // include-source - 0x104: 0xc2905, // pause - 0x105: 0x1fc04, // bold - 0x106: 0xcc40c, // unicode-bidi - 0x108: 0x67604, // fill - 0x109: 0x75c09, // darkgreen - 0x10b: 0x45d05, // clear - 0x10c: 0x67d08, // deeppink - 0x110: 0x8e913, // animation-direction - 0x112: 0x1b811, // background-repeat - 0x117: 0xca506, // progid - 0x11d: 0x8a614, // scrollbar-base-color - 0x11e: 0xa, // -ms-filter - 0x11f: 0x2ca09, // lawngreen - 0x120: 0x51406, // cursor - 0x121: 0x44e05, // clamp - 0x123: 0x48811, // column-rule-color - 0x128: 0x40f0c, // caption-side - 0x12a: 0xc9b0a, // powderblue - 0x12b: 0xdba17, // text-underline-position - 0x12d: 0x72315, // scrollbar-track-color - 0x131: 0x81c0e, // grid-auto-flow - 0x132: 0x7810c, // speak-header - 0x133: 0x25409, // font-face - 0x136: 0xa710b, // springgreen - 0x13a: 0xc7e0a, // place-self - 0x13d: 0xc206, // repeat - 0x13e: 0x9800f, // linear-gradient - 0x142: 0x5010c, // currentcolor - 0x145: 0xad706, // offset - 0x14a: 0x69e0f, // grid-column-gap - 0x14c: 0x6905, // space - 0x14e: 0x39b0a, // sans-serif - 0x14f: 0x6360a, // font-style - 0x153: 0x66607, // fuchsia - 0x154: 0xb7904, // clip - 0x155: 0xae409, // mistyrose - 0x158: 0x9d08, // overflow - 0x15d: 0xc7806, // stroke - 0x162: 0x80510, // layout-grid-char - 0x163: 0xa420c, // mediumpurple - 0x165: 0x4f503, // env - 0x168: 0x4690d, // counter-reset - 0x16b: 0x5cb09, // keyframes - 0x16f: 0x7b05, // white - 0x172: 0x1004, // grad - 0x174: 0xda40d, // margin-bottom - 0x175: 0x31212, // border-right-color - 0x177: 0x25404, // font - 0x178: 0xc100d, // palegoldenrod - 0x179: 0x73815, // grid-template-columns - 0x17a: 0x7e0f, // text-decoration - 0x17e: 0x89d0a, // flex-basis - 0x186: 0x7ef0b, // align-items - 0x189: 0x4bb0c, // column-width - 0x18a: 0x3c710, // border-top-style - 0x18b: 0x1d604, // size - 0x18c: 0xd3805, // media - 0x191: 0xb7c0e, // padding-bottom - 0x194: 0x2df11, // border-left-color - 0x195: 0x7a70a, // blueviolet - 0x198: 0x92c0b, // lightsalmon - 0x19d: 0x27108, // lavender - 0x19e: 0x5a716, // layer-background-image - 0x1a0: 0x6500b, // white-space - 0x1a3: 0xe00d, // ruby-overhang - 0x1a4: 0x24b0c, // lemonchiffon - 0x1a5: 0x3be03, // top - 0x1a9: 0x2c308, // seashell - 0x1aa: 0x7ae0e, // letter-spacing - 0x1ac: 0x2b0a, // background - 0x1af: 0x64503, // var - 0x1b0: 0xaed02, // mm - 0x1b6: 0x12015, // scrollbar-arrow-color - 0x1b8: 0xd970e, // text-transform - 0x1b9: 0x65b0b, // font-weight - 0x1ba: 0x53802, // cm - 0x1bb: 0x12006, // scroll - 0x1c0: 0x21710, // background-color - 0x1c1: 0x2710d, // lavenderblush - 0x1c6: 0xb5115, // text-decoration-style - 0x1c9: 0x79607, // inherit - 0x1cf: 0x2e604, // left - 0x1d0: 0x6490c, // antiquewhite - 0x1d4: 0xb6609, // olivedrab - 0x1da: 0x2990a, // ghostwhite - 0x1dd: 0x91009, // lightgray - 0x1e2: 0x26f04, // hsla - 0x1e3: 0x26f03, // hsl - 0x1e4: 0xbd809, // palegreen - 0x1e5: 0x4190b, // deepskyblue - 0x1e8: 0xac809, // mintcream - 0x1ea: 0x7e406, // invert - 0x1eb: 0x6400c, // font-variant - 0x1ec: 0x8fc14, // lightgoldenrodyellow - 0x1ee: 0x62f07, // charset - 0x1ef: 0xc8f0c, // writing-mode - 0x1f0: 0x5c30a, // whitesmoke - 0x1f5: 0x9d0a, // overflow-x - 0x1f6: 0xaa90c, // midnightblue - 0x1f7: 0xcb706, // quotes - 0x1f8: 0x22706, // border - 0x1fa: 0x42f0a, // chartreuse - 0x1fc: 0xba707, // outline - 0x1fd: 0xa281a, // transition-timing-function - 0x1fe: 0xcbc08, // supports - 0x204: 0x1670a, // word-break - 0x205: 0xaa009, // monospace - 0x206: 0x2850a, // box-shadow - 0x209: 0x5680b, // flex-shrink - 0x20f: 0xd0a0c, // padding-left - 0x214: 0xc4d0b, // place-items - 0x216: 0xc070a, // papayawhip - 0x217: 0x17111, // background-origin - 0x218: 0x52408, // document - 0x219: 0x52c0a, // dodgerblue - 0x21c: 0x9440c, // lightskyblue - 0x21e: 0x6bd11, // grid-column-start - 0x221: 0x30111, // border-left-width - 0x224: 0x68c08, // xx-small - 0x226: 0x1f408, // darkblue - 0x229: 0x25d13, // border-bottom-width - 0x22a: 0x98f10, // list-style-image - 0x22d: 0x44504, // auto - 0x230: 0x1e205, // black - 0x231: 0xaf211, // speak-punctuation - 0x232: 0x13908, // position - 0x234: 0xc340c, // pause-before - 0x236: 0x95e0e, // lightsteelblue - 0x23a: 0xcd10b, // play-during - 0x23f: 0x83509, // firebrick - 0x249: 0x6ce08, // grid-row - 0x24a: 0x55d02, // px - 0x24c: 0x1a315, // background-position-y - 0x251: 0xd1f04, // turn - 0x256: 0xba70d, // outline-color - 0x257: 0x9c304, // calc - 0x258: 0xd3c19, // animation-iteration-count - 0x259: 0xad70d, // offset-anchor - 0x25b: 0xa4e0e, // mediumseagreen - 0x25e: 0x4620c, // column-count - 0x263: 0x10e0a, // text-align - 0x266: 0x66c13, // animation-fill-mode - 0x267: 0x32412, // border-right-style - 0x268: 0xa707, // x-large - 0x269: 0x8d40e, // flex-direction - 0x26a: 0x4f70a, // visibility - 0x26f: 0xb2c0b, // offset-path - 0x270: 0x27e0a, // border-box - 0x276: 0x70103, // deg - 0x278: 0x1713, // text-emphasis-color - 0x27f: 0xc1c0d, // darkslateblue - 0x283: 0x55f09, // flex-grow - 0x285: 0x8e209, // lightcyan - 0x28a: 0x102, // ms - 0x28d: 0xa906, // larger - 0x28e: 0xa990a, // darksalmon - 0x292: 0x2f011, // border-left-style - 0x293: 0xa8209, // turquoise - 0x294: 0x3a407, // fantasy - 0x296: 0xec09, // gainsboro - 0x297: 0x201, // s - 0x298: 0x23a13, // border-bottom-style - 0x299: 0xce90b, // darkmagenta - 0x29b: 0xb50b, // saddlebrown - 0x2a0: 0x59505, // float - 0x2a3: 0x6ec07, // row-gap - 0x2a5: 0xd3406, // volume - 0x2a6: 0xab50a, // min-height - 0x2a7: 0x77012, // grid-template-rows - 0x2a9: 0x3760b, // accelerator - 0x2b0: 0x68f05, // small - 0x2b1: 0x59804, // attr - 0x2b2: 0x28e0c, // word-spacing - 0x2b3: 0x35d12, // animation-duration - 0x2b5: 0x4dd03, // cue - 0x2b6: 0x95509, // slateblue - 0x2b8: 0x38e04, // none - 0x2b9: 0x6a30a, // column-gap - 0x2ba: 0x4e0f, // justify-content - 0x2bb: 0x5607, // content - 0x2bd: 0x54f03, // dpi - 0x2be: 0x87116, // scrollbar-shadow-color - 0x2bf: 0x78d06, // import - 0x2c0: 0xc8709, // flex-flow - 0x2c1: 0x69509, // royalblue - 0x2c3: 0x9c609, // cadetblue - 0x2c4: 0x490c, // text-justify - 0x2cb: 0x8c30a, // lightcoral - 0x2cf: 0xb890c, // margin-right - 0x2d2: 0x76506, // yellow - 0x2d3: 0x26b05, // width - 0x2d6: 0x14d03, // min - 0x2da: 0x1340d, // ruby-position - 0x2dc: 0x40708, // darkgray - 0x2e2: 0x69e0b, // grid-column - 0x2e4: 0xa1409, // darkkhaki - 0x2e5: 0xc400d, // place-content - 0x2e7: 0xbee0d, // palevioletred - 0x2ea: 0x5bd0b, // floralwhite - 0x2eb: 0xc208, // repeat-y - 0x2ee: 0x980d, // text-overflow - 0x2f1: 0xca0e, // animation-name - 0x2fb: 0x7cb19, // scrollbar-highlight-color - 0x2fe: 0x5500b, // pitch-range - 0x302: 0x3005, // round - 0x305: 0x4c70e, // cornflowerblue - 0x307: 0x7f90d, // speak-numeral - 0x308: 0x9e606, // medium - 0x30a: 0x170d, // text-emphasis - 0x30d: 0x9dd09, // max-width - 0x311: 0x36e06, // normal - 0x312: 0x68403, // khz - 0x315: 0x2903, // rgb - 0x316: 0x8ba09, // lightblue - 0x317: 0x8d909, // direction - 0x31a: 0xd280c, // voice-family - 0x31c: 0x3480e, // border-spacing - 0x321: 0x6d09, // elevation - 0x323: 0x1c308, // repeat-x - 0x324: 0x83e10, // layout-grid-line - 0x326: 0xa000c, // mediumorchid - 0x32b: 0xa6b11, // mediumspringgreen - 0x32d: 0xa905, // large - 0x32e: 0xd860a, // ruby-align - 0x330: 0xbfa0d, // darkslategray - 0x332: 0x5c12, // text-kashida-space - 0x334: 0xbb40d, // outline-style - 0x336: 0x3a005, // serif - 0x337: 0x4240b, // caret-color - 0x33a: 0x37205, // alpha - 0x33c: 0x71113, // grid-template-areas - 0x33d: 0x49911, // column-rule-style - 0x33f: 0xcf80b, // layout-flow - 0x340: 0x31905, // right - 0x341: 0x3e70c, // border-width - 0x343: 0xb6e0f, // background-clip - 0x345: 0x74c05, // solid - 0x346: 0x2df0b, // border-left - 0x348: 0x9ec0a, // aquamarine - 0x349: 0x3850a, // sandybrown - 0x34a: 0x16008, // honeydew - 0x34b: 0x75409, // orangered - 0x34c: 0xb110c, // darkseagreen - 0x34d: 0x37f07, // orphans - 0x34e: 0x6e70c, // grid-row-gap - 0x351: 0x22e06, // bottom - 0x359: 0x9c105, // local - 0x35c: 0x8cb0a, // align-self - 0x35e: 0x33612, // border-right-width - 0x360: 0x2b15, // background-attachment - 0x364: 0x9190a, // lightgreen - 0x366: 0x39302, // pt - 0x368: 0x4400e, // text-autospace - 0x36b: 0x3f403, // url - 0x36c: 0x68502, // hz - 0x371: 0x9306, // height - 0x372: 0x5ad10, // background-image - 0x377: 0x903, // rad - 0x37c: 0x21116, // layer-background-color - 0x37d: 0x1ff08, // darkcyan - 0x382: 0x18e13, // background-position - 0x384: 0x9d303, // max - 0x38c: 0xa608, // xx-large - 0x38d: 0x3f309, // burlywood - 0x38f: 0xd6f18, // scrollbar-3d-light-color - 0x390: 0x3ff09, // goldenrod - 0x392: 0x92309, // lightpink - 0x393: 0x8e0b, // line-height - 0x396: 0x22713, // border-bottom-color - 0x398: 0x80518, // layout-grid-char-spacing - 0x39c: 0x2904, // rgba - 0x3a1: 0x9f60a, // mediumblue - 0x3a3: 0x9d30a, // max-height - 0x3a4: 0x7bb11, // grid-auto-columns - 0x3a5: 0xa0b0a, // darkorchid - 0x3a9: 0x7600b, // greenyellow - 0x3ae: 0x96c0b, // lightyellow - 0x3b1: 0x4750a, // transition - 0x3b3: 0x4e60a, // cue-before - 0x3b9: 0x96309, // steelblue - 0x3be: 0xa5c0f, // mediumslateblue - 0x3bf: 0xcaa0d, // darkturquoise - 0x3c0: 0x43909, // chocolate - 0x3c3: 0x5f909, // font-size - 0x3c5: 0x55f04, // flex - 0x3c7: 0xd2305, // unset - 0x3c8: 0xd600b, // text-shadow - 0x3ca: 0x4ec0b, // forestgreen - 0x3cc: 0xbfe09, // slategray - 0x3cd: 0x6ac11, // page-break-before - 0x3ce: 0x55b04, // dppx - 0x3d0: 0x2270d, // border-bottom - 0x3d3: 0xb1d0f, // offset-distance - 0x3d4: 0x3fb0d, // darkgoldenrod - 0x3d6: 0x53604, // dpcm - 0x3d8: 0x7500a, // darkorange - 0x3dc: 0xb9413, // transition-duration - 0x3de: 0x2d30c, // border-color - 0x3df: 0x18e15, // background-position-x - 0x3e0: 0x55005, // pitch - 0x3e2: 0xdb00b, // margin-left - 0x3e3: 0x58504, // page - 0x3e5: 0x57b0b, // padding-top - 0x3e7: 0xb460d, // offset-rotate - 0x3e8: 0x93c08, // seagreen - 0x3e9: 0x4d508, // cornsilk - 0x3ea: 0x68f07, // smaller - 0x3ec: 0xcf20c, // table-layout - 0x3ed: 0xfc14, // animation-play-state - 0x3ef: 0xa2207, // default - 0x3f0: 0x68d07, // x-small - 0x3f3: 0x9e610, // mediumaquamarine - 0x3f4: 0xad00d, // marker-offset - 0x3f9: 0xd409, // namespace - 0x3fa: 0x9cf04, // mask - 0x3fb: 0x45207, // padding - 0x3fd: 0x9b20f, // list-style-type - 0x3ff: 0x3910b, // empty-cells -} diff --git a/vendor/github.com/tdewolff/parse/v2/css/lex.go b/vendor/github.com/tdewolff/parse/v2/css/lex.go deleted file mode 100644 index 61c033fbab714..0000000000000 --- a/vendor/github.com/tdewolff/parse/v2/css/lex.go +++ /dev/null @@ -1,717 +0,0 @@ -// Package css is a CSS3 lexer and parser following the specifications at http://www.w3.org/TR/css-syntax-3/. -package css - -// TODO: \uFFFD replacement character for NULL bytes in strings for example, or atleast don't end the string early - -import ( - "bytes" - "io" - "strconv" - - "github.com/tdewolff/parse/v2" - "github.com/tdewolff/parse/v2/buffer" -) - -// TokenType determines the type of token, eg. a number or a semicolon. -type TokenType uint32 - -// TokenType values. -const ( - ErrorToken TokenType = iota // extra token when errors occur - IdentToken - FunctionToken // rgb( rgba( ... - AtKeywordToken // @abc - HashToken // #abc - StringToken - BadStringToken - URLToken - BadURLToken - DelimToken // any unmatched character - NumberToken // 5 - PercentageToken // 5% - DimensionToken // 5em - UnicodeRangeToken // U+554A - IncludeMatchToken // ~= - DashMatchToken // |= - PrefixMatchToken // ^= - SuffixMatchToken // $= - SubstringMatchToken // *= - ColumnToken // || - WhitespaceToken // space \t \r \n \f - CDOToken // - ColonToken // : - SemicolonToken // ; - CommaToken // , - LeftBracketToken // [ - RightBracketToken // ] - LeftParenthesisToken // ( - RightParenthesisToken // ) - LeftBraceToken // { - RightBraceToken // } - CommentToken // extra token for comments - EmptyToken - CustomPropertyNameToken - CustomPropertyValueToken -) - -// String returns the string representation of a TokenType. -func (tt TokenType) String() string { - switch tt { - case ErrorToken: - return "Error" - case IdentToken: - return "Ident" - case FunctionToken: - return "Function" - case AtKeywordToken: - return "AtKeyword" - case HashToken: - return "Hash" - case StringToken: - return "String" - case BadStringToken: - return "BadString" - case URLToken: - return "URL" - case BadURLToken: - return "BadURL" - case DelimToken: - return "Delim" - case NumberToken: - return "Number" - case PercentageToken: - return "Percentage" - case DimensionToken: - return "Dimension" - case UnicodeRangeToken: - return "UnicodeRange" - case IncludeMatchToken: - return "IncludeMatch" - case DashMatchToken: - return "DashMatch" - case PrefixMatchToken: - return "PrefixMatch" - case SuffixMatchToken: - return "SuffixMatch" - case SubstringMatchToken: - return "SubstringMatch" - case ColumnToken: - return "Column" - case WhitespaceToken: - return "Whitespace" - case CDOToken: - return "CDO" - case CDCToken: - return "CDC" - case ColonToken: - return "Colon" - case SemicolonToken: - return "Semicolon" - case CommaToken: - return "Comma" - case LeftBracketToken: - return "LeftBracket" - case RightBracketToken: - return "RightBracket" - case LeftParenthesisToken: - return "LeftParenthesis" - case RightParenthesisToken: - return "RightParenthesis" - case LeftBraceToken: - return "LeftBrace" - case RightBraceToken: - return "RightBrace" - case CommentToken: - return "Comment" - case EmptyToken: - return "Empty" - case CustomPropertyNameToken: - return "CustomPropertyName" - case CustomPropertyValueToken: - return "CustomPropertyValue" - } - return "Invalid(" + strconv.Itoa(int(tt)) + ")" -} - -//////////////////////////////////////////////////////////////// - -// Lexer is the state for the lexer. -type Lexer struct { - r *buffer.Lexer -} - -// NewLexer returns a new Lexer for a given io.Reader. -func NewLexer(r io.Reader) *Lexer { - return &Lexer{ - buffer.NewLexer(r), - } -} - -// Err returns the error encountered during lexing, this is often io.EOF but also other errors can be returned. -func (l *Lexer) Err() error { - return l.r.Err() -} - -// Restore restores the NULL byte at the end of the buffer. -func (l *Lexer) Restore() { - l.r.Restore() -} - -// Offset returns the current position in the input stream. -func (l *Lexer) Offset() int { - return l.r.Offset() -} - -// Next returns the next Token. It returns ErrorToken when an error was encountered. Using Err() one can retrieve the error message. -func (l *Lexer) Next() (TokenType, []byte) { - switch l.r.Peek(0) { - case ' ', '\t', '\n', '\r', '\f': - l.r.Move(1) - for l.consumeWhitespace() { - } - return WhitespaceToken, l.r.Shift() - case ':': - l.r.Move(1) - return ColonToken, l.r.Shift() - case ';': - l.r.Move(1) - return SemicolonToken, l.r.Shift() - case ',': - l.r.Move(1) - return CommaToken, l.r.Shift() - case '(', ')', '[', ']', '{', '}': - if t := l.consumeBracket(); t != ErrorToken { - return t, l.r.Shift() - } - case '#': - if l.consumeHashToken() { - return HashToken, l.r.Shift() - } - case '"', '\'': - if t := l.consumeString(); t != ErrorToken { - return t, l.r.Shift() - } - case '.', '+': - if t := l.consumeNumeric(); t != ErrorToken { - return t, l.r.Shift() - } - case '-': - if t := l.consumeNumeric(); t != ErrorToken { - return t, l.r.Shift() - } else if t := l.consumeIdentlike(); t != ErrorToken { - return t, l.r.Shift() - } else if l.consumeCDCToken() { - return CDCToken, l.r.Shift() - } else if l.consumeCustomVariableToken() { - return CustomPropertyNameToken, l.r.Shift() - } - case '@': - if l.consumeAtKeywordToken() { - return AtKeywordToken, l.r.Shift() - } - case '$', '*', '^', '~': - if t := l.consumeMatch(); t != ErrorToken { - return t, l.r.Shift() - } - case '/': - if l.consumeComment() { - return CommentToken, l.r.Shift() - } - case '<': - if l.consumeCDOToken() { - return CDOToken, l.r.Shift() - } - case '\\': - if t := l.consumeIdentlike(); t != ErrorToken { - return t, l.r.Shift() - } - case 'u', 'U': - if l.consumeUnicodeRangeToken() { - return UnicodeRangeToken, l.r.Shift() - } else if t := l.consumeIdentlike(); t != ErrorToken { - return t, l.r.Shift() - } - case '|': - if t := l.consumeMatch(); t != ErrorToken { - return t, l.r.Shift() - } else if l.consumeColumnToken() { - return ColumnToken, l.r.Shift() - } - case 0: - if l.r.Err() != nil { - return ErrorToken, nil - } - default: - if t := l.consumeNumeric(); t != ErrorToken { - return t, l.r.Shift() - } else if t := l.consumeIdentlike(); t != ErrorToken { - return t, l.r.Shift() - } - } - // can't be rune because consumeIdentlike consumes that as an identifier - l.r.Move(1) - return DelimToken, l.r.Shift() -} - -//////////////////////////////////////////////////////////////// - -/* -The following functions follow the railroad diagrams in http://www.w3.org/TR/css3-syntax/ -*/ - -func (l *Lexer) consumeByte(c byte) bool { - if l.r.Peek(0) == c { - l.r.Move(1) - return true - } - return false -} - -func (l *Lexer) consumeComment() bool { - if l.r.Peek(0) != '/' || l.r.Peek(1) != '*' { - return false - } - l.r.Move(2) - for { - c := l.r.Peek(0) - if c == 0 && l.r.Err() != nil { - break - } else if c == '*' && l.r.Peek(1) == '/' { - l.r.Move(2) - return true - } - l.r.Move(1) - } - return true -} - -func (l *Lexer) consumeNewline() bool { - c := l.r.Peek(0) - if c == '\n' || c == '\f' { - l.r.Move(1) - return true - } else if c == '\r' { - if l.r.Peek(1) == '\n' { - l.r.Move(2) - } else { - l.r.Move(1) - } - return true - } - return false -} - -func (l *Lexer) consumeWhitespace() bool { - c := l.r.Peek(0) - if c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '\f' { - l.r.Move(1) - return true - } - return false -} - -func (l *Lexer) consumeDigit() bool { - c := l.r.Peek(0) - if c >= '0' && c <= '9' { - l.r.Move(1) - return true - } - return false -} - -func (l *Lexer) consumeHexDigit() bool { - c := l.r.Peek(0) - if (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F') { - l.r.Move(1) - return true - } - return false -} - -func (l *Lexer) consumeEscape() bool { - if l.r.Peek(0) != '\\' { - return false - } - mark := l.r.Pos() - l.r.Move(1) - if l.consumeNewline() { - l.r.Rewind(mark) - return false - } else if l.consumeHexDigit() { - for k := 1; k < 6; k++ { - if !l.consumeHexDigit() { - break - } - } - l.consumeWhitespace() - return true - } else { - c := l.r.Peek(0) - if c >= 0xC0 { - _, n := l.r.PeekRune(0) - l.r.Move(n) - return true - } else if c == 0 && l.r.Err() != nil { - l.r.Rewind(mark) - return false - } - } - l.r.Move(1) - return true -} - -func (l *Lexer) consumeIdentToken() bool { - mark := l.r.Pos() - if l.r.Peek(0) == '-' { - l.r.Move(1) - } - c := l.r.Peek(0) - if !((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_' || c >= 0x80) { - if c != '\\' || !l.consumeEscape() { - l.r.Rewind(mark) - return false - } - } else { - l.r.Move(1) - } - for { - c := l.r.Peek(0) - if !((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_' || c == '-' || c >= 0x80) { - if c != '\\' || !l.consumeEscape() { - break - } - } else { - l.r.Move(1) - } - } - return true -} - -// support custom variables, https://www.w3.org/TR/css-variables-1/ -func (l *Lexer) consumeCustomVariableToken() bool { - // expect to be on a '-' - l.r.Move(1) - if l.r.Peek(0) != '-' { - l.r.Move(-1) - return false - } - if !l.consumeIdentToken() { - l.r.Move(-1) - return false - } - return true -} - -func (l *Lexer) consumeAtKeywordToken() bool { - // expect to be on an '@' - l.r.Move(1) - if !l.consumeIdentToken() { - l.r.Move(-1) - return false - } - return true -} - -func (l *Lexer) consumeHashToken() bool { - // expect to be on a '#' - mark := l.r.Pos() - l.r.Move(1) - c := l.r.Peek(0) - if !((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_' || c == '-' || c >= 0x80) { - if c != '\\' || !l.consumeEscape() { - l.r.Rewind(mark) - return false - } - } else { - l.r.Move(1) - } - for { - c := l.r.Peek(0) - if !((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_' || c == '-' || c >= 0x80) { - if c != '\\' || !l.consumeEscape() { - break - } - } else { - l.r.Move(1) - } - } - return true -} - -func (l *Lexer) consumeNumberToken() bool { - mark := l.r.Pos() - c := l.r.Peek(0) - if c == '+' || c == '-' { - l.r.Move(1) - } - firstDigit := l.consumeDigit() - if firstDigit { - for l.consumeDigit() { - } - } - if l.r.Peek(0) == '.' { - l.r.Move(1) - if l.consumeDigit() { - for l.consumeDigit() { - } - } else if firstDigit { - // . could belong to the next token - l.r.Move(-1) - return true - } else { - l.r.Rewind(mark) - return false - } - } else if !firstDigit { - l.r.Rewind(mark) - return false - } - mark = l.r.Pos() - c = l.r.Peek(0) - if c == 'e' || c == 'E' { - l.r.Move(1) - c = l.r.Peek(0) - if c == '+' || c == '-' { - l.r.Move(1) - } - if !l.consumeDigit() { - // e could belong to next token - l.r.Rewind(mark) - return true - } - for l.consumeDigit() { - } - } - return true -} - -func (l *Lexer) consumeUnicodeRangeToken() bool { - c := l.r.Peek(0) - if (c != 'u' && c != 'U') || l.r.Peek(1) != '+' { - return false - } - mark := l.r.Pos() - l.r.Move(2) - if l.consumeHexDigit() { - // consume up to 6 hexDigits - k := 1 - for ; k < 6; k++ { - if !l.consumeHexDigit() { - break - } - } - - // either a minus or a question mark or the end is expected - if l.consumeByte('-') { - // consume another up to 6 hexDigits - if l.consumeHexDigit() { - for k := 1; k < 6; k++ { - if !l.consumeHexDigit() { - break - } - } - } else { - l.r.Rewind(mark) - return false - } - } else { - // could be filled up to 6 characters with question marks or else regular hexDigits - if l.consumeByte('?') { - k++ - for ; k < 6; k++ { - if !l.consumeByte('?') { - l.r.Rewind(mark) - return false - } - } - } - } - } else { - // consume 6 question marks - for k := 0; k < 6; k++ { - if !l.consumeByte('?') { - l.r.Rewind(mark) - return false - } - } - } - return true -} - -func (l *Lexer) consumeColumnToken() bool { - if l.r.Peek(0) == '|' && l.r.Peek(1) == '|' { - l.r.Move(2) - return true - } - return false -} - -func (l *Lexer) consumeCDOToken() bool { - if l.r.Peek(0) == '<' && l.r.Peek(1) == '!' && l.r.Peek(2) == '-' && l.r.Peek(3) == '-' { - l.r.Move(4) - return true - } - return false -} - -func (l *Lexer) consumeCDCToken() bool { - if l.r.Peek(0) == '-' && l.r.Peek(1) == '-' && l.r.Peek(2) == '>' { - l.r.Move(3) - return true - } - return false -} - -//////////////////////////////////////////////////////////////// - -// consumeMatch consumes any MatchToken. -func (l *Lexer) consumeMatch() TokenType { - if l.r.Peek(1) == '=' { - switch l.r.Peek(0) { - case '~': - l.r.Move(2) - return IncludeMatchToken - case '|': - l.r.Move(2) - return DashMatchToken - case '^': - l.r.Move(2) - return PrefixMatchToken - case '$': - l.r.Move(2) - return SuffixMatchToken - case '*': - l.r.Move(2) - return SubstringMatchToken - } - } - return ErrorToken -} - -// consumeBracket consumes any bracket token. -func (l *Lexer) consumeBracket() TokenType { - switch l.r.Peek(0) { - case '(': - l.r.Move(1) - return LeftParenthesisToken - case ')': - l.r.Move(1) - return RightParenthesisToken - case '[': - l.r.Move(1) - return LeftBracketToken - case ']': - l.r.Move(1) - return RightBracketToken - case '{': - l.r.Move(1) - return LeftBraceToken - case '}': - l.r.Move(1) - return RightBraceToken - } - return ErrorToken -} - -// consumeNumeric consumes NumberToken, PercentageToken or DimensionToken. -func (l *Lexer) consumeNumeric() TokenType { - if l.consumeNumberToken() { - if l.consumeByte('%') { - return PercentageToken - } else if l.consumeIdentToken() { - return DimensionToken - } - return NumberToken - } - return ErrorToken -} - -// consumeString consumes a string and may return BadStringToken when a newline is encountered. -func (l *Lexer) consumeString() TokenType { - // assume to be on " or ' - delim := l.r.Peek(0) - l.r.Move(1) - for { - c := l.r.Peek(0) - if c == 0 && l.r.Err() != nil { - break - } else if c == '\n' || c == '\r' || c == '\f' { - l.r.Move(1) - return BadStringToken - } else if c == delim { - l.r.Move(1) - break - } else if c == '\\' { - if !l.consumeEscape() { - // either newline or EOF after backslash - l.r.Move(1) - l.consumeNewline() - } - } else { - l.r.Move(1) - } - } - return StringToken -} - -func (l *Lexer) consumeUnquotedURL() bool { - for { - c := l.r.Peek(0) - if c == 0 && l.r.Err() != nil || c == ')' { - break - } else if c == '"' || c == '\'' || c == '(' || c == '\\' || c == ' ' || c <= 0x1F || c == 0x7F { - if c != '\\' || !l.consumeEscape() { - return false - } - } else { - l.r.Move(1) - } - } - return true -} - -// consumeRemnantsBadUrl consumes bytes of a BadUrlToken so that normal tokenization may continue. -func (l *Lexer) consumeRemnantsBadURL() { - for { - if l.consumeByte(')') || l.r.Err() != nil { - break - } else if !l.consumeEscape() { - l.r.Move(1) - } - } -} - -// consumeIdentlike consumes IdentToken, FunctionToken or UrlToken. -func (l *Lexer) consumeIdentlike() TokenType { - if l.consumeIdentToken() { - if l.r.Peek(0) != '(' { - return IdentToken - } else if !parse.EqualFold(bytes.Replace(l.r.Lexeme(), []byte{'\\'}, nil, -1), []byte{'u', 'r', 'l'}) { - l.r.Move(1) - return FunctionToken - } - l.r.Move(1) - - // consume url - for l.consumeWhitespace() { - } - if c := l.r.Peek(0); c == '"' || c == '\'' { - if l.consumeString() == BadStringToken { - l.consumeRemnantsBadURL() - return BadURLToken - } - } else if !l.consumeUnquotedURL() && !l.consumeWhitespace() { // if unquoted URL fails due to encountering whitespace, continue - l.consumeRemnantsBadURL() - return BadURLToken - } - for l.consumeWhitespace() { - } - if !l.consumeByte(')') && l.r.Err() != io.EOF { - l.consumeRemnantsBadURL() - return BadURLToken - } - return URLToken - } - return ErrorToken -} diff --git a/vendor/github.com/tdewolff/parse/v2/css/parse.go b/vendor/github.com/tdewolff/parse/v2/css/parse.go deleted file mode 100644 index 5cc9460ee9faa..0000000000000 --- a/vendor/github.com/tdewolff/parse/v2/css/parse.go +++ /dev/null @@ -1,459 +0,0 @@ -package css - -import ( - "bytes" - "io" - "strconv" - - "github.com/tdewolff/parse/v2" -) - -var wsBytes = []byte(" ") -var endBytes = []byte("}") -var emptyBytes = []byte("") - -// GrammarType determines the type of grammar. -type GrammarType uint32 - -// GrammarType values. -const ( - ErrorGrammar GrammarType = iota // extra token when errors occur - CommentGrammar - AtRuleGrammar - BeginAtRuleGrammar - EndAtRuleGrammar - QualifiedRuleGrammar - BeginRulesetGrammar - EndRulesetGrammar - DeclarationGrammar - TokenGrammar - CustomPropertyGrammar -) - -// String returns the string representation of a GrammarType. -func (tt GrammarType) String() string { - switch tt { - case ErrorGrammar: - return "Error" - case CommentGrammar: - return "Comment" - case AtRuleGrammar: - return "AtRule" - case BeginAtRuleGrammar: - return "BeginAtRule" - case EndAtRuleGrammar: - return "EndAtRule" - case QualifiedRuleGrammar: - return "QualifiedRule" - case BeginRulesetGrammar: - return "BeginRuleset" - case EndRulesetGrammar: - return "EndRuleset" - case DeclarationGrammar: - return "Declaration" - case TokenGrammar: - return "Token" - case CustomPropertyGrammar: - return "CustomProperty" - } - return "Invalid(" + strconv.Itoa(int(tt)) + ")" -} - -//////////////////////////////////////////////////////////////// - -// State is the state function the parser currently is in. -type State func(*Parser) GrammarType - -// Token is a single TokenType and its associated data. -type Token struct { - TokenType - Data []byte -} - -func (t Token) String() string { - return t.TokenType.String() + "('" + string(t.Data) + "')" -} - -// Parser is the state for the parser. -type Parser struct { - l *Lexer - state []State - err error - - buf []Token - level int - - tt TokenType - data []byte - keepWS bool - prevWS bool - prevEnd bool - prevComment bool -} - -// NewParser returns a new CSS parser from an io.Reader. isInline specifies whether this is an inline style attribute. -func NewParser(r io.Reader, isInline bool) *Parser { - l := NewLexer(r) - p := &Parser{ - l: l, - state: make([]State, 0, 4), - } - - if isInline { - p.state = append(p.state, (*Parser).parseDeclarationList) - } else { - p.state = append(p.state, (*Parser).parseStylesheet) - } - return p -} - -// Err returns the error encountered during parsing, this is often io.EOF but also other errors can be returned. -func (p *Parser) Err() error { - if p.err != nil { - return p.err - } - return p.l.Err() -} - -// Restore restores the NULL byte at the end of the buffer. -func (p *Parser) Restore() { - p.l.Restore() -} - -// Offset returns the current position in the input stream. -func (p *Parser) Offset() int { - return p.l.Offset() -} - -// Next returns the next Grammar. It returns ErrorGrammar when an error was encountered. Using Err() one can retrieve the error message. -func (p *Parser) Next() (GrammarType, TokenType, []byte) { - p.err = nil - - if p.prevEnd { - p.tt, p.data = RightBraceToken, endBytes - p.prevEnd = false - } else { - p.tt, p.data = p.popToken(true) - } - gt := p.state[len(p.state)-1](p) - return gt, p.tt, p.data -} - -// Values returns a slice of Tokens for the last Grammar. Only AtRuleGrammar, BeginAtRuleGrammar, BeginRulesetGrammar and Declaration will return the at-rule components, ruleset selector and declaration values respectively. -func (p *Parser) Values() []Token { - return p.buf -} - -func (p *Parser) popToken(allowComment bool) (TokenType, []byte) { - p.prevWS = false - p.prevComment = false - tt, data := p.l.Next() - for !p.keepWS && tt == WhitespaceToken || tt == CommentToken { - if tt == WhitespaceToken { - p.prevWS = true - } else { - p.prevComment = true - if allowComment && len(p.state) == 1 { - break - } - } - tt, data = p.l.Next() - } - return tt, data -} - -func (p *Parser) initBuf() { - p.buf = p.buf[:0] -} - -func (p *Parser) pushBuf(tt TokenType, data []byte) { - p.buf = append(p.buf, Token{tt, data}) -} - -//////////////////////////////////////////////////////////////// - -func (p *Parser) parseStylesheet() GrammarType { - if p.tt == CDOToken || p.tt == CDCToken { - return TokenGrammar - } else if p.tt == AtKeywordToken { - return p.parseAtRule() - } else if p.tt == CommentToken { - return CommentGrammar - } else if p.tt == ErrorToken { - return ErrorGrammar - } - return p.parseQualifiedRule() -} - -func (p *Parser) parseDeclarationList() GrammarType { - if p.tt == CommentToken { - p.tt, p.data = p.popToken(false) - } - for p.tt == SemicolonToken { - p.tt, p.data = p.popToken(false) - } - - // IE hack: *color:red; - if p.tt == DelimToken && p.data[0] == '*' { - tt, data := p.popToken(false) - p.tt = tt - p.data = append(p.data, data...) - } - - if p.tt == ErrorToken { - return ErrorGrammar - } else if p.tt == AtKeywordToken { - return p.parseAtRule() - } else if p.tt == IdentToken || p.tt == DelimToken { - return p.parseDeclaration() - } else if p.tt == CustomPropertyNameToken { - return p.parseCustomProperty() - } - - // parse error - p.initBuf() - p.l.r.Move(-len(p.data)) - p.err = parse.NewErrorLexer(p.l.r, "CSS parse error: unexpected token '%s' in declaration", string(p.data)) - p.l.r.Move(len(p.data)) - - if p.tt == RightBraceToken { - // right brace token will occur when we've had a decl error that ended in a right brace token - // as these are not handled by decl error, we handle it here explictly. Normally its used to end eg. the qual rule. - p.pushBuf(p.tt, p.data) - return ErrorGrammar - } - return p.parseDeclarationError(p.tt, p.data) -} - -//////////////////////////////////////////////////////////////// - -func (p *Parser) parseAtRule() GrammarType { - p.initBuf() - parse.ToLower(p.data) - atRuleName := p.data - if len(atRuleName) > 0 && atRuleName[1] == '-' { - if i := bytes.IndexByte(atRuleName[2:], '-'); i != -1 { - atRuleName = atRuleName[i+2:] // skip vendor specific prefix - } - } - atRule := ToHash(atRuleName[1:]) - - first := true - skipWS := false - for { - tt, data := p.popToken(false) - if tt == LeftBraceToken && p.level == 0 { - if atRule == Font_Face || atRule == Page { - p.state = append(p.state, (*Parser).parseAtRuleDeclarationList) - } else if atRule == Document || atRule == Keyframes || atRule == Media || atRule == Supports { - p.state = append(p.state, (*Parser).parseAtRuleRuleList) - } else { - p.state = append(p.state, (*Parser).parseAtRuleUnknown) - } - return BeginAtRuleGrammar - } else if (tt == SemicolonToken || tt == RightBraceToken) && p.level == 0 || tt == ErrorToken { - p.prevEnd = (tt == RightBraceToken) - return AtRuleGrammar - } else if tt == LeftParenthesisToken || tt == LeftBraceToken || tt == LeftBracketToken || tt == FunctionToken { - p.level++ - } else if tt == RightParenthesisToken || tt == RightBraceToken || tt == RightBracketToken { - p.level-- - } - if first { - if tt == LeftParenthesisToken || tt == LeftBracketToken { - p.prevWS = false - } - first = false - } - if len(data) == 1 && (data[0] == ',' || data[0] == ':') { - skipWS = true - } else if p.prevWS && !skipWS && tt != RightParenthesisToken { - p.pushBuf(WhitespaceToken, wsBytes) - } else { - skipWS = false - } - if tt == LeftParenthesisToken { - skipWS = true - } - p.pushBuf(tt, data) - } -} - -func (p *Parser) parseAtRuleRuleList() GrammarType { - if p.tt == RightBraceToken || p.tt == ErrorToken { - p.state = p.state[:len(p.state)-1] - return EndAtRuleGrammar - } else if p.tt == AtKeywordToken { - return p.parseAtRule() - } else { - return p.parseQualifiedRule() - } -} - -func (p *Parser) parseAtRuleDeclarationList() GrammarType { - for p.tt == SemicolonToken { - p.tt, p.data = p.popToken(false) - } - if p.tt == RightBraceToken || p.tt == ErrorToken { - p.state = p.state[:len(p.state)-1] - return EndAtRuleGrammar - } - return p.parseDeclarationList() -} - -func (p *Parser) parseAtRuleUnknown() GrammarType { - p.keepWS = true - if p.tt == RightBraceToken && p.level == 0 || p.tt == ErrorToken { - p.state = p.state[:len(p.state)-1] - p.keepWS = false - return EndAtRuleGrammar - } - if p.tt == LeftParenthesisToken || p.tt == LeftBraceToken || p.tt == LeftBracketToken || p.tt == FunctionToken { - p.level++ - } else if p.tt == RightParenthesisToken || p.tt == RightBraceToken || p.tt == RightBracketToken { - p.level-- - } - return TokenGrammar -} - -func (p *Parser) parseQualifiedRule() GrammarType { - p.initBuf() - first := true - inAttrSel := false - skipWS := true - var tt TokenType - var data []byte - for { - if first { - tt, data = p.tt, p.data - p.tt = WhitespaceToken - p.data = emptyBytes - first = false - } else { - tt, data = p.popToken(false) - } - if tt == LeftBraceToken && p.level == 0 { - p.state = append(p.state, (*Parser).parseQualifiedRuleDeclarationList) - return BeginRulesetGrammar - } else if tt == ErrorToken { - p.err = parse.NewErrorLexer(p.l.r, "CSS parse error: unexpected ending in qualified rule") - return ErrorGrammar - } else if tt == LeftParenthesisToken || tt == LeftBraceToken || tt == LeftBracketToken || tt == FunctionToken { - p.level++ - } else if tt == RightParenthesisToken || tt == RightBraceToken || tt == RightBracketToken { - p.level-- - } - if len(data) == 1 && (data[0] == ',' || data[0] == '>' || data[0] == '+' || data[0] == '~') { - if data[0] == ',' { - return QualifiedRuleGrammar - } - skipWS = true - } else if p.prevWS && !skipWS && !inAttrSel { - p.pushBuf(WhitespaceToken, wsBytes) - } else { - skipWS = false - } - if tt == LeftBracketToken { - inAttrSel = true - } else if tt == RightBracketToken { - inAttrSel = false - } - p.pushBuf(tt, data) - } -} - -func (p *Parser) parseQualifiedRuleDeclarationList() GrammarType { - for p.tt == SemicolonToken { - p.tt, p.data = p.popToken(false) - } - if p.tt == RightBraceToken || p.tt == ErrorToken { - p.state = p.state[:len(p.state)-1] - return EndRulesetGrammar - } - return p.parseDeclarationList() -} - -func (p *Parser) parseDeclaration() GrammarType { - p.initBuf() - parse.ToLower(p.data) - - ttName, dataName := p.tt, p.data - tt, data := p.popToken(false) - if tt != ColonToken { - p.l.r.Move(-len(data)) - p.err = parse.NewErrorLexer(p.l.r, "CSS parse error: expected colon in declaration") - p.l.r.Move(len(data)) - p.pushBuf(ttName, dataName) - return p.parseDeclarationError(tt, data) - } - - skipWS := true - for { - tt, data := p.popToken(false) - if (tt == SemicolonToken || tt == RightBraceToken) && p.level == 0 || tt == ErrorToken { - p.prevEnd = (tt == RightBraceToken) - return DeclarationGrammar - } else if tt == LeftParenthesisToken || tt == LeftBraceToken || tt == LeftBracketToken || tt == FunctionToken { - p.level++ - } else if tt == RightParenthesisToken || tt == RightBraceToken || tt == RightBracketToken { - p.level-- - } - if len(data) == 1 && (data[0] == ',' || data[0] == '/' || data[0] == ':' || data[0] == '!' || data[0] == '=') { - skipWS = true - } else if (p.prevWS || p.prevComment) && !skipWS { - p.pushBuf(WhitespaceToken, wsBytes) - } else { - skipWS = false - } - p.pushBuf(tt, data) - } -} - -func (p *Parser) parseDeclarationError(tt TokenType, data []byte) GrammarType { - // we're on the offending (tt,data), keep popping tokens till we reach ;, }, or EOF - p.tt, p.data = tt, data - for { - if (tt == SemicolonToken || tt == RightBraceToken) && p.level == 0 || tt == ErrorToken { - p.prevEnd = (tt == RightBraceToken) - if tt == SemicolonToken { - p.pushBuf(tt, data) - } - return ErrorGrammar - } else if tt == LeftParenthesisToken || tt == LeftBraceToken || tt == LeftBracketToken || tt == FunctionToken { - p.level++ - } else if tt == RightParenthesisToken || tt == RightBraceToken || tt == RightBracketToken { - p.level-- - } - - if p.prevWS { - p.pushBuf(WhitespaceToken, wsBytes) - } - p.pushBuf(tt, data) - - tt, data = p.popToken(false) - } -} - -func (p *Parser) parseCustomProperty() GrammarType { - p.initBuf() - if tt, data := p.popToken(false); tt != ColonToken { - p.l.r.Move(-len(data)) - p.err = parse.NewErrorLexer(p.l.r, "CSS parse error: expected colon in custom property") - p.l.r.Move(len(data)) - return ErrorGrammar - } - val := []byte{} - for { - tt, data := p.l.Next() - if (tt == SemicolonToken || tt == RightBraceToken) && p.level == 0 || tt == ErrorToken { - p.prevEnd = (tt == RightBraceToken) - p.pushBuf(CustomPropertyValueToken, val) - return CustomPropertyGrammar - } else if tt == LeftParenthesisToken || tt == LeftBraceToken || tt == LeftBracketToken || tt == FunctionToken { - p.level++ - } else if tt == RightParenthesisToken || tt == RightBraceToken || tt == RightBracketToken { - p.level-- - } - val = append(val, data...) - } -} diff --git a/vendor/github.com/tdewolff/parse/v2/css/util.go b/vendor/github.com/tdewolff/parse/v2/css/util.go deleted file mode 100644 index d0dcaf7bf1105..0000000000000 --- a/vendor/github.com/tdewolff/parse/v2/css/util.go +++ /dev/null @@ -1,49 +0,0 @@ -package css - -import ( - "github.com/tdewolff/parse/v2/buffer" -) - -// IsIdent returns true if the bytes are a valid identifier. -func IsIdent(b []byte) bool { - l := NewLexer(buffer.NewReader(b)) - l.consumeIdentToken() - l.r.Restore() - return l.r.Pos() == len(b) -} - -// IsURLUnquoted returns true if the bytes are a valid unquoted URL. -func IsURLUnquoted(b []byte) bool { - l := NewLexer(buffer.NewReader(b)) - l.consumeUnquotedURL() - l.r.Restore() - return l.r.Pos() == len(b) -} - -// HSL2RGB converts HSL to RGB with all of range [0,1] -// from http://www.w3.org/TR/css3-color/#hsl-color -func HSL2RGB(h, s, l float64) (float64, float64, float64) { - m2 := l * (s + 1) - if l > 0.5 { - m2 = l + s - l*s - } - m1 := l*2 - m2 - return hue2rgb(m1, m2, h+1.0/3.0), hue2rgb(m1, m2, h), hue2rgb(m1, m2, h-1.0/3.0) -} - -func hue2rgb(m1, m2, h float64) float64 { - if h < 0.0 { - h += 1.0 - } - if h > 1.0 { - h -= 1.0 - } - if h*6.0 < 1.0 { - return m1 + (m2-m1)*h*6.0 - } else if h*2.0 < 1.0 { - return m2 - } else if h*3.0 < 2.0 { - return m1 + (m2-m1)*(2.0/3.0-h)*6.0 - } - return m1 -} diff --git a/vendor/github.com/tdewolff/parse/v2/error.go b/vendor/github.com/tdewolff/parse/v2/error.go deleted file mode 100644 index d55c2d6570454..0000000000000 --- a/vendor/github.com/tdewolff/parse/v2/error.go +++ /dev/null @@ -1,48 +0,0 @@ -package parse - -import ( - "fmt" - "io" - - "github.com/tdewolff/parse/v2/buffer" -) - -// Error is a parsing error returned by parser. It contains a message and an offset at which the error occurred. -type Error struct { - Message string - Line int - Column int - Context string -} - -// NewError creates a new error -func NewError(r io.Reader, offset int, message string, a ...interface{}) *Error { - line, column, context := Position(r, offset) - if 0 < len(a) { - message = fmt.Sprintf(message, a...) - } - return &Error{ - Message: message, - Line: line, - Column: column, - Context: context, - } -} - -// NewErrorLexer creates a new error from an active Lexer. -func NewErrorLexer(l *buffer.Lexer, message string, a ...interface{}) *Error { - r := buffer.NewReader(l.Bytes()) - offset := l.Offset() - return NewError(r, offset, message, a...) -} - -// Positions returns the line, column, and context of the error. -// Context is the entire line at which the error occurred. -func (e *Error) Position() (int, int, string) { - return e.Line, e.Column, e.Context -} - -// Error returns the error string, containing the context and line + column number. -func (e *Error) Error() string { - return fmt.Sprintf("%s on line %d and column %d\n%s", e.Message, e.Line, e.Column, e.Context) -} diff --git a/vendor/github.com/tdewolff/parse/v2/go.mod b/vendor/github.com/tdewolff/parse/v2/go.mod deleted file mode 100644 index 6432178e8b493..0000000000000 --- a/vendor/github.com/tdewolff/parse/v2/go.mod +++ /dev/null @@ -1,5 +0,0 @@ -module github.com/tdewolff/parse/v2 - -go 1.13 - -require github.com/tdewolff/test v1.0.6 diff --git a/vendor/github.com/tdewolff/parse/v2/go.sum b/vendor/github.com/tdewolff/parse/v2/go.sum deleted file mode 100644 index 7893d5c89e00e..0000000000000 --- a/vendor/github.com/tdewolff/parse/v2/go.sum +++ /dev/null @@ -1,2 +0,0 @@ -github.com/tdewolff/test v1.0.6 h1:76mzYJQ83Op284kMT+63iCNCI7NEERsIN8dLM+RiKr4= -github.com/tdewolff/test v1.0.6/go.mod h1:6DAvZliBAAnD7rhVgwaM7DE5/d9NMOAJ09SqYqeK4QE= diff --git a/vendor/github.com/tdewolff/parse/v2/position.go b/vendor/github.com/tdewolff/parse/v2/position.go deleted file mode 100644 index a9a9720014d73..0000000000000 --- a/vendor/github.com/tdewolff/parse/v2/position.go +++ /dev/null @@ -1,99 +0,0 @@ -package parse - -import ( - "fmt" - "io" - "strings" - - "github.com/tdewolff/parse/v2/buffer" -) - -// Position returns the line and column number for a certain position in a file. It is useful for recovering the position in a file that caused an error. -// It only treates \n, \r, and \r\n as newlines, which might be different from some languages also recognizing \f, \u2028, and \u2029 to be newlines. -func Position(r io.Reader, offset int) (line, col int, context string) { - l := buffer.NewLexer(r) - - line = 1 - for { - c := l.Peek(0) - if c == 0 && l.Err() != nil || offset == l.Pos() { - col = l.Pos() + 1 - context = positionContext(l, line, col) - return - } - - n := 1 - newline := false - if c == '\n' { - newline = true - } else if c == '\r' { - if l.Peek(1) == '\n' { - newline = true - n = 2 - } else { - newline = true - } - } else if c >= 0xC0 { - var r rune - if r, n = l.PeekRune(0); r == '\u2028' || r == '\u2029' { - newline = true - } - } - - if 1 < n && offset < l.Pos()+n { - // move onto offset position, let next iteration handle it - l.Move(offset - l.Pos()) - continue - } - l.Move(n) - - if newline { - line++ - offset -= l.Pos() - l.Skip() - } - } -} - -func positionContext(l *buffer.Lexer, line, col int) (context string) { - for { - c := l.Peek(0) - if c == 0 && l.Err() != nil || c == '\n' || c == '\r' { - break - } - l.Move(1) - } - - // cut off front or rear of context to stay between 60 characters - b := l.Lexeme() - limit := 60 - offset := 20 - ellipsisFront := "" - ellipsisRear := "" - if limit < len(b) { - if col <= limit-offset { - ellipsisRear = "..." - b = b[:limit-3] - } else if col >= len(b)-offset-3 { - ellipsisFront = "..." - col -= len(b) - offset - offset - 7 - b = b[len(b)-offset-offset-4:] - } else { - ellipsisFront = "..." - ellipsisRear = "..." - b = b[col-offset-1 : col+offset] - col = offset + 4 - } - } - - // replace unprintable characters by a space - for i, c := range b { - if c < 0x20 || c == 0x7F { - b[i] = ' ' - } - } - - context += fmt.Sprintf("%5d: %s%s%s\n", line, ellipsisFront, string(b), ellipsisRear) - context += fmt.Sprintf("%s^", strings.Repeat(" ", col+6)) - return -} diff --git a/vendor/github.com/tdewolff/parse/v2/strconv/float.go b/vendor/github.com/tdewolff/parse/v2/strconv/float.go deleted file mode 100644 index ed165b0c989b9..0000000000000 --- a/vendor/github.com/tdewolff/parse/v2/strconv/float.go +++ /dev/null @@ -1,251 +0,0 @@ -package strconv - -import ( - "math" -) - -var float64pow10 = []float64{ - 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, - 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19, - 1e20, 1e21, 1e22, -} - -// Float parses a byte-slice and returns the float it represents. -// If an invalid character is encountered, it will stop there. -func ParseFloat(b []byte) (float64, int) { - i := 0 - neg := false - if i < len(b) && (b[i] == '+' || b[i] == '-') { - neg = b[i] == '-' - i++ - } - - dot := -1 - trunk := -1 - n := uint64(0) - for ; i < len(b); i++ { - c := b[i] - if c >= '0' && c <= '9' { - if trunk == -1 { - if n > math.MaxUint64/10 { - trunk = i - } else { - n *= 10 - n += uint64(c - '0') - } - } - } else if dot == -1 && c == '.' { - dot = i - } else { - break - } - } - - f := float64(n) - if neg { - f = -f - } - - mantExp := int64(0) - if dot != -1 { - if trunk == -1 { - trunk = i - } - mantExp = int64(trunk - dot - 1) - } else if trunk != -1 { - mantExp = int64(trunk - i) - } - expExp := int64(0) - if i < len(b) && (b[i] == 'e' || b[i] == 'E') { - i++ - if e, expLen := ParseInt(b[i:]); expLen > 0 { - expExp = e - i += expLen - } - } - exp := expExp - mantExp - - // copied from strconv/atof.go - if exp == 0 { - return f, i - } else if exp > 0 && exp <= 15+22 { // int * 10^k - // If exponent is big but number of digits is not, - // can move a few zeros into the integer part. - if exp > 22 { - f *= float64pow10[exp-22] - exp = 22 - } - if f <= 1e15 && f >= -1e15 { - return f * float64pow10[exp], i - } - } else if exp < 0 && exp >= -22 { // int / 10^k - return f / float64pow10[-exp], i - } - f *= math.Pow10(int(-mantExp)) - return f * math.Pow10(int(expExp)), i -} - -const log2 = 0.3010299956639812 - -func float64exp(f float64) int { - exp2 := 0 - if f != 0.0 { - x := math.Float64bits(f) - exp2 = int(x>>(64-11-1))&0x7FF - 1023 + 1 - } - - exp10 := float64(exp2) * log2 - if exp10 < 0 { - exp10 -= 1.0 - } - return int(exp10) -} - -// AppendFloat appends a float to `b` with precision `prec`. It returns the new slice and whether succesful or not. Precision is the number of decimals to display, thus prec + 1 == number of significant digits. -func AppendFloat(b []byte, f float64, prec int) ([]byte, bool) { - if math.IsNaN(f) || math.IsInf(f, 0) { - return b, false - } - - neg := false - if f < 0.0 { - f = -f - neg = true - } - if prec < 0 || 17 < prec { - prec = 17 // maximum number of significant digits in double - } - prec -= float64exp(f) // number of digits in front of the dot - f *= math.Pow10(prec) - - // calculate mantissa and exponent - mant := int64(f) - mantLen := LenInt(mant) - mantExp := mantLen - prec - 1 - if mant == 0 { - return append(b, '0'), true - } - - // expLen is zero for positive exponents, because positive exponents are determined later on in the big conversion loop - exp := 0 - expLen := 0 - if mantExp > 0 { - // positive exponent is determined in the loop below - // but if we initially decreased the exponent to fit in an integer, we can't set the new exponent in the loop alone, - // since the number of zeros at the end determines the positive exponent in the loop, and we just artificially lost zeros - if prec < 0 { - exp = mantExp - } - expLen = 1 + LenInt(int64(exp)) // e + digits - } else if mantExp < -3 { - exp = mantExp - expLen = 2 + LenInt(int64(exp)) // e + minus + digits - } else if mantExp < -1 { - mantLen += -mantExp - 1 // extra zero between dot and first digit - } - - // reserve space in b - i := len(b) - maxLen := 1 + mantLen + expLen // dot + mantissa digits + exponent - if neg { - maxLen++ - } - if i+maxLen > cap(b) { - b = append(b, make([]byte, maxLen)...) - } else { - b = b[:i+maxLen] - } - - // write to string representation - if neg { - b[i] = '-' - i++ - } - - // big conversion loop, start at the end and move to the front - // initially print trailing zeros and remove them later on - // for example if the first non-zero digit is three positions in front of the dot, it will overwrite the zeros with a positive exponent - zero := true - last := i + mantLen // right-most position of digit that is non-zero + dot - dot := last - prec - exp // position of dot - j := last - for mant > 0 { - if j == dot { - b[j] = '.' - j-- - } - newMant := mant / 10 - digit := mant - 10*newMant - if zero && digit > 0 { - // first non-zero digit, if we are still behind the dot we can trim the end to this position - // otherwise trim to the dot (including the dot) - if j > dot { - i = j + 1 - // decrease negative exponent further to get rid of dot - if exp < 0 { - newExp := exp - (j - dot) - // getting rid of the dot shouldn't lower the exponent to more digits (e.g. -9 -> -10) - if LenInt(int64(newExp)) == LenInt(int64(exp)) { - exp = newExp - dot = j - j-- - i-- - } - } - } else { - i = dot - } - last = j - zero = false - } - b[j] = '0' + byte(digit) - j-- - mant = newMant - } - - if j > dot { - // extra zeros behind the dot - for j > dot { - b[j] = '0' - j-- - } - b[j] = '.' - } else if last+3 < dot { - // add positive exponent because we have 3 or more zeros in front of the dot - i = last + 1 - exp = dot - last - 1 - } else if j == dot { - // handle 0.1 - b[j] = '.' - } - - // exponent - if exp != 0 { - if exp == 1 { - b[i] = '0' - i++ - } else if exp == 2 { - b[i] = '0' - b[i+1] = '0' - i += 2 - } else { - b[i] = 'e' - i++ - if exp < 0 { - b[i] = '-' - i++ - exp = -exp - } - i += LenInt(int64(exp)) - j := i - for exp > 0 { - newExp := exp / 10 - digit := exp - 10*newExp - j-- - b[j] = '0' + byte(digit) - exp = newExp - } - } - } - return b[:i], true -} diff --git a/vendor/github.com/tdewolff/parse/v2/strconv/int.go b/vendor/github.com/tdewolff/parse/v2/strconv/int.go deleted file mode 100644 index ed174e023166f..0000000000000 --- a/vendor/github.com/tdewolff/parse/v2/strconv/int.go +++ /dev/null @@ -1,83 +0,0 @@ -package strconv - -import ( - "math" -) - -// Int parses a byte-slice and returns the integer it represents. -// If an invalid character is encountered, it will stop there. -func ParseInt(b []byte) (int64, int) { - i := 0 - neg := false - if len(b) > 0 && (b[0] == '+' || b[0] == '-') { - neg = b[0] == '-' - i++ - } - n := uint64(0) - for i < len(b) { - c := b[i] - if n > math.MaxUint64/10 { - return 0, 0 - } else if c >= '0' && c <= '9' { - n *= 10 - n += uint64(c - '0') - } else { - break - } - i++ - } - if !neg && n > uint64(math.MaxInt64) || n > uint64(math.MaxInt64)+1 { - return 0, 0 - } else if neg { - return -int64(n), i - } - return int64(n), i -} - -func LenInt(i int64) int { - if i < 0 { - if i == -9223372036854775808 { - return 19 - } - i = -i - } - switch { - case i < 10: - return 1 - case i < 100: - return 2 - case i < 1000: - return 3 - case i < 10000: - return 4 - case i < 100000: - return 5 - case i < 1000000: - return 6 - case i < 10000000: - return 7 - case i < 100000000: - return 8 - case i < 1000000000: - return 9 - case i < 10000000000: - return 10 - case i < 100000000000: - return 11 - case i < 1000000000000: - return 12 - case i < 10000000000000: - return 13 - case i < 100000000000000: - return 14 - case i < 1000000000000000: - return 15 - case i < 10000000000000000: - return 16 - case i < 100000000000000000: - return 17 - case i < 1000000000000000000: - return 18 - } - return 19 -} diff --git a/vendor/github.com/tdewolff/parse/v2/strconv/price.go b/vendor/github.com/tdewolff/parse/v2/strconv/price.go deleted file mode 100644 index 94b38343e8cdc..0000000000000 --- a/vendor/github.com/tdewolff/parse/v2/strconv/price.go +++ /dev/null @@ -1,83 +0,0 @@ -package strconv - -// AppendPrice will append an int64 formatted as a price, where the int64 is the price in cents. -// It does not display whether a price is negative or not. -func AppendPrice(b []byte, price int64, dec bool, milSeparator byte, decSeparator byte) []byte { - if price < 0 { - if price == -9223372036854775808 { - x := []byte("92 233 720 368 547 758 08") - x[2] = milSeparator - x[6] = milSeparator - x[10] = milSeparator - x[14] = milSeparator - x[18] = milSeparator - x[22] = decSeparator - return append(b, x...) - } - price = -price - } - - // rounding - if !dec { - firstDec := (price / 10) % 10 - if firstDec >= 5 { - price += 100 - } - } - - // calculate size - n := LenInt(price) - 2 - if n > 0 { - n += (n - 1) / 3 // mil separator - } else { - n = 1 - } - if dec { - n += 2 + 1 // decimals + dec separator - } - - // resize byte slice - i := len(b) - if i+n > cap(b) { - b = append(b, make([]byte, n)...) - } else { - b = b[:i+n] - } - - // print fractional-part - i += n - 1 - if dec { - for j := 0; j < 2; j++ { - c := byte(price%10) + '0' - price /= 10 - b[i] = c - i-- - } - b[i] = decSeparator - i-- - } else { - price /= 100 - } - - if price == 0 { - b[i] = '0' - return b - } - - // print integer-part - j := 0 - for price > 0 { - if j == 3 { - b[i] = milSeparator - i-- - j = 0 - } - - c := byte(price%10) + '0' - price /= 10 - b[i] = c - i-- - j++ - } - return b -} diff --git a/vendor/github.com/tdewolff/parse/v2/util.go b/vendor/github.com/tdewolff/parse/v2/util.go deleted file mode 100644 index c0bdffb436e27..0000000000000 --- a/vendor/github.com/tdewolff/parse/v2/util.go +++ /dev/null @@ -1,425 +0,0 @@ -package parse - -import ( - "bytes" - "strconv" -) - -// Copy returns a copy of the given byte slice. -func Copy(src []byte) (dst []byte) { - dst = make([]byte, len(src)) - copy(dst, src) - return -} - -// ToLower converts all characters in the byte slice from A-Z to a-z. -func ToLower(src []byte) []byte { - for i, c := range src { - if c >= 'A' && c <= 'Z' { - src[i] = c + ('a' - 'A') - } - } - return src -} - -// EqualFold returns true when s matches case-insensitively the targetLower (which must be lowercase). -func EqualFold(s, targetLower []byte) bool { - if len(s) != len(targetLower) { - return false - } - for i, c := range targetLower { - d := s[i] - if d != c && (d < 'A' || d > 'Z' || d+('a'-'A') != c) { - return false - } - } - return true -} - -var whitespaceTable = [256]bool{ - // ASCII - false, false, false, false, false, false, false, false, - false, true, true, false, true, true, false, false, // tab, new line, form feed, carriage return - false, false, false, false, false, false, false, false, - false, false, false, false, false, false, false, false, - - true, false, false, false, false, false, false, false, // space - false, false, false, false, false, false, false, false, - false, false, false, false, false, false, false, false, - false, false, false, false, false, false, false, false, - - false, false, false, false, false, false, false, false, - false, false, false, false, false, false, false, false, - false, false, false, false, false, false, false, false, - false, false, false, false, false, false, false, false, - - false, false, false, false, false, false, false, false, - false, false, false, false, false, false, false, false, - false, false, false, false, false, false, false, false, - false, false, false, false, false, false, false, false, - - // non-ASCII - false, false, false, false, false, false, false, false, - false, false, false, false, false, false, false, false, - false, false, false, false, false, false, false, false, - false, false, false, false, false, false, false, false, - - false, false, false, false, false, false, false, false, - false, false, false, false, false, false, false, false, - false, false, false, false, false, false, false, false, - false, false, false, false, false, false, false, false, - - false, false, false, false, false, false, false, false, - false, false, false, false, false, false, false, false, - false, false, false, false, false, false, false, false, - false, false, false, false, false, false, false, false, - - false, false, false, false, false, false, false, false, - false, false, false, false, false, false, false, false, - false, false, false, false, false, false, false, false, - false, false, false, false, false, false, false, false, -} - -// IsWhitespace returns true for space, \n, \r, \t, \f. -func IsWhitespace(c byte) bool { - return whitespaceTable[c] -} - -var newlineTable = [256]bool{ - // ASCII - false, false, false, false, false, false, false, false, - false, false, true, false, false, true, false, false, // new line, carriage return - false, false, false, false, false, false, false, false, - false, false, false, false, false, false, false, false, - - false, false, false, false, false, false, false, false, - false, false, false, false, false, false, false, false, - false, false, false, false, false, false, false, false, - false, false, false, false, false, false, false, false, - - false, false, false, false, false, false, false, false, - false, false, false, false, false, false, false, false, - false, false, false, false, false, false, false, false, - false, false, false, false, false, false, false, false, - - false, false, false, false, false, false, false, false, - false, false, false, false, false, false, false, false, - false, false, false, false, false, false, false, false, - false, false, false, false, false, false, false, false, - - // non-ASCII - false, false, false, false, false, false, false, false, - false, false, false, false, false, false, false, false, - false, false, false, false, false, false, false, false, - false, false, false, false, false, false, false, false, - - false, false, false, false, false, false, false, false, - false, false, false, false, false, false, false, false, - false, false, false, false, false, false, false, false, - false, false, false, false, false, false, false, false, - - false, false, false, false, false, false, false, false, - false, false, false, false, false, false, false, false, - false, false, false, false, false, false, false, false, - false, false, false, false, false, false, false, false, - - false, false, false, false, false, false, false, false, - false, false, false, false, false, false, false, false, - false, false, false, false, false, false, false, false, - false, false, false, false, false, false, false, false, -} - -// IsNewline returns true for \n, \r. -func IsNewline(c byte) bool { - return newlineTable[c] -} - -// IsAllWhitespace returns true when the entire byte slice consists of space, \n, \r, \t, \f. -func IsAllWhitespace(b []byte) bool { - for _, c := range b { - if !IsWhitespace(c) { - return false - } - } - return true -} - -// TrimWhitespace removes any leading and trailing whitespace characters. -func TrimWhitespace(b []byte) []byte { - n := len(b) - start := n - for i := 0; i < n; i++ { - if !IsWhitespace(b[i]) { - start = i - break - } - } - end := n - for i := n - 1; i >= start; i-- { - if !IsWhitespace(b[i]) { - end = i + 1 - break - } - } - return b[start:end] -} - -// ReplaceMultipleWhitespace replaces character series of space, \n, \t, \f, \r into a single space or newline (when the serie contained a \n or \r). -func ReplaceMultipleWhitespace(b []byte) []byte { - j, k := 0, 0 // j is write position, k is start of next text section - for i := 0; i < len(b); i++ { - if IsWhitespace(b[i]) { - start := i - newline := IsNewline(b[i]) - i++ - for ; i < len(b) && IsWhitespace(b[i]); i++ { - if IsNewline(b[i]) { - newline = true - } - } - if newline { - b[start] = '\n' - } else { - b[start] = ' ' - } - if 1 < i-start { // more than one whitespace - if j == 0 { - j = start + 1 - } else { - j += copy(b[j:], b[k:start+1]) - } - k = i - } - } - } - if j == 0 { - return b - } else if j == 1 { // only if starts with whitespace - b[k-1] = b[0] - return b[k-1:] - } else if k < len(b) { - j += copy(b[j:], b[k:]) - } - return b[:j] -} - -// replaceEntities will replace in b at index i, assuming that b[i] == '&' and that i+3= '0' && b[j] <= '9' || b[j] >= 'a' && b[j] <= 'f' || b[j] >= 'A' && b[j] <= 'F'); j++ { - if b[j] <= '9' { - c = c<<4 + int(b[j]-'0') - } else if b[j] <= 'F' { - c = c<<4 + int(b[j]-'A') + 10 - } else if b[j] <= 'f' { - c = c<<4 + int(b[j]-'a') + 10 - } - } - if j <= i+3 || 10000 <= c { - return b, j - 1 - } - if c < 128 { - r = []byte{byte(c)} - } else { - r = append(r, '&', '#') - r = strconv.AppendInt(r, int64(c), 10) - r = append(r, ';') - } - } else { - c := 0 - for ; j < len(b) && c < 128 && b[j] >= '0' && b[j] <= '9'; j++ { - c = c*10 + int(b[j]-'0') - } - if j <= i+2 || 128 <= c { - return b, j - 1 - } - r = []byte{byte(c)} - } - } else { - for ; j < len(b) && j-i-1 <= MaxEntityLength && b[j] != ';'; j++ { - } - if j <= i+1 || len(b) <= j { - return b, j - 1 - } - - var ok bool - r, ok = entitiesMap[string(b[i+1:j])] - if !ok { - return b, j - } - } - - // j is at semicolon - n := j + 1 - i - if j < len(b) && b[j] == ';' && 2 < n { - if len(r) == 1 { - if q, ok := revEntitiesMap[r[0]]; ok { - if len(q) == len(b[i:j+1]) && bytes.Equal(q, b[i:j+1]) { - return b, j - } - r = q - } else if r[0] == '&' { - // check if for example & is followed by something that could potentially be an entity - k := j + 1 - if k < len(b) && b[k] == '#' { - k++ - } - for ; k < len(b) && k-j <= MaxEntityLength && (b[k] >= '0' && b[k] <= '9' || b[k] >= 'a' && b[k] <= 'z' || b[k] >= 'A' && b[k] <= 'Z'); k++ { - } - if k < len(b) && b[k] == ';' { - return b, k - } - } - } - - copy(b[i:], r) - copy(b[i+len(r):], b[j+1:]) - b = b[:len(b)-n+len(r)] - return b, i + len(r) - 1 - } - return b, i -} - -// ReplaceEntities replaces all occurrences of entites (such as ") to their respective unencoded bytes. -func ReplaceEntities(b []byte, entitiesMap map[string][]byte, revEntitiesMap map[byte][]byte) []byte { - for i := 0; i < len(b); i++ { - if b[i] == '&' && i+3 < len(b) { - b, i = replaceEntities(b, i, entitiesMap, revEntitiesMap) - } - } - return b -} - -// ReplaceMultipleWhitespaceAndEntities is a combination of ReplaceMultipleWhitespace and ReplaceEntities. It is faster than executing both sequentially. -func ReplaceMultipleWhitespaceAndEntities(b []byte, entitiesMap map[string][]byte, revEntitiesMap map[byte][]byte) []byte { - j, k := 0, 0 // j is write position, k is start of next text section - for i := 0; i < len(b); i++ { - if IsWhitespace(b[i]) { - start := i - newline := IsNewline(b[i]) - i++ - for ; i < len(b) && IsWhitespace(b[i]); i++ { - if IsNewline(b[i]) { - newline = true - } - } - if newline { - b[start] = '\n' - } else { - b[start] = ' ' - } - if 1 < i-start { // more than one whitespace - if j == 0 { - j = start + 1 - } else { - j += copy(b[j:], b[k:start+1]) - } - k = i - } - } - if i+3 < len(b) && b[i] == '&' { - b, i = replaceEntities(b, i, entitiesMap, revEntitiesMap) - } - } - if j == 0 { - return b - } else if j == 1 { // only if starts with whitespace - b[k-1] = b[0] - return b[k-1:] - } else if k < len(b) { - j += copy(b[j:], b[k:]) - } - return b[:j] -} - -func DecodeURL(b []byte) []byte { - for i := 0; i < len(b); i++ { - if b[i] == '%' && i+2 < len(b) { - j := i + 1 - c := 0 - for ; j < i+3 && (b[j] >= '0' && b[j] <= '9' || b[j] >= 'a' && b[j] <= 'z' || b[j] >= 'A' && b[j] <= 'Z'); j++ { - if b[j] <= '9' { - c = c<<4 + int(b[j]-'0') - } else if b[j] <= 'F' { - c = c<<4 + int(b[j]-'A') + 10 - } else if b[j] <= 'f' { - c = c<<4 + int(b[j]-'a') + 10 - } - } - if j == i+3 && c < 128 { - b[i] = byte(c) - b = append(b[:i+1], b[i+3:]...) - } - } else if b[i] == '+' { - b[i] = ' ' - } - } - return b -} - -var URLEncodingTable = [256]bool{ - // ASCII - true, true, true, true, true, true, true, true, - true, true, true, true, true, true, true, true, - true, true, true, true, true, true, true, true, - true, true, true, true, true, true, true, true, - - false, false, true, true, true, true, true, false, // space, !, ' - false, false, false, true, true, false, false, true, // (, ), *, -, . - false, false, false, false, false, false, false, false, // 0, 1, 2, 3, 4, 5, 6, 7 - false, false, true, true, true, true, true, true, // 8, 9 - - true, false, false, false, false, false, false, false, // A, B, C, D, E, F, G - false, false, false, false, false, false, false, false, // H, I, J, K, L, M, N, O - false, false, false, false, false, false, false, false, // P, Q, R, S, T, U, V, W - false, false, false, true, true, true, true, false, // X, Y, Z, _ - - true, false, false, false, false, false, false, false, // a, b, c, d, e, f, g - false, false, false, false, false, false, false, false, // h, i, j, k, l, m, n, o - false, false, false, false, false, false, false, false, // p, q, r, s, t, u, v, w - false, false, false, true, true, true, false, true, // x, y, z, ~ - - // non-ASCII - true, true, true, true, true, true, true, true, - true, true, true, true, true, true, true, true, - true, true, true, true, true, true, true, true, - true, true, true, true, true, true, true, true, - - true, true, true, true, true, true, true, true, - true, true, true, true, true, true, true, true, - true, true, true, true, true, true, true, true, - true, true, true, true, true, true, true, true, - - true, true, true, true, true, true, true, true, - true, true, true, true, true, true, true, true, - true, true, true, true, true, true, true, true, - true, true, true, true, true, true, true, true, - - true, true, true, true, true, true, true, true, - true, true, true, true, true, true, true, true, - true, true, true, true, true, true, true, true, - true, true, true, true, true, true, true, true, -} - -func EncodeURL(b []byte, table [256]bool) []byte { - for i := 0; i < len(b); i++ { - c := b[i] - if table[c] { - b = append(b, 0, 0) - copy(b[i+3:], b[i+1:]) - b[i+0] = '%' - b[i+1] = "0123456789ABCDEF"[c>>4] - b[i+2] = "0123456789ABCDEF"[c&15] - } else if c == ' ' { - b[i] = '+' - } - } - return b -} diff --git a/vendor/github.com/tdewolff/parse/v2/xml/README.md b/vendor/github.com/tdewolff/parse/v2/xml/README.md deleted file mode 100644 index 60fe3f531024b..0000000000000 --- a/vendor/github.com/tdewolff/parse/v2/xml/README.md +++ /dev/null @@ -1,101 +0,0 @@ -# XML [![GoDoc](http://godoc.org/github.com/tdewolff/parse/xml?status.svg)](http://godoc.org/github.com/tdewolff/parse/xml) - -This package is an XML lexer written in [Go][1]. It follows the specification at [Extensible Markup Language (XML) 1.0 (Fifth Edition)](http://www.w3.org/TR/REC-xml/). The lexer takes an io.Reader and converts it into tokens until the EOF. - -## Installation -Run the following command - - go get -u github.com/tdewolff/parse/v2/xml - -or add the following import and run project with `go get` - - import "github.com/tdewolff/parse/v2/xml" - -## Lexer -### Usage -The following initializes a new Lexer with io.Reader `r`: -``` go -l := xml.NewLexer(r) -``` - -To tokenize until EOF an error, use: -``` go -for { - tt, data := l.Next() - switch tt { - case xml.ErrorToken: - // error or EOF set in l.Err() - return - case xml.StartTagToken: - // ... - for { - ttAttr, dataAttr := l.Next() - if ttAttr != xml.AttributeToken { - // handle StartTagCloseToken/StartTagCloseVoidToken/StartTagClosePIToken - break - } - // ... - } - case xml.EndTagToken: - // ... - } -} -``` - -All tokens: -``` go -ErrorToken TokenType = iota // extra token when errors occur -CommentToken -CDATAToken -StartTagToken -StartTagCloseToken -StartTagCloseVoidToken -StartTagClosePIToken -EndTagToken -AttributeToken -TextToken -``` - -### Examples -``` go -package main - -import ( - "os" - - "github.com/tdewolff/parse/v2/xml" -) - -// Tokenize XML from stdin. -func main() { - l := xml.NewLexer(os.Stdin) - for { - tt, data := l.Next() - switch tt { - case xml.ErrorToken: - if l.Err() != io.EOF { - fmt.Println("Error on line", l.Line(), ":", l.Err()) - } - return - case xml.StartTagToken: - fmt.Println("Tag", string(data)) - for { - ttAttr, dataAttr := l.Next() - if ttAttr != xml.AttributeToken { - break - } - - key := dataAttr - val := l.AttrVal() - fmt.Println("Attribute", string(key), "=", string(val)) - } - // ... - } - } -} -``` - -## License -Released under the [MIT license](https://github.com/tdewolff/parse/blob/master/LICENSE.md). - -[1]: http://golang.org/ "Go Language" diff --git a/vendor/github.com/tdewolff/parse/v2/xml/lex.go b/vendor/github.com/tdewolff/parse/v2/xml/lex.go deleted file mode 100644 index 9a79432c92ef4..0000000000000 --- a/vendor/github.com/tdewolff/parse/v2/xml/lex.go +++ /dev/null @@ -1,352 +0,0 @@ -// Package xml is an XML1.0 lexer following the specifications at http://www.w3.org/TR/xml/. -package xml - -import ( - "io" - "strconv" - - "github.com/tdewolff/parse/v2" - "github.com/tdewolff/parse/v2/buffer" -) - -// TokenType determines the type of token, eg. a number or a semicolon. -type TokenType uint32 - -// TokenType values. -const ( - ErrorToken TokenType = iota // extra token when errors occur - CommentToken - DOCTYPEToken - CDATAToken - StartTagToken - StartTagPIToken - StartTagCloseToken - StartTagCloseVoidToken - StartTagClosePIToken - EndTagToken - AttributeToken - TextToken -) - -// String returns the string representation of a TokenType. -func (tt TokenType) String() string { - switch tt { - case ErrorToken: - return "Error" - case CommentToken: - return "Comment" - case DOCTYPEToken: - return "DOCTYPE" - case CDATAToken: - return "CDATA" - case StartTagToken: - return "StartTag" - case StartTagPIToken: - return "StartTagPI" - case StartTagCloseToken: - return "StartTagClose" - case StartTagCloseVoidToken: - return "StartTagCloseVoid" - case StartTagClosePIToken: - return "StartTagClosePI" - case EndTagToken: - return "EndTag" - case AttributeToken: - return "Attribute" - case TextToken: - return "Text" - } - return "Invalid(" + strconv.Itoa(int(tt)) + ")" -} - -//////////////////////////////////////////////////////////////// - -// Lexer is the state for the lexer. -type Lexer struct { - r *buffer.Lexer - err error - - inTag bool - - text []byte - attrVal []byte -} - -// NewLexer returns a new Lexer for a given io.Reader. -func NewLexer(r io.Reader) *Lexer { - return &Lexer{ - r: buffer.NewLexer(r), - } -} - -// Err returns the error encountered during lexing, this is often io.EOF but also other errors can be returned. -func (l *Lexer) Err() error { - if l.err != nil { - return l.err - } - return l.r.Err() -} - -// Restore restores the NULL byte at the end of the buffer. -func (l *Lexer) Restore() { - l.r.Restore() -} - -// Offset returns the current position in the input stream. -func (l *Lexer) Offset() int { - return l.r.Offset() -} - -// Text returns the textual representation of a token. This excludes delimiters and additional leading/trailing characters. -func (l *Lexer) Text() []byte { - return l.text -} - -// AttrVal returns the attribute value when an AttributeToken was returned from Next. -func (l *Lexer) AttrVal() []byte { - return l.attrVal -} - -// Next returns the next Token. It returns ErrorToken when an error was encountered. Using Err() one can retrieve the error message. -func (l *Lexer) Next() (TokenType, []byte) { - l.text = nil - var c byte - if l.inTag { - l.attrVal = nil - for { // before attribute name state - if c = l.r.Peek(0); c == ' ' || c == '\t' || c == '\n' || c == '\r' { - l.r.Move(1) - continue - } - break - } - if c == 0 { - if l.r.Err() == nil { - l.err = parse.NewErrorLexer(l.r, "XML parse error: unexpected NULL character") - } - return ErrorToken, nil - } else if c != '>' && (c != '/' && c != '?' || l.r.Peek(1) != '>') { - return AttributeToken, l.shiftAttribute() - } - l.r.Skip() - l.inTag = false - if c == '/' { - l.r.Move(2) - return StartTagCloseVoidToken, l.r.Shift() - } else if c == '?' { - l.r.Move(2) - return StartTagClosePIToken, l.r.Shift() - } else { - l.r.Move(1) - return StartTagCloseToken, l.r.Shift() - } - } - - for { - c = l.r.Peek(0) - if c == '<' { - if l.r.Pos() > 0 { - l.text = l.r.Shift() - return TextToken, l.text - } - c = l.r.Peek(1) - if c == '/' { - l.r.Move(2) - return EndTagToken, l.shiftEndTag() - } else if c == '!' { - l.r.Move(2) - if l.at('-', '-') { - l.r.Move(2) - return CommentToken, l.shiftCommentText() - } else if l.at('[', 'C', 'D', 'A', 'T', 'A', '[') { - l.r.Move(7) - return CDATAToken, l.shiftCDATAText() - } else if l.at('D', 'O', 'C', 'T', 'Y', 'P', 'E') { - l.r.Move(7) - return DOCTYPEToken, l.shiftDOCTYPEText() - } - l.r.Move(-2) - } else if c == '?' { - l.r.Move(2) - l.inTag = true - return StartTagPIToken, l.shiftStartTag() - } - l.r.Move(1) - l.inTag = true - return StartTagToken, l.shiftStartTag() - } else if c == 0 { - if l.r.Pos() > 0 { - l.text = l.r.Shift() - return TextToken, l.text - } - if l.r.Err() == nil { - l.err = parse.NewErrorLexer(l.r, "XML parse error: unexpected NULL character") - } - return ErrorToken, nil - } - l.r.Move(1) - } -} - -//////////////////////////////////////////////////////////////// - -// The following functions follow the specifications at http://www.w3.org/html/wg/drafts/html/master/syntax.html - -func (l *Lexer) shiftDOCTYPEText() []byte { - inString := false - inBrackets := false - for { - c := l.r.Peek(0) - if c == '"' { - inString = !inString - } else if (c == '[' || c == ']') && !inString { - inBrackets = (c == '[') - } else if c == '>' && !inString && !inBrackets { - l.text = l.r.Lexeme()[9:] - l.r.Move(1) - return l.r.Shift() - } else if c == 0 { - l.text = l.r.Lexeme()[9:] - return l.r.Shift() - } - l.r.Move(1) - } -} - -func (l *Lexer) shiftCDATAText() []byte { - for { - c := l.r.Peek(0) - if c == ']' && l.r.Peek(1) == ']' && l.r.Peek(2) == '>' { - l.text = l.r.Lexeme()[9:] - l.r.Move(3) - return l.r.Shift() - } else if c == 0 { - l.text = l.r.Lexeme()[9:] - return l.r.Shift() - } - l.r.Move(1) - } -} - -func (l *Lexer) shiftCommentText() []byte { - for { - c := l.r.Peek(0) - if c == '-' && l.r.Peek(1) == '-' && l.r.Peek(2) == '>' { - l.text = l.r.Lexeme()[4:] - l.r.Move(3) - return l.r.Shift() - } else if c == 0 { - return l.r.Shift() - } - l.r.Move(1) - } -} - -func (l *Lexer) shiftStartTag() []byte { - nameStart := l.r.Pos() - for { - if c := l.r.Peek(0); c == ' ' || c == '>' || (c == '/' || c == '?') && l.r.Peek(1) == '>' || c == '\t' || c == '\n' || c == '\r' || c == 0 { - break - } - l.r.Move(1) - } - l.text = l.r.Lexeme()[nameStart:] - return l.r.Shift() -} - -func (l *Lexer) shiftAttribute() []byte { - nameStart := l.r.Pos() - var c byte - for { // attribute name state - if c = l.r.Peek(0); c == ' ' || c == '=' || c == '>' || (c == '/' || c == '?') && l.r.Peek(1) == '>' || c == '\t' || c == '\n' || c == '\r' || c == 0 { - break - } - l.r.Move(1) - } - nameEnd := l.r.Pos() - for { // after attribute name state - if c = l.r.Peek(0); c == ' ' || c == '\t' || c == '\n' || c == '\r' { - l.r.Move(1) - continue - } - break - } - if c == '=' { - l.r.Move(1) - for { // before attribute value state - if c = l.r.Peek(0); c == ' ' || c == '\t' || c == '\n' || c == '\r' { - l.r.Move(1) - continue - } - break - } - attrPos := l.r.Pos() - delim := c - if delim == '"' || delim == '\'' { // attribute value single- and double-quoted state - l.r.Move(1) - for { - c = l.r.Peek(0) - if c == delim { - l.r.Move(1) - break - } else if c == 0 { - break - } - l.r.Move(1) - if c == '\t' || c == '\n' || c == '\r' { - l.r.Lexeme()[l.r.Pos()-1] = ' ' - } - } - } else { // attribute value unquoted state - for { - if c = l.r.Peek(0); c == ' ' || c == '>' || (c == '/' || c == '?') && l.r.Peek(1) == '>' || c == '\t' || c == '\n' || c == '\r' || c == 0 { - break - } - l.r.Move(1) - } - } - l.attrVal = l.r.Lexeme()[attrPos:] - } else { - l.r.Rewind(nameEnd) - l.attrVal = nil - } - l.text = l.r.Lexeme()[nameStart:nameEnd] - return l.r.Shift() -} - -func (l *Lexer) shiftEndTag() []byte { - for { - c := l.r.Peek(0) - if c == '>' { - l.text = l.r.Lexeme()[2:] - l.r.Move(1) - break - } else if c == 0 { - l.text = l.r.Lexeme()[2:] - break - } - l.r.Move(1) - } - - end := len(l.text) - for end > 0 { - if c := l.text[end-1]; c == ' ' || c == '\t' || c == '\n' || c == '\r' { - end-- - continue - } - break - } - l.text = l.text[:end] - return l.r.Shift() -} - -//////////////////////////////////////////////////////////////// - -func (l *Lexer) at(b ...byte) bool { - for i, c := range b { - if l.r.Peek(i) != c { - return false - } - } - return true -} diff --git a/vendor/github.com/tdewolff/parse/v2/xml/util.go b/vendor/github.com/tdewolff/parse/v2/xml/util.go deleted file mode 100644 index 766549557a06e..0000000000000 --- a/vendor/github.com/tdewolff/parse/v2/xml/util.go +++ /dev/null @@ -1,94 +0,0 @@ -package xml - -var ( - ltEntityBytes = []byte("<") - ampEntityBytes = []byte("&") - singleQuoteEntityBytes = []byte("'") - doubleQuoteEntityBytes = []byte(""") -) - -// Entities are all named character entities. -var EntitiesMap = map[string][]byte{ - "apos": []byte("'"), - "gt": []byte(">"), - "quot": []byte("\""), -} - -// EscapeAttrVal returns the escape attribute value bytes without quotes. -func EscapeAttrVal(buf *[]byte, b []byte) []byte { - singles := 0 - doubles := 0 - for _, c := range b { - if c == '"' { - doubles++ - } else if c == '\'' { - singles++ - } - } - - n := len(b) + 2 - var quote byte - var escapedQuote []byte - if doubles > singles { - n += singles * 4 - quote = '\'' - escapedQuote = singleQuoteEntityBytes - } else { - n += doubles * 4 - quote = '"' - escapedQuote = doubleQuoteEntityBytes - } - if n > cap(*buf) { - *buf = make([]byte, 0, n) // maximum size, not actual size - } - t := (*buf)[:n] // maximum size, not actual size - t[0] = quote - j := 1 - start := 0 - for i, c := range b { - if c == quote { - j += copy(t[j:], b[start:i]) - j += copy(t[j:], escapedQuote) - start = i + 1 - } - } - j += copy(t[j:], b[start:]) - t[j] = quote - return t[:j+1] -} - -// EscapeCDATAVal returns the escaped text bytes. -func EscapeCDATAVal(buf *[]byte, b []byte) ([]byte, bool) { - n := 0 - for _, c := range b { - if c == '<' || c == '&' { - if c == '<' { - n += 3 // < - } else { - n += 4 // & - } - if n > len("") { - return b, false - } - } - } - if len(b)+n > cap(*buf) { - *buf = make([]byte, 0, len(b)+n) - } - t := (*buf)[:len(b)+n] - j := 0 - start := 0 - for i, c := range b { - if c == '<' { - j += copy(t[j:], b[start:i]) - j += copy(t[j:], ltEntityBytes) - start = i + 1 - } else if c == '&' { - j += copy(t[j:], b[start:i]) - j += copy(t[j:], ampEntityBytes) - start = i + 1 - } - } - j += copy(t[j:], b[start:]) - return t[:j], true -} diff --git a/vendor/modules.txt b/vendor/modules.txt index bf45ee17b4711..729e7f88fd0c9 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -608,18 +608,6 @@ github.com/syndtr/goleveldb/leveldb/opt github.com/syndtr/goleveldb/leveldb/storage github.com/syndtr/goleveldb/leveldb/table github.com/syndtr/goleveldb/leveldb/util -# github.com/tdewolff/minify/v2 v2.7.3 -## explicit -github.com/tdewolff/minify/v2 -github.com/tdewolff/minify/v2/css -github.com/tdewolff/minify/v2/svg -github.com/tdewolff/minify/v2/xml -# github.com/tdewolff/parse/v2 v2.4.2 -github.com/tdewolff/parse/v2 -github.com/tdewolff/parse/v2/buffer -github.com/tdewolff/parse/v2/css -github.com/tdewolff/parse/v2/strconv -github.com/tdewolff/parse/v2/xml # github.com/tecbot/gorocksdb v0.0.0-20181010114359-8752a9433481 ## explicit # github.com/tinylib/msgp v1.1.1 @@ -678,8 +666,6 @@ go.mongodb.org/mongo-driver/bson/bsonrw go.mongodb.org/mongo-driver/bson/bsontype go.mongodb.org/mongo-driver/bson/primitive go.mongodb.org/mongo-driver/x/bsonx/bsoncore -# golang.org/dl v0.0.0-20200414231856-f86334ee252a -## explicit # golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073 ## explicit golang.org/x/crypto/acme