Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
.gradle
.idea
build
19 changes: 19 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
apply plugin: 'java'

repositories {
mavenCentral()
maven {
url 'https://repository.jboss.org/nexus/content/repositories/thirdparty-releases/'
}
}

dependencies {
compile 'net.sf:jargs:1.0'
testCompile 'junit:junit:4.11'
}

compileJava {
sourceCompatibility = 1.7
targetCompatibility = 1.7
options.compilerArgs = ['-Xlint:all']
}
1 change: 1 addition & 0 deletions settings.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
rootProject.name = "csscompressor"
Original file line number Diff line number Diff line change
Expand Up @@ -71,8 +71,8 @@ public CssCompressor(Reader in) throws IOException {

protected String mergeRules(String inputCss) {

Map ruleMap = new HashMap();
StringBuffer mergedCss = new StringBuffer();
Map<String, String> ruleMap = new HashMap<String, String>();
StringBuilder mergedCss = new StringBuilder();

Pattern p = Pattern.compile("([^\\{]*)\\{(.*?)\\}");
Matcher m = p.matcher(inputCss);
Expand All @@ -84,30 +84,28 @@ protected String mergeRules(String inputCss) {
rules = compressDimensions(rules);

if (ruleMap.containsKey(rules)) {
ruleMap.put(rules, ruleMap.get(rules) + "," + selectors);
ruleMap.put(rules, ruleMap.get(rules) + ',' + selectors);
}
else {
ruleMap.put(rules, selectors);
}
}

String rule;
for (Iterator i = ruleMap.keySet().iterator(); i.hasNext();) {
rule = (String)i.next();
mergedCss.append(ruleMap.get(rule)+"{"+rule+"}");
for (String rule : ruleMap.keySet()) {
mergedCss.append(ruleMap.get(rule)).append('{').append(rule).append('}');
}

return mergedCss.toString();
}

protected String removeDuplicateProperties(String inputCssRule) {

StringBuffer cssRule = new StringBuffer();
StringBuilder cssRule = new StringBuilder();

Set ruleSet = new HashSet(Arrays.asList(inputCssRule.split(";")));
Set<String> ruleSet = new HashSet<String>(Arrays.asList(inputCssRule.split(";")));

for (Iterator i = ruleSet.iterator(); i.hasNext();) {
cssRule.append((String)i.next() + ";");
for (String aRuleSet : ruleSet) {
cssRule.append(aRuleSet).append(";");
}

return cssRule.toString();
Expand All @@ -117,18 +115,18 @@ protected String compressDimensions(String inputCssRule) {
Pattern p = Pattern.compile("(border|margin):(\\d+(?:\\p{Alpha}*))(\\2){3}");
Matcher m;

StringBuffer cssRule = new StringBuffer();
StringBuilder cssRule = new StringBuilder();

for (String rule: inputCssRule.split(";")) {

String condensedRule = rule.replaceAll(" +", "");
m = p.matcher(condensedRule);
if (m.find()) {
cssRule.append(condensedRule.substring(0, m.start()));
cssRule.append(m.group(1) + ':' + m.group(2) + ';');
cssRule.append(m.group(1)).append(':').append(m.group(2)).append(';');
}
else {
cssRule.append(rule + ';');
cssRule.append(rule).append(';');
}
}

Expand Down Expand Up @@ -223,9 +221,9 @@ public void compress(Writer out, int linebreakpos)
sb = new StringBuffer();
while (m.find()) {
String[] rgbcolors = m.group(1).split(",");
StringBuffer hexcolor = new StringBuffer("#");
for (int i = 0; i < rgbcolors.length; i++) {
int val = Integer.parseInt(rgbcolors[i]);
StringBuilder hexcolor = new StringBuilder("#");
for (String rgbcolor : rgbcolors) {
int val = Integer.parseInt(rgbcolor);
if (val < 16) {
hexcolor.append("0");
}
Expand All @@ -246,7 +244,7 @@ public void compress(Writer out, int linebreakpos)
m = p.matcher(css);
sb = new StringBuffer();

Map colorMap = new HashMap();
Map<String, String> colorMap = new HashMap<String, String>();
colorMap.put("C0C0C0", "silver");
colorMap.put("800000", "maroon");
colorMap.put("800080", "purple");
Expand Down
65 changes: 65 additions & 0 deletions src/test/java/andyr/csscompressor/CssCompressorTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package andyr.csscompressor;

import org.junit.Test;

import java.io.*;

import static org.junit.Assert.*;

public class CssCompressorTest {

@Test
public void testCompressionMergesDuplicates() throws Exception {
checkCompression(".myclassA { font-style: bold; }\n.myclassB { font-style: bold; }", ".myclassA,\n.myclassB{font-style:bold}");
}

@Test
public void testCompressionCompressesDimensions() throws Exception {
checkCompression(".myclass { border: 4px 4px 4px 4px; } ", ".myclass{border:4px}");
}

@Test
public void testCompressionRemovesLastSemiColon() throws Exception {
checkCompression(".myclass { font-style: bold; color: red; }", ".myclass{font-style:bold;color:red}");
}

@Test
public void testCompressionRemovesWhitespaces() throws Exception {
checkCompression(".myclass { font-style: bold; }", ".myclass{font-style:bold}");
}

@Test
public void testCompressionStripsUnitValuesOnZeros() throws Exception {
checkCompression(".myclass { margin-left: 0px; }", ".myclass{margin-left:0}");
}

@Test
public void testCompressionCompressesColors() throws Exception {
checkCompression(".myclass { color: rgb(51,102,153); }", ".myclass{color:#369}");
checkCompression(".myclass { color: #AABBCC; }", ".myclass{color:#ABC}");
}

@Test
public void testCompressionRemovesComments() throws Exception {
checkCompression(".myclass { font-style: bold; /* comment */ }", ".myclass{font-style:bold}");
}

@Test
public void testCompressionRemovesEmptyRules() throws Exception {
checkCompression(".myclass { }", "");
}

@Test
public void testCompressionAcceptsBlankInputs() throws Exception {
checkCompression("", "");
checkCompression("\n\n", "");
}

private void checkCompression(String cssIn, String cssOut) throws IOException {
Reader in = new StringReader(cssIn);
Writer out = new StringWriter();
new CssCompressor(in).compress(out, 4);
assertEquals(cssOut, out.toString());
}

}