~ryanford/git-blog-tup

d8390984e0768640da13fe74570177153973151b — Ryan Ford 3 years ago a81a0cc
add html minifier plugin
2 files changed, 70 insertions(+), 0 deletions(-)

M Tuprules.tup
A plugins/minify_html
M Tuprules.tup => Tuprules.tup +1 -0
@@ 10,5 10,6 @@ PIPELINE = to_json
PIPELINE += syntax_highlighting
PIPELINE += convert_markdown
PIPELINE += to_html
PIPELINE += minify_html

.gitignore

A plugins/minify_html => plugins/minify_html +69 -0
@@ 0,0 1,69 @@
#!/usr/bin/env lua

local unpack = unpack or table.unpack
local lpeg = require("lpeg")
lpeg.locale(lpeg)
local P, S, V, C, Ct, Cg, Cc, Cb, Cmt  = lpeg.P, lpeg.S, lpeg.V, lpeg.C, lpeg.Ct, lpeg.Cg, lpeg.Cc, lpeg.Cb, lpeg.Cmt
local alpha, space = lpeg.alpha, lpeg.space

local function is_even(_, _, close, start) return close:lower() == start:lower() end

local function any_case(str)
   if not str or #str == 0 then return P(false) end
   local pattern = P(0)
   for c in str:gmatch(".") do
      pattern = pattern * S(c:upper() .. c:lower())
   end
   return pattern
end

local function one_of(patterns)
   if not patterns then return P(false) end
   local pattern = any_case(table.remove(patterns, 1))
   for _, str in ipairs(patterns) do
      pattern = pattern + any_case(str)
   end
   return pattern
end

local document = P{
   "document",
   document = Ct((V"doctype" * V"html" ^ 0) + (V"html" ^ 1)) / table.concat,
   html = V"comment" + V"void_element" + V"self_closing" + V"pre" + V"start_tag" + V"close_tag" + V"whitespace" + V"text_node",
   pre = C(V"start_pre" * (1 - V"close_pre") ^ 0 * V"close_pre"),
   start_pre = P"<" * any_case"pre" * (V"whitespace" * V"modifiers") ^ -1 * V"optional_space" * P">",
   close_pre = P"</" * any_case"pre" * V"optional_space" * P">",
   text_node = C(P(1 - (space ^ 2 + V"comment" + V"start_tag" + V"close_tag" + V"void_element")) ^ 1),
   start_tag = Ct(C(P"<") * V"optional_space" *  C(V"tag_name") * (V"whitespace" * V"modifiers") ^ -1 * V"optional_space" * C(P">")) / unpack,
   close_tag = Ct(C(P"</") * V"optional_space" * C(V"tag_name") * V"optional_space" * C(P">")) / unpack,
   self_closing = Ct(C(P"<") * C(V"tag_name") * (V"whitespace" * V"modifiers") ^ -1 * V"optional_space" * P"/>") / unpack,
   void_element = Ct(C(P"<") * C(V"void_type") * (V"whitespace" * V"modifiers") ^ -1 * V"optional_space" * C(P"/>" + P">")) / unpack,
   void_type = (one_of{"area", "base", "br", "col", "hr", "img", "input", "link", "meta", "param", "command", "keygen", "source"}),
   tag_name = alpha ^ 1 * (P"-" * alpha ^ 1) ^ 0,
   modifiers = Cc" " * V"modifier" * (Cc" " * V"whitespace" * V"modifier") ^ 0,
   modifier = V"attribute" + V"property",
   attribute = C(V"property" * P"=" * V"quoted_string") / 1,
   property = C(alpha ^ 1 * (P"-" * alpha ^ 1) ^ 0),
   quoted_string = (V"open_quote" * (P"\\" * V"matching_quote" + (1 - V"matching_quote")) ^ 0 * V"close_quote") / 0,
   matching_quote = Cmt(V"close_quote" * Cb"open_quote", is_even),
   close_quote = C(V"quote"),
   open_quote = Cg(V"quote", "open_quote"),
   quote = S[["']],
   doctype = C(P"<!" * any_case"doctype html" * P">"),
   comment = V"comment_start" * (1 - V"comment_close") ^ 0 * V"comment_close",
   comment_close = P"-->",
   comment_start = P"<!--",
   whitespace = space * V"optional_space",
   optional_space = space ^ 0,
}

local input = io.input(arg[1])
local output = io.output(arg[2])

local str = input:read("*a")
if arg[1] then input:close() end

output:write(document:match(str))
if arg[2] then output:close() end

os.exit(0, true)