From 14ced0b3f91bfc9d4fda878b399bba07ff5d3492 Mon Sep 17 00:00:00 2001 From: Samppa Saarela Date: Mon, 15 Apr 2013 14:30:52 +0300 Subject: [PATCH] Support for external js/css sources file. Closure language-in option. --- .../maven/minify/plugin/MinifyMojo.java | 708 ++++++++++-------- .../minify/plugin/ProcessJSFilesTask.java | 298 ++++---- 2 files changed, 541 insertions(+), 465 deletions(-) diff --git a/src/main/java/com/samaxes/maven/minify/plugin/MinifyMojo.java b/src/main/java/com/samaxes/maven/minify/plugin/MinifyMojo.java index b6fc1a46..356e6cef 100644 --- a/src/main/java/com/samaxes/maven/minify/plugin/MinifyMojo.java +++ b/src/main/java/com/samaxes/maven/minify/plugin/MinifyMojo.java @@ -1,320 +1,388 @@ -/* - * $Id$ - * - * Minify Maven Plugin - * https://github.com/samaxes/minify-maven-plugin - * - * Copyright (c) 2009 samaxes.com - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.samaxes.maven.minify.plugin; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.Future; - -import org.apache.maven.plugin.AbstractMojo; -import org.apache.maven.plugin.MojoExecutionException; -import org.apache.maven.plugin.MojoFailureException; - -import com.google.common.base.Strings; - -/** - * Goal for combining and minifying CSS and JavaScript files. - * - * @goal minify - * @phase process-resources - */ -public class MinifyMojo extends AbstractMojo { - - /** - * Webapp source directory. - * - * @parameter expression="${webappSourceDir}" default-value="${basedir}/src/main/webapp" - */ - private String webappSourceDir; - - /** - * Webapp target directory. - * - * @parameter expression="${webappTargetDir}" default-value="${project.build.directory}/${project.build.finalName}" - */ - private String webappTargetDir; - - /** - * CSS source directory. - * - * @parameter expression="${cssSourceDir}" default-value="css" - */ - private String cssSourceDir; - - /** - * JavaScript source directory. - * - * @parameter expression="${jsSourceDir}" default-value="js" - */ - private String jsSourceDir; - - /** - * CSS source filenames list. - * - * @parameter expression="${cssSourceFiles}" alias="cssFiles" - */ - private ArrayList cssSourceFiles; - - /** - * JavaScript source filenames list. - * - * @parameter expression="${jsSourceFiles}" alias="jsFiles" - */ - private ArrayList jsSourceFiles; - - /** - * CSS files to include. Specified as fileset patterns which are relative to the CSS source directory. - * - * @parameter expression="${cssSourceIncludes}" alias="cssIncludes" - * @since 1.2 - */ - private ArrayList cssSourceIncludes; - - /** - * JavaScript files to include. Specified as fileset patterns which are relative to the JavaScript source directory. - * - * @parameter expression="${jsSourceIncludes}" alias="jsIncludes" - * @since 1.2 - */ - private ArrayList jsSourceIncludes; - - /** - * CSS files to exclude. Specified as fileset patterns which are relative to the CSS source directory. - * - * @parameter expression="${cssSourceExcludes}" alias="cssExcludes" - * @since 1.2 - */ - private ArrayList cssSourceExcludes; - - /** - * JavaScript files to exclude. Specified as fileset patterns which are relative to the JavaScript source directory. - * - * @parameter expression="${jsSourceExcludes}" alias="jsExcludes" - * @since 1.2 - */ - private ArrayList jsSourceExcludes; - - /** - * CSS target directory. - *

- * Takes the same value as cssSourceDir when empty. - *

- * - * @parameter expression="${cssTargetDir}" - * @since 1.3.2 - */ - private String cssTargetDir; - - /** - * JavaScript target directory. - *

- * Takes the same value as jsSourceDir when empty. - *

- * - * @parameter expression="${jsTargetDir}" - * @since 1.3.2 - */ - private String jsTargetDir; - - /** - * CSS output filename. - * - * @parameter expression="${cssFinalFile}" default-value="style.css" - */ - private String cssFinalFile; - - /** - * JavaScript output filename. - * - * @parameter expression="${jsFinalFile}" default-value="script.js" - */ - private String jsFinalFile; - - /** - * The output filename suffix. - * - * @parameter expression="${suffix}" default-value="min" - * @since 1.3.2 - */ - private String suffix; - - /** - * Do not append a suffix to the minified output filename, independently of the value in the suffix - * parameter. - * - * @parameter expression="${nosuffix}" default-value="false" - * @since 1.7 - */ - private boolean nosuffix; - - /** - *

- * If a supported character set is specified, it will be used to read the input file. Otherwise, it will assume that - * the platform's default character set is being used. The output file is encoded using the same character set. - *

- *

- * See the IANA Charset Registry for a list of valid - * encoding types. - *

- * - * @parameter expression="${charset}" default-value="UTF-8" - * @since 1.3.2 - */ - private String charset; - - /** - * Some source control tools don't like files containing lines longer than, say 8000 characters. The linebreak - * option is used in that case to split long lines after a specific column. It can also be used to make the code - * more readable, easier to debug (especially with the MS Script Debugger). Specify 0 to get a line break after each - * semi-colon in JavaScript, and after each rule in CSS. Specify -1 to disallow line breaks. - * - * @parameter expression="${linebreak}" default-value="-1" - */ - private int linebreak; - - /** - * JAVASCRIPT ONLY OPTION!
- * Minify only. Do not obfuscate local symbols. - * - * @parameter expression="${munge}" default-value="false" - */ - private boolean nomunge; - - /** - * JAVASCRIPT ONLY OPTION!
- * Display informational messages and warnings. - * - * @parameter expression="${verbose}" default-value="false" - */ - private boolean verbose; - - /** - * JAVASCRIPT ONLY OPTION!
- * Preserve unnecessary semicolons (such as right before a '}'). This option is useful when compressed code has to - * be run through JSLint (which is the case of YUI for example). - * - * @parameter expression="${preserveAllSemiColons}" default-value="false" - */ - private boolean preserveAllSemiColons; - - /** - * JAVASCRIPT ONLY OPTION!
- * Disable all the built-in micro optimizations. - * - * @parameter expression="${disableOptimizations}" default-value="false" - */ - private boolean disableOptimizations; - - /** - * Size of the buffer used to read source files. - * - * @parameter expression="${bufferSize}" default-value="4096" - */ - private int bufferSize; - - /** - * Show source file paths in log output. - * - * @parameter expression="${debug}" default-value="false" - * @since 1.5.2 - */ - private boolean debug; - - /** - * Skip the merge step. Minification will be applied to each source file individually. - * - * @parameter expression="${skipMerge}" default-value="false" - * @since 1.5.2 - */ - private boolean skipMerge; - - /** - * Skip the minify step. Useful when merging files that are already minified. - * - * @parameter expression="${skipMinify}" default-value="false" - * @since 1.5.2 - */ - private boolean skipMinify; - - /** - *

- * JAVASCRIPT ONLY OPTION!
- * Define the JavaScript compressor engine to use. - *

- *

- * Possible values are: - *

- * - * - * @parameter expression="${jsEngine}" default-value="yui" - * @since 1.6 - */ - private String jsEngine; - - /** - * Executed when the goal is invoked, it will first invoke a parallel lifecycle, ending at the given phase. - */ - @Override - public void execute() throws MojoExecutionException, MojoFailureException { - if (skipMerge && skipMinify) { - getLog().warn("Both merge and minify steps are configured to be skipped."); - return; - } - if (Strings.isNullOrEmpty(cssTargetDir)) { - cssTargetDir = cssSourceDir; - } - if (Strings.isNullOrEmpty(jsTargetDir)) { - jsTargetDir = jsSourceDir; - } - - Collection processFilesTasks = new ArrayList(); - processFilesTasks.add(new ProcessCSSFilesTask(getLog(), bufferSize, debug, skipMerge, skipMinify, - webappSourceDir, webappTargetDir, cssSourceDir, cssSourceFiles, cssSourceIncludes, cssSourceExcludes, - cssTargetDir, cssFinalFile, suffix, nosuffix, charset, linebreak)); - processFilesTasks.add(new ProcessJSFilesTask(getLog(), bufferSize, debug, skipMerge, skipMinify, - webappSourceDir, webappTargetDir, jsSourceDir, jsSourceFiles, jsSourceIncludes, jsSourceExcludes, - jsTargetDir, jsFinalFile, suffix, nosuffix, charset, linebreak, jsEngine, !nomunge, verbose, - preserveAllSemiColons, disableOptimizations)); - - ExecutorService executor = Executors.newFixedThreadPool(2); - try { - List> futures = executor.invokeAll(processFilesTasks); - for (Future future : futures) { - try { - future.get(); - } catch (ExecutionException e) { - throw new MojoFailureException(e.getMessage(), e); - } - } - executor.shutdown(); - } catch (InterruptedException e) { - executor.shutdownNow(); - throw new MojoFailureException(e.getMessage(), e); - } - } -} +/* + * $Id$ + * + * Minify Maven Plugin + * https://github.com/samaxes/minify-maven-plugin + * + * Copyright (c) 2009 samaxes.com + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.samaxes.maven.minify.plugin; + +import java.io.File; +import java.io.IOException; +import java.nio.charset.Charset; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; + +import javax.annotation.Nullable; + +import org.apache.maven.plugin.AbstractMojo; +import org.apache.maven.plugin.MojoExecutionException; +import org.apache.maven.plugin.MojoFailureException; + +import com.google.common.base.Function; +import com.google.common.base.Predicate; +import com.google.common.base.Predicates; +import com.google.common.base.Strings; +import com.google.common.collect.Iterables; +import com.google.common.collect.Lists; +import com.google.common.io.Files; +import com.google.javascript.jscomp.CompilerOptions.LanguageMode; + +/** + * Goal for combining and minifying CSS and JavaScript files. + * + * @goal minify + * @phase process-resources + */ +public class MinifyMojo extends AbstractMojo { + + private static final Function TRIM_AND_REMOVE_COMMENTS = new Function() { + @Override + public String apply(@Nullable String input) { + if (input == null) { + return null; + } else { + String result = input.trim(); + if (result.startsWith("#")) { + return null; + } else { + return Strings.emptyToNull(result); + } + } + } + }; + + private static final Predicate NOT_NULL = Predicates.not(Predicates.isNull()); + + /** + * Webapp source directory. + * + * @parameter expression="${webappSourceDir}" default-value="${basedir}/src/main/webapp" + */ + private String webappSourceDir; + + /** + * Webapp target directory. + * + * @parameter expression="${webappTargetDir}" default-value="${project.build.directory}/${project.build.finalName}" + */ + private String webappTargetDir; + + /** + * CSS source directory. + * + * @parameter expression="${cssSourceDir}" default-value="css" + */ + private String cssSourceDir; + + /** + * JavaScript source directory. + * + * @parameter expression="${jsSourceDir}" default-value="js" + */ + private String jsSourceDir; + + /** + * CSS source filenames list. + * + * @parameter expression="${cssSourceFiles}" alias="cssFiles" + */ + private ArrayList cssSourceFiles; + + /** + * A file containing a new-line separated list of CSS source file names. + * + * @parameter expression="${cssSourcesFile}" alias="csssFiles" + */ + private String cssSourcesFile; + + /** + * JavaScript source filenames list. + * + * @parameter expression="${jsSourceFiles}" alias="jsFiles" + */ + private ArrayList jsSourceFiles; + + /** + * A file containing a new-line separated list of JavaScript source file names. + * + * @parameter expression="${jsSourcesFile}" alias="jssFile" + */ + private String jsSourcesFile; + + /** + * CSS files to include. Specified as fileset patterns which are relative to the CSS source directory. + * + * @parameter expression="${cssSourceIncludes}" alias="cssIncludes" + * @since 1.2 + */ + private ArrayList cssSourceIncludes; + + /** + * JavaScript files to include. Specified as fileset patterns which are relative to the JavaScript source directory. + * + * @parameter expression="${jsSourceIncludes}" alias="jsIncludes" + * @since 1.2 + */ + private ArrayList jsSourceIncludes; + + /** + * CSS files to exclude. Specified as fileset patterns which are relative to the CSS source directory. + * + * @parameter expression="${cssSourceExcludes}" alias="cssExcludes" + * @since 1.2 + */ + private ArrayList cssSourceExcludes; + + /** + * JavaScript files to exclude. Specified as fileset patterns which are relative to the JavaScript source directory. + * + * @parameter expression="${jsSourceExcludes}" alias="jsExcludes" + * @since 1.2 + */ + private ArrayList jsSourceExcludes; + + /** + * CSS target directory. + *

+ * Takes the same value as cssSourceDir when empty. + *

+ * + * @parameter expression="${cssTargetDir}" + * @since 1.3.2 + */ + private String cssTargetDir; + + /** + * JavaScript target directory. + *

+ * Takes the same value as jsSourceDir when empty. + *

+ * + * @parameter expression="${jsTargetDir}" + * @since 1.3.2 + */ + private String jsTargetDir; + + /** + * CSS output filename. + * + * @parameter expression="${cssFinalFile}" default-value="style.css" + */ + private String cssFinalFile; + + /** + * JavaScript output filename. + * + * @parameter expression="${jsFinalFile}" default-value="script.js" + */ + private String jsFinalFile; + + /** + * The output filename suffix. + * + * @parameter expression="${suffix}" default-value="min" + * @since 1.3.2 + */ + private String suffix; + + /** + * Do not append a suffix to the minified output filename, independently of the value in the suffix + * parameter. + * + * @parameter expression="${nosuffix}" default-value="false" + * @since 1.7 + */ + private boolean nosuffix; + + /** + *

+ * If a supported character set is specified, it will be used to read the input file. Otherwise, it will assume that + * the platform's default character set is being used. The output file is encoded using the same character set. + *

+ *

+ * See the IANA Charset Registry for a list of valid + * encoding types. + *

+ * + * @parameter expression="${charset}" default-value="UTF-8" + * @since 1.3.2 + */ + private String charset; + + /** + * Some source control tools don't like files containing lines longer than, say 8000 characters. The linebreak + * option is used in that case to split long lines after a specific column. It can also be used to make the code + * more readable, easier to debug (especially with the MS Script Debugger). Specify 0 to get a line break after each + * semi-colon in JavaScript, and after each rule in CSS. Specify -1 to disallow line breaks. + * + * @parameter expression="${linebreak}" default-value="-1" + */ + private int linebreak; + + /** + * JAVASCRIPT ONLY OPTION!
+ * Minify only. Do not obfuscate local symbols. + * + * @parameter expression="${munge}" default-value="false" + */ + private boolean nomunge; + + /** + * JAVASCRIPT ONLY OPTION!
+ * Display informational messages and warnings. + * + * @parameter expression="${verbose}" default-value="false" + */ + private boolean verbose; + + /** + * JAVASCRIPT ONLY OPTION!
+ * Preserve unnecessary semicolons (such as right before a '}'). This option is useful when compressed code has to + * be run through JSLint (which is the case of YUI for example). + * + * @parameter expression="${preserveAllSemiColons}" default-value="false" + */ + private boolean preserveAllSemiColons; + + /** + * JAVASCRIPT ONLY OPTION!
+ * Disable all the built-in micro optimizations. + * + * @parameter expression="${disableOptimizations}" default-value="false" + */ + private boolean disableOptimizations; + + /** + * Size of the buffer used to read source files. + * + * @parameter expression="${bufferSize}" default-value="4096" + */ + private int bufferSize; + + /** + * Show source file paths in log output. + * + * @parameter expression="${debug}" default-value="false" + * @since 1.5.2 + */ + private boolean debug; + + /** + * Skip the merge step. Minification will be applied to each source file individually. + * + * @parameter expression="${skipMerge}" default-value="false" + * @since 1.5.2 + */ + private boolean skipMerge; + + /** + * Skip the minify step. Useful when merging files that are already minified. + * + * @parameter expression="${skipMinify}" default-value="false" + * @since 1.5.2 + */ + private boolean skipMinify; + + /** + *

+ * JAVASCRIPT ONLY OPTION!
+ * Define the JavaScript compressor engine to use. + *

+ *

+ * Possible values are: + *

+ * + * + * @parameter expression="${jsEngine}" default-value="yui" + * @since 1.6 + */ + private String jsEngine; + + /** + * Closure language-in compiler option + * + * @parameter expression="${closureLanguageIn}" + */ + private LanguageMode closureLanguageIn; + + /** + * Executed when the goal is invoked, it will first invoke a parallel lifecycle, ending at the given phase. + */ + @Override + public void execute() throws MojoExecutionException, MojoFailureException { + if (skipMerge && skipMinify) { + getLog().warn("Both merge and minify steps are configured to be skipped."); + return; + } + if (Strings.isNullOrEmpty(cssTargetDir)) { + cssTargetDir = cssSourceDir; + } + if (Strings.isNullOrEmpty(jsTargetDir)) { + jsTargetDir = jsSourceDir; + } + if (!Strings.isNullOrEmpty(jsSourcesFile)) { + jsSourceFiles = getFiles(jsSourcesFile); + } + if (!Strings.isNullOrEmpty(cssSourcesFile)) { + cssSourceFiles = getFiles(cssSourcesFile); + } + + Collection processFilesTasks = new ArrayList(); + processFilesTasks.add(new ProcessCSSFilesTask(getLog(), bufferSize, debug, skipMerge, skipMinify, + webappSourceDir, webappTargetDir, cssSourceDir, cssSourceFiles, cssSourceIncludes, cssSourceExcludes, + cssTargetDir, cssFinalFile, suffix, nosuffix, charset, linebreak)); + processFilesTasks.add(new ProcessJSFilesTask(getLog(), bufferSize, debug, skipMerge, skipMinify, + webappSourceDir, webappTargetDir, jsSourceDir, jsSourceFiles, jsSourceIncludes, jsSourceExcludes, + jsTargetDir, jsFinalFile, suffix, nosuffix, charset, linebreak, jsEngine, !nomunge, verbose, + preserveAllSemiColons, disableOptimizations, closureLanguageIn)); + + ExecutorService executor = Executors.newFixedThreadPool(2); + try { + List> futures = executor.invokeAll(processFilesTasks); + for (Future future : futures) { + try { + future.get(); + } catch (ExecutionException e) { + throw new MojoFailureException(e.getMessage(), e); + } + } + executor.shutdown(); + } catch (InterruptedException e) { + executor.shutdownNow(); + throw new MojoFailureException(e.getMessage(), e); + } + } + + private ArrayList getFiles(String bundleDescriptor) throws MojoFailureException { + try { + Iterable files = Files.readLines(new File(bundleDescriptor), Charset.forName(charset)); + files = Iterables.transform(files, TRIM_AND_REMOVE_COMMENTS); + files = Iterables.filter(files, NOT_NULL); + return Lists.newArrayList(files); + } catch (IOException e) { + throw new MojoFailureException(e.getMessage(), e); + } + } +} diff --git a/src/main/java/com/samaxes/maven/minify/plugin/ProcessJSFilesTask.java b/src/main/java/com/samaxes/maven/minify/plugin/ProcessJSFilesTask.java index 1d68c015..410ff4c5 100644 --- a/src/main/java/com/samaxes/maven/minify/plugin/ProcessJSFilesTask.java +++ b/src/main/java/com/samaxes/maven/minify/plugin/ProcessJSFilesTask.java @@ -1,145 +1,153 @@ -/* - * $Id$ - * - * Minify Maven Plugin - * https://github.com/samaxes/minify-maven-plugin - * - * Copyright (c) 2009 samaxes.com - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.samaxes.maven.minify.plugin; - -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.OutputStream; -import java.io.OutputStreamWriter; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; - -import org.apache.maven.plugin.logging.Log; - -import com.google.javascript.jscomp.CompilationLevel; -import com.google.javascript.jscomp.Compiler; -import com.google.javascript.jscomp.CompilerOptions; -import com.google.javascript.jscomp.SourceFile; -import com.samaxes.maven.minify.common.JavaScriptErrorReporter; -import com.yahoo.platform.yui.compressor.JavaScriptCompressor; - -/** - * Task for merging and compressing JavaScript files. - */ -public class ProcessJSFilesTask extends ProcessFilesTask { - - private final String jsEngine; - - private final boolean munge; - - private final boolean verbose; - - private final boolean preserveAllSemiColons; - - private final boolean disableOptimizations; - - /** - * Task constructor. - * - * @param log Maven plugin log - * @param bufferSize size of the buffer used to read source files - * @param debug show source file paths in log output - * @param skipMerge whether to skip the merge step or not - * @param skipMinify whether to skip the minify step or not - * @param jsEngine minify processor engine selected - * @param webappSourceDir web resources source directory - * @param webappTargetDir web resources target directory - * @param inputDir directory containing source files - * @param sourceFiles list of source files to include - * @param sourceIncludes list of source files to include - * @param sourceExcludes list of source files to exclude - * @param outputDir directory to write the final file - * @param outputFilename the output file name - * @param suffix final filename suffix - * @param nosuffix whether to use a suffix for the minified filename or not - * @param charset if a character set is specified, a byte-to-char variant allows the encoding to be selected. - * Otherwise, only byte-to-byte operations are used - * @param linebreak split long lines after a specific column - * @param munge minify only - * @param verbose display informational messages and warnings - * @param preserveAllSemiColons preserve unnecessary semicolons - * @param disableOptimizations disable all the built-in micro optimizations - */ - public ProcessJSFilesTask(Log log, Integer bufferSize, boolean debug, boolean skipMerge, boolean skipMinify, - String webappSourceDir, String webappTargetDir, String inputDir, List sourceFiles, - List sourceIncludes, List sourceExcludes, String outputDir, String outputFilename, - String suffix, boolean nosuffix, String charset, int linebreak, String jsEngine, boolean munge, - boolean verbose, boolean preserveAllSemiColons, boolean disableOptimizations) { - super(log, bufferSize, debug, skipMerge, skipMinify, webappSourceDir, webappTargetDir, inputDir, sourceFiles, - sourceIncludes, sourceExcludes, outputDir, outputFilename, suffix, nosuffix, charset, linebreak); - - this.jsEngine = jsEngine; - this.munge = munge; - this.verbose = verbose; - this.preserveAllSemiColons = preserveAllSemiColons; - this.disableOptimizations = disableOptimizations; - } - - /** - * Minifies a JavaScript file. - * - * @param mergedFile input file resulting from the merged step - * @param minifiedFile output file resulting from the minify step - * @throws IOException when the minify step fails - */ - @Override - protected void minify(File mergedFile, File minifiedFile) throws IOException { - try (InputStream in = new FileInputStream(mergedFile); - OutputStream out = new FileOutputStream(minifiedFile); - InputStreamReader reader = new InputStreamReader(in, charset); - OutputStreamWriter writer = new OutputStreamWriter(out, charset)) { - log.info("Creating the minified file [" + ((debug) ? minifiedFile.getPath() : minifiedFile.getName()) - + "]."); - - if ("closure".equals(jsEngine)) { - log.debug("Using Google Closure Compiler engine."); - - CompilerOptions options = new CompilerOptions(); - CompilationLevel.SIMPLE_OPTIMIZATIONS.setOptionsForCompilationLevel(options); - options.setOutputCharset(charset); - - SourceFile input = SourceFile.fromInputStream(mergedFile.getName(), in); - List externs = Collections.emptyList(); - - Compiler compiler = new Compiler(); - compiler.compile(externs, Arrays.asList(new SourceFile[] { input }), options); - - writer.append(compiler.toSource()); - } else { - log.debug("Using YUI Compressor engine."); - - JavaScriptCompressor compressor = new JavaScriptCompressor(reader, new JavaScriptErrorReporter(log, - mergedFile.getName())); - compressor.compress(writer, linebreak, munge, verbose, preserveAllSemiColons, disableOptimizations); - } - } catch (IOException e) { - log.error("Failed to compress the JavaScript file [" + mergedFile.getName() + "].", e); - throw e; - } - - logCompressionGains(mergedFile, minifiedFile); - } -} +/* + * $Id$ + * + * Minify Maven Plugin + * https://github.com/samaxes/minify-maven-plugin + * + * Copyright (c) 2009 samaxes.com + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.samaxes.maven.minify.plugin; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +import org.apache.maven.plugin.logging.Log; + +import com.google.javascript.jscomp.CompilationLevel; +import com.google.javascript.jscomp.Compiler; +import com.google.javascript.jscomp.CompilerOptions; +import com.google.javascript.jscomp.SourceFile; +import com.google.javascript.jscomp.CompilerOptions.LanguageMode; +import com.samaxes.maven.minify.common.JavaScriptErrorReporter; +import com.yahoo.platform.yui.compressor.JavaScriptCompressor; + +/** + * Task for merging and compressing JavaScript files. + */ +public class ProcessJSFilesTask extends ProcessFilesTask { + + private final String jsEngine; + + private final boolean munge; + + private final boolean verbose; + + private final boolean preserveAllSemiColons; + + private final boolean disableOptimizations; + + private final LanguageMode closureLanguageIn; + + /** + * Task constructor. + * + * @param log Maven plugin log + * @param bufferSize size of the buffer used to read source files + * @param debug show source file paths in log output + * @param skipMerge whether to skip the merge step or not + * @param skipMinify whether to skip the minify step or not + * @param jsEngine minify processor engine selected + * @param webappSourceDir web resources source directory + * @param webappTargetDir web resources target directory + * @param inputDir directory containing source files + * @param sourceFiles list of source files to include + * @param sourceIncludes list of source files to include + * @param sourceExcludes list of source files to exclude + * @param outputDir directory to write the final file + * @param outputFilename the output file name + * @param suffix final filename suffix + * @param nosuffix whether to use a suffix for the minified filename or not + * @param charset if a character set is specified, a byte-to-char variant allows the encoding to be selected. + * Otherwise, only byte-to-byte operations are used + * @param linebreak split long lines after a specific column + * @param munge minify only + * @param verbose display informational messages and warnings + * @param preserveAllSemiColons preserve unnecessary semicolons + * @param disableOptimizations disable all the built-in micro optimizations + */ + public ProcessJSFilesTask(Log log, Integer bufferSize, boolean debug, boolean skipMerge, boolean skipMinify, + String webappSourceDir, String webappTargetDir, String inputDir, List sourceFiles, + List sourceIncludes, List sourceExcludes, String outputDir, String outputFilename, + String suffix, boolean nosuffix, String charset, int linebreak, String jsEngine, boolean munge, + boolean verbose, boolean preserveAllSemiColons, boolean disableOptimizations, + LanguageMode closureLanguageIn) { + super(log, bufferSize, debug, skipMerge, skipMinify, webappSourceDir, webappTargetDir, inputDir, sourceFiles, + sourceIncludes, sourceExcludes, outputDir, outputFilename, suffix, nosuffix, charset, linebreak); + + this.jsEngine = jsEngine; + this.munge = munge; + this.verbose = verbose; + this.preserveAllSemiColons = preserveAllSemiColons; + this.disableOptimizations = disableOptimizations; + this.closureLanguageIn = closureLanguageIn; + } + + /** + * Minifies a JavaScript file. + * + * @param mergedFile input file resulting from the merged step + * @param minifiedFile output file resulting from the minify step + * @throws IOException when the minify step fails + */ + @Override + protected void minify(File mergedFile, File minifiedFile) throws IOException { + try (InputStream in = new FileInputStream(mergedFile); + OutputStream out = new FileOutputStream(minifiedFile); + InputStreamReader reader = new InputStreamReader(in, charset); + OutputStreamWriter writer = new OutputStreamWriter(out, charset)) { + log.info("Creating the minified file [" + ((debug) ? minifiedFile.getPath() : minifiedFile.getName()) + + "]."); + + if ("closure".equals(jsEngine)) { + log.debug("Using Google Closure Compiler engine."); + + CompilerOptions options = new CompilerOptions(); + CompilationLevel.SIMPLE_OPTIMIZATIONS.setOptionsForCompilationLevel(options); + options.setOutputCharset(charset); + if (closureLanguageIn != null) { + options.setLanguageIn(closureLanguageIn); + } + + SourceFile input = SourceFile.fromInputStream(mergedFile.getName(), in); + List externs = Collections.emptyList(); + + Compiler compiler = new Compiler(); + compiler.compile(externs, Arrays.asList(new SourceFile[] { input }), options); + + writer.append(compiler.toSource()); + } else { + log.debug("Using YUI Compressor engine."); + + JavaScriptCompressor compressor = new JavaScriptCompressor(reader, new JavaScriptErrorReporter(log, + mergedFile.getName())); + compressor.compress(writer, linebreak, munge, verbose, preserveAllSemiColons, disableOptimizations); + } + } catch (IOException e) { + log.error("Failed to compress the JavaScript file [" + mergedFile.getName() + "].", e); + throw e; + } + + logCompressionGains(mergedFile, minifiedFile); + } +}