parseComment method

void parseComment(
  1. SourceElement element
)

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);
}