dartdoc icon indicating copy to clipboard operation
dartdoc copied to clipboard

Dartdoc should support arguments comments, metadata

Open matanlurey opened this issue 9 years ago • 14 comments
trafficstars

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

matanlurey avatar Oct 11 '16 18:10 matanlurey

cc @Hixie

sethladd avatar Oct 11 '16 18:10 sethladd

@matanlurey did you have any ideas how this would look when generated into HTML?

sethladd avatar Oct 11 '16 18:10 sethladd

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:

matanlurey avatar Oct 11 '16 18:10 matanlurey

My main rationale here is actually for the IDE

Ah, you might have to file a feature request with analyzer then?

sethladd avatar Oct 11 '16 18:10 sethladd

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.)

Hixie avatar Oct 11 '16 19:10 Hixie

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.

marcoms avatar Dec 21 '18 17:12 marcoms

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.

Jordan-Nelson avatar Jul 01 '22 16:07 Jordan-Nelson

No updates to this issue. I agree it would be a great enhancement.

srawlins avatar Jul 01 '22 17:07 srawlins

Okay. Thanks for the quick response.

Jordan-Nelson avatar Jul 01 '22 19:07 Jordan-Nelson

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.

Jordan-Nelson avatar Jul 01 '22 19:07 Jordan-Nelson

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

navaronbracke avatar Sep 27 '23 06:09 navaronbracke

There has not been more work on this.

srawlins avatar Sep 27 '23 09:09 srawlins

This could help many plugins and packages.

g-apparence avatar Nov 22 '23 09:11 g-apparence

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

CHB61 avatar Feb 09 '24 16:02 CHB61