Skip to content

Commit

Permalink
Merge 6e2ac91 into 05256fa
Browse files Browse the repository at this point in the history
  • Loading branch information
mathieu-aubin committed Jan 15, 2020
2 parents 05256fa + 6e2ac91 commit 3d30834
Show file tree
Hide file tree
Showing 6 changed files with 107 additions and 41 deletions.
52 changes: 50 additions & 2 deletions cmd/minify/install.sh
Original file line number Diff line number Diff line change
@@ -1,5 +1,53 @@
#!/bin/bash

go install -ldflags "-X 'main.Version=devel' -X 'main.Commit=$(git rev-list -1 HEAD)' -X 'main.Date=$(date)'"
# Adds the possibility to create a static executable.
# Must provide --static as first argument to enable.
if [[ ! ${CGO_ENABLED} == 0 && ${1} == "--static" ]]; then
export CGO_ENABLED=0; shift;
fi

source minify_bash_tab_completion
# Compile/strip/install with variable data injection
go install -ldflags "-s -w -X 'main.Version=devel' -X 'main.Commit=$(git rev-list -1 HEAD)' -X 'main.Date=$(date)'";

# Completion url, redirected from https://git.io
COMPURL=https://git.io/minify-completion.bash;

# Bash completion directory variables
BASH_COMPLETION_DIR=${1};

# Install bash completions to proper directory, if any found
if [[ -n "${BASH_COMPLETION_DIR}" ]]; then
echo -e "User-defined directory: ${BASH_COMPLETION_DIR}\n" >&2;

elif [[ -n "${BASH_COMPLETION_DIR_COMPAT_DIR}" ]]; then
# Added for MACOS support with Homebrew
BASH_COMPLETION_DIR=${BASH_COMPLETION_COMPAT_DIR};

elif [[ -r /usr/local/etc/bash_completion.d ]]; then
# Added for MACOS support with Homebrew
BASH_COMPLETION_DIR=/usr/local/etc/bash_completion.d;

elif [[ -n "${BASH_COMPLETION_USER_DIR}" ]]; then
BASH_COMPLETION_DIR=${BASH_COMPLETION_USER_DIR};

elif [[ -r /usr/share/bash-completion/completions ]]; then
BASH_COMPLETION_DIR=/usr/share/bash-completion/completions;

elif [[ -r /etc/bash_completion.d ]]; then
BASH_COMPLETION_DIR=/etc/bash_completion.d;

fi

if [[ -r ${BASH_COMPLETION_DIR} ]]; then
echo "Installing bash completion into ${BASH_COMPLETION_DIR}";
# Try installing from URL first, if that fails, resort to using the existing file
curl -sLko ${BASH_COMPLETION_DIR}/minify.bash ${COMPURL} 2>/dev/null || [[ -f minify_bash_tab_completion ]] && cat minify_bash_tab_completion >${BASH_COMPLETION_DIR}/minify.bash 2>/dev/null;

else
# Could not find directory, show error message
echo -e "Could not find bash completion directory. Try running again\nwith a valid completion directory as parameter or manually\ndownload and save: ${COMPURL}" >&2;

fi

# Source file for immediate use
source minify_bash_tab_completion;
69 changes: 39 additions & 30 deletions common.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,39 +36,45 @@ func Mediatype(b []byte) []byte {

// 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 parse.URLEncodingTable[c] {
asciiLen += 2
}
if asciiLen > base64Len {
break
}
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 {
encoded := make([]byte, base64Len-len(";base64"))
base64.StdEncoding.Encode(encoded, dataURI)
dataURI = encoded
mediatype = append(mediatype, []byte(";base64")...)
} else {
dataURI = parse.EncodeURL(dataURI, parse.URLEncodingTable)
}
if len("text/plain") <= len(mediatype) && parse.EqualFold(mediatype[:len("text/plain")], []byte("text/plain")) {
mediatype = mediatype[len("text/plain"):]
break
}
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
}
}
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
}
dataURI = append(append(append([]byte("data:"), mediatype...), ','), dataURI...)
}
return dataURI
return append(append(append([]byte("data:"), mediatype...), ','), data...)
}

const MaxInt = int(^uint(0) >> 1)
Expand Down Expand Up @@ -150,12 +156,15 @@ func Decimal(num []byte, prec int) []byte {
break
} else if inc && i < dot { // end inc for integer
num[i] = '0'
break
} else if !inc && (i < dot || num[i] != '0') {
break
}
}
end = i + 1
if i < dot {
end = dot
} else {
end = i + 1
}

if inc {
if dot == start && end == start+1 {
Expand Down
7 changes: 5 additions & 2 deletions common_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,11 +43,12 @@ func TestDataURI(t *testing.T) {
{"data:text/svg+xml;base64,PT09PT09", "data:text/svg+xml;base64,PT09PT09"},
{"data:text/xml;version=2.0,content", "data:text/xml;version=2.0,content"},
{"data:text/xml; version = 2.0,content", "data:text/xml;version=2.0,content"},
{"data:,=====", "data:,%3D%3D%3D%3D%3D"},
{"data:,======", "data:;base64,PT09PT09"},
{"data:,%3D%3D%3D%3D%3D", "data:,%3D%3D%3D%3D%3D"},
{"data:,%3D%3D%3D%3D%3D%3D", "data:;base64,PT09PT09"},
{"data:text/x,<?xx?>", "data:text/x,%3C%3Fxx%3F%3E"},
{"data:text/other,\"<\u2318", "data:text/other,%22%3C%E2%8C%98"},
{"data:text/other,\"<\u2318>", "data:text/other;base64,IjzijJg+"},
{`data:text/svg+xml,%3Csvg height="100" width="100"><circle cx="50" cy="50" r="40" stroke="black" stroke-width="3" fill="red" /></svg>`, `data:text/svg+xml,%3Csvg height="100" width="100"><circle cx="50" cy="50" r="40" stroke="black" stroke-width="3" fill="red" /></svg>`},
}
m := New()
m.AddFunc("text/x", func(_ *M, w io.Writer, r io.Reader, _ map[string]string) error {
Expand Down Expand Up @@ -133,6 +134,7 @@ func TestDecimalTruncate(t *testing.T) {
{"100000000000009", 15, "100000000000009"},
{"1000000000000009", 15, "1000000000000009"},
{"10000000000000009", 15, "10000000000000009"},
{"139.99999999", 8, "140"},
}
for _, tt := range numberTests {
t.Run(tt.number, func(t *testing.T) {
Expand Down Expand Up @@ -288,6 +290,7 @@ func TestNumberTruncate(t *testing.T) {
{".3333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333397e-903", 0, ".3333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333397e-903"},
{"29.629775e-9", 0, ".29629775e-7"},
{"e-9223372036854775808", 0, "e-9223372036854775808"},
{"139.99999999", 8, "140"},
}
for _, tt := range numberTests {
t.Run(tt.number, func(t *testing.T) {
Expand Down
5 changes: 4 additions & 1 deletion css/css.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ var (
transparentBytes = []byte("transparent")
initialBytes = []byte("initial")
importantBytes = []byte("!important")
dataSchemeBytes = []byte("data:")
)

type cssMinifier struct {
Expand Down Expand Up @@ -522,7 +523,9 @@ func (c *cssMinifier) minifyTokens(prop Hash, values []Token) []Token {
uri = removeMarkupNewlines(uri)
uri = uri[1 : len(uri)-1]
}
uri = minify.DataURI(c.m, uri)
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 {
Expand Down
11 changes: 5 additions & 6 deletions svg/pathdata.go
Original file line number Diff line number Diff line change
Expand Up @@ -105,11 +105,10 @@ func (p *PathData) ShortenPathData(b []byte) []byte {
i += n - 1
}
}
if cmd != 0 {
j += p.copyInstruction(b[j:], cmd)
} else {
j = len(b)
if cmd == 0 {
return b
}
j += p.copyInstruction(b[j:], cmd)
return b[:j]
}

Expand Down Expand Up @@ -219,7 +218,7 @@ func (p *PathData) copyInstruction(b []byte, cmd byte) int {
// 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 (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 {
Expand Down Expand Up @@ -265,7 +264,7 @@ func (p *PathData) copyInstruction(b []byte, cmd byte) int {
// 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 (cmd == 'Q' || cmd == 'q' || i+di >= n) && (cpx == p.x && cpy == p.y || cpx == ax && cpy == ay) {
if isRelCmd {
cmd = 'l'
} else {
Expand Down
4 changes: 4 additions & 0 deletions svg/pathdata_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@ func TestPathData(t *testing.T) {
{
"q6.55 0 10.56-2.93a9.36 9.36 0 004-8 10 10 0 00-3.37-7.83q-3.37-3-9.9-4.79A25.38 25.38 0 0137.76 44",
"q6.55.0 10.56-2.93a9.36 9.36.0 004-8 10 10 0 00-3.37-7.83q-3.37-3-9.9-4.79A25.38 25.38.0 0137.76 44"}, // #275
{
"m-3.5498-0.0882q0-5.1924-4.5861-5.1924h-1.819v10.495h1.4662q4.9389-0+4.9389-5.3027z",
"m-3.5498-.0882q0-5.1924-4.5861-5.1924h-1.819v10.495h1.4662q4.9389.0 4.9389-5.3027z"}, // #284
{"C10 0 0 10 10 10", "C10 0 0 10 10 10"},

// change/remove commands
{"M10 10L10 10L20 10z", "M10 10H20z"},
Expand Down

0 comments on commit 3d30834

Please sign in to comment.