[chore]: Bump github.com/tdewolff/minify/v2 from 2.20.19 to 2.20.20 (#2875)
This commit is contained in:
parent
d3bac8bbec
commit
bfc21e4850
4
go.mod
4
go.mod
|
@ -53,7 +53,7 @@ require (
|
||||||
github.com/superseriousbusiness/activity v1.6.0-gts.0.20240408131430-247f7f7110f0
|
github.com/superseriousbusiness/activity v1.6.0-gts.0.20240408131430-247f7f7110f0
|
||||||
github.com/superseriousbusiness/httpsig v1.2.0-SSB
|
github.com/superseriousbusiness/httpsig v1.2.0-SSB
|
||||||
github.com/superseriousbusiness/oauth2/v4 v4.3.2-SSB.0.20230227143000-f4900831d6c8
|
github.com/superseriousbusiness/oauth2/v4 v4.3.2-SSB.0.20230227143000-f4900831d6c8
|
||||||
github.com/tdewolff/minify/v2 v2.20.19
|
github.com/tdewolff/minify/v2 v2.20.20
|
||||||
github.com/technologize/otel-go-contrib v1.1.1
|
github.com/technologize/otel-go-contrib v1.1.1
|
||||||
github.com/tomnomnom/linkheader v0.0.0-20180905144013-02ca5825eb80
|
github.com/tomnomnom/linkheader v0.0.0-20180905144013-02ca5825eb80
|
||||||
github.com/ulule/limiter/v3 v3.11.2
|
github.com/ulule/limiter/v3 v3.11.2
|
||||||
|
@ -196,7 +196,7 @@ require (
|
||||||
github.com/subosito/gotenv v1.6.0 // indirect
|
github.com/subosito/gotenv v1.6.0 // indirect
|
||||||
github.com/superseriousbusiness/go-jpeg-image-structure/v2 v2.0.0-20220321154430-d89a106fdabe // indirect
|
github.com/superseriousbusiness/go-jpeg-image-structure/v2 v2.0.0-20220321154430-d89a106fdabe // indirect
|
||||||
github.com/superseriousbusiness/go-png-image-structure/v2 v2.0.1-SSB // indirect
|
github.com/superseriousbusiness/go-png-image-structure/v2 v2.0.1-SSB // indirect
|
||||||
github.com/tdewolff/parse/v2 v2.7.12 // indirect
|
github.com/tdewolff/parse/v2 v2.7.13 // indirect
|
||||||
github.com/tmthrgd/go-hex v0.0.0-20190904060850-447a3041c3bc // indirect
|
github.com/tmthrgd/go-hex v0.0.0-20190904060850-447a3041c3bc // indirect
|
||||||
github.com/toqueteos/webbrowser v1.2.0 // indirect
|
github.com/toqueteos/webbrowser v1.2.0 // indirect
|
||||||
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
|
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
|
||||||
|
|
8
go.sum
8
go.sum
|
@ -552,10 +552,10 @@ github.com/superseriousbusiness/httpsig v1.2.0-SSB h1:BinBGKbf2LSuVT5+MuH0XynHN9
|
||||||
github.com/superseriousbusiness/httpsig v1.2.0-SSB/go.mod h1:+rxfATjFaDoDIVaJOTSP0gj6UrbicaYPEptvCLC9F28=
|
github.com/superseriousbusiness/httpsig v1.2.0-SSB/go.mod h1:+rxfATjFaDoDIVaJOTSP0gj6UrbicaYPEptvCLC9F28=
|
||||||
github.com/superseriousbusiness/oauth2/v4 v4.3.2-SSB.0.20230227143000-f4900831d6c8 h1:nTIhuP157oOFcscuoK1kCme1xTeGIzztSw70lX9NrDQ=
|
github.com/superseriousbusiness/oauth2/v4 v4.3.2-SSB.0.20230227143000-f4900831d6c8 h1:nTIhuP157oOFcscuoK1kCme1xTeGIzztSw70lX9NrDQ=
|
||||||
github.com/superseriousbusiness/oauth2/v4 v4.3.2-SSB.0.20230227143000-f4900831d6c8/go.mod h1:uYC/W92oVRJ49Vh1GcvTqpeFqHi+Ovrl2sMllQWRAEo=
|
github.com/superseriousbusiness/oauth2/v4 v4.3.2-SSB.0.20230227143000-f4900831d6c8/go.mod h1:uYC/W92oVRJ49Vh1GcvTqpeFqHi+Ovrl2sMllQWRAEo=
|
||||||
github.com/tdewolff/minify/v2 v2.20.19 h1:tX0SR0LUrIqGoLjXnkIzRSIbKJ7PaNnSENLD4CyH6Xo=
|
github.com/tdewolff/minify/v2 v2.20.20 h1:vhULb+VsW2twkplgsawAoUY957efb+EdiZ7zu5fUhhk=
|
||||||
github.com/tdewolff/minify/v2 v2.20.19/go.mod h1:ulkFoeAVWMLEyjuDz1ZIWOA31g5aWOawCFRp9R/MudM=
|
github.com/tdewolff/minify/v2 v2.20.20/go.mod h1:GYaLXFpIIwsX99apQHXfGdISUdlA98wmaoWxjT9C37k=
|
||||||
github.com/tdewolff/parse/v2 v2.7.12 h1:tgavkHc2ZDEQVKy1oWxwIyh5bP4F5fEh/JmBwPP/3LQ=
|
github.com/tdewolff/parse/v2 v2.7.13 h1:iSiwOUkCYLNfapHoqdLcqZVgvQ0jrsao8YYKP/UJYTI=
|
||||||
github.com/tdewolff/parse/v2 v2.7.12/go.mod h1:3FbJWZp3XT9OWVN3Hmfp0p/a08v4h8J9W1aghka0soA=
|
github.com/tdewolff/parse/v2 v2.7.13/go.mod h1:3FbJWZp3XT9OWVN3Hmfp0p/a08v4h8J9W1aghka0soA=
|
||||||
github.com/tdewolff/test v1.0.11-0.20231101010635-f1265d231d52/go.mod h1:6DAvZliBAAnD7rhVgwaM7DE5/d9NMOAJ09SqYqeK4QE=
|
github.com/tdewolff/test v1.0.11-0.20231101010635-f1265d231d52/go.mod h1:6DAvZliBAAnD7rhVgwaM7DE5/d9NMOAJ09SqYqeK4QE=
|
||||||
github.com/tdewolff/test v1.0.11-0.20240106005702-7de5f7df4739 h1:IkjBCtQOOjIn03u/dMQK9g+Iw9ewps4mCl1nB8Sscbo=
|
github.com/tdewolff/test v1.0.11-0.20240106005702-7de5f7df4739 h1:IkjBCtQOOjIn03u/dMQK9g+Iw9ewps4mCl1nB8Sscbo=
|
||||||
github.com/tdewolff/test v1.0.11-0.20240106005702-7de5f7df4739/go.mod h1:XPuWBzvdUzhCuxWO1ojpXsyzsA5bFoS3tO/Q3kFuTG8=
|
github.com/tdewolff/test v1.0.11-0.20240106005702-7de5f7df4739/go.mod h1:XPuWBzvdUzhCuxWO1ojpXsyzsA5bFoS3tO/Q3kFuTG8=
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
# Minify <a name="minify"></a> [![API reference](https://img.shields.io/badge/godoc-reference-5272B4)](https://pkg.go.dev/github.com/tdewolff/minify/v2?tab=doc) [![Go Report Card](https://goreportcard.com/badge/github.com/tdewolff/minify)](https://goreportcard.com/report/github.com/tdewolff/minify) [![codecov](https://codecov.io/gh/tdewolff/minify/branch/master/graph/badge.svg?token=Cr7r2EKPj2)](https://codecov.io/gh/tdewolff/minify) [![Donate](https://img.shields.io/badge/patreon-donate-DFB317)](https://www.patreon.com/tdewolff)
|
# Minify <a name="minify"></a> [![API reference](https://img.shields.io/badge/godoc-reference-5272B4)](https://pkg.go.dev/github.com/tdewolff/minify/v2?tab=doc) [![Go Report Card](https://goreportcard.com/badge/github.com/tdewolff/minify)](https://goreportcard.com/report/github.com/tdewolff/minify) [![codecov](https://codecov.io/gh/tdewolff/minify/branch/master/graph/badge.svg?token=Cr7r2EKPj2)](https://codecov.io/gh/tdewolff/minify)
|
||||||
|
|
||||||
**[Online demo](https://go.tacodewolff.nl/minify)** if you need to minify files *now*.
|
**[Online demo](https://go.tacodewolff.nl/minify)** if you need to minify files *now*.
|
||||||
|
|
||||||
|
@ -19,11 +19,10 @@ Minify is a minifier package written in [Go][1]. It provides HTML5, CSS3, JS, JS
|
||||||
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, ...).
|
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, ...).
|
||||||
|
|
||||||
### Sponsors
|
### Sponsors
|
||||||
|
I'm actively looking for support in the form of donations or sponsorships to keep developing this library and highly appreciate any gesture. Please see the Sponsors button in GitHub for ways to contribute, or contact me directly.
|
||||||
|
|
||||||
[![SiteGround](https://www.siteground.com/img/downloads/siteground-logo-black-transparent-vector.svg)](https://www.siteground.com/)
|
[![SiteGround](https://www.siteground.com/img/downloads/siteground-logo-black-transparent-vector.svg)](https://www.siteground.com/)
|
||||||
|
|
||||||
Please see https://www.patreon.com/tdewolff for ways to contribute, otherwise please contact me directly!
|
|
||||||
|
|
||||||
#### Table of Contents
|
#### Table of Contents
|
||||||
|
|
||||||
- [Minify](#minify)
|
- [Minify](#minify)
|
||||||
|
|
|
@ -5,6 +5,7 @@ import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"errors"
|
"errors"
|
||||||
|
"strconv"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -235,3 +236,307 @@ func QuoteEntity(b []byte) (quote byte, n int) {
|
||||||
}
|
}
|
||||||
return 0, 0
|
return 0, 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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<len(b). The returned int will be the last character of the entity, so that the next iteration can safely do i++ to continue and not miss any entitites.
|
||||||
|
func replaceEntities(b []byte, i int, entitiesMap map[string][]byte, revEntitiesMap map[byte][]byte) ([]byte, int) {
|
||||||
|
const MaxEntityLength = 31 // longest HTML entity: CounterClockwiseContourIntegral
|
||||||
|
var r []byte
|
||||||
|
j := i + 1
|
||||||
|
if b[j] == '#' {
|
||||||
|
j++
|
||||||
|
if b[j] == 'x' {
|
||||||
|
j++
|
||||||
|
c := 0
|
||||||
|
for ; j < len(b) && (b[j] >= '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] >= '0' && b[k] <= '9' || b[k] >= 'a' && b[k] <= 'z' || b[k] >= 'A' && b[k] <= 'Z' || 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]
|
||||||
|
}
|
||||||
|
|
||||||
|
// URLEncodingTable is a charmap for which characters need escaping in the URL encoding scheme
|
||||||
|
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,
|
||||||
|
|
||||||
|
true, false, true, true, true, true, true, false, // space, ", #, $, %, &
|
||||||
|
false, false, false, true, true, false, false, true, // +, comma, /
|
||||||
|
false, false, false, false, false, false, false, false,
|
||||||
|
false, false, true, true, true, true, true, true, // :, ;, <, =, >, ?
|
||||||
|
|
||||||
|
true, false, false, false, false, false, false, false, // @
|
||||||
|
false, false, false, false, false, false, false, false,
|
||||||
|
false, false, false, false, false, false, false, false,
|
||||||
|
false, false, false, true, true, true, true, false, // [, \, ], ^
|
||||||
|
|
||||||
|
true, false, false, false, false, false, false, false, // `
|
||||||
|
false, false, false, false, false, false, false, false,
|
||||||
|
false, false, false, false, false, false, false, false,
|
||||||
|
false, false, false, true, true, true, false, true, // {, |, }, DEL
|
||||||
|
|
||||||
|
// 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,
|
||||||
|
}
|
||||||
|
|
||||||
|
// DataURIEncodingTable is a charmap for which characters need escaping in the Data URI encoding scheme
|
||||||
|
// Escape only non-printable characters, unicode and %, #, &.
|
||||||
|
// IE11 additionally requires encoding of \, [, ], ", <, >, `, {, }, |, ^ which is not required by Chrome, Firefox, Opera, Edge, Safari, Yandex
|
||||||
|
// To pass the HTML validator, restricted URL characters must be escaped: non-printable characters, space, <, >, #, %, "
|
||||||
|
var DataURIEncodingTable = [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,
|
||||||
|
|
||||||
|
true, false, true, true, false, true, true, false, // space, ", #, %, &
|
||||||
|
false, false, false, false, false, false, false, false,
|
||||||
|
false, false, false, false, false, false, false, false,
|
||||||
|
false, false, false, false, true, false, true, false, // <, >
|
||||||
|
|
||||||
|
false, false, false, false, false, false, false, false,
|
||||||
|
false, false, false, false, false, false, false, false,
|
||||||
|
false, false, false, false, false, false, false, false,
|
||||||
|
false, false, false, true, true, true, true, false, // [, \, ], ^
|
||||||
|
|
||||||
|
true, false, false, false, false, false, false, false, // `
|
||||||
|
false, false, false, false, false, false, false, false,
|
||||||
|
false, false, false, false, false, false, false, false,
|
||||||
|
false, false, false, true, true, true, false, true, // {, |, }, DEL
|
||||||
|
|
||||||
|
// 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,
|
||||||
|
}
|
||||||
|
|
||||||
|
// EncodeURL encodes bytes using the URL encoding scheme
|
||||||
|
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]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
// DecodeURL decodes an URL encoded using the URL encoding scheme
|
||||||
|
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] <= '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 && c < 128 {
|
||||||
|
b[i] = byte(c)
|
||||||
|
b = append(b[:i+1], b[i+3:]...)
|
||||||
|
}
|
||||||
|
} else if b[i] == '+' {
|
||||||
|
b[i] = ' '
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
|
@ -1,9 +1,8 @@
|
||||||
package parse
|
package parse
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"strconv"
|
"io"
|
||||||
"unicode"
|
"unicode"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -176,306 +175,38 @@ func TrimWhitespace(b []byte) []byte {
|
||||||
return b[start:end]
|
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).
|
type Indenter struct {
|
||||||
func ReplaceMultipleWhitespace(b []byte) []byte {
|
io.Writer
|
||||||
j, k := 0, 0 // j is write position, k is start of next text section
|
b []byte
|
||||||
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<len(b). The returned int will be the last character of the entity, so that the next iteration can safely do i++ to continue and not miss any entitites.
|
func NewIndenter(w io.Writer, n int) Indenter {
|
||||||
func replaceEntities(b []byte, i int, entitiesMap map[string][]byte, revEntitiesMap map[byte][]byte) ([]byte, int) {
|
if wi, ok := w.(Indenter); ok {
|
||||||
const MaxEntityLength = 31 // longest HTML entity: CounterClockwiseContourIntegral
|
w = wi.Writer
|
||||||
var r []byte
|
n += len(wi.b)
|
||||||
j := i + 1
|
|
||||||
if b[j] == '#' {
|
|
||||||
j++
|
|
||||||
if b[j] == 'x' {
|
|
||||||
j++
|
|
||||||
c := 0
|
|
||||||
for ; j < len(b) && (b[j] >= '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
|
b := make([]byte, n)
|
||||||
r, ok = entitiesMap[string(b[i+1:j])]
|
for i := range b {
|
||||||
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] >= '0' && b[k] <= '9' || b[k] >= 'a' && b[k] <= 'z' || b[k] >= 'A' && b[k] <= 'Z' || 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]
|
|
||||||
}
|
|
||||||
|
|
||||||
// URLEncodingTable is a charmap for which characters need escaping in the URL encoding scheme
|
|
||||||
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,
|
|
||||||
|
|
||||||
true, false, true, true, true, true, true, false, // space, ", #, $, %, &
|
|
||||||
false, false, false, true, true, false, false, true, // +, comma, /
|
|
||||||
false, false, false, false, false, false, false, false,
|
|
||||||
false, false, true, true, true, true, true, true, // :, ;, <, =, >, ?
|
|
||||||
|
|
||||||
true, false, false, false, false, false, false, false, // @
|
|
||||||
false, false, false, false, false, false, false, false,
|
|
||||||
false, false, false, false, false, false, false, false,
|
|
||||||
false, false, false, true, true, true, true, false, // [, \, ], ^
|
|
||||||
|
|
||||||
true, false, false, false, false, false, false, false, // `
|
|
||||||
false, false, false, false, false, false, false, false,
|
|
||||||
false, false, false, false, false, false, false, false,
|
|
||||||
false, false, false, true, true, true, false, true, // {, |, }, DEL
|
|
||||||
|
|
||||||
// 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,
|
|
||||||
}
|
|
||||||
|
|
||||||
// DataURIEncodingTable is a charmap for which characters need escaping in the Data URI encoding scheme
|
|
||||||
// Escape only non-printable characters, unicode and %, #, &.
|
|
||||||
// IE11 additionally requires encoding of \, [, ], ", <, >, `, {, }, |, ^ which is not required by Chrome, Firefox, Opera, Edge, Safari, Yandex
|
|
||||||
// To pass the HTML validator, restricted URL characters must be escaped: non-printable characters, space, <, >, #, %, "
|
|
||||||
var DataURIEncodingTable = [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,
|
|
||||||
|
|
||||||
true, false, true, true, false, true, true, false, // space, ", #, %, &
|
|
||||||
false, false, false, false, false, false, false, false,
|
|
||||||
false, false, false, false, false, false, false, false,
|
|
||||||
false, false, false, false, true, false, true, false, // <, >
|
|
||||||
|
|
||||||
false, false, false, false, false, false, false, false,
|
|
||||||
false, false, false, false, false, false, false, false,
|
|
||||||
false, false, false, false, false, false, false, false,
|
|
||||||
false, false, false, true, true, true, true, false, // [, \, ], ^
|
|
||||||
|
|
||||||
true, false, false, false, false, false, false, false, // `
|
|
||||||
false, false, false, false, false, false, false, false,
|
|
||||||
false, false, false, false, false, false, false, false,
|
|
||||||
false, false, false, true, true, true, false, true, // {, |, }, DEL
|
|
||||||
|
|
||||||
// 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,
|
|
||||||
}
|
|
||||||
|
|
||||||
// EncodeURL encodes bytes using the URL encoding scheme
|
|
||||||
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]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return b
|
|
||||||
}
|
|
||||||
|
|
||||||
// DecodeURL decodes an URL encoded using the URL encoding scheme
|
|
||||||
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] <= '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 && c < 128 {
|
|
||||||
b[i] = byte(c)
|
|
||||||
b = append(b[:i+1], b[i+3:]...)
|
|
||||||
}
|
|
||||||
} else if b[i] == '+' {
|
|
||||||
b[i] = ' '
|
b[i] = ' '
|
||||||
}
|
}
|
||||||
|
return Indenter{
|
||||||
|
Writer: w,
|
||||||
|
b: b,
|
||||||
}
|
}
|
||||||
return b
|
}
|
||||||
|
|
||||||
|
func (in Indenter) Write(b []byte) (int, error) {
|
||||||
|
n, j := 0, 0
|
||||||
|
for i, c := range b {
|
||||||
|
if c == '\n' {
|
||||||
|
m, _ := in.Writer.Write(b[j : i+1])
|
||||||
|
n += m
|
||||||
|
m, _ = in.Writer.Write(in.b)
|
||||||
|
n += m
|
||||||
|
j = i + 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
m, err := in.Writer.Write(b[j:])
|
||||||
|
return n + m, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -801,11 +801,11 @@ github.com/superseriousbusiness/oauth2/v4/generates
|
||||||
github.com/superseriousbusiness/oauth2/v4/manage
|
github.com/superseriousbusiness/oauth2/v4/manage
|
||||||
github.com/superseriousbusiness/oauth2/v4/models
|
github.com/superseriousbusiness/oauth2/v4/models
|
||||||
github.com/superseriousbusiness/oauth2/v4/server
|
github.com/superseriousbusiness/oauth2/v4/server
|
||||||
# github.com/tdewolff/minify/v2 v2.20.19
|
# github.com/tdewolff/minify/v2 v2.20.20
|
||||||
## explicit; go 1.18
|
## explicit; go 1.18
|
||||||
github.com/tdewolff/minify/v2
|
github.com/tdewolff/minify/v2
|
||||||
github.com/tdewolff/minify/v2/html
|
github.com/tdewolff/minify/v2/html
|
||||||
# github.com/tdewolff/parse/v2 v2.7.12
|
# github.com/tdewolff/parse/v2 v2.7.13
|
||||||
## explicit; go 1.13
|
## explicit; go 1.13
|
||||||
github.com/tdewolff/parse/v2
|
github.com/tdewolff/parse/v2
|
||||||
github.com/tdewolff/parse/v2/buffer
|
github.com/tdewolff/parse/v2/buffer
|
||||||
|
|
Loading…
Reference in New Issue