stripDartComments function

String stripDartComments(
  1. String source
)

source with comments removed and line breaks preserved.

The distinction between prose and code is what a source rule needs: a doc comment may explain a rule in the words the rule bans, and a scan that could not tell a comment from code would be unfixable without rewording the notes that justify it.

The scanner tracks string literals rather than cutting at the first //, because 'https://…' is not a comment.

Implementation

String stripDartComments(String source) {
  final out = StringBuffer();
  var i = 0;
  while (i < source.length) {
    final c = source[i];

    if (c == '/' && i + 1 < source.length) {
      final next = source[i + 1];
      if (next == '/') {
        while (i < source.length && source[i] != '\n') {
          i++;
        }
        continue;
      }
      if (next == '*') {
        i += 2;
        while (i < source.length &&
            !(source[i] == '*' &&
                i + 1 < source.length &&
                source[i + 1] == '/')) {
          // Newlines survive, so a violation's line number still points at the
          // line it is on.
          if (source[i] == '\n') out.write('\n');
          i++;
        }
        i += 2;
        continue;
      }
    }

    if (c == "'" || c == '"') {
      final triple = source.startsWith(c * 3, i);
      final terminator = triple ? c * 3 : c;
      // A raw string has no escapes, so a trailing backslash must not swallow
      // its closing quote.
      final raw = i > 0 && (source[i - 1] == 'r' || source[i - 1] == 'R');
      out.write(terminator);
      i += terminator.length;
      while (i < source.length && !source.startsWith(terminator, i)) {
        if (!raw && source[i] == r'\' && i + 1 < source.length) {
          out.write(source[i]);
          i++;
        }
        out.write(source[i]);
        i++;
      }
      if (i < source.length) {
        out.write(terminator);
        i += terminator.length;
      }
      continue;
    }

    out.write(c);
    i++;
  }
  return out.toString();
}