dvMinifyCss function
css without its comments or the whitespace that only made it readable.
The spaces that carry meaning stay: the one between nav and a that
makes a descendant selector, the ones around the operators in calc(),
and every character inside a string.
Implementation
String dvMinifyCss(String css) {
final StringBuffer out = StringBuffer();
int depth = 0;
int parens = 0;
bool space = false;
// Nothing needs a space before it at the start of a file, and nothing needs
// one after a brace, a semicolon or a comma.
bool tightAfter = true;
for (int i = 0; i < css.length; i++) {
final String c = css[i];
if (c == '/' && i + 1 < css.length && css[i + 1] == '*') {
final int end = css.indexOf('*/', i + 2);
i = end < 0 ? css.length : end + 1;
// A comment separates two tokens exactly as whitespace does.
space = true;
continue;
}
if (_isSpace(c)) {
space = true;
continue;
}
// In a declaration or inside parentheses, `:` separates a property from
// its value. In a selector it starts a pseudo-class, where the space in
// `p :first-child` is a combinator and not decoration.
final bool inValue = depth > 0 || parens > 0;
final bool selector = depth == 0 && parens == 0;
final bool combinator = selector && (c == '>' || c == '+' || c == '~');
final bool tightBefore =
c == '{' || c == '}' || c == ';' || c == ',' || c == ')' || (c == ':' && inValue) || combinator;
final bool nowTightAfter =
c == '{' || c == '}' || c == ';' || c == ',' || c == '(' || (c == ':' && inValue) || combinator;
if (c == '}') {
// The last declaration's semicolon closes nothing.
final String written = out.toString();
if (written.endsWith(';')) {
out.clear();
out.write(written.substring(0, written.length - 1));
}
}
if (space && !tightBefore && !tightAfter && out.isNotEmpty) out.write(' ');
space = false;
if (c == '"' || c == "'") {
final int end = _stringEnd(css, i, c);
out.write(css.substring(i, end));
i = end - 1;
tightAfter = false;
continue;
}
out.write(c);
tightAfter = nowTightAfter;
if (c == '{') depth++;
if (c == '}' && depth > 0) depth--;
if (c == '(') parens++;
if (c == ')' && parens > 0) parens--;
}
return out.toString().trim();
}