esp8266_deauther/utils/web_converter/css_html_js_minify/js_minifier.py

185 lines
6.6 KiB
Python

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# Created by: juancarlospaco
# GitHub Repo: https://github.com/juancarlospaco/css-html-js-minify
# Modified by: xdavidhu
"""JavaScript Minifier functions for CSS-HTML-JS-Minify."""
from io import StringIO # pure-Python StringIO supports unicode.
import logging as log
import re
from .css_minifier import condense_semicolons
__all__ = ['js_minify']
def remove_commented_lines(js):
"""Force remove commented out lines from Javascript."""
log.debug("Force remove commented out lines from Javascript.")
result = ""
for line in js.splitlines():
line = re.sub(r"/\*.*\*/" ,"" ,line) # (/*COMMENT */)
line = re.sub(r"//.*","" ,line) # (//COMMENT)
result += '\n'+line
return result
def simple_replacer_js(js):
"""Force strip simple replacements from Javascript."""
log.debug("Force strip simple replacements from Javascript.")
return condense_semicolons(js.replace("debugger;", ";").replace(
";}", "}").replace("; ", ";").replace(" ;", ";").rstrip("\n;"))
def js_minify_keep_comments(js):
"""Return a minified version of the Javascript string."""
log.info("Compressing Javascript...")
ins, outs = StringIO(js), StringIO()
JavascriptMinify(ins, outs).minify()
return force_single_line_js(outs.getvalue())
def force_single_line_js(js):
"""Force Javascript to a single line, even if need to add semicolon."""
log.debug("Forcing JS from ~{0} to 1 Line.".format(len(js.splitlines())))
return ";".join(js.splitlines()) if len(js.splitlines()) > 1 else js
class JavascriptMinify(object):
"""Minify an input stream of Javascript, writing to an output stream."""
def __init__(self, instream=None, outstream=None):
"""Init class."""
self.ins, self.outs = instream, outstream
def minify(self, instream=None, outstream=None):
"""Minify Javascript using StringIO."""
if instream and outstream:
self.ins, self.outs = instream, outstream
write, read = self.outs.write, self.ins.read
space_strings = ("abcdefghijklmnopqrstuvwxyz"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_$\\")
starters, enders = '{[(+-', '}])+-"\''
newlinestart_strings = starters + space_strings
newlineend_strings = enders + space_strings
do_newline, do_space = False, False
doing_single_comment, doing_multi_comment = False, False
previous_before_comment, in_quote = '', ''
in_re, quote_buf = False, []
previous = read(1)
next1 = read(1)
if previous == '/':
if next1 == '/':
doing_single_comment = True
elif next1 == '*':
doing_multi_comment = True
else:
write(previous)
elif not previous:
return
elif previous >= '!':
if previous in "'\"":
in_quote = previous
write(previous)
previous_non_space = previous
else:
previous_non_space = ' '
if not next1:
return
while True:
next2 = read(1)
if not next2:
last = next1.strip()
conditional_1 = (doing_single_comment or doing_multi_comment)
if not conditional_1 and last not in ('', '/'):
write(last)
break
if doing_multi_comment:
if next1 == '*' and next2 == '/':
doing_multi_comment = False
next2 = read(1)
elif doing_single_comment:
if next1 in '\r\n':
doing_single_comment = False
while next2 in '\r\n':
next2 = read(1)
if not next2:
break
if previous_before_comment in ')}]':
do_newline = True
elif previous_before_comment in space_strings:
write('\n')
elif in_quote:
quote_buf.append(next1)
if next1 == in_quote:
numslashes = 0
for c in reversed(quote_buf[:-1]):
if c != '\\':
break
else:
numslashes += 1
if numslashes % 2 == 0:
in_quote = ''
write(''.join(quote_buf))
elif next1 in '\r\n':
conditional_2 = previous_non_space in newlineend_strings
if conditional_2 or previous_non_space > '~':
while 1:
if next2 < '!':
next2 = read(1)
if not next2:
break
else:
conditional_3 = next2 in newlinestart_strings
if conditional_3 or next2 > '~' or next2 == '/':
do_newline = True
break
elif next1 < '!' and not in_re:
conditional_4 = next2 in space_strings or next2 > '~'
conditional_5 = previous_non_space in space_strings
conditional_6 = previous_non_space > '~'
if (conditional_5 or conditional_6) and (conditional_4):
do_space = True
elif next1 == '/':
if in_re:
if previous != '\\':
in_re = False
write('/')
elif next2 == '/':
doing_single_comment = True
previous_before_comment = previous_non_space
elif next2 == '*':
doing_multi_comment = True
else:
in_re = previous_non_space in '(,=:[?!&|'
write('/')
else:
if do_space:
do_space = False
write(' ')
if do_newline:
write('\n')
do_newline = False
write(next1)
if not in_re and next1 in "'\"":
in_quote = next1
quote_buf = []
previous = next1
next1 = next2
if previous >= '!':
previous_non_space = previous
def js_minify(js):
"""Minify a JavaScript string."""
js = remove_commented_lines(js)
js = js_minify_keep_comments(js)
return js.strip()