@@ -9,6 +9,7 @@ import 'package:analyzer/src/generated/ast.dart';
9
9
import 'package:analyzer/src/generated/element.dart'
10
10
show
11
11
LibraryElement,
12
+ Element,
12
13
ConstructorElement,
13
14
ClassMemberElement,
14
15
PropertyAccessorElement;
@@ -27,44 +28,71 @@ final List<md.InlineSyntax> _markdown_syntaxes = [new _InlineCodeSyntax()];
27
28
// We don't emit warnings currently: #572.
28
29
const bool _emitWarning = false ;
29
30
30
- String renderMarkdownToHtml (String text, [ModelElement element]) {
31
- // TODO: `renderMarkdownToHtml` is never called with an element arg.
32
- // TODO(keertip): use this for the one liner.
33
- md.Node _linkResolver (String name) {
34
- NodeList <CommentReference > commentRefs = _getCommentRefs (element);
35
- if (commentRefs == null || commentRefs.isEmpty) {
36
- return new md.Text ('[$name ]' );
31
+ String _linkDocReference (String reference, ModelElement element,
32
+ NodeList <CommentReference > commentRefs) {
33
+ String link;
34
+ // support for [new Constructor] and [new Class.namedCtr]
35
+ var refs = reference.split (' ' );
36
+ if (refs.length == 2 && refs.first == 'new' ) {
37
+ link = _getMatchingLink (refs[1 ], element, commentRefs, isConstructor: true );
38
+ } else {
39
+ link = _getMatchingLink (reference, element, commentRefs);
40
+ }
41
+ if (link != null && link.isNotEmpty) {
42
+ return '<a href="$link ">$reference </a>' ;
43
+ } else {
44
+ if (_emitWarning) {
45
+ print (" warning: unresolved doc reference '$reference ' (in $element )" );
37
46
}
38
- // support for [new Constructor] and [new Class.namedCtr]
39
- var link;
40
- var refs = name.split (' ' );
41
- if (refs.length == 2 && refs.first == 'new' ) {
42
- link =
43
- _getMatchingLink (refs[1 ], element, commentRefs, isConstructor: true );
47
+ return '<code>$reference </code>' ;
48
+ }
49
+ }
50
+
51
+ class Documentation {
52
+ final ModelElement element;
53
+ String _asHtml;
54
+ String _asOneLiner;
55
+ Document _asHtmlDocument;
56
+
57
+ Documentation (this .element) {
58
+ _processDocsAsMarkdown ();
59
+ }
60
+
61
+ String get raw => this .element.documentation;
62
+
63
+ String get asHtml => _asHtml;
64
+
65
+ Document get asHtmlDocument => _asHtmlDocument;
66
+
67
+ String get asOneLiner => _asOneLiner;
68
+
69
+ void _processDocsAsMarkdown () {
70
+ String tempHtml = renderMarkdownToHtml (raw, element);
71
+ _asHtmlDocument = parse (tempHtml);
72
+ _asHtmlDocument.querySelectorAll ('script' ).forEach ((s) => s.remove ());
73
+ _asHtmlDocument.querySelectorAll ('code' ).forEach ((e) {
74
+ e.classes.addAll (['prettyprint' , 'lang-dart' ]);
75
+ });
76
+ _asHtml = _asHtmlDocument.body.innerHtml;
77
+
78
+ if (_asHtmlDocument.body.children.isEmpty) {
79
+ _asOneLiner = '' ;
44
80
} else {
45
- link = _getMatchingLink (name, element, commentRefs) ;
81
+ _asOneLiner = _asHtmlDocument.body.children.first.innerHtml ;
46
82
}
47
- if (link != null ) {
48
- return new md.Text ('<a href="$link ">$name </a>' );
49
- }
50
- return new md.Text ('$name ' );
83
+ }
84
+ }
85
+
86
+ String renderMarkdownToHtml (String text, [ModelElement element]) {
87
+ md.Node _linkResolver (String name) {
88
+ NodeList <CommentReference > commentRefs = _getCommentRefs (element);
89
+ return new md.Text (_linkDocReference (name, element, commentRefs));
51
90
}
52
91
53
92
return md.markdownToHtml (text,
54
93
inlineSyntaxes: _markdown_syntaxes, linkResolver: _linkResolver);
55
94
}
56
95
57
- String processDocsAsMarkdown (ModelElement element) {
58
- if (element == null || element.documentation == null ) return '' ;
59
- String html = renderMarkdownToHtml (element.documentation, element);
60
- Document doc = parse (html);
61
- doc.querySelectorAll ('script' ).forEach ((s) => s.remove ());
62
- doc.querySelectorAll ('code' ).forEach ((e) {
63
- e.classes.addAll (['prettyprint' , 'lang-dart' ]);
64
- });
65
- return doc.body.innerHtml;
66
- }
67
-
68
96
class _InlineCodeSyntax extends md.InlineSyntax {
69
97
_InlineCodeSyntax () : super (r'\[:\s?((?:.|\n)*?)\s?:\]' );
70
98
@@ -81,129 +109,6 @@ class _InlineCodeSyntax extends md.InlineSyntax {
81
109
82
110
const List <String > _oneLinerSkipTags = const ["code" , "pre" ];
83
111
84
- String oneLinerWithoutReferences (String text) {
85
- if (text == null ) return '' ;
86
- // Parse with Markdown, but only care about the first block or paragraph.
87
- Iterable <String > lines = text.replaceAll ('\r\n ' , '\n ' ).split ('\n ' );
88
- md.Document document = new md.Document (inlineSyntaxes: _markdown_syntaxes);
89
- document.parseRefLinks (lines);
90
- List blocks = document.parseLines (lines);
91
-
92
- while (blocks.isNotEmpty &&
93
- ((blocks.first is md.Element &&
94
- _oneLinerSkipTags.contains (blocks.first.tag)) ||
95
- (blocks.first is md.Text && blocks.first.text.isEmpty))) {
96
- blocks.removeAt (0 );
97
- }
98
-
99
- if (blocks.isEmpty) return '' ;
100
-
101
- String firstPara = new PlainTextRenderer ().render ([blocks.first]);
102
- return firstPara.trim ();
103
- }
104
-
105
- String oneLiner (ModelElement element) {
106
- if (element == null ||
107
- element.documentation == null ||
108
- element.documentation.isEmpty) return '' ;
109
-
110
- return _resolveDocReferences (
111
- oneLinerWithoutReferences (element.documentation), element).trim ();
112
- }
113
-
114
- class PlainTextRenderer implements md.NodeVisitor {
115
- static final _BLOCK_TAGS =
116
- new RegExp ('blockquote|h1|h2|h3|h4|h5|h6|hr|p|pre' );
117
-
118
- StringBuffer _buffer;
119
-
120
- String render (List <md.Node > nodes) {
121
- _buffer = new StringBuffer ();
122
-
123
- for (final node in nodes) {
124
- node.accept (this );
125
- }
126
-
127
- return _buffer.toString ();
128
- }
129
-
130
- @override
131
- void visitText (md.Text text) {
132
- _buffer.write (text.text);
133
- }
134
-
135
- @override
136
- bool visitElementBefore (md.Element element) {
137
- // do nothing
138
- return true ;
139
- }
140
-
141
- @override
142
- void visitElementAfter (md.Element element) {
143
- // Hackish. Separate block-level elements with newlines.
144
- if (! _buffer.isEmpty && _BLOCK_TAGS .firstMatch (element.tag) != null ) {
145
- _buffer.write ('\n\n ' );
146
- }
147
- }
148
- }
149
-
150
- String _replaceAllLinks (ModelElement element, String str,
151
- List <CommentReference > commentRefs, String findMatchingLink (
152
- String input, ModelElement element, List <CommentReference > commentRefs,
153
- {bool isConstructor})) {
154
- int lastWritten = 0 ;
155
- int index = str.indexOf (_leftChar);
156
- StringBuffer buf = new StringBuffer ();
157
-
158
- while (index != - 1 ) {
159
- int end = str.indexOf (_rightChar, index + 1 );
160
- if (end != - 1 ) {
161
- if (index - lastWritten > 0 ) {
162
- buf.write (str.substring (lastWritten, index));
163
- }
164
- String codeRef = str.substring (index + _leftChar.length, end);
165
- if (codeRef != null ) {
166
- var link;
167
- // support for [new Constructor] and [new Class.namedCtr]
168
- var refs = codeRef.split (' ' );
169
- if (refs.length == 2 && refs.first == 'new' ) {
170
- link = findMatchingLink (refs[1 ], element, commentRefs,
171
- isConstructor: true );
172
- } else {
173
- link = findMatchingLink (codeRef, element, commentRefs);
174
- }
175
- if (link != null ) {
176
- buf.write ('<a href="$link ">$codeRef </a>' );
177
- } else {
178
- if (_emitWarning) {
179
- print (
180
- " warning: unresolved doc reference '$codeRef ' (in $element )" );
181
- }
182
- buf.write (codeRef);
183
- }
184
- }
185
- lastWritten = end + _rightChar.length;
186
- } else {
187
- break ;
188
- }
189
- index = str.indexOf (_leftChar, end + 1 );
190
- }
191
- if (lastWritten < str.length) {
192
- buf.write (str.substring (lastWritten, str.length));
193
- }
194
- return buf.toString ();
195
- }
196
-
197
- String _resolveDocReferences (String docsAfterMarkdown, ModelElement element) {
198
- NodeList <CommentReference > commentRefs = _getCommentRefs (element);
199
- if (commentRefs == null || commentRefs.isEmpty) {
200
- return docsAfterMarkdown;
201
- }
202
-
203
- return _replaceAllLinks (
204
- element, docsAfterMarkdown, commentRefs, _getMatchingLink);
205
- }
206
-
207
112
NodeList <CommentReference > _getCommentRefs (ModelElement modelElement) {
208
113
if (modelElement == null ) return null ;
209
114
if (modelElement.documentation == null && modelElement.canOverride ()) {
@@ -238,14 +143,17 @@ NodeList<CommentReference> _getCommentRefs(ModelElement modelElement) {
238
143
return null ;
239
144
}
240
145
146
+ /// Returns null if element is a parameter.
241
147
String _getMatchingLink (
242
148
String codeRef, ModelElement element, List <CommentReference > commentRefs,
243
149
{bool isConstructor: false }) {
244
- var refElement;
150
+ if (commentRefs == null ) return null ;
151
+
152
+ Element refElement;
245
153
246
154
for (CommentReference ref in commentRefs) {
247
155
if (ref.identifier.name == codeRef) {
248
- var isConstrElement = ref.identifier.staticElement is ConstructorElement ;
156
+ bool isConstrElement = ref.identifier.staticElement is ConstructorElement ;
249
157
if (isConstructor && isConstrElement ||
250
158
! isConstructor && ! isConstrElement) {
251
159
refElement = ref.identifier.staticElement;
@@ -256,14 +164,19 @@ String _getMatchingLink(
256
164
257
165
if (refElement == null ) return null ;
258
166
259
- var refLibrary;
167
+ Library refLibrary;
260
168
var e = refElement is ClassMemberElement ||
261
169
refElement is PropertyAccessorElement
262
170
? refElement.enclosingElement
263
171
: refElement;
172
+
173
+ // If e is a ParameterElement, it's
174
+ // never going to be in a library. So refLibrary is going to be null.
264
175
refLibrary = element.package.libraries.firstWhere (
265
176
(lib) => lib.hasInNamespace (e), orElse: () => null );
266
177
if (refLibrary != null ) {
178
+ // Is there a way to pull this from a registry of known elements?
179
+ // Seems like we're creating too many objects this way.
267
180
return new ModelElement .from (refElement, refLibrary).href;
268
181
}
269
182
return null ;
0 commit comments