A tool for maintaining Dart comments (daco).
- Format doc comments as Markdown
- Format Dart code examples
- Analyze Dart code examples
- Analyzer plugin
- Analyzes Dart code examples and provides errors
- Highlights Dart code examples
This package is in an early stage of development. Please file an issue if you find a bug or start a discussion if you have a question.
-
Make sure you have a recent version of NodeJS (>=14) installed and on the path. daco uses prettier to format Markdown.
-
Install daco globally:
dart pub global activate daco
-
Optional: Install daco locally:
dart pub add --dev daco
When daco is executed within your project, the version that was resolved by
pub get
will be used. To fully lock the version of daco you either need to specify a fixed version (e.g. no^
) in yourpubspec.yaml
or checkpubspec.lock
into your version control system. The latter option is recommended because it givespub get
more flexibility to resolve dependencies.By doing this you can ensure that all contributors to a project as well as the CI/CD pipeline use the same version of daco.
-
Format the Dart files within the current directory:
daco format .
-
Add
daco
as a development dependency to the each package where the plugin should be active:dart pub add --dev daco
-
Enable the plugin in the package's
analysis_options.yaml
:analyzer: plugins: - daco
daco formats Dart files, including documentation comments.
prettier is used to format comments as Markdown. This means that the conventions
of prettier are applied, such as using **
to bold text instead of __
. A nice
feature of prettier is that Markdown tables are pretty-printed.
Prose is reprinted to optimally fit within the specified line length (defaults to 80):
-/// Formats the given [source] string containing an entire Dart compilation unit.
+/// Formats the given [source] string containing an entire Dart compilation
+/// unit.
Future<String> format(String source, {String? path}) async;
This is useful when writing and updating documentation comments, and an edit pushes some text beyond the preferred line length.
Example code in fenced code blocks that is marked as Dart code is formatted:
/// Greets the user.
///
/// ```dart
-/// greet(name: 'Alice',);
+/// greet(
+/// name: 'Alice',
+/// );
/// ```
void greet({required String name});
Formatting of example code and documentation comments is recursive. That means documentation comments in example code are formatted, too.
The example code is parsed and if it contains syntactic errors they are reported with correct line and column numbers. This provides a basic check, ensuring that the code is at least syntactically correct.
Dartdoc supports tags for features such as templates. Dartdoc tags should be separated from other content with an empty line, since prettier does not recognize them as special and formats them as simple text:
/// A top level constant.
///
/// {@template foo}
///
/// The template content.
///
/// {@endtemplate}
const foo = 'bar';
When formatting a preexisting codebase, special attention should be paid to the location of dartdoc tags after formatting.
daco analyzes the example code in documentation comments.
Take for example the following file:
/// Greets the user.
///
/// ```dart main
/// greet();
/// ```
void greet({required String name}) {}
The example code is not passing the required name
parameter.
When running daco analyze
, an error message with the correct error location is
printed:
$ daco analyze
lib/greeter.dart:4:5 • The named parameter 'name' is required, but there's no corresponding argument. • MISSING_REQUIRED_ARGUMENT
The package which contains the example code is automatically imported.
Example code can be annotated with attributes to influence how it is processed.
Example code must represent a valid Dart file. Often it is preferable to write example code as if it were contained in a function, but without the function syntax and indentation.
By annotating example code with the main
attribute the code is wrapped in a
main
function before processing:
/// Greets the user.
///
/// ```dart main
/// greet(name: 'Alice');
/// ```
void greet({required String name}) {}
Sometimes it is useful to breaker larger examples into multiple code blocks, explaining each block individually.
/// Greets the user.
///
/// The source of the user's name could be an environment variable:
///
/// ```dart main multi_begin
/// var name = Platform.environment['NAME'] || 'Alice';
/// ```
///
/// Let's make sure the name is not empty:
///
/// ```dart main
/// if (name.isEmpty) {
/// throw ArgumentError.value(name, 'name', 'must not be empty');
/// }
/// ```
///
/// Finally pass the `name` to `greet`:
///
/// ```dart main multi_end
/// greet(name: name);
/// ```
void greet({required String name}) {}
A code block annotated with multi_begin
marks the beginning of a multi-part
code example and a code block annotated with multi_end
the end. The annotated
code blocks, as well as all code blocks in between, belong to the same code
example.
All the code blocks of a multi-part code example are composed into one Dart
file. Multiple code blocks annotated with main
are collected into a single
main
function, where each block appears in the same order as in the source
file.
The ignore
and no_format
attributes can be used on code blocks that are part
of a multi-part code example and work as usual.
If the no_analyze
is used on any one of the code blocks, the whole code
example won't be analyzed.
If example code should not be processed, it can be ignored by annotating it with
the ignore
attribute.
The example code below is not valid and would result in an error, but it is instead ignored:
/// Greets the user.
///
/// ```dart ignore
/// greet(name: ...);
/// ```
void greet({required String name}) {}
If example code should not be formatted, it can be annotated with the
no_format
attribute:
/// Greets the user.
///
/// ```dart main no_format
/// // Keep this strange formatting.
/// greet(
/// name:
/// 'Alice'
/// );
/// ```
void greet({required String name}) {}
If example code should not be analyzed for semantic errors, it can be annotated
with the no_analyze
attribute:
/// Greets the user.
///
/// ```dart main no_analyze
/// greet(name: 'Alice') as String;
/// ```
void greet({required String name}) {}
Syntactic errors will still be reported. To suppress all errors use the ignore
attribute.
Sometimes code is required to make a code example complete, but the code is not relevant for the reader.
This code can be hidden by placing it in a commented-out code block, while making the block part of a multi-part code example.
/// Greets the user.
///
/// <!--
/// ```dart multi_begin
/// const name = 'Alice';
/// ```
/// -->
///
/// ```dart main multi_end
/// greet(name: name);
/// ```
void greet({required String name}) {}
- Support formatting of end of line comments
- Support disabling formatting for a comment
- Integrate formatting with IDEs
- Analyze comments
- Spelling
- Punctuation
- Format Dart code in Markdown files
- Test Dart code embedded in Markdown
- Embedded templates in Markdown
- Template is commented out
- Below template, output of template is injected/updated
Gabriel Terwesten • GitHub @blaugold • Twitter @GTerwesten • Medium @gabriel.terwesten