001
014
015 package com.liferay.portal.minifier;
016
017 import com.google.javascript.jscomp.BasicErrorManager;
018 import com.google.javascript.jscomp.CheckLevel;
019 import com.google.javascript.jscomp.Compiler;
020 import com.google.javascript.jscomp.CompilerOptions;
021 import com.google.javascript.jscomp.DiagnosticGroups;
022 import com.google.javascript.jscomp.JSError;
023 import com.google.javascript.jscomp.MessageFormatter;
024 import com.google.javascript.jscomp.PropertyRenamingPolicy;
025 import com.google.javascript.jscomp.SourceFile;
026 import com.google.javascript.jscomp.VariableRenamingPolicy;
027
028 import com.liferay.portal.kernel.log.Log;
029 import com.liferay.portal.kernel.log.LogFactoryUtil;
030 import com.liferay.portal.kernel.util.StringPool;
031
032
035 public class GoogleJavaScriptMinifier implements JavaScriptMinifier {
036
037 @Override
038 public String compress(String resourceName, String content) {
039 Compiler compiler = new Compiler(new LogErrorManager());
040
041 SourceFile sourceFile = SourceFile.fromCode(resourceName, content);
042
043 CompilerOptions compilerOptions = new CompilerOptions();
044
045 compilerOptions.setWarningLevel(
046 DiagnosticGroups.NON_STANDARD_JSDOC, CheckLevel.OFF);
047
048 setCompileOptions(compilerOptions);
049
050 compiler.compile(
051 SourceFile.fromCode("extern", StringPool.BLANK), sourceFile,
052 compilerOptions);
053
054 return compiler.toSource();
055 }
056
057 protected void setCompileOptions(CompilerOptions compilerOptions) {
058 compilerOptions.checkGlobalThisLevel = CheckLevel.OFF;
059 compilerOptions.closurePass = true;
060 compilerOptions.coalesceVariableNames = true;
061 compilerOptions.collapseVariableDeclarations = true;
062 compilerOptions.convertToDottedProperties = true;
063 compilerOptions.deadAssignmentElimination = true;
064 compilerOptions.flowSensitiveInlineVariables = true;
065 compilerOptions.foldConstants = true;
066 compilerOptions.labelRenaming = true;
067 compilerOptions.removeDeadCode = true;
068 compilerOptions.optimizeArgumentsArray = true;
069
070 compilerOptions.setAssumeClosuresOnlyCaptureReferences(false);
071 compilerOptions.setInlineFunctions(CompilerOptions.Reach.LOCAL_ONLY);
072 compilerOptions.setInlineVariables(CompilerOptions.Reach.LOCAL_ONLY);
073 compilerOptions.setRenamingPolicy(
074 VariableRenamingPolicy.LOCAL, PropertyRenamingPolicy.OFF);
075 compilerOptions.setRemoveUnusedVariables(
076 CompilerOptions.Reach.LOCAL_ONLY);
077 }
078
079 private static final Log _log = LogFactoryUtil.getLog(
080 GoogleJavaScriptMinifier.class);
081
082 private class LogErrorManager extends BasicErrorManager {
083
084 @Override
085 public void println(CheckLevel checkLevel, JSError jsError) {
086 if (checkLevel == CheckLevel.ERROR) {
087 if (_log.isErrorEnabled()) {
088 _log.error(
089 jsError.format(checkLevel, _simpleMessageFormatter));
090 }
091 }
092 else if (checkLevel == CheckLevel.WARNING) {
093 if (_log.isWarnEnabled()) {
094 _log.warn(
095 jsError.format(checkLevel, _simpleMessageFormatter));
096 }
097 }
098 }
099
100 @Override
101 protected void printSummary() {
102 if (_log.isErrorEnabled() && (getErrorCount() > 0)) {
103 _log.error(_buildMessage());
104 }
105 else if (_log.isWarnEnabled() && (getWarningCount() > 0)) {
106 _log.warn(_buildMessage());
107 }
108 }
109
110 private String _buildMessage() {
111 return String.format(
112 "{0} error(s), {1} warning(s)", getErrorCount(),
113 getWarningCount());
114 }
115
116 private final MessageFormatter _simpleMessageFormatter =
117 new SimpleMessageFormatter();
118
119 }
120
121 private class SimpleMessageFormatter implements MessageFormatter {
122
123 @Override
124 public String formatError(JSError jsError) {
125 return String.format(
126 "(%s:%d): %s", jsError.sourceName, jsError.lineNumber,
127 jsError.description);
128 }
129
130 @Override
131 public String formatWarning(JSError jsError) {
132 return formatError(jsError);
133 }
134
135 }
136
137 }