net.jawr.web.minification.CSSMinifier Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jawr-core Show documentation
Show all versions of jawr-core Show documentation
Javascript/CSS bundling and compressing tool for java web apps.
By using jawr resources are automatically bundled together and optionally minified and gzipped.
Jawr provides tag libraries to reference a generated bundle either by id or by using the name of any of its members.
/**
* Copyright 2007-2012 Jordi Hernández Sellés, Ibrahim Chaehoi
*
* 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 net.jawr.web.minification;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import net.jawr.web.resource.bundle.factory.util.RegexUtil;
/**
* Minifies CSS files by removing expendable whitespace and comments.
*
* @author Jordi Hernández Sellés
* @author ibrahim Chaehoi
*/
public class CSSMinifier {
// This regex captures comments
private static final String COMMENT_REGEX = "(/\\*[^*]*\\*+([^/][^*]*\\*+)*/)";
// Captures CSS strings
// private static final String QUOTED_CONTENT_REGEX =
// "('(\\\\'|[^'])*?')|(\"(\\\\\"|[^\"])*?\")";
private static final String QUOTED_CONTENT_REGEX = "([\"']).*?\\1";
// A placeholder string to replace and restore CSS strings
private static final String STRING_PLACEHOLDER = "______'JAWR_STRING'______";
// Captured CSS rules (requires replacing CSS strings with a placeholder, or
// quoted braces will fool it.
private static final String RULES_REGEX = "([^\\{\\}]*)(\\{[^\\{\\}]*})";
// Captures newlines and tabs
private static final String NEW_LINE_TABS_REGEX = "\\r|\\n|\\t|\\f";
// This regex captures, in order:
// (\\s*\\{\\s*)|(\\s*\\}\\s*)|(\\s*\\(\\s*)|(\\s*;\\s*)|(\\s*\\))
// brackets, parentheses,colons and semicolons and any spaces around them
// (except spaces AFTER a parentheses closing
// symbol),
// and ( +) occurrences of one or more spaces.
/**
* There is a special case when the space should not be removed when
* preceeded by and keyword. Ex:
*
* @media only screen and (max-width:767px){ }
*/
private static final String SPACES_REGEX = "(?ims)(\\s*\\{\\s*)|(\\s*\\}\\s*)|((? strings = new ArrayList();
final Matcher stringMatcher = QUOTED_CONTENT_PATTERN
.matcher(compressed);
compressed = new MatcherProcessorCallback() {
String matchCallback(final Matcher matcher) {
final String match = matcher.group();
strings.add(match);
return STRING_PLACEHOLDER;
}
}.processWithMatcher(stringMatcher);
// Grab all rules and replace whitespace in selectors
final Matcher rulesmatcher = RULES_PATTERN.matcher(compressed);
compressed = new MatcherProcessorCallback() {
String matchCallback(final Matcher matcher) {
final String match = matcher.group(1);
final String spaced = NEW_LINES_TAB_PATTERN
.matcher(match.toString()).replaceAll(SPACE).trim();
return spaced + matcher.group(2);
}
}.processWithMatcher(rulesmatcher);
// Replace all linefeeds and tabs
compressed = NEW_LINES_TAB_PATTERN.matcher(compressed).replaceAll(" ");
// Match all empty space we can minify
final Matcher matcher = SPACES_PATTERN.matcher(compressed);
compressed = new MatcherProcessorCallback() {
String matchCallback(final Matcher matcher) {
String replacement = SPACE;
final String match = matcher.group();
if (match.indexOf(BRACKET_OPEN) != -1)
replacement = BRACKET_OPEN;
else if (match.indexOf(BRACKET_CLOSE) != -1)
replacement = BRACKET_CLOSE;
else if (match.indexOf(PAREN_OPEN) != -1)
replacement = PAREN_OPEN;
else if (match.indexOf(COLON) != -1)
replacement = COLON;
else if (match.indexOf(SEMICOLON) != -1)
replacement = SEMICOLON;
else if (match.indexOf(PAREN_CLOSE) != -1)
replacement = PAREN_CLOSE;
return replacement;
}
}.processWithMatcher(matcher);
// Restore all Strings
final Matcher restoreMatcher = STRING_PLACE_HOLDE_PATTERN
.matcher(compressed);
final Iterator it = strings.iterator();
compressed = new MatcherProcessorCallback() {
String matchCallback(final Matcher matcher) {
final String replacement = it.next();
return replacement;
}
}.processWithMatcher(restoreMatcher);
return new StringBuffer(compressed);
}
}