001    /**
002     * Copyright (c) 2000-present Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
013     */
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    /**
033     * @author Carlos Sierra Andr??s
034     */
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    }