parseComment method
This parses the documentation comment on a single SourceElement and
assigns the resulting samples to the samples
member of the given
element
.
Implementation
void parseComment(SourceElement element) {
// Whether or not we're in a snippet code sample.
bool inSnippet = false;
// Whether or not we're in a '```dart' segment.
bool inDart = false;
bool foundSourceLink = false;
bool foundDartSection = false;
File? linkedFile;
List<SourceLine> block = <SourceLine>[];
List<String> snippetArgs = <String>[];
final List<CodeSample> samples = <CodeSample>[];
final Directory flutterRoot = FlutterInformation.instance.getFlutterRoot();
int index = 0;
for (final SourceLine line in element.comment) {
final String trimmedLine = line.text.trim();
if (inSnippet) {
if (!trimmedLine.startsWith(_dartDocPrefix)) {
throw SnippetException('Snippet section unterminated.',
file: line.file?.path, line: line.line);
}
if (_dartDocSampleEndRegex.hasMatch(trimmedLine)) {
switch (snippetArgs.first) {
case 'snippet':
samples.add(
SnippetSample(
block,
index: index++,
lineProto: line,
),
);
break;
case 'sample':
if (linkedFile != null) {
samples.add(
ApplicationSample.fromFile(
input: block,
args: snippetArgs,
sourceFile: linkedFile,
index: index++,
lineProto: line,
),
);
break;
}
samples.add(
ApplicationSample(
input: block,
args: snippetArgs,
index: index++,
lineProto: line,
),
);
break;
case 'dartpad':
if (linkedFile != null) {
samples.add(
DartpadSample.fromFile(
input: block,
args: snippetArgs,
sourceFile: linkedFile,
index: index++,
lineProto: line,
),
);
break;
}
samples.add(
DartpadSample(
input: block,
args: snippetArgs,
index: index++,
lineProto: line,
),
);
break;
default:
throw SnippetException(
'Unknown snippet type ${snippetArgs.first}');
}
snippetArgs = <String>[];
block = <SourceLine>[];
inSnippet = false;
foundSourceLink = false;
foundDartSection = false;
linkedFile = null;
} else if (_filePointerRegex.hasMatch(trimmedLine)) {
foundSourceLink = true;
if (foundDartSection) {
throw SnippetException(
'Snippet contains a source link and a dart section. Cannot contain both.',
file: line.file?.path,
line: line.line,
);
}
if (linkedFile != null) {
throw SnippetException(
'Found more than one linked sample. Only one linked file per sample is allowed.',
file: line.file?.path,
line: line.line,
);
}
final RegExpMatch match = _filePointerRegex.firstMatch(trimmedLine)!;
linkedFile = filesystem.file(
path.join(flutterRoot.absolute.path, match.namedGroup('file')));
} else {
block.add(line.copyWith(
text: line.text.replaceFirst(RegExp(r'\s*/// ?'), '')));
}
} else {
if (_dartDocSampleEndRegex.hasMatch(trimmedLine)) {
if (inDart) {
throw SnippetException(
"Dart section didn't terminate before end of sample",
file: line.file?.path,
line: line.line);
}
}
if (inDart) {
if (_codeBlockEndRegex.hasMatch(trimmedLine)) {
inDart = false;
block = <SourceLine>[];
} else if (trimmedLine == _dartDocPrefix) {
block.add(line.copyWith(text: ''));
} else {
final int index = line.text.indexOf(_dartDocPrefixWithSpace);
if (index < 0) {
throw SnippetException(
'Dart section inexplicably did not contain "$_dartDocPrefixWithSpace" prefix.',
file: line.file?.path,
line: line.line,
);
}
block.add(line.copyWith(text: line.text.substring(index + 4)));
}
} else if (_codeBlockStartRegex.hasMatch(trimmedLine)) {
if (foundSourceLink) {
throw SnippetException(
'Snippet contains a source link and a dart section. Cannot contain both.',
file: line.file?.path,
line: line.line,
);
}
assert(block.isEmpty);
inDart = true;
foundDartSection = true;
}
}
if (!inSnippet && !inDart) {
final RegExpMatch? sampleMatch =
_dartDocSampleBeginRegex.firstMatch(trimmedLine);
if (sampleMatch != null) {
inSnippet = sampleMatch.namedGroup('type') == 'snippet' ||
sampleMatch.namedGroup('type') == 'sample' ||
sampleMatch.namedGroup('type') == 'dartpad';
if (inSnippet) {
if (sampleMatch.namedGroup('args') != null) {
// There are arguments to the snippet tool to keep track of.
snippetArgs = <String>[
sampleMatch.namedGroup('type')!,
..._splitUpQuotedArgs(sampleMatch.namedGroup('args')!)
];
} else {
snippetArgs = <String>[
sampleMatch.namedGroup('type')!,
];
}
}
}
}
}
for (final CodeSample sample in samples) {
sample.metadata.addAll(<String, Object?>{
'id': '${sample.element}.${sample.index}',
'element': sample.element,
'sourcePath': sample.start.file?.path ?? '',
'sourceLine': sample.start.line,
});
}
element.replaceSamples(samples);
}