@@ -39,6 +39,7 @@ import 'package:analyzer/src/dart/element/member.dart'
3939import 'package:analyzer/src/dart/analysis/driver.dart' ;
4040import 'package:args/args.dart' ;
4141import 'package:collection/collection.dart' ;
42+ import 'package:crypto/crypto.dart' ;
4243import 'package:dartdoc/src/dartdoc_options.dart' ;
4344import 'package:dartdoc/src/element_type.dart' ;
4445import 'package:dartdoc/src/io_utils.dart' ;
@@ -3142,6 +3143,7 @@ abstract class ModelElement extends Canonicalization
31423143 _rawDocs = _injectExamples (_rawDocs);
31433144 _rawDocs = _injectAnimations (_rawDocs);
31443145 _rawDocs = _stripMacroTemplatesAndAddToIndex (_rawDocs);
3146+ _rawDocs = _stripHtmlAndAddToIndex (_rawDocs);
31453147 }
31463148 return _rawDocs;
31473149 }
@@ -3287,8 +3289,13 @@ abstract class ModelElement extends Canonicalization
32873289 return false ;
32883290 }
32893291
3292+ String _htmlDocumentation;
32903293 @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+ }
32923299
32933300 @override
32943301 Element get element => _element;
@@ -4047,6 +4054,51 @@ abstract class ModelElement extends Canonicalization
40474054 });
40484055 }
40494056
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+
40504102 /// Replace {@macro ...} in API comments with the contents of the macro
40514103 ///
40524104 /// Syntax:
@@ -4084,7 +4136,8 @@ abstract class ModelElement extends Canonicalization
40844136 });
40854137 }
40864138
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.
40884141 ///
40894142 /// Syntax:
40904143 ///
@@ -4102,6 +4155,31 @@ abstract class ModelElement extends Canonicalization
41024155 });
41034156 }
41044157
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+
41054183 /// Helper to process arguments given as a (possibly quoted) string.
41064184 ///
41074185 /// First, this will split the given [argsAsString] into separate arguments,
@@ -4434,7 +4512,7 @@ class PackageGraph {
44344512 // Go through docs of every ModelElement in package to pre-build the macros
44354513 // index.
44364514 allLocalModelElements.forEach ((m) => m.documentationLocal);
4437- _macrosAdded = true ;
4515+ _localDocumentationBuilt = true ;
44384516
44394517 // Scan all model elements to insure that interceptor and other special
44404518 // objects are found.
@@ -4539,8 +4617,9 @@ class PackageGraph {
45394617
45404618 final Map <Element , Library > _elementToLibrary = {};
45414619 final Map <String , String > _macros = {};
4620+ final Map <String , String > _htmlFragments = {};
45424621 bool allLibrariesAdded = false ;
4543- bool _macrosAdded = false ;
4622+ bool _localDocumentationBuilt = false ;
45444623
45454624 /// Returns true if there's at least one library documented in the package
45464625 /// that has the same package path as the library for the given element.
@@ -4685,6 +4764,9 @@ class PackageGraph {
46854764 case PackageWarning .unknownMacro:
46864765 warningMessage = "undefined macro [${message }]" ;
46874766 break ;
4767+ case PackageWarning .unknownHtmlFragment:
4768+ warningMessage = "undefined HTML fragment identifier [${message }]" ;
4769+ break ;
46884770 case PackageWarning .brokenLink:
46894771 warningMessage = 'dartdoc generated a broken link to: ${message }' ;
46904772 warnablePrefix = 'to element' ;
@@ -5165,14 +5247,24 @@ class PackageGraph {
51655247 }
51665248
51675249 String getMacro (String name) {
5168- assert (_macrosAdded );
5250+ assert (_localDocumentationBuilt );
51695251 return _macros[name];
51705252 }
51715253
51725254 void _addMacro (String name, String content) {
5173- assert (! _macrosAdded );
5255+ assert (! _localDocumentationBuilt );
51745256 _macros[name] = content;
51755257 }
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+ }
51765268}
51775269
51785270/// A set of [Class] es, [Enum] s, [TopLevelVariable] s, [ModelFunction] s,
@@ -5887,8 +5979,8 @@ abstract class SourceCodeMixin implements Documentable {
58875979
58885980 String get _crossdartPath {
58895981 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;
58925984 var filePath = source.fullName;
58935985 var uri = source.uri.toString ();
58945986 var packageMeta = library.packageGraph.packageMeta;
0 commit comments