anchor.diff:    ///
     /// This is extracted to save memory during the check; be careful not to hang
     /// on to anything referencing the full file and doc tree.
  -  Tuple2<Iterable<String>, String?>? _getStringLinksAndHref(String fullPath) {
  +  _PageLinks? _getLinksAndBaseHref(String fullPath) {
       final file = _config.resourceProvider.getFile(fullPath);
       if (!file.exists) {
         return null;
  
positive.code:       return;
      }
      _visited.add(fullPath);
      final stringLinks = stringLinksAndHref.item1;
      final baseHref = stringLinksAndHref.item2;
  
      // Prevent extremely large stacks by storing the paths we are using
      // here instead -- occasionally, very large jobs have overflowed
      // the stack without this.
      // (newPathToCheck, newFullPath)
      final toVisit = <Tuple2<String, String>>{};
  
      for (final href in stringLinks) {
        if (href.startsWith('https:') ||
            href.startsWith('http:') ||
            href.startsWith('mailto:') ||
            href.startsWith('ftp:')) {
          continue;
        }
        final uri = Uri.tryParse(href);
        if (uri == null || !uri.hasAuthority && !uri.hasFragment) {
          var linkPath = baseHref != null
              ? '${p.dirname(pathToCheck)}/$baseHref/$href'
              : '${p.dirname(pathToCheck)}/$href';
  
          linkPath = p.normalize(linkPath);
          final newFullPath = p.join(_origin, linkPath);
  
negative.code:         message: message, referredFrom: referredFromElements);
    }
  }
  
  /// Stores all links found in a page, and the base href.
  class _PageLinks {
    final Set<String> links;
    final String? baseHref;
  
    const _PageLinks(this.links, this.baseHref);
  }
  