@@ -39,6 +39,7 @@ import 'package:analyzer/src/dart/element/member.dart'
39
39
import 'package:analyzer/src/dart/analysis/driver.dart' ;
40
40
import 'package:args/args.dart' ;
41
41
import 'package:collection/collection.dart' ;
42
+ import 'package:crypto/crypto.dart' ;
42
43
import 'package:dartdoc/src/dartdoc_options.dart' ;
43
44
import 'package:dartdoc/src/element_type.dart' ;
44
45
import 'package:dartdoc/src/io_utils.dart' ;
@@ -3142,6 +3143,7 @@ abstract class ModelElement extends Canonicalization
3142
3143
_rawDocs = _injectExamples (_rawDocs);
3143
3144
_rawDocs = _injectAnimations (_rawDocs);
3144
3145
_rawDocs = _stripMacroTemplatesAndAddToIndex (_rawDocs);
3146
+ _rawDocs = _stripHtmlAndAddToIndex (_rawDocs);
3145
3147
}
3146
3148
return _rawDocs;
3147
3149
}
@@ -3287,8 +3289,13 @@ abstract class ModelElement extends Canonicalization
3287
3289
return false ;
3288
3290
}
3289
3291
3292
+ String _htmlDocumentation;
3290
3293
@override
3291
- String get documentationAsHtml => _documentation.asHtml;
3294
+ String get documentationAsHtml {
3295
+ if (_htmlDocumentation != null ) return _htmlDocumentation;
3296
+ _htmlDocumentation = _injectHtmlFragments (_documentation.asHtml);
3297
+ return _htmlDocumentation;
3298
+ }
3292
3299
3293
3300
@override
3294
3301
Element get element => _element;
@@ -4047,6 +4054,51 @@ abstract class ModelElement extends Canonicalization
4047
4054
});
4048
4055
}
4049
4056
4057
+ /// Replace <<dartdoc-html>[digest] </dartdoc-html>> in API comments with
4058
+ /// the contents of the HTML fragment earlier defined by the
4059
+ /// {@inject-html} directive. The [digest] is a SHA1 of the contents
4060
+ /// of the HTML fragment, automatically generated upon parsing the
4061
+ /// {@inject-html} directive.
4062
+ ///
4063
+ /// This markup is generated and inserted by [_stripHtmlAndAddToIndex] when it
4064
+ /// removes the HTML fragment in preparation for markdown processing. It isn't
4065
+ /// meant to be used at a user level.
4066
+ ///
4067
+ /// Example:
4068
+ ///
4069
+ /// You place the fragment in a dartdoc comment:
4070
+ ///
4071
+ /// Some comments
4072
+ /// {@inject-html}
4073
+ /// <p>[HTML contents!]</p>
4074
+ /// {@endtemplate}
4075
+ /// More comments
4076
+ ///
4077
+ /// and [_stripHtmlAndAddToIndex] will replace your HTML fragment with this:
4078
+ ///
4079
+ /// Some comments
4080
+ /// <dartdoc-html>4cc02f877240bf69855b4c7291aba8a16e5acce0</dartdoc-html>
4081
+ /// More comments
4082
+ ///
4083
+ /// Which will render in the final HTML output as:
4084
+ ///
4085
+ /// Some comments
4086
+ /// <p>[HTML contents!]</p>
4087
+ /// More comments
4088
+ ///
4089
+ /// And the HTML fragment will not have been processed or changed by Markdown,
4090
+ /// but just injected verbatim.
4091
+ String _injectHtmlFragments (String rawDocs) {
4092
+ final macroRegExp = new RegExp (r'<dartdoc-html>([a-f0-9]+)</dartdoc-html>' );
4093
+ return rawDocs.replaceAllMapped (macroRegExp, (match) {
4094
+ String fragment = packageGraph.getHtmlFragment (match[1 ]);
4095
+ if (fragment == null ) {
4096
+ warn (PackageWarning .unknownHtmlFragment, message: match[1 ]);
4097
+ }
4098
+ return fragment;
4099
+ });
4100
+ }
4101
+
4050
4102
/// Replace {@macro ...} in API comments with the contents of the macro
4051
4103
///
4052
4104
/// Syntax:
@@ -4084,7 +4136,8 @@ abstract class ModelElement extends Canonicalization
4084
4136
});
4085
4137
}
4086
4138
4087
- /// Parse {@template ...} in API comments and store them in the index on the package.
4139
+ /// Parse and remove {@template ...} in API comments and store them
4140
+ /// in the index on the package.
4088
4141
///
4089
4142
/// Syntax:
4090
4143
///
@@ -4102,6 +4155,31 @@ abstract class ModelElement extends Canonicalization
4102
4155
});
4103
4156
}
4104
4157
4158
+ /// Parse and remove {@inject-html ...} in API comments and store
4159
+ /// them in the index on the package, replacing them with a SHA1 hash of the
4160
+ /// contents, where the HTML will be re-injected after Markdown processing of
4161
+ /// the rest of the text is complete.
4162
+ ///
4163
+ /// Syntax:
4164
+ ///
4165
+ /// {@inject-html}
4166
+ /// <p>The HTML to inject.</p>
4167
+ /// {@end-inject-html}
4168
+ ///
4169
+ String _stripHtmlAndAddToIndex (String rawDocs) {
4170
+ final templateRegExp = new RegExp (
4171
+ r'[ ]*{@inject-html\s*}([\s\S]+?){@end-inject-html}[ ]*\n?' ,
4172
+ multiLine: true );
4173
+ return rawDocs.replaceAllMapped (templateRegExp, (match) {
4174
+ String fragment = match[1 ];
4175
+ String digest = sha1.convert (fragment.codeUnits).toString ();
4176
+ packageGraph._addHtmlFragment (digest, fragment);
4177
+ // The newlines are so that Markdown will pass this through without
4178
+ // touching it.
4179
+ return '\n <dartdoc-html>$digest </dartdoc-html>\n ' ;
4180
+ });
4181
+ }
4182
+
4105
4183
/// Helper to process arguments given as a (possibly quoted) string.
4106
4184
///
4107
4185
/// First, this will split the given [argsAsString] into separate arguments,
@@ -4434,7 +4512,7 @@ class PackageGraph {
4434
4512
// Go through docs of every ModelElement in package to pre-build the macros
4435
4513
// index.
4436
4514
allLocalModelElements.forEach ((m) => m.documentationLocal);
4437
- _macrosAdded = true ;
4515
+ _localDocumentationBuilt = true ;
4438
4516
4439
4517
// Scan all model elements to insure that interceptor and other special
4440
4518
// objects are found.
@@ -4539,8 +4617,9 @@ class PackageGraph {
4539
4617
4540
4618
final Map <Element , Library > _elementToLibrary = {};
4541
4619
final Map <String , String > _macros = {};
4620
+ final Map <String , String > _htmlFragments = {};
4542
4621
bool allLibrariesAdded = false ;
4543
- bool _macrosAdded = false ;
4622
+ bool _localDocumentationBuilt = false ;
4544
4623
4545
4624
/// Returns true if there's at least one library documented in the package
4546
4625
/// that has the same package path as the library for the given element.
@@ -4685,6 +4764,9 @@ class PackageGraph {
4685
4764
case PackageWarning .unknownMacro:
4686
4765
warningMessage = "undefined macro [${message }]" ;
4687
4766
break ;
4767
+ case PackageWarning .unknownHtmlFragment:
4768
+ warningMessage = "undefined HTML fragment identifier [${message }]" ;
4769
+ break ;
4688
4770
case PackageWarning .brokenLink:
4689
4771
warningMessage = 'dartdoc generated a broken link to: ${message }' ;
4690
4772
warnablePrefix = 'to element' ;
@@ -5165,14 +5247,24 @@ class PackageGraph {
5165
5247
}
5166
5248
5167
5249
String getMacro (String name) {
5168
- assert (_macrosAdded );
5250
+ assert (_localDocumentationBuilt );
5169
5251
return _macros[name];
5170
5252
}
5171
5253
5172
5254
void _addMacro (String name, String content) {
5173
- assert (! _macrosAdded );
5255
+ assert (! _localDocumentationBuilt );
5174
5256
_macros[name] = content;
5175
5257
}
5258
+
5259
+ String getHtmlFragment (String name) {
5260
+ assert (_localDocumentationBuilt);
5261
+ return _htmlFragments[name];
5262
+ }
5263
+
5264
+ void _addHtmlFragment (String name, String content) {
5265
+ assert (! _localDocumentationBuilt);
5266
+ _htmlFragments[name] = content;
5267
+ }
5176
5268
}
5177
5269
5178
5270
/// A set of [Class] es, [Enum] s, [TopLevelVariable] s, [ModelFunction] s,
@@ -5887,8 +5979,8 @@ abstract class SourceCodeMixin implements Documentable {
5887
5979
5888
5980
String get _crossdartPath {
5889
5981
var node = element.computeNode ();
5890
- if (node is Declaration && node.element != null ) {
5891
- var source = node.element .source;
5982
+ if (node is Declaration && node.declaredElement != null ) {
5983
+ var source = node.declaredElement .source;
5892
5984
var filePath = source.fullName;
5893
5985
var uri = source.uri.toString ();
5894
5986
var packageMeta = library.packageGraph.packageMeta;
0 commit comments