splitTopLevelComma function

({String after, String before})? splitTopLevelComma(
  1. String input
)

Splits the arguments of a CSS function body on the first top-level comma.

Handles nested functions such as rgba(), color-mix() and var(), and quoted strings — so light-dark(rgba(0, 0, 0, 0.1), #FFF) splits after the closing ) of rgba, not at its first inner comma.

Returns null when there is no top-level comma.

Implementation

({String before, String after})? splitTopLevelComma(String input) {
  var depth = 0;
  String? quote;
  var isEscaped = false;

  for (var i = 0; i < input.length; i++) {
    final char = input[i];

    // Backslash escaping applies only inside a quoted string, as upstream has
    // it. At the top level a backslash is an ordinary character.
    if (quote != null) {
      if (isEscaped) {
        isEscaped = false;
      } else if (char == r'\') {
        isEscaped = true;
      } else if (char == quote) {
        quote = null;
      }
      continue;
    }
    if (char == '"' || char == "'") {
      quote = char;
      continue;
    }
    if (char == '(') {
      depth++;
    } else if (char == ')') {
      // Clamped, so a stray closing paren cannot drive the depth negative and
      // swallow every later top-level comma.
      depth = math.max(0, depth - 1);
    } else if (char == ',' && depth == 0) {
      return (before: input.substring(0, i), after: input.substring(i + 1));
    }
  }

  return null;
}