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 compiler.disableThreads();
042
043 SourceFile sourceFile = SourceFile.fromCode(resourceName, content);
044
045 CompilerOptions compilerOptions = new CompilerOptions();
046
047 compilerOptions.setWarningLevel(
048 DiagnosticGroups.NON_STANDARD_JSDOC, CheckLevel.OFF);
049
050 setCompileOptions(compilerOptions);
051
052 compiler.compile(
053 SourceFile.fromCode("extern", StringPool.BLANK), sourceFile,
054 compilerOptions);
055
056 return compiler.toSource();
057 }
058
059 protected void setCompileOptions(CompilerOptions compilerOptions) {
060 compilerOptions.checkGlobalThisLevel = CheckLevel.OFF;
061 compilerOptions.closurePass = true;
062 compilerOptions.coalesceVariableNames = true;
063 compilerOptions.collapseVariableDeclarations = true;
064 compilerOptions.convertToDottedProperties = true;
065 compilerOptions.deadAssignmentElimination = true;
066 compilerOptions.flowSensitiveInlineVariables = true;
067 compilerOptions.foldConstants = true;
068 compilerOptions.labelRenaming = true;
069 compilerOptions.removeDeadCode = true;
070 compilerOptions.optimizeArgumentsArray = true;
071
072 compilerOptions.setAssumeClosuresOnlyCaptureReferences(false);
073 compilerOptions.setInlineFunctions(CompilerOptions.Reach.LOCAL_ONLY);
074 compilerOptions.setInlineVariables(CompilerOptions.Reach.LOCAL_ONLY);
075 compilerOptions.setRenamingPolicy(
076 VariableRenamingPolicy.LOCAL, PropertyRenamingPolicy.OFF);
077 compilerOptions.setRemoveUnusedVariables(
078 CompilerOptions.Reach.LOCAL_ONLY);
079 }
080
081 private static final Log _log = LogFactoryUtil.getLog(
082 GoogleJavaScriptMinifier.class);
083
084 private class LogErrorManager extends BasicErrorManager {
085
086 @Override
087 public void println(CheckLevel checkLevel, JSError jsError) {
088 if (checkLevel == CheckLevel.ERROR) {
089 if (_log.isErrorEnabled()) {
090 _log.error(
091 jsError.format(checkLevel, _simpleMessageFormatter));
092 }
093 }
094 else if (checkLevel == CheckLevel.WARNING) {
095 if (_log.isWarnEnabled()) {
096 _log.warn(
097 jsError.format(checkLevel, _simpleMessageFormatter));
098 }
099 }
100 }
101
102 @Override
103 protected void printSummary() {
104 if (_log.isErrorEnabled() && (getErrorCount() > 0)) {
105 _log.error(_buildMessage());
106 }
107 else if (_log.isWarnEnabled() && (getWarningCount() > 0)) {
108 _log.warn(_buildMessage());
109 }
110 }
111
112 private String _buildMessage() {
113 return String.format(
114 "{0} error(s), {1} warning(s)", getErrorCount(),
115 getWarningCount());
116 }
117
118 private final MessageFormatter _simpleMessageFormatter =
119 new SimpleMessageFormatter();
120
121 }
122
123 private class SimpleMessageFormatter implements MessageFormatter {
124
125 @Override
126 public String formatError(JSError jsError) {
127 return String.format(
128 "(%s:%d): %s", jsError.sourceName, jsError.lineNumber,
129 jsError.description);
130 }
131
132 @Override
133 public String formatWarning(JSError jsError) {
134 return formatError(jsError);
135 }
136
137 }
138
139 }