mirror of
https://github.com/flutter/flutter
synced 2024-08-24 18:36:03 +00:00
![Kallen Tu](/assets/img/avatar_default.png)
In preparation to add the lint `missing_code_block_language_in_doc_comment`, added info strings to a bunch of fenced code blocks. Related to issue: https://github.com/dart-lang/linter/issues/4904 ## Pre-launch Checklist - [X] I read the [Contributor Guide] and followed the process outlined there for submitting PRs. - [X] I read the [Tree Hygiene] wiki page, which explains my responsibilities. - [X] I read and followed the [Flutter Style Guide], including [Features we expect every widget to implement]. - [X] I signed the [CLA]. - [X] I listed at least one issue that this PR fixes in the description above. - [X] I updated/added relevant documentation (doc comments with `///`). - [X] I added new tests to check the change I am making, or this PR is [test-exempt]. - [X] I followed the [breaking change policy] and added [Data Driven Fixes] where supported. - [X] All existing and new tests are passing. If you need help, consider asking for advice on the #hackers-new channel on [Discord]. <!-- Links --> [Contributor Guide]: https://github.com/flutter/flutter/wiki/Tree-hygiene#overview [Tree Hygiene]: https://github.com/flutter/flutter/wiki/Tree-hygiene [test-exempt]: https://github.com/flutter/flutter/wiki/Tree-hygiene#tests [Flutter Style Guide]: https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo [Features we expect every widget to implement]: https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo#features-we-expect-every-widget-to-implement [CLA]: https://cla.developers.google.com/ [flutter/tests]: https://github.com/flutter/tests [breaking change policy]: https://github.com/flutter/flutter/wiki/Tree-hygiene#handling-breaking-changes [Discord]: https://github.com/flutter/flutter/wiki/Chat [Data Driven Fixes]: https://github.com/flutter/flutter/wiki/Data-driven-Fixes
126 lines
4.3 KiB
Dart
126 lines
4.3 KiB
Dart
// Copyright 2014 The Flutter Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
import 'dart:io';
|
|
|
|
import 'package:meta/meta.dart';
|
|
import 'package:path/path.dart' as path;
|
|
|
|
/// Makes sure that the path we were given contains some of the expected
|
|
/// libraries.
|
|
@visibleForTesting
|
|
const List<String> dartdocDirectiveCanaryLibraries = <String>[
|
|
'animation',
|
|
'cupertino',
|
|
'material',
|
|
'widgets',
|
|
'rendering',
|
|
'flutter_driver',
|
|
];
|
|
|
|
/// Makes sure that the path we were given contains some of the expected
|
|
/// HTML files.
|
|
@visibleForTesting
|
|
const List<String> dartdocDirectiveCanaryFiles = <String>[
|
|
'Widget-class.html',
|
|
'Material-class.html',
|
|
'Canvas-class.html',
|
|
];
|
|
|
|
/// Scans the dartdoc HTML output in the provided `dartDocDir` for
|
|
/// unresolved dartdoc directives (`{@foo x y}`).
|
|
///
|
|
/// Dartdoc usually replaces those directives with other content. However,
|
|
/// if the directive is misspelled (or contains other errors) it is placed
|
|
/// verbatim into the HTML output. That's not desirable and this check verifies
|
|
/// that no directives appear verbatim in the output by checking that the
|
|
/// string `{@` does not appear in the HTML output outside of <code> sections.
|
|
///
|
|
/// The string `{@` is allowed in <code> sections, because those may contain
|
|
/// sample code where the sequence is perfectly legal, e.g. for required named
|
|
/// parameters of a method:
|
|
///
|
|
/// ```dart
|
|
/// void foo({@required int bar});
|
|
/// ```
|
|
void checkForUnresolvedDirectives(Directory dartDocDir) {
|
|
if (!dartDocDir.existsSync()) {
|
|
throw Exception('Directory with dartdoc output (${dartDocDir.path}) does not exist.');
|
|
}
|
|
|
|
// Make a copy since this will be mutated
|
|
final List<String> canaryLibraries = dartdocDirectiveCanaryLibraries.toList();
|
|
final List<String> canaryFiles = dartdocDirectiveCanaryFiles.toList();
|
|
|
|
print('Scanning for unresolved dartdoc directives...');
|
|
|
|
final List<FileSystemEntity> toScan = dartDocDir.listSync();
|
|
int count = 0;
|
|
|
|
while (toScan.isNotEmpty) {
|
|
final FileSystemEntity entity = toScan.removeLast();
|
|
if (entity is File) {
|
|
if (path.extension(entity.path) != '.html') {
|
|
continue;
|
|
}
|
|
canaryFiles.remove(path.basename(entity.path));
|
|
count += _scanFile(entity);
|
|
} else if (entity is Directory) {
|
|
canaryLibraries.remove(path.basename(entity.path));
|
|
toScan.addAll(entity.listSync());
|
|
} else {
|
|
throw Exception('$entity is neither file nor directory.');
|
|
}
|
|
}
|
|
|
|
if (canaryLibraries.isNotEmpty) {
|
|
throw Exception('Did not find docs for the following libraries: ${canaryLibraries.join(', ')}.');
|
|
}
|
|
if (canaryFiles.isNotEmpty) {
|
|
throw Exception('Did not find docs for the following files: ${canaryFiles.join(', ')}.');
|
|
}
|
|
if (count > 0) {
|
|
throw Exception('Found $count unresolved dartdoc directives (see log above).');
|
|
}
|
|
print('No unresolved dartdoc directives detected.');
|
|
}
|
|
|
|
int _scanFile(File file) {
|
|
assert(path.extension(file.path) == '.html');
|
|
final Iterable<String> matches = _pattern.allMatches(file.readAsStringSync())
|
|
.map((RegExpMatch m ) => m.group(0)!);
|
|
|
|
if (matches.isNotEmpty) {
|
|
stderr.writeln('Found unresolved dartdoc directives in ${file.path}:');
|
|
for (final String match in matches) {
|
|
stderr.writeln(' $match');
|
|
}
|
|
}
|
|
return matches.length;
|
|
}
|
|
|
|
// Matches all `{@` that are not within `<code></code>` sections.
|
|
//
|
|
// This regex may lead to false positives if the docs ever contain nested tags
|
|
// inside <code> sections. Since we currently don't do that, doing the matching
|
|
// with a regex is a lot faster than using an HTML parser to strip out the
|
|
// <code> sections.
|
|
final RegExp _pattern = RegExp(r'({@[^}\n]*}?)(?![^<>]*</code)');
|
|
|
|
// Usually, the checker is invoked directly from `dartdoc.dart`. Main method
|
|
// is included for convenient local runs without having to regenerate
|
|
// the dartdocs every time.
|
|
//
|
|
// Provide the path to the dartdoc HTML output as an argument when running the
|
|
// program.
|
|
void main(List<String> args) {
|
|
if (args.length != 1) {
|
|
throw Exception('Must provide the path to the dartdoc HTML output as argument.');
|
|
}
|
|
if (!Directory(args.single).existsSync()) {
|
|
throw Exception('The dartdoc HTML output directory ${args.single} does not exist.');
|
|
}
|
|
checkForUnresolvedDirectives(Directory(args.single));
|
|
}
|