Skip to content

Add a hideConstantImplementations dartdoc directive #3398

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 18 commits into from
May 4, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
## 6.2.2-dev
* Add a hideImplementations directive to disable showing constant
implementations alongside one-line docs on class pages (#3398)

## 6.2.2
* Add chips to class pages for class modifiers (#3401)
* Fix a case where dartdoc was not properly handling extension
Expand Down
35 changes: 35 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -412,6 +412,41 @@ markdown link isn't linked).
It's best to only inject HTML that is self-contained and doesn't depend upon
other elements on the page, since those may change in future versions of Dartdoc.

### Skipping constant rendering with one-line docs

For some classes or libraries full of well-documented constants, showing the
implementation on the enclosing `class` or `library` page can be distracting
or even misleading. To prevent the rendering of constant implementations,
place the `{@hideConstantImplementations}` in the documentation comment for
the enclosing context where the constant is defined. For members of a class,
place the directive in the class documentation where the constants are defined.
For top level constants, place the directive in the library where the constants
are defined.

For example:

```dart
/// This is truly an amazing library.
/// {@hideConstantImplementations}
library my_library;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: I think we're steering away from named libraries like this; we can use library; in Dart 2.19.


/// This top level constant will not show its implementation.
const a = 7;

/// {@hideConstantImplementations}
class A {
/// This constant will not show its implementation.
static const aConst = 12;
}

class B {
/// Despite the library directive, because this is a class
/// member and there is no hideConstantImplementations
/// directive on the class, we will show this implementation.
static const bConst = 27;
}
```

### Auto including dependencies

If `--auto-include-dependencies` flag is provided, dartdoc tries to automatically add
Expand Down
2 changes: 1 addition & 1 deletion dartdoc_options.yaml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
dartdoc:
linkToSource:
root: '.'
uriTemplate: 'https://github.com/dart-lang/dartdoc/blob/v6.2.2/%f%#L%l%'
uriTemplate: 'https://github.com/dart-lang/dartdoc/blob/v6.2.2-dev/%f%#L%l%'
4 changes: 2 additions & 2 deletions lib/src/generator/generator_utils.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import 'dart:convert';

import 'package:collection/collection.dart';
import 'package:dartdoc/src/model/categorization.dart';
import 'package:dartdoc/src/model/directives/categorization.dart';
import 'package:dartdoc/src/model/enclosed_element.dart';
import 'package:dartdoc/src/model/indexable.dart';
import 'package:dartdoc/src/model/model_element.dart';
Expand Down Expand Up @@ -73,7 +73,7 @@ String generateSearchIndexJson(
}

// Compares two elements, first by fully qualified name, then by kind.
int _compareElementRepresentations(Indexable a, Indexable b) {
int _compareElementRepresentations<T extends Indexable>(T a, T b) {
final value = compareNatural(a.fullyQualifiedName, b.fullyQualifiedName);
if (value == 0) {
return compareNatural(a.kind, b.kind);
Expand Down
103 changes: 97 additions & 6 deletions lib/src/generator/templates.runtime_renderers.dart
Original file line number Diff line number Diff line change
Expand Up @@ -686,6 +686,40 @@ class _Renderer_Callable extends RendererBase<Callable> {
}
}

class _Renderer_CanonicalFor extends RendererBase<CanonicalFor> {
static final Map<Type, Object> _propertyMapCache = {};
static Map<String, Property<CT_>> propertyMap<CT_ extends CanonicalFor>() =>
_propertyMapCache.putIfAbsent(
CT_,
() => {
'canonicalFor': Property(
getValue: (CT_ c) => c.canonicalFor,
renderVariable: (CT_ c, Property<CT_> self,
List<String> remainingNames) =>
self.renderSimpleVariable(
c, remainingNames, 'Set<String>'),
renderIterable: (CT_ c, RendererBase<CT_> r,
List<MustachioNode> ast, StringSink sink) {
return c.canonicalFor.map((e) =>
_render_String(e, ast, r.template, sink, parent: r));
},
),
}) as Map<String, Property<CT_>>;

_Renderer_CanonicalFor(CanonicalFor context, RendererBase<Object>? parent,
Template template, StringSink sink)
: super(context, parent, template, sink);

@override
Property<CanonicalFor>? getProperty(String key) {
if (propertyMap<CanonicalFor>().containsKey(key)) {
return propertyMap<CanonicalFor>()[key];
} else {
return null;
}
}
}

class _Renderer_Canonicalization extends RendererBase<Canonicalization> {
static final Map<Type, Object> _propertyMapCache = {};
static Map<String, Property<CT_>> propertyMap<
Expand Down Expand Up @@ -2660,6 +2694,7 @@ class _Renderer_Container extends RendererBase<Container> {
..._Renderer_ModelElement.propertyMap<CT_>(),
..._Renderer_Categorization.propertyMap<CT_>(),
..._Renderer_TypeParameters.propertyMap<CT_>(),
..._Renderer_HideConstantImplementations.propertyMap<CT_>(),
'allCanonicalModelElements': Property(
getValue: (CT_ c) => c.allCanonicalModelElements,
renderVariable: (CT_ c, Property<CT_> self,
Expand Down Expand Up @@ -5547,6 +5582,13 @@ class _Renderer_Field extends RendererBase<Field> {
parent: r);
},
),
'hasHideConstantImplementation': Property(
getValue: (CT_ c) => c.hasHideConstantImplementation,
renderVariable: (CT_ c, Property<CT_> self,
List<String> remainingNames) =>
self.renderSimpleVariable(c, remainingNames, 'bool'),
getBool: (CT_ c) => c.hasHideConstantImplementation == true,
),
'href': Property(
getValue: (CT_ c) => c.href,
renderVariable:
Expand Down Expand Up @@ -6270,6 +6312,13 @@ class _Renderer_GetterSetterCombo extends RendererBase<GetterSetterCombo> {
self.renderSimpleVariable(c, remainingNames, 'bool'),
getBool: (CT_ c) => c.hasGetterOrSetter == true,
),
'hasHideConstantImplementation': Property(
getValue: (CT_ c) => c.hasHideConstantImplementation,
renderVariable: (CT_ c, Property<CT_> self,
List<String> remainingNames) =>
self.renderSimpleVariable(c, remainingNames, 'bool'),
getBool: (CT_ c) => c.hasHideConstantImplementation == true,
),
'hasNoGetterSetter': Property(
getValue: (CT_ c) => c.hasNoGetterSetter,
renderVariable: (CT_ c, Property<CT_> self,
Expand Down Expand Up @@ -6528,6 +6577,38 @@ class _Renderer_HasNoPage extends RendererBase<HasNoPage> {
}
}

class _Renderer_HideConstantImplementations
extends RendererBase<HideConstantImplementations> {
static final Map<Type, Object> _propertyMapCache = {};
static Map<String, Property<CT_>>
propertyMap<CT_ extends HideConstantImplementations>() =>
_propertyMapCache.putIfAbsent(
CT_,
() => {
'hasHideConstantImplementations': Property(
getValue: (CT_ c) => c.hasHideConstantImplementations,
renderVariable: (CT_ c, Property<CT_> self,
List<String> remainingNames) =>
self.renderSimpleVariable(c, remainingNames, 'bool'),
getBool: (CT_ c) =>
c.hasHideConstantImplementations == true,
),
}) as Map<String, Property<CT_>>;

_Renderer_HideConstantImplementations(HideConstantImplementations context,
RendererBase<Object>? parent, Template template, StringSink sink)
: super(context, parent, template, sink);

@override
Property<HideConstantImplementations>? getProperty(String key) {
if (propertyMap<HideConstantImplementations>().containsKey(key)) {
return propertyMap<HideConstantImplementations>()[key];
} else {
return null;
}
}
}

class _Renderer_Indexable extends RendererBase<Indexable> {
static final Map<Type, Object> _propertyMapCache = {};
static Map<String, Property<CT_>> propertyMap<CT_ extends Indexable>() =>
Expand Down Expand Up @@ -7643,6 +7724,8 @@ class _Renderer_Library extends RendererBase<Library> {
..._Renderer_ModelElement.propertyMap<CT_>(),
..._Renderer_Categorization.propertyMap<CT_>(),
..._Renderer_TopLevelContainer.propertyMap<CT_>(),
..._Renderer_CanonicalFor.propertyMap<CT_>(),
..._Renderer_HideConstantImplementations.propertyMap<CT_>(),
'allClasses': Property(
getValue: (CT_ c) => c.allClasses,
renderVariable: (CT_ c, Property<CT_> self,
Expand All @@ -7668,15 +7751,15 @@ class _Renderer_Library extends RendererBase<Library> {
parent: r));
},
),
'canonicalFor': Property(
getValue: (CT_ c) => c.canonicalFor,
'allOriginalModelElementNames': Property(
getValue: (CT_ c) => c.allOriginalModelElementNames,
renderVariable: (CT_ c, Property<CT_> self,
List<String> remainingNames) =>
self.renderSimpleVariable(
c, remainingNames, 'Set<String>'),
c, remainingNames, 'Iterable<String>'),
renderIterable: (CT_ c, RendererBase<CT_> r,
List<MustachioNode> ast, StringSink sink) {
return c.canonicalFor.map((e) =>
return c.allOriginalModelElementNames.map((e) =>
_render_String(e, ast, r.template, sink, parent: r));
},
),
Expand Down Expand Up @@ -12085,7 +12168,7 @@ class _Renderer_Package extends RendererBase<Package> {
}
}

String renderSearchPage(PackageTemplateData context, Template template) {
String renderIndex(PackageTemplateData context, Template template) {
var buffer = StringBuffer();
_render_PackageTemplateData(context, template.ast, template, buffer);
return buffer.toString();
Expand Down Expand Up @@ -12323,7 +12406,7 @@ class _Renderer_PackageTemplateData extends RendererBase<PackageTemplateData> {
}
}

String renderIndex(PackageTemplateData context, Template template) {
String renderSearchPage(PackageTemplateData context, Template template) {
var buffer = StringBuffer();
_render_PackageTemplateData(context, template.ast, template, buffer);
return buffer.toString();
Expand Down Expand Up @@ -14529,6 +14612,13 @@ class _Renderer_TopLevelVariable extends RendererBase<TopLevelVariable> {
parent: r);
},
),
'hasHideConstantImplementation': Property(
getValue: (CT_ c) => c.hasHideConstantImplementation,
renderVariable: (CT_ c, Property<CT_> self,
List<String> remainingNames) =>
self.renderSimpleVariable(c, remainingNames, 'bool'),
getBool: (CT_ c) => c.hasHideConstantImplementation == true,
),
'href': Property(
getValue: (CT_ c) => c.href,
renderVariable:
Expand Down Expand Up @@ -16155,6 +16245,7 @@ const _invisibleGetters = {
'hasExplicitSetter',
'hasGetter',
'hasGetterOrSetter',
'hasHideConstantImplementation',
'hasNoGetterSetter',
'hasParameters',
'hasPublicGetter',
Expand Down
2 changes: 1 addition & 1 deletion lib/src/model/container.dart
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ import 'package:meta/meta.dart';
/// * **has** : boolean getters indicating whether the underlying collections
/// are empty. These are available mostly for the templating system.
abstract class Container extends ModelElement
with Categorization, TypeParameters {
with Categorization, TypeParameters, HideConstantImplementations {
Container(super.library, super.packageGraph);

// TODO(jcollins-g): Implement a ContainerScope that flattens supertypes?
Expand Down
40 changes: 40 additions & 0 deletions lib/src/model/directives/canonical_for.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

import 'package:dartdoc/src/model/documentation_comment.dart';
import 'package:dartdoc/src/model/library.dart';

final _canonicalRegExp = RegExp(r'{@canonicalFor\s([^}]+)}');

/// Used by [Library] to implement the `canonicalFor` directive.
mixin CanonicalFor on DocumentationComment {
Set<String>? _canonicalFor;

Set<String> get canonicalFor {
if (_canonicalFor == null) {
buildDocumentationAddition(documentationComment);
}
return _canonicalFor!;
}

/// Hides `canonicalFor` from doc while leaving a note to ourselves to
/// help with ambiguous canonicalization determination.
///
/// Example:
///
/// {@canonicalFor libname.ClassName}
@override
String buildDocumentationAddition(String rawDocs) {
rawDocs = super.buildDocumentationAddition(rawDocs);
var newCanonicalFor = <String>{};
rawDocs = rawDocs.replaceAllMapped(_canonicalRegExp, (Match match) {
var elementName = match.group(1)!;
newCanonicalFor.add(elementName);
return '';
});

_canonicalFor = newCanonicalFor;
return rawDocs;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,11 @@ final RegExp _categoryRegExp = RegExp(
r'[ ]*{@(api|category|subCategory|image|samples) (.+?)}[ ]*\n?',
multiLine: true);

/// Mixin implementing dartdoc categorization for ModelElements.
mixin Categorization implements ModelElement {
/// Mixin parsing the `@category` directive for ModelElements.
mixin Categorization on DocumentationComment implements Indexable {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice cleanup!

@override
String buildDocumentationAddition(String rawDocs) =>
_stripAndSetDartdocCategories(rawDocs);
_stripAndSetDartdocCategories(super.buildDocumentationAddition(rawDocs));

/// Parse `{@category ...}` and related information in API comments, stripping
/// out that information from the given comments and returning the stripped
Expand Down Expand Up @@ -61,7 +61,6 @@ mixin Categorization implements ModelElement {
return _subCategoryNames;
}

@override
bool get hasCategoryNames => categoryNames?.isNotEmpty ?? false;
List<String>? _categoryNames;

Expand Down Expand Up @@ -99,7 +98,6 @@ mixin Categorization implements ModelElement {
...?categoryNames?.map((n) => package.nameToCategory[n]).whereNotNull()
]..sort();

@override
Iterable<Category> get displayedCategories {
if (config.showUndocumentedCategories) return categories;
return categories.where((c) => c.isDocumented);
Expand Down
41 changes: 41 additions & 0 deletions lib/src/model/directives/hide_constant_implementations.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

import 'package:dartdoc/src/model/documentation_comment.dart';
import 'package:dartdoc/src/model/model_element.dart';

final _hideConstantImplementationsRegExp =
RegExp(r'{@hideConstantImplementations}');

/// Implement parsing the hideConstantImplementations dartdoc directive
/// for this [ModelElement]. Used by [Container].
mixin HideConstantImplementations on DocumentationComment {
bool? _hasHideConstantImplementations;

/// [true] if the `{@hideConstantImplementations}` dartdoc directive is
/// present in the documentation for this class.
bool get hasHideConstantImplementations {
if (_hasHideConstantImplementations == null) {
buildDocumentationAddition(documentationComment);
}
return _hasHideConstantImplementations!;
}

/// Hides `{@hideConstantImplementations}` from doc while leaving a note to
/// ourselves to change rendering for these constants.
/// Example:
///
/// {@hideConstantImplementations}
@override
String buildDocumentationAddition(String rawDocs) {
rawDocs = super.buildDocumentationAddition(rawDocs);
_hasHideConstantImplementations = false;
rawDocs = rawDocs.replaceAllMapped(_hideConstantImplementationsRegExp,
(Match match) {
_hasHideConstantImplementations = true;
return '';
});
return rawDocs;
}
}
Loading