-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathminify-html
More file actions
executable file
·120 lines (98 loc) · 2.72 KB
/
Copy pathminify-html
File metadata and controls
executable file
·120 lines (98 loc) · 2.72 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
#!/usr/bin/env python3
from pathlib import Path
import json
import subprocess
import sys
from bs4 import BeautifulSoup, NavigableString, Comment
def sassc(css: str) -> str:
"""Minify CSS using the sassc compiler.
Parameters
----------
css : str
The CSS to minify.
Returns
-------
str
The minified CSS.
"""
cmd = ["sassc", "-t", "compressed", "-s"]
css_buf = css.encode("utf-8")
return subprocess.check_output(cmd, input=css_buf).decode("utf-8").strip()
def out(f, *t):
for x in t:
f.write(x)
def htmlentities(text: str) -> str:
"""Convert special characters to HTML entities."""
text = text.replace("&", "&")
text = text.replace("<", "<")
text = text.replace(">", ">")
return text
def output_elem(f, tag, ws=False, escape=False):
if isinstance(tag, Comment):
return
if isinstance(tag, NavigableString):
s = tag.string
if escape:
s = htmlentities(s)
if ws:
out(f, s)
return
s = s.replace("\n", " ")
new = ""
while new != s:
new = s
s = new.replace(" ", " ")
out(f, new)
return
out(f, "<", tag.name)
for attr in sorted(tag.attrs):
x = tag.attrs[attr]
if isinstance(x, list):
x = " ".join(x)
if attr == "style":
x = f".c {{ {x} }}"
x = sassc(x)
x = x.rstrip("}")
x = x.rstrip(";")
x = x.lstrip(".c")
x = x.lstrip(" ")
x = x.lstrip("{")
out(f, " ", attr, '="', htmlentities(x), '"')
if not list(tag.children) and tag.name in [
"meta",
"input",
"br",
"hr",
"link",
"img",
]:
out(f, "/>")
return
out(f, ">")
for ch in tag.children:
if (
tag.name == "script"
and tag.attrs.get("type") == "application/ld+json"
):
out(f, json.dumps(json.loads(tag.string), separators=(",", ":")))
elif tag.name == "style":
out(f, sassc(tag.string))
else:
output_elem(
f,
ch,
ws
or tag.name in ["textarea", "script", "style", "pre"]
or "pre-wrap" in tag.attrs.get("style", ""),
tag.name not in ["script", "style"],
)
out(f, "</", tag.name, ">")
def minify_path(p):
with Path(p).open("r") as f:
orig = f.read()
soup = BeautifulSoup(orig, "html5lib")
with Path(p).open("w") as f:
out(f, "<!DOCTYPE html>")
output_elem(f, soup.html)
for p in sys.argv[1:]:
minify_path(p)