001/* 002 * Minify Maven Plugin 003 * https://github.com/samaxes/minify-maven-plugin 004 * 005 * Copyright (c) 2009 samaxes.com 006 * 007 * Licensed under the Apache License, Version 2.0 (the "License"); 008 * you may not use this file except in compliance with the License. 009 * You may obtain a copy of the License at 010 * 011 * http://www.apache.org/licenses/LICENSE-2.0 012 * 013 * Unless required by applicable law or agreed to in writing, software 014 * distributed under the License is distributed on an "AS IS" BASIS, 015 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 016 * See the License for the specific language governing permissions and 017 * limitations under the License. 018 */ 019package com.samaxes.maven.minify.plugin; 020 021import com.google.common.base.Strings; 022import com.google.gson.Gson; 023import com.google.javascript.jscomp.*; 024import com.google.javascript.jscomp.CompilerOptions.LanguageMode; 025import com.samaxes.maven.minify.common.Aggregation; 026import com.samaxes.maven.minify.common.AggregationConfiguration; 027import com.samaxes.maven.minify.common.ClosureConfig; 028import com.samaxes.maven.minify.common.YuiConfig; 029import org.apache.maven.plugin.AbstractMojo; 030import org.apache.maven.plugin.MojoExecutionException; 031import org.apache.maven.plugin.MojoFailureException; 032import org.apache.maven.plugins.annotations.LifecyclePhase; 033import org.apache.maven.plugins.annotations.Mojo; 034import org.apache.maven.plugins.annotations.Parameter; 035 036import java.io.*; 037import java.nio.charset.Charset; 038import java.util.*; 039import java.util.concurrent.ExecutionException; 040import java.util.concurrent.ExecutorService; 041import java.util.concurrent.Executors; 042import java.util.concurrent.Future; 043 044import static com.google.common.collect.Lists.newArrayList; 045 046/** 047 * Goal for combining and minifying CSS and JavaScript files. 048 */ 049@Mojo(name = "minify", defaultPhase = LifecyclePhase.PROCESS_RESOURCES, threadSafe = true) 050public class MinifyMojo extends AbstractMojo { 051 052 /** 053 * Engine used for minification. 054 */ 055 public enum Engine { 056 /** 057 * YUI Compressor 058 */ 059 YUI, 060 /** 061 * Google Closure Compiler 062 */ 063 CLOSURE 064 } 065 066 /* ************** */ 067 /* Global Options */ 068 /* ************** */ 069 070 /** 071 * Show source file paths in log output. 072 * 073 * @since 1.5.2 074 * @deprecated Use {@link #verbose} instead. 075 */ 076 @Deprecated 077 @Parameter(property = "debug") 078 private Boolean debug; 079 080 /** 081 * Display additional informational messages and warnings. 082 */ 083 @Parameter(property = "verbose", defaultValue = "false") 084 private boolean verbose; 085 086 /** 087 * Size of the buffer used to read source files. 088 */ 089 @Parameter(property = "bufferSize", defaultValue = "4096") 090 private int bufferSize; 091 092 /** 093 * If a supported character set is specified, it will be used to read the input file. Otherwise, it will assume that 094 * the platform's default character set is being used. The output file is encoded using the same character set.<br/> 095 * See the <a href="http://www.iana.org/assignments/character-sets">IANA Charset Registry</a> for a list of valid 096 * encoding types. 097 * 098 * @since 1.3.2 099 */ 100 @Parameter(property = "charset", defaultValue = "${project.build.sourceEncoding}") 101 private String charset; 102 103 /** 104 * The output file name suffix. 105 * 106 * @since 1.3.2 107 */ 108 @Parameter(property = "suffix", defaultValue = ".min") 109 private String suffix; 110 111 /** 112 * Do not append a suffix to the minified output file name, independently of the value in the {@code suffix} 113 * parameter.<br/> 114 * <strong>Warning:</strong> when both the options {@code nosuffix} and {@code skipMerge} are set to {@code true}, 115 * the plugin execution phase needs to be set to {@code package}, otherwise the output files will be overridden by 116 * the source files during the packaging. 117 * 118 * @since 1.7 119 */ 120 @Parameter(property = "nosuffix", defaultValue = "false") 121 private boolean nosuffix; 122 123 /** 124 * Skip the merge step. Minification will be applied to each source file individually. 125 * 126 * @since 1.5.2 127 */ 128 @Parameter(property = "skipMerge", defaultValue = "false") 129 private boolean skipMerge; 130 131 /** 132 * Skip the minify step. Useful when merging files that are already minified. 133 * 134 * @since 1.5.2 135 */ 136 @Parameter(property = "skipMinify", defaultValue = "false") 137 private boolean skipMinify; 138 139 /** 140 * Webapp source directory. 141 */ 142 @Parameter(property = "webappSourceDir", defaultValue = "${basedir}/src/main/webapp") 143 private String webappSourceDir; 144 145 /** 146 * Webapp target directory. 147 */ 148 @Parameter(property = "webappTargetDir", defaultValue = "${project.build.directory}/${project.build.finalName}") 149 private String webappTargetDir; 150 151 /** 152 * Specify aggregations in an external JSON formatted config file. 153 * 154 * @since 1.7.5 155 */ 156 @Parameter(property = "bundleConfiguration") 157 private String bundleConfiguration; 158 159 /* *********** */ 160 /* CSS Options */ 161 /* *********** */ 162 163 /** 164 * CSS source directory. 165 */ 166 @Parameter(property = "cssSourceDir", defaultValue = "css") 167 private String cssSourceDir; 168 169 /** 170 * CSS source file names list. 171 */ 172 @Parameter(property = "cssSourceFiles", alias = "cssFiles") 173 private ArrayList<String> cssSourceFiles; 174 175 /** 176 * CSS files to include. Specified as fileset patterns which are relative to the CSS source directory. 177 * 178 * @since 1.2 179 */ 180 @Parameter(property = "cssSourceIncludes", alias = "cssIncludes") 181 private ArrayList<String> cssSourceIncludes; 182 183 /** 184 * CSS files to exclude. Specified as fileset patterns which are relative to the CSS source directory. 185 * 186 * @since 1.2 187 */ 188 @Parameter(property = "cssSourceExcludes", alias = "cssExcludes") 189 private ArrayList<String> cssSourceExcludes; 190 191 /** 192 * CSS target directory. Takes the same value as {@code cssSourceDir} when empty. 193 * 194 * @since 1.3.2 195 */ 196 @Parameter(property = "cssTargetDir") 197 private String cssTargetDir; 198 199 /** 200 * CSS output file name. 201 */ 202 @Parameter(property = "cssFinalFile", defaultValue = "style.css") 203 private String cssFinalFile; 204 205 /** 206 * Define the CSS compressor engine to use.<br/> 207 * Possible values are: 208 * <ul> 209 * <li>{@code YUI}: <a href="http://yui.github.io/yuicompressor/">YUI Compressor</a></li> 210 * </ul> 211 * 212 * @since 1.7.1 213 */ 214 @Parameter(property = "cssEngine", defaultValue = "YUI") 215 private Engine cssEngine; 216 217 /* ****************** */ 218 /* JavaScript Options */ 219 /* ****************** */ 220 221 /** 222 * JavaScript source directory. 223 */ 224 @Parameter(property = "jsSourceDir", defaultValue = "js") 225 private String jsSourceDir; 226 227 /** 228 * JavaScript source file names list. 229 */ 230 @Parameter(property = "jsSourceFiles", alias = "jsFiles") 231 private ArrayList<String> jsSourceFiles; 232 233 /** 234 * JavaScript files to include. Specified as fileset patterns which are relative to the JavaScript source directory. 235 * 236 * @since 1.2 237 */ 238 @Parameter(property = "jsSourceIncludes", alias = "jsIncludes") 239 private ArrayList<String> jsSourceIncludes; 240 241 /** 242 * JavaScript files to exclude. Specified as fileset patterns which are relative to the JavaScript source directory. 243 * 244 * @since 1.2 245 */ 246 @Parameter(property = "jsSourceExcludes", alias = "jsExcludes") 247 private ArrayList<String> jsSourceExcludes; 248 249 /** 250 * JavaScript target directory. Takes the same value as {@code jsSourceDir} when empty. 251 * 252 * @since 1.3.2 253 */ 254 @Parameter(property = "jsTargetDir") 255 private String jsTargetDir; 256 257 /** 258 * JavaScript output file name. 259 */ 260 @Parameter(property = "jsFinalFile", defaultValue = "script.js") 261 private String jsFinalFile; 262 263 /** 264 * Define the JavaScript compressor engine to use.<br/> 265 * Possible values are: 266 * <ul> 267 * <li>{@code YUI}: <a href="http://yui.github.io/yuicompressor/">YUI Compressor</a></li> 268 * <li>{@code CLOSURE}: <a href="https://developers.google.com/closure/compiler/">Google Closure Compiler</a></li> 269 * </ul> 270 * 271 * @since 1.6 272 */ 273 @Parameter(property = "jsEngine", defaultValue = "YUI") 274 private Engine jsEngine; 275 276 /* *************************** */ 277 /* YUI Compressor Only Options */ 278 /* *************************** */ 279 280 /** 281 * Some source control tools don't like files containing lines longer than, say 8000 characters. The line-break 282 * option is used in that case to split long lines after a specific column. It can also be used to make the code 283 * more readable and easier to debug. Specify {@code 0} to get a line break after each semi-colon in JavaScript, and 284 * after each rule in CSS. Specify {@code -1} to disallow line breaks. 285 * 286 * @deprecated Use {@link #yuiLineBreak} instead. 287 */ 288 @Deprecated 289 @Parameter(property = "linebreak") 290 private Integer linebreak; 291 292 /** 293 * Some source control tools don't like files containing lines longer than, say 8000 characters. The line-break 294 * option is used in that case to split long lines after a specific column. It can also be used to make the code 295 * more readable and easier to debug. Specify {@code 0} to get a line break after each semi-colon in JavaScript, and 296 * after each rule in CSS. Specify {@code -1} to disallow line breaks. 297 */ 298 @Parameter(property = "yuiLineBreak", defaultValue = "-1") 299 private int yuiLineBreak; 300 301 /** 302 * Obfuscate local symbols in addition to minification. 303 * 304 * @deprecated Use {@link #yuiNoMunge} instead. 305 */ 306 @Deprecated 307 @Parameter(property = "munge") 308 private Boolean munge; 309 310 /** 311 * Minify only. Do not obfuscate local symbols. 312 */ 313 @Parameter(property = "yuiNoMunge", defaultValue = "false") 314 private boolean yuiNoMunge; 315 316 /** 317 * Preserve unnecessary semicolons (such as right before a '}'). This option is useful when compressed code has to 318 * be run through JSLint. 319 * 320 * @deprecated Use {@link #yuiPreserveSemicolons} instead. 321 */ 322 @Deprecated 323 @Parameter(property = "preserveAllSemiColons") 324 private Boolean preserveAllSemiColons; 325 326 /** 327 * Preserve unnecessary semicolons (such as right before a '}'). This option is useful when compressed code has to 328 * be run through JSLint. 329 */ 330 @Parameter(property = "yuiPreserveSemicolons", defaultValue = "false") 331 private boolean yuiPreserveSemicolons; 332 333 /** 334 * Disable all the built-in micro-optimizations. 335 * 336 * @deprecated Use {@link #yuiDisableOptimizations} instead. 337 */ 338 @Deprecated 339 @Parameter(property = "disableOptimizations") 340 private Boolean disableOptimizations; 341 342 /** 343 * Disable all the built-in micro-optimizations. 344 */ 345 @Parameter(property = "yuiDisableOptimizations", defaultValue = "false") 346 private boolean yuiDisableOptimizations; 347 348 /* ************************************ */ 349 /* Google Closure Compiler Only Options */ 350 /* ************************************ */ 351 352 /** 353 * Refers to which version of ECMAScript to assume when checking for errors in your code.<br/> 354 * Possible values are: 355 * <ul> 356 * <li>{@code ECMASCRIPT3}: Checks code assuming ECMAScript 3 compliance, and gives errors for code using features only present in later versions of ECMAScript.</li> 357 * <li>{@code ECMASCRIPT5}: Checks code assuming ECMAScript 5 compliance, allowing new features not present in ECMAScript 3, and gives errors for code using features only present in later versions of ECMAScript.</li> 358 * <li>{@code ECMASCRIPT5_STRICT}: Like {@code ECMASCRIPT5} but assumes compliance with strict mode ({@code 'use strict';}).</li> 359 * <li>{@code ECMASCRIPT6}: Checks code assuming ECMAScript 6 compliance, allowing new features not present in ECMAScript 5.</li> 360 * <li>{@code ECMASCRIPT6_STRICT}: Like {@code ECMASCRIPT6} but assumes compliance with strict mode ({@code 'use strict';}).</li> 361 * </ul> 362 * 363 * @since 1.7.2 364 */ 365 @Parameter(property = "closureLanguageIn", defaultValue = "ECMASCRIPT6") 366 private LanguageMode closureLanguageIn; 367 368 /** 369 * Refers to which version of ECMAScript your code will be returned in.<br/> 370 * It accepts the same options as {@code closureLanguageIn} and is used to transpile between different levels of ECMAScript. 371 * 372 * @since 1.7.5 373 */ 374 @Parameter(property = "closureLanguageOut", defaultValue = "ECMASCRIPT5") 375 private LanguageMode closureLanguageOut; 376 377 /** 378 * Determines the set of builtin externs to load.<br/> 379 * Options: BROWSER, CUSTOM. 380 * 381 * @since 1.7.5 382 */ 383 @Parameter(property = "closureEnvironment", defaultValue = "BROWSER") 384 private CompilerOptions.Environment closureEnvironment; 385 386 /** 387 * The degree of compression and optimization to apply to your JavaScript.<br/> 388 * There are three possible compilation levels: 389 * <ul> 390 * <li>{@code WHITESPACE_ONLY}: Just removes whitespace and comments from your JavaScript.</li> 391 * <li>{@code SIMPLE_OPTIMIZATIONS}: Performs compression and optimization that does not interfere with the 392 * interaction between the compiled JavaScript and other JavaScript. This level renames only local variables.</li> 393 * <li>{@code ADVANCED_OPTIMIZATIONS}: Achieves the highest level of compression by renaming symbols in your 394 * JavaScript. When using {@code ADVANCED_OPTIMIZATIONS} compilation you must perform extra steps to preserve 395 * references to external symbols. See <a href="/closure/compiler/docs/api-tutorial3">Advanced Compilation and 396 * Externs</a> for more information about {@code ADVANCED_OPTIMIZATIONS}.</li> 397 * </ul> 398 * 399 * @since 1.7.2 400 */ 401 @Parameter(property = "closureCompilationLevel", defaultValue = "SIMPLE_OPTIMIZATIONS") 402 private CompilationLevel closureCompilationLevel; 403 404 /** 405 * List of JavaScript files containing code that declares function names or other symbols. Use 406 * {@code closureExterns} to preserve symbols that are defined outside of the code you are compiling. The 407 * {@code closureExterns} parameter only has an effect if you are using a {@code CompilationLevel} of 408 * {@code ADVANCED_OPTIMIZATIONS}.<br/> 409 * These file names are relative to {@link #webappSourceDir} directory. 410 * 411 * @since 1.7.2 412 */ 413 @Parameter(property = "closureExterns") 414 private ArrayList<String> closureExterns; 415 416 /** 417 * Collects information mapping the generated (compiled) source back to its original source for debugging purposes.<br/> 418 * Please visit <a href="https://docs.google.com/document/d/1U1RGAehQwRypUTovF1KRlpiOFze0b-_2gc6fAH0KY0k/edit">Source Map Revision 3 Proposal</a> for more information. 419 * 420 * @since 1.7.3 421 */ 422 @Parameter(property = "closureCreateSourceMap", defaultValue = "false") 423 private boolean closureCreateSourceMap; 424 425 /** 426 * Enables or disables sorting mode for Closure Library dependencies.<br/> 427 * If {@code true}, automatically sort dependencies so that a file that {@code goog.provides} symbol X will always come 428 * before a file that {@code goog.requires} symbol X. 429 * 430 * @since 1.7.4 431 */ 432 @Parameter(property = "closureSortDependencies", defaultValue = "false") 433 private boolean closureSortDependencies; 434 435 /** 436 * Treat certain warnings as the specified CheckLevel: 437 * <ul> 438 * <li>{@code ERROR}: Makes all warnings of the given group to build-breaking error.</li> 439 * <li>{@code WARNING}: Makes all warnings of the given group a non-breaking warning.</li> 440 * <li>{@code OFF}: Silences all warnings of the given group.</li> 441 * </ul> 442 * Example: 443 * <pre><code class="language-java"> 444 * <closureWarningLevels> 445 * <nonStandardJsDocs>OFF</nonStandardJsDocs> 446 * </closureWarningLevels> 447 * </code></pre> 448 * For the complete list of diagnostic groups please visit <a href="https://github.com/google/closure-compiler/wiki/Warnings">https://github.com/google/closure-compiler/wiki/Warnings</a>. 449 * 450 * @since 1.7.5 451 */ 452 @Parameter(property = "closureWarningLevels") 453 private HashMap<String, String> closureWarningLevels; 454 455 /** 456 * Generate {@code $inject} properties for AngularJS for functions annotated with {@code @ngInject}. 457 * 458 * @since 1.7.3 459 */ 460 @Parameter(property = "closureAngularPass", defaultValue = "false") 461 private boolean closureAngularPass; 462 463 /** 464 * A whitelist of tag names in JSDoc. Needed to support JSDoc extensions like ngdoc. 465 * 466 * @since 1.7.5 467 */ 468 @Parameter(property = "closureExtraAnnotations") 469 private ArrayList<String> closureExtraAnnotations; 470 471 /** 472 * Override the value of variables annotated with {@code @define}.<br/> 473 * The format is: 474 * <pre><code class="language-java"> 475 * <define> 476 * <name>value</name> 477 * </define> 478 * </code></pre> 479 * where {@code <name>} is the name of a {@code @define} variable and {@code value} is a boolean, number or string. 480 * 481 * @since 1.7.5 482 */ 483 @Parameter(property = "closureDefine") 484 private HashMap<String, String> closureDefine; 485 486 /** 487 * Executed when the goal is invoked, it will first invoke a parallel lifecycle, ending at the given phase. 488 */ 489 @Override 490 public void execute() throws MojoExecutionException, MojoFailureException { 491 checkDeprecatedOptions(); 492 493 if (skipMerge && skipMinify) { 494 getLog().warn("Both merge and minify steps are configured to be skipped."); 495 return; 496 } 497 498 fillOptionalValues(); 499 500 YuiConfig yuiConfig = fillYuiConfig(); 501 ClosureConfig closureConfig = fillClosureConfig(); 502 Collection<ProcessFilesTask> processFilesTasks; 503 try { 504 processFilesTasks = createTasks(yuiConfig, closureConfig); 505 } catch (FileNotFoundException e) { 506 throw new MojoFailureException(e.getMessage(), e); 507 } 508 509 ExecutorService executor = Executors.newFixedThreadPool(processFilesTasks.size()); 510 try { 511 List<Future<Object>> futures = executor.invokeAll(processFilesTasks); 512 for (Future<Object> future : futures) { 513 try { 514 future.get(); 515 } catch (ExecutionException e) { 516 throw new MojoExecutionException(e.getMessage(), e); 517 } 518 } 519 executor.shutdown(); 520 } catch (InterruptedException e) { 521 executor.shutdownNow(); 522 throw new MojoExecutionException(e.getMessage(), e); 523 } 524 } 525 526 private void checkDeprecatedOptions() { 527 if (debug == null) { 528 debug = verbose; 529 } else { 530 getLog().warn( 531 "The option 'debug' is deprecated and will be removed on the next version. Use 'verbose' instead."); 532 } 533 if (linebreak == null) { 534 linebreak = yuiLineBreak; 535 } else { 536 getLog().warn( 537 "The option 'linebreak' is deprecated and will be removed on the next version. Use 'yuiLineBreak' instead."); 538 } 539 if (munge == null) { 540 munge = !yuiNoMunge; 541 } else { 542 getLog().warn( 543 "The option 'munge' is deprecated and will be removed on the next version. Use 'yuiNoMunge' instead."); 544 } 545 if (preserveAllSemiColons == null) { 546 preserveAllSemiColons = yuiPreserveSemicolons; 547 } else { 548 getLog().warn( 549 "The option 'preserveAllSemiColons' is deprecated and will be removed on the next version. Use 'yuiPreserveSemicolons' instead."); 550 } 551 if (disableOptimizations == null) { 552 disableOptimizations = yuiDisableOptimizations; 553 } else { 554 getLog().warn( 555 "The option 'disableOptimizations' is deprecated and will be removed on the next version. Use 'yuiDisableOptimizations' instead."); 556 } 557 } 558 559 private void fillOptionalValues() { 560 if (Strings.isNullOrEmpty(cssTargetDir)) { 561 cssTargetDir = cssSourceDir; 562 } 563 if (Strings.isNullOrEmpty(jsTargetDir)) { 564 jsTargetDir = jsSourceDir; 565 } 566 if (Strings.isNullOrEmpty(charset)) { 567 charset = Charset.defaultCharset().name(); 568 } 569 } 570 571 private YuiConfig fillYuiConfig() { 572 return new YuiConfig(linebreak, munge, preserveAllSemiColons, disableOptimizations); 573 } 574 575 private ClosureConfig fillClosureConfig() throws MojoFailureException { 576 DependencyOptions dependencyOptions = new DependencyOptions(); 577 dependencyOptions.setDependencySorting(closureSortDependencies); 578 579 List<SourceFile> externs = new ArrayList<>(); 580 for (String extern : closureExterns) { 581 externs.add(SourceFile.fromFile(webappSourceDir + File.separator + extern, Charset.forName(charset))); 582 } 583 584 Map<DiagnosticGroup, CheckLevel> warningLevels = new HashMap<>(); 585 DiagnosticGroups diagnosticGroups = new DiagnosticGroups(); 586 for (Map.Entry<String, String> warningLevel : closureWarningLevels.entrySet()) { 587 DiagnosticGroup diagnosticGroup = diagnosticGroups.forName(warningLevel.getKey()); 588 if (diagnosticGroup == null) { 589 throw new MojoFailureException("Failed to process closureWarningLevels: " + warningLevel.getKey() + " is an invalid DiagnosticGroup"); 590 } 591 592 try { 593 CheckLevel checkLevel = CheckLevel.valueOf(warningLevel.getValue()); 594 warningLevels.put(diagnosticGroup, checkLevel); 595 } catch (IllegalArgumentException e) { 596 throw new MojoFailureException("Failed to process closureWarningLevels: " + warningLevel.getKey() + " is an invalid CheckLevel"); 597 } 598 } 599 600 return new ClosureConfig(closureLanguageIn, closureLanguageOut, closureEnvironment, closureCompilationLevel, 601 dependencyOptions, externs, closureCreateSourceMap, warningLevels, closureAngularPass, 602 closureExtraAnnotations, closureDefine); 603 } 604 605 private Collection<ProcessFilesTask> createTasks(YuiConfig yuiConfig, ClosureConfig closureConfig) 606 throws MojoFailureException, FileNotFoundException { 607 List<ProcessFilesTask> tasks = newArrayList(); 608 609 if (!Strings.isNullOrEmpty(bundleConfiguration)) { // If a bundleConfiguration is defined, attempt to use that 610 AggregationConfiguration aggregationConfiguration; 611 try (Reader bundleConfigurationReader = new FileReader(bundleConfiguration)) { 612 aggregationConfiguration = new Gson().fromJson(bundleConfigurationReader, 613 AggregationConfiguration.class); 614 } catch (IOException e) { 615 throw new MojoFailureException("Failed to open the bundle configuration file [" + bundleConfiguration 616 + "].", e); 617 } 618 619 for (Aggregation aggregation : aggregationConfiguration.getBundles()) { 620 if (Aggregation.AggregationType.css.equals(aggregation.getType())) { 621 tasks.add(createCSSTask(yuiConfig, closureConfig, aggregation.getFiles(), 622 Collections.<String>emptyList(), Collections.<String>emptyList(), aggregation.getName())); 623 } else if (Aggregation.AggregationType.js.equals(aggregation.getType())) { 624 tasks.add(createJSTask(yuiConfig, closureConfig, aggregation.getFiles(), 625 Collections.<String>emptyList(), Collections.<String>emptyList(), aggregation.getName())); 626 } 627 } 628 } else { // Otherwise, fallback to the default behavior 629 tasks.add(createCSSTask(yuiConfig, closureConfig, cssSourceFiles, cssSourceIncludes, cssSourceExcludes, 630 cssFinalFile)); 631 tasks.add(createJSTask(yuiConfig, closureConfig, jsSourceFiles, jsSourceIncludes, jsSourceExcludes, 632 jsFinalFile)); 633 } 634 635 return tasks; 636 } 637 638 private ProcessFilesTask createCSSTask(YuiConfig yuiConfig, ClosureConfig closureConfig, 639 List<String> cssSourceFiles, List<String> cssSourceIncludes, List<String> cssSourceExcludes, 640 String cssFinalFile) throws FileNotFoundException { 641 return new ProcessCSSFilesTask(getLog(), debug, bufferSize, Charset.forName(charset), suffix, nosuffix, 642 skipMerge, skipMinify, webappSourceDir, webappTargetDir, cssSourceDir, cssSourceFiles, 643 cssSourceIncludes, cssSourceExcludes, cssTargetDir, cssFinalFile, cssEngine, yuiConfig); 644 } 645 646 private ProcessFilesTask createJSTask(YuiConfig yuiConfig, ClosureConfig closureConfig, List<String> jsSourceFiles, 647 List<String> jsSourceIncludes, List<String> jsSourceExcludes, String jsFinalFile) 648 throws FileNotFoundException { 649 return new ProcessJSFilesTask(getLog(), debug, bufferSize, Charset.forName(charset), suffix, nosuffix, 650 skipMerge, skipMinify, webappSourceDir, webappTargetDir, jsSourceDir, jsSourceFiles, jsSourceIncludes, 651 jsSourceExcludes, jsTargetDir, jsFinalFile, jsEngine, yuiConfig, closureConfig); 652 } 653}