Skip to content

Commit 24af8a1

Browse files
authored
Add a hideConstantImplementations dartdoc directive (#3398)
1 parent 078d42f commit 24af8a1

21 files changed

+372
-75
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
## 6.2.2-dev
2+
* Add a hideImplementations directive to disable showing constant
3+
implementations alongside one-line docs on class pages (#3398)
4+
15
## 6.2.2
26
* Add chips to class pages for class modifiers (#3401)
37
* Fix a case where dartdoc was not properly handling extension

README.md

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -412,6 +412,41 @@ markdown link isn't linked).
412412
It's best to only inject HTML that is self-contained and doesn't depend upon
413413
other elements on the page, since those may change in future versions of Dartdoc.
414414

415+
### Skipping constant rendering with one-line docs
416+
417+
For some classes or libraries full of well-documented constants, showing the
418+
implementation on the enclosing `class` or `library` page can be distracting
419+
or even misleading. To prevent the rendering of constant implementations,
420+
place the `{@hideConstantImplementations}` in the documentation comment for
421+
the enclosing context where the constant is defined. For members of a class,
422+
place the directive in the class documentation where the constants are defined.
423+
For top level constants, place the directive in the library where the constants
424+
are defined.
425+
426+
For example:
427+
428+
```dart
429+
/// This is truly an amazing library.
430+
/// {@hideConstantImplementations}
431+
library my_library;
432+
433+
/// This top level constant will not show its implementation.
434+
const a = 7;
435+
436+
/// {@hideConstantImplementations}
437+
class A {
438+
/// This constant will not show its implementation.
439+
static const aConst = 12;
440+
}
441+
442+
class B {
443+
/// Despite the library directive, because this is a class
444+
/// member and there is no hideConstantImplementations
445+
/// directive on the class, we will show this implementation.
446+
static const bConst = 27;
447+
}
448+
```
449+
415450
### Auto including dependencies
416451

417452
If `--auto-include-dependencies` flag is provided, dartdoc tries to automatically add

dartdoc_options.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
dartdoc:
22
linkToSource:
33
root: '.'
4-
uriTemplate: 'https://github.com/dart-lang/dartdoc/blob/v6.2.2/%f%#L%l%'
4+
uriTemplate: 'https://github.com/dart-lang/dartdoc/blob/v6.2.2-dev/%f%#L%l%'

lib/src/generator/generator_utils.dart

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
import 'dart:convert';
66

77
import 'package:collection/collection.dart';
8-
import 'package:dartdoc/src/model/categorization.dart';
8+
import 'package:dartdoc/src/model/directives/categorization.dart';
99
import 'package:dartdoc/src/model/enclosed_element.dart';
1010
import 'package:dartdoc/src/model/indexable.dart';
1111
import 'package:dartdoc/src/model/model_element.dart';
@@ -73,7 +73,7 @@ String generateSearchIndexJson(
7373
}
7474

7575
// Compares two elements, first by fully qualified name, then by kind.
76-
int _compareElementRepresentations(Indexable a, Indexable b) {
76+
int _compareElementRepresentations<T extends Indexable>(T a, T b) {
7777
final value = compareNatural(a.fullyQualifiedName, b.fullyQualifiedName);
7878
if (value == 0) {
7979
return compareNatural(a.kind, b.kind);

lib/src/generator/templates.runtime_renderers.dart

Lines changed: 97 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -686,6 +686,40 @@ class _Renderer_Callable extends RendererBase<Callable> {
686686
}
687687
}
688688

689+
class _Renderer_CanonicalFor extends RendererBase<CanonicalFor> {
690+
static final Map<Type, Object> _propertyMapCache = {};
691+
static Map<String, Property<CT_>> propertyMap<CT_ extends CanonicalFor>() =>
692+
_propertyMapCache.putIfAbsent(
693+
CT_,
694+
() => {
695+
'canonicalFor': Property(
696+
getValue: (CT_ c) => c.canonicalFor,
697+
renderVariable: (CT_ c, Property<CT_> self,
698+
List<String> remainingNames) =>
699+
self.renderSimpleVariable(
700+
c, remainingNames, 'Set<String>'),
701+
renderIterable: (CT_ c, RendererBase<CT_> r,
702+
List<MustachioNode> ast, StringSink sink) {
703+
return c.canonicalFor.map((e) =>
704+
_render_String(e, ast, r.template, sink, parent: r));
705+
},
706+
),
707+
}) as Map<String, Property<CT_>>;
708+
709+
_Renderer_CanonicalFor(CanonicalFor context, RendererBase<Object>? parent,
710+
Template template, StringSink sink)
711+
: super(context, parent, template, sink);
712+
713+
@override
714+
Property<CanonicalFor>? getProperty(String key) {
715+
if (propertyMap<CanonicalFor>().containsKey(key)) {
716+
return propertyMap<CanonicalFor>()[key];
717+
} else {
718+
return null;
719+
}
720+
}
721+
}
722+
689723
class _Renderer_Canonicalization extends RendererBase<Canonicalization> {
690724
static final Map<Type, Object> _propertyMapCache = {};
691725
static Map<String, Property<CT_>> propertyMap<
@@ -2660,6 +2694,7 @@ class _Renderer_Container extends RendererBase<Container> {
26602694
..._Renderer_ModelElement.propertyMap<CT_>(),
26612695
..._Renderer_Categorization.propertyMap<CT_>(),
26622696
..._Renderer_TypeParameters.propertyMap<CT_>(),
2697+
..._Renderer_HideConstantImplementations.propertyMap<CT_>(),
26632698
'allCanonicalModelElements': Property(
26642699
getValue: (CT_ c) => c.allCanonicalModelElements,
26652700
renderVariable: (CT_ c, Property<CT_> self,
@@ -5547,6 +5582,13 @@ class _Renderer_Field extends RendererBase<Field> {
55475582
parent: r);
55485583
},
55495584
),
5585+
'hasHideConstantImplementation': Property(
5586+
getValue: (CT_ c) => c.hasHideConstantImplementation,
5587+
renderVariable: (CT_ c, Property<CT_> self,
5588+
List<String> remainingNames) =>
5589+
self.renderSimpleVariable(c, remainingNames, 'bool'),
5590+
getBool: (CT_ c) => c.hasHideConstantImplementation == true,
5591+
),
55505592
'href': Property(
55515593
getValue: (CT_ c) => c.href,
55525594
renderVariable:
@@ -6270,6 +6312,13 @@ class _Renderer_GetterSetterCombo extends RendererBase<GetterSetterCombo> {
62706312
self.renderSimpleVariable(c, remainingNames, 'bool'),
62716313
getBool: (CT_ c) => c.hasGetterOrSetter == true,
62726314
),
6315+
'hasHideConstantImplementation': Property(
6316+
getValue: (CT_ c) => c.hasHideConstantImplementation,
6317+
renderVariable: (CT_ c, Property<CT_> self,
6318+
List<String> remainingNames) =>
6319+
self.renderSimpleVariable(c, remainingNames, 'bool'),
6320+
getBool: (CT_ c) => c.hasHideConstantImplementation == true,
6321+
),
62736322
'hasNoGetterSetter': Property(
62746323
getValue: (CT_ c) => c.hasNoGetterSetter,
62756324
renderVariable: (CT_ c, Property<CT_> self,
@@ -6528,6 +6577,38 @@ class _Renderer_HasNoPage extends RendererBase<HasNoPage> {
65286577
}
65296578
}
65306579

6580+
class _Renderer_HideConstantImplementations
6581+
extends RendererBase<HideConstantImplementations> {
6582+
static final Map<Type, Object> _propertyMapCache = {};
6583+
static Map<String, Property<CT_>>
6584+
propertyMap<CT_ extends HideConstantImplementations>() =>
6585+
_propertyMapCache.putIfAbsent(
6586+
CT_,
6587+
() => {
6588+
'hasHideConstantImplementations': Property(
6589+
getValue: (CT_ c) => c.hasHideConstantImplementations,
6590+
renderVariable: (CT_ c, Property<CT_> self,
6591+
List<String> remainingNames) =>
6592+
self.renderSimpleVariable(c, remainingNames, 'bool'),
6593+
getBool: (CT_ c) =>
6594+
c.hasHideConstantImplementations == true,
6595+
),
6596+
}) as Map<String, Property<CT_>>;
6597+
6598+
_Renderer_HideConstantImplementations(HideConstantImplementations context,
6599+
RendererBase<Object>? parent, Template template, StringSink sink)
6600+
: super(context, parent, template, sink);
6601+
6602+
@override
6603+
Property<HideConstantImplementations>? getProperty(String key) {
6604+
if (propertyMap<HideConstantImplementations>().containsKey(key)) {
6605+
return propertyMap<HideConstantImplementations>()[key];
6606+
} else {
6607+
return null;
6608+
}
6609+
}
6610+
}
6611+
65316612
class _Renderer_Indexable extends RendererBase<Indexable> {
65326613
static final Map<Type, Object> _propertyMapCache = {};
65336614
static Map<String, Property<CT_>> propertyMap<CT_ extends Indexable>() =>
@@ -7643,6 +7724,8 @@ class _Renderer_Library extends RendererBase<Library> {
76437724
..._Renderer_ModelElement.propertyMap<CT_>(),
76447725
..._Renderer_Categorization.propertyMap<CT_>(),
76457726
..._Renderer_TopLevelContainer.propertyMap<CT_>(),
7727+
..._Renderer_CanonicalFor.propertyMap<CT_>(),
7728+
..._Renderer_HideConstantImplementations.propertyMap<CT_>(),
76467729
'allClasses': Property(
76477730
getValue: (CT_ c) => c.allClasses,
76487731
renderVariable: (CT_ c, Property<CT_> self,
@@ -7668,15 +7751,15 @@ class _Renderer_Library extends RendererBase<Library> {
76687751
parent: r));
76697752
},
76707753
),
7671-
'canonicalFor': Property(
7672-
getValue: (CT_ c) => c.canonicalFor,
7754+
'allOriginalModelElementNames': Property(
7755+
getValue: (CT_ c) => c.allOriginalModelElementNames,
76737756
renderVariable: (CT_ c, Property<CT_> self,
76747757
List<String> remainingNames) =>
76757758
self.renderSimpleVariable(
7676-
c, remainingNames, 'Set<String>'),
7759+
c, remainingNames, 'Iterable<String>'),
76777760
renderIterable: (CT_ c, RendererBase<CT_> r,
76787761
List<MustachioNode> ast, StringSink sink) {
7679-
return c.canonicalFor.map((e) =>
7762+
return c.allOriginalModelElementNames.map((e) =>
76807763
_render_String(e, ast, r.template, sink, parent: r));
76817764
},
76827765
),
@@ -12085,7 +12168,7 @@ class _Renderer_Package extends RendererBase<Package> {
1208512168
}
1208612169
}
1208712170

12088-
String renderSearchPage(PackageTemplateData context, Template template) {
12171+
String renderIndex(PackageTemplateData context, Template template) {
1208912172
var buffer = StringBuffer();
1209012173
_render_PackageTemplateData(context, template.ast, template, buffer);
1209112174
return buffer.toString();
@@ -12323,7 +12406,7 @@ class _Renderer_PackageTemplateData extends RendererBase<PackageTemplateData> {
1232312406
}
1232412407
}
1232512408

12326-
String renderIndex(PackageTemplateData context, Template template) {
12409+
String renderSearchPage(PackageTemplateData context, Template template) {
1232712410
var buffer = StringBuffer();
1232812411
_render_PackageTemplateData(context, template.ast, template, buffer);
1232912412
return buffer.toString();
@@ -14529,6 +14612,13 @@ class _Renderer_TopLevelVariable extends RendererBase<TopLevelVariable> {
1452914612
parent: r);
1453014613
},
1453114614
),
14615+
'hasHideConstantImplementation': Property(
14616+
getValue: (CT_ c) => c.hasHideConstantImplementation,
14617+
renderVariable: (CT_ c, Property<CT_> self,
14618+
List<String> remainingNames) =>
14619+
self.renderSimpleVariable(c, remainingNames, 'bool'),
14620+
getBool: (CT_ c) => c.hasHideConstantImplementation == true,
14621+
),
1453214622
'href': Property(
1453314623
getValue: (CT_ c) => c.href,
1453414624
renderVariable:
@@ -16155,6 +16245,7 @@ const _invisibleGetters = {
1615516245
'hasExplicitSetter',
1615616246
'hasGetter',
1615716247
'hasGetterOrSetter',
16248+
'hasHideConstantImplementation',
1615816249
'hasNoGetterSetter',
1615916250
'hasParameters',
1616016251
'hasPublicGetter',

lib/src/model/container.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ import 'package:meta/meta.dart';
2828
/// * **has** : boolean getters indicating whether the underlying collections
2929
/// are empty. These are available mostly for the templating system.
3030
abstract class Container extends ModelElement
31-
with Categorization, TypeParameters {
31+
with Categorization, TypeParameters, HideConstantImplementations {
3232
Container(super.library, super.packageGraph);
3333

3434
// TODO(jcollins-g): Implement a ContainerScope that flattens supertypes?
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
import 'package:dartdoc/src/model/documentation_comment.dart';
6+
import 'package:dartdoc/src/model/library.dart';
7+
8+
final _canonicalRegExp = RegExp(r'{@canonicalFor\s([^}]+)}');
9+
10+
/// Used by [Library] to implement the `canonicalFor` directive.
11+
mixin CanonicalFor on DocumentationComment {
12+
Set<String>? _canonicalFor;
13+
14+
Set<String> get canonicalFor {
15+
if (_canonicalFor == null) {
16+
buildDocumentationAddition(documentationComment);
17+
}
18+
return _canonicalFor!;
19+
}
20+
21+
/// Hides `canonicalFor` from doc while leaving a note to ourselves to
22+
/// help with ambiguous canonicalization determination.
23+
///
24+
/// Example:
25+
///
26+
/// {@canonicalFor libname.ClassName}
27+
@override
28+
String buildDocumentationAddition(String rawDocs) {
29+
rawDocs = super.buildDocumentationAddition(rawDocs);
30+
var newCanonicalFor = <String>{};
31+
rawDocs = rawDocs.replaceAllMapped(_canonicalRegExp, (Match match) {
32+
var elementName = match.group(1)!;
33+
newCanonicalFor.add(elementName);
34+
return '';
35+
});
36+
37+
_canonicalFor = newCanonicalFor;
38+
return rawDocs;
39+
}
40+
}

lib/src/model/categorization.dart renamed to lib/src/model/directives/categorization.dart

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,11 @@ final RegExp _categoryRegExp = RegExp(
99
r'[ ]*{@(api|category|subCategory|image|samples) (.+?)}[ ]*\n?',
1010
multiLine: true);
1111

12-
/// Mixin implementing dartdoc categorization for ModelElements.
13-
mixin Categorization implements ModelElement {
12+
/// Mixin parsing the `@category` directive for ModelElements.
13+
mixin Categorization on DocumentationComment implements Indexable {
1414
@override
1515
String buildDocumentationAddition(String rawDocs) =>
16-
_stripAndSetDartdocCategories(rawDocs);
16+
_stripAndSetDartdocCategories(super.buildDocumentationAddition(rawDocs));
1717

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

64-
@override
6564
bool get hasCategoryNames => categoryNames?.isNotEmpty ?? false;
6665
List<String>? _categoryNames;
6766

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

102-
@override
103101
Iterable<Category> get displayedCategories {
104102
if (config.showUndocumentedCategories) return categories;
105103
return categories.where((c) => c.isDocumented);
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
import 'package:dartdoc/src/model/documentation_comment.dart';
6+
import 'package:dartdoc/src/model/model_element.dart';
7+
8+
final _hideConstantImplementationsRegExp =
9+
RegExp(r'{@hideConstantImplementations}');
10+
11+
/// Implement parsing the hideConstantImplementations dartdoc directive
12+
/// for this [ModelElement]. Used by [Container].
13+
mixin HideConstantImplementations on DocumentationComment {
14+
bool? _hasHideConstantImplementations;
15+
16+
/// [true] if the `{@hideConstantImplementations}` dartdoc directive is
17+
/// present in the documentation for this class.
18+
bool get hasHideConstantImplementations {
19+
if (_hasHideConstantImplementations == null) {
20+
buildDocumentationAddition(documentationComment);
21+
}
22+
return _hasHideConstantImplementations!;
23+
}
24+
25+
/// Hides `{@hideConstantImplementations}` from doc while leaving a note to
26+
/// ourselves to change rendering for these constants.
27+
/// Example:
28+
///
29+
/// {@hideConstantImplementations}
30+
@override
31+
String buildDocumentationAddition(String rawDocs) {
32+
rawDocs = super.buildDocumentationAddition(rawDocs);
33+
_hasHideConstantImplementations = false;
34+
rawDocs = rawDocs.replaceAllMapped(_hideConstantImplementationsRegExp,
35+
(Match match) {
36+
_hasHideConstantImplementations = true;
37+
return '';
38+
});
39+
return rawDocs;
40+
}
41+
}

0 commit comments

Comments
 (0)