Remove closure in favor of a simple JSMin implementation
Closure is a great js-minifier, but js-minification is really outside the scope of this project. A simple space/line stripper should be suffcient.
This commit is contained in:
6
pom.xml
6
pom.xml
@@ -51,12 +51,6 @@
|
|||||||
<artifactId>commons-lang3</artifactId>
|
<artifactId>commons-lang3</artifactId>
|
||||||
<version>3.4</version>
|
<version>3.4</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
|
||||||
<groupId>com.google.javascript</groupId>
|
|
||||||
<artifactId>closure-compiler</artifactId>
|
|
||||||
<version>v20151015</version>
|
|
||||||
<optional>true</optional>
|
|
||||||
</dependency>
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<packaging>jar</packaging>
|
<packaging>jar</packaging>
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ public class InlineStaticResource {
|
|||||||
if(fileString != null) {
|
if(fileString != null) {
|
||||||
switch(format) {
|
switch(format) {
|
||||||
case CSS_MIN : return style().with(unsafeHtml(compressCss(fileString)));
|
case CSS_MIN : return style().with(unsafeHtml(compressCss(fileString)));
|
||||||
case JS_MIN : return script().with(unsafeHtml(compressJs(fileString, path)));
|
case JS_MIN : return script().with(unsafeHtml(compressJs(fileString)));
|
||||||
case CSS : return style().with(unsafeHtml(fileString));
|
case CSS : return style().with(unsafeHtml(fileString));
|
||||||
case JS : return script().with(unsafeHtml(fileString));
|
case JS : return script().with(unsafeHtml(fileString));
|
||||||
default : return errorAlert;
|
default : return errorAlert;
|
||||||
@@ -35,8 +35,8 @@ public class InlineStaticResource {
|
|||||||
return CSSMin.compress(code);
|
return CSSMin.compress(code);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String compressJs(String code, String debugPath) {
|
private static String compressJs(String code) {
|
||||||
return JSMin.compressJs(code, debugPath);
|
return JSMin.compressJs(code);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,32 +1,305 @@
|
|||||||
package j2html.utils;
|
package j2html.utils;
|
||||||
|
/*
|
||||||
|
* JSMin.java 2006-02-13
|
||||||
|
*
|
||||||
|
* Copyright (c) 2006 John Reilly (www.inconspicuous.org)
|
||||||
|
*
|
||||||
|
* This work is a translation from C to Java of jsmin.c published by
|
||||||
|
* Douglas Crockford. Permission is hereby granted to use the Java
|
||||||
|
* version under the same conditions as the jsmin.c on which it is
|
||||||
|
* based.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* jsmin.c 2003-04-21
|
||||||
|
*
|
||||||
|
* Copyright (c) 2002 Douglas Crockford (www.crockford.com)
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* The Software shall be used for Good, not Evil.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// package org.inconspicuous.jsmin;
|
||||||
|
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.io.PushbackInputStream;
|
||||||
|
|
||||||
import com.google.javascript.jscomp.*;
|
|
||||||
import com.google.javascript.jscomp.Compiler;
|
|
||||||
|
|
||||||
public class JSMin {
|
public class JSMin {
|
||||||
|
|
||||||
private JSMin() {}
|
/**
|
||||||
|
* Compress a JS-string
|
||||||
public static String compressJs(String code, String sourcePath) {
|
*
|
||||||
return isPresent("com.google.javascript.jscomp.Compiler") ? compressJsUsingClosureCompiler(code, sourcePath) : code;
|
* @param code the js-code you want to compress
|
||||||
}
|
* @return the compressed code
|
||||||
|
*/
|
||||||
private static boolean isPresent(String className) {
|
public static String compressJs(String code) {
|
||||||
|
InputStream inStream = new ByteArrayInputStream(code.getBytes());
|
||||||
|
ByteArrayOutputStream outStream = new ByteArrayOutputStream();
|
||||||
|
JSMin jsmin = new JSMin(inStream, outStream);
|
||||||
try {
|
try {
|
||||||
Class.forName(className);
|
jsmin.jsmin();
|
||||||
return true;
|
return outStream.toString().trim();
|
||||||
} catch (Exception e) {
|
} catch (IOException | UnterminatedRegExpLiteralException | UnterminatedCommentException | UnterminatedStringLiteralException e) {
|
||||||
return false;
|
e.printStackTrace();
|
||||||
|
return "";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String compressJsUsingClosureCompiler(String code, String sourcePath) {
|
private static final int EOF = -1;
|
||||||
com.google.javascript.jscomp.Compiler compiler = new Compiler();
|
|
||||||
CompilerOptions options = new CompilerOptions();
|
private PushbackInputStream in;
|
||||||
CompilationLevel.SIMPLE_OPTIMIZATIONS.setOptionsForCompilationLevel(options);
|
private OutputStream out;
|
||||||
SourceFile extern = SourceFile.fromCode("externs.js", "");
|
|
||||||
SourceFile input = SourceFile.fromCode(sourcePath, code);
|
private int theA;
|
||||||
compiler.compile(extern, input, options);
|
private int theB;
|
||||||
return compiler.toSource();
|
|
||||||
|
private JSMin(InputStream in, OutputStream out) {
|
||||||
|
this.in = new PushbackInputStream(in);
|
||||||
|
this.out = out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* isAlphanum -- return true if the character is a letter, digit,
|
||||||
|
* underscore, dollar sign, or non-ASCII character.
|
||||||
|
*/
|
||||||
|
private static boolean isAlphanum(int c) {
|
||||||
|
return ((c >= 'a' && c <= 'z') ||
|
||||||
|
(c >= '0' && c <= '9') ||
|
||||||
|
(c >= 'A' && c <= 'Z') ||
|
||||||
|
c == '_' ||
|
||||||
|
c == '$' ||
|
||||||
|
c == '\\' ||
|
||||||
|
c > 126);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get -- return the next character from stdin. Watch out for lookahead. If
|
||||||
|
* the character is a control character, translate it to a space or
|
||||||
|
* linefeed.
|
||||||
|
*/
|
||||||
|
private int get() throws IOException {
|
||||||
|
int c = in.read();
|
||||||
|
|
||||||
|
if (c >= ' ' || c == '\n' || c == EOF) {
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c == '\r') {
|
||||||
|
return '\n';
|
||||||
|
}
|
||||||
|
|
||||||
|
return ' ';
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the next character without getting it.
|
||||||
|
*/
|
||||||
|
private int peek() throws IOException {
|
||||||
|
int lookaheadChar = in.read();
|
||||||
|
in.unread(lookaheadChar);
|
||||||
|
return lookaheadChar;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* next -- get the next character, excluding comments. peek() is used to see
|
||||||
|
* if a '/' is followed by a '/' or '*'.
|
||||||
|
*/
|
||||||
|
private int next() throws IOException, UnterminatedCommentException {
|
||||||
|
int c = get();
|
||||||
|
if (c == '/') {
|
||||||
|
switch (peek()) {
|
||||||
|
case '/':
|
||||||
|
for (; ; ) {
|
||||||
|
c = get();
|
||||||
|
if (c <= '\n') {
|
||||||
|
return c;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case '*':
|
||||||
|
get();
|
||||||
|
for (; ; ) {
|
||||||
|
switch (get()) {
|
||||||
|
case '*':
|
||||||
|
if (peek() == '/') {
|
||||||
|
get();
|
||||||
|
return ' ';
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case EOF:
|
||||||
|
throw new UnterminatedCommentException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* action -- do something! What you do is determined by the argument: 1
|
||||||
|
* Output A. Copy B to A. Get the next B. 2 Copy B to A. Get the next B.
|
||||||
|
* (Delete A). 3 Get the next B. (Delete B). action treats a string as a
|
||||||
|
* single character. Wow! action recognizes a regular expression if it is
|
||||||
|
* preceded by ( or , or =.
|
||||||
|
*/
|
||||||
|
|
||||||
|
private void action(int d) throws IOException, UnterminatedRegExpLiteralException,
|
||||||
|
UnterminatedCommentException, UnterminatedStringLiteralException {
|
||||||
|
switch (d) {
|
||||||
|
case 1:
|
||||||
|
out.write(theA);
|
||||||
|
case 2:
|
||||||
|
theA = theB;
|
||||||
|
|
||||||
|
if (theA == '\'' || theA == '"') {
|
||||||
|
for (; ; ) {
|
||||||
|
out.write(theA);
|
||||||
|
theA = get();
|
||||||
|
if (theA == theB) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (theA <= '\n') {
|
||||||
|
throw new UnterminatedStringLiteralException();
|
||||||
|
}
|
||||||
|
if (theA == '\\') {
|
||||||
|
out.write(theA);
|
||||||
|
theA = get();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
case 3:
|
||||||
|
theB = next();
|
||||||
|
if (theB == '/' && (theA == '(' || theA == ',' || theA == '=')) {
|
||||||
|
out.write(theA);
|
||||||
|
out.write(theB);
|
||||||
|
for (; ; ) {
|
||||||
|
theA = get();
|
||||||
|
if (theA == '/') {
|
||||||
|
break;
|
||||||
|
} else if (theA == '\\') {
|
||||||
|
out.write(theA);
|
||||||
|
theA = get();
|
||||||
|
} else if (theA <= '\n') {
|
||||||
|
throw new UnterminatedRegExpLiteralException();
|
||||||
|
}
|
||||||
|
out.write(theA);
|
||||||
|
}
|
||||||
|
theB = next();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* jsmin -- Copy the input to the output, deleting the characters which are
|
||||||
|
* insignificant to JavaScript. Comments will be removed. Tabs will be
|
||||||
|
* replaced with spaces. Carriage returns will be replaced with linefeeds.
|
||||||
|
* Most spaces and linefeeds will be removed.
|
||||||
|
*/
|
||||||
|
public void jsmin() throws IOException, UnterminatedRegExpLiteralException, UnterminatedCommentException, UnterminatedStringLiteralException {
|
||||||
|
theA = '\n';
|
||||||
|
action(3);
|
||||||
|
while (theA != EOF) {
|
||||||
|
switch (theA) {
|
||||||
|
case ' ':
|
||||||
|
if (isAlphanum(theB)) {
|
||||||
|
action(1);
|
||||||
|
} else {
|
||||||
|
action(2);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case '\n':
|
||||||
|
switch (theB) {
|
||||||
|
case '{':
|
||||||
|
case '[':
|
||||||
|
case '(':
|
||||||
|
case '+':
|
||||||
|
case '-':
|
||||||
|
action(1);
|
||||||
|
break;
|
||||||
|
case ' ':
|
||||||
|
action(3);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
if (isAlphanum(theB)) {
|
||||||
|
action(1);
|
||||||
|
} else {
|
||||||
|
action(2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
switch (theB) {
|
||||||
|
case ' ':
|
||||||
|
if (isAlphanum(theA)) {
|
||||||
|
action(1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
action(3);
|
||||||
|
break;
|
||||||
|
case '\n':
|
||||||
|
switch (theA) {
|
||||||
|
case '}':
|
||||||
|
case ']':
|
||||||
|
case ')':
|
||||||
|
case '+':
|
||||||
|
case '-':
|
||||||
|
case '"':
|
||||||
|
case '\'':
|
||||||
|
action(1);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
if (isAlphanum(theA)) {
|
||||||
|
action(1);
|
||||||
|
} else {
|
||||||
|
action(3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
action(1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
out.flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
private class UnterminatedCommentException extends Exception {
|
||||||
|
}
|
||||||
|
|
||||||
|
private class UnterminatedStringLiteralException extends Exception {
|
||||||
|
}
|
||||||
|
|
||||||
|
private class UnterminatedRegExpLiteralException extends Exception {
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -70,7 +70,7 @@ public class TagCreatorTest {
|
|||||||
assertEquals(text("<script> and \"</script>\"").render(), "<script> and "</script>"");
|
assertEquals(text("<script> and \"</script>\"").render(), "<script> and "</script>"");
|
||||||
assertEquals(unsafeHtml("<script>").render(), "<script>");
|
assertEquals(unsafeHtml("<script>").render(), "<script>");
|
||||||
assertEquals(styleWithInlineFile_min("/test.css").render(), "<style>body{background:#daa520;margin-bottom:10px;margin-left:10px;margin-right:10px;margin-top:10px}</style>");
|
assertEquals(styleWithInlineFile_min("/test.css").render(), "<style>body{background:#daa520;margin-bottom:10px;margin-left:10px;margin-right:10px;margin-top:10px}</style>");
|
||||||
assertEquals(scriptWithInlineFile_min("/test.js").render(), "<script>(function(){console.log(15)})();</script>");
|
assertEquals(scriptWithInlineFile_min("/test.js").render(), "<script>(function(){var test=5;var tast=10;var testTast=test+tast;console.log(testTast);})();</script>");
|
||||||
assertEquals(fileAsString("/test.html").render(), "<body>" + EOL + " Any content" + EOL + "</body>" + EOL);
|
assertEquals(fileAsString("/test.html").render(), "<body>" + EOL + " Any content" + EOL + "</body>" + EOL);
|
||||||
assertEquals(fileAsEscapedString("/test.html").render(), "<body>" + EOL + " Any content" + EOL + "</body>" + EOL);
|
assertEquals(fileAsEscapedString("/test.html").render(), "<body>" + EOL + " Any content" + EOL + "</body>" + EOL);
|
||||||
assertEquals(fileAsString("/AnyContent.java").render(), "public class AnyContent{}" + EOL);
|
assertEquals(fileAsString("/AnyContent.java").render(), "public class AnyContent{}" + EOL);
|
||||||
|
|||||||
Reference in New Issue
Block a user