2
\$\begingroup\$

I have this script that opens a file containing (possibly) bad CSS, lexes the content of it and creates a new file with the same code in a more pleasant way to look at. It formats it and sorts the properties alphabetically.

I would love to hear some very critical feedback on coding style, best practises and how I can make it cleaner.

Some concerns I have right now are the global variables (like i and iSort), the hard coded file path and the use of while loops.

I am trying to make it as easy as possible for others to read, but to me it seems as if passing around file[i] and other variables makes it more cluttered than it should be.

The exception handling seems unnecessary, but without it, the index overflows at some point and the program execution just stops. Is there a way I can avoid it in this case?

import 'dart:io';
import "dart:core";

class Token {
  String identifier;
  String value;
  Token(this.identifier, this.value);
}

List<Token> tokens = [];

void main() {
  String rootPath = "C:/Users/User/Desktop/Datein/AlphaCSS/bin/";
  String originalFilePath = "samplecss.css";

  new File(rootPath + originalFilePath).readAsString().then((String file) {
    List<Token> tokens = getTokensFromFile(file);
    List<Token> sortedTokens = getSortedTokens(tokens);
    new File(rootPath + "newcss.txt").writeAsStringSync(reconstructCSS(sortedTokens));
  });
}

int i = 0;

List<Token> getTokensFromFile(file){
  String value = "";
  while (i < file.length-1){
    value = "";
    if (isValidStart(file[i])){
      value = getTokenContent(file);
      addTokenBasedOnType(file[i], value);
    }
    else if (isEndOfSelector(file[i])){
      addTokenBasedOnType(file[i], "");
    }
    i++;
  }
  return tokens;
}

bool isValidStart(String char){
  RegExp regex = new RegExp(r"[a-zA-Z0-9#.]");
  return (regex.hasMatch(char)) ? true : false;
}

bool isEndOfSelector(String char){
  return (char == "}") ? true : false;
}

String getTokenContent(String file){
  String content = "";
  while (file[i] != "{" && file[i] != ";"){
    content += file[i];
    i++;
  }
  return content;
}

void addTokenBasedOnType(String char, String value){
  if (char == "{"){
    tokens.add(new Token("SELECTOR", value));
  }
  else if (char == "}"){
    tokens.add(new Token("END", ""));
  }
  else {
    tokens.add(new Token("PROPERTY", value));
  }
}

int iSort = 0;

List<Token> getSortedTokens(tokens){

  List<Token> sortedTokens = [];
  try {
    while (iSort < tokens.length){
      if (tokens[iSort].identifier == "PROPERTY"){
        List<Token> toSort = getAllPropertiesInSelector();
        iSort--;
        toSort.sort((current, next) => current.value.compareTo(next.value));
        for (var elem in toSort){
          sortedTokens.add(elem);
        }
      }
      else {
        sortedTokens.add(tokens[iSort]);
      }
      iSort++;
    }
  }
  catch(ex) { }
  return sortedTokens;
}

List<Token> getAllPropertiesInSelector(){
  List<Token> properties = [];
  try {
    while (tokens[iSort].identifier == "PROPERTY"){
      properties.add(tokens[iSort]);
      iSort++;
    }
  }
  catch(ex) { };
  return properties;
}

String reconstructCSS(List<Token> sortedTokens) {
  String finalString = "";

  for (var elem in sortedTokens){
    if (elem.identifier == "SELECTOR"){
      finalString += "${elem.value}{\n";
    }
    else if (elem.identifier == "END"){
      finalString += "}\n\n";
    }
    else if (elem.identifier == "PROPERTY"){
      finalString += "  ${elem.value};\n";
    }
  }
  return finalString;
}
\$\endgroup\$
3
\$\begingroup\$

Sorting the properties alphabetically does not yield "the same code". Properties that appear later in a rule override properties that occur earlier in the same rule. Mozilla Developer Network gives an example of a tricky edge case:

  1. A value which is not specified is set to its initial value. That sounds anecdotal, but it really means that it overrides previously set values. Therefore:

    background-color: red;
    background: url(images/bg.gif) no-repeat top right;
    

    will not set the color of the background to red but to background-color's default, transparent, as the second rule has precedence.

If you reverse the properties in that example, you would get a different result.

\$\endgroup\$
  • \$\begingroup\$ It doesn't actually sort the selectors, but only the properties inside of them. But yes you're right, if someone declares two properties of the same type in the same selector, it might get messed up. But that should be rare I guess. \$\endgroup\$ – OhMad May 31 '17 at 14:10
  • \$\begingroup\$ The same principle applies to the order of properties within a rule: don't mess with it unless you know exactly what you are doing. I have rewritten my answer (Rev 2). \$\endgroup\$ – 200_success May 31 '17 at 14:25
  • \$\begingroup\$ yep, you're right, I will add sorting only as an additional option, thanks :) Any thoughts on the code itself? \$\endgroup\$ – OhMad May 31 '17 at 14:28
  • 1
    \$\begingroup\$ Dunno. My only recommendation when it comes to reordering things automatically in CSS is: Don't do it! \$\endgroup\$ – 200_success May 31 '17 at 14:30

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.