stripDartComments function
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();
}