dartdoc
dartdoc copied to clipboard
Dartdoc should support arguments comments, metadata
Using long sets of named arguments is more common in Dart, especially given it's a style guide preference for Flutter.
For example:
class SweetToothState {
/// Creates a new [SweetToothState].
///
/// Given a [sugarEater] and a number of [stores], represents different bakeries and ice
/// cream stores they still go to (haven't been banned from).
factory SweetToothState({
String sugarEater,
int stores,
List<String> allowed,
}) = ...
}
It would be preferable to write:
class SweetToothState {
/// Creates a new [SweetToothState] to represent an [sugarEater] wanting to go to [stores].
factory SweetToothState({
/// Name of the sugar eater.
@required
String sugarEater,
/// How many stores the sugar eater wants to attend tonight.
@required
int stores,
/// Optional; where the sugar eater is still allowed entry to.
List<String> allowed,
}) = ...
}
When using an IDE or viewing in Dartdoc, you could have nice doc comments for these complex sets of arguments. One addendum is that if you use a field initializer (this.) we should automatically use the public API comment there:
class SugarEaterState {
/// Name of the sugar eater.
@required
final String sugarEater;
SugarEaterState({this.sugarEater});
}
cc @Hixie
@matanlurey did you have any ideas how this would look when generated into HTML?
I am not too creative - something similar to JavaDoc?
My main rationale here is actually for the IDE, when you type:
new SugarEaterState(...)
I'd like to see:
|-----------------------------------|
| Name of the sugar eater, required.|
|-----------------------------------|
sugarEater:
My main rationale here is actually for the IDE
Ah, you might have to file a feature request with analyzer then?
Oh, yeah, being able to annotate individual arguments would be great for some of our classes. (And yeah, this.foo should automatically default the arg to the docs for foo.)
IMO this is a pretty significant area where dartdoc could improve. Since there is no way for an editor to parse argument documentation, not being able to get any argument-specific documentation when hovering over it in VSCode or any other editor degrades the development experience quite a lot compared to Typescript for example (which a lot of React Native and web devs are coming from, me included).
Instead you have to search through the whole function documentation, and for functions with lots of arguments this gets quite painful.
Interestingly VSCode manages to extract docs for constructor arguments that correspond to member variables which themselves have doc comments. It would be nice if there was a way to do this for methods or freestanding functions
@matanlurey's suggestion of allowing doc comments above the arguments themselves seems quite elegant. Alternatively dartdoc could just support the commonly used @param syntax.
Are there any updates in this issue? I believe this is making it much harder for library developers to maintain proper documentation.
For example, it is very hard to provide good documentation in factory constructors. One scenario in which I see this is when using built_value, which has become very popular. Below is an example from their examples dir.
abstract class VerySimpleValue
implements Built<VerySimpleValue, VerySimpleValueBuilder> {
static Serializer<VerySimpleValue> get serializer =>
_$verySimpleValueSerializer;
int get value;
factory VerySimpleValue(int value) => _$VerySimpleValue._(value: value);
VerySimpleValue._();
}
If VerySimpleValue is exposed as part of the public API of my library, I want to ensure it has proper docs. If I add the docs below, consumers of my library will not see that when they use the constructor.
abstract class VerySimpleValue
implements Built<VerySimpleValue, VerySimpleValueBuilder> {
static Serializer<VerySimpleValue> get serializer =>
_$verySimpleValueSerializer;
/// Sets the value for the object
int get value;
factory VerySimpleValue(int value) => _$VerySimpleValue._(value: value);
VerySimpleValue._();
}
I could do something like below, but this is repetitive and not what consumers would expect since it doesn't match what the docs would look like if this was a non-factory constructor with value as a member of VerySimpleValue.
abstract class VerySimpleValue
implements Built<VerySimpleValue, VerySimpleValueBuilder> {
static Serializer<VerySimpleValue> get serializer =>
_$verySimpleValueSerializer;
/// Sets the value for the object
int get value;
/// Very simple value
///
/// [value] sets the value for the object
factory VerySimpleValue(int value) => _$VerySimpleValue._(value: value);
VerySimpleValue._();
}
I could use a template/macro to get rid of the repetition, but the docs become somewhat clunky, and again - not what consumers expect.
What I really want is to do this:
abstract class VerySimpleValue
implements Built<VerySimpleValue, VerySimpleValueBuilder> {
static Serializer<VerySimpleValue> get serializer =>
_$verySimpleValueSerializer;
/// {@template very_simple_value.value}
/// Sets the value for the object
/// {@endtemplate}
int get value;
/// Very simple value
factory VerySimpleValue({
/// {@macro very_simple_value.value}
required int value
}) => _$VerySimpleValue._(value: value);
VerySimpleValue._();
}
And then of course the doc for value would be visible to consumers using the factory constructor.
This would not involve any repeated code, and give consumers a good experience, with info about constructor arguments in a predictable location.
built_value and factory constructors are just one common use case I see, but this can be applied to many other cases. Take the simple class below.
class Foo {
/// Foo class.
///
/// [name] does something
const Foo({
required this.value,
required String name,
}) : _name = 'foo_$name';
/// doc for value
final int value;
final String _name;
}
I believe this is how the dart docs would suggest this class is commented. But this isn't a great DX. The consumer of Foo has to look in two different places to find the doc comments for the two arguments to the constructor.
No updates to this issue. I agree it would be a great enhancement.
Okay. Thanks for the quick response.
I want to add a more common example of where the DX could be improved incase it helps bump the priority of this.
ThemeData is a class most flutter developers use. The commonly used constructors are factory constructors. The ThemeData() factory constructor accepts 83 arguments, not counting deprecated arguments. There are great API docs for these, but you have to search though the source code to find them.
Has there been more work on this? With the new JS interop functionality, this is something I would like to see being implemented.
Especially since there is now a concrete use case, documenting external factory constructors for anonymous types.
Today you can get the parameters documented if they have fields, but external factories might not have corresponding fields.
I.e.
import 'dart:js_interop';
/// Create a JS Object like `{foo: 'some sring', bar: 42}`,
/// using static interop.
@JS()
@anonymous
@staticInterop
class MyAnonType {
external factory MyAnonType({
String? foo,
int bar,
});
}
There has not been more work on this.
This could help many plugins and packages.
Interested to see this supported.
It would also be helpful for widgets like TextFormField where most parameters don't have dartdocs available since they are not class variables. Instead the dartdoc on the constructor says: "For documentation about the various parameters, see the [TextField] class and [TextField.new], the constructor".
In my case, I would like to do something like this:
class SelectableList<T> extends StatefulWidget {
/// The initial value for a list.
final List<T>? initialValueList;
/// The initial value for a single item.
final T? initialValueSingle;
const SelectableList.single({
super.key,
/// either add dartdoc here, or would be nice if I could point to the respective class variable's dartdoc
T? initialValue,
}) : initialValueList = null,
initialValueSingle = initialValue;
const SelectableList.multi({
super.key,
List<T>? initialValue,
}) : initialValueList = initialValue,
initialValueSingle = null;
@override
State<SelectableList<T>> createState() => _SelectableListState<T>();
}