Add --inject-html flag to enable {@inject-html}, and update README.md (#1793)
* Update the README.md to include information about {@inject-html}
* Add the --inject-html command line flag to enable HTML injection.
* Add negatable to --inject-html option
diff --git a/README.md b/README.md
index 4837c12..38e7c36 100644
--- a/README.md
+++ b/README.md
@@ -301,6 +301,35 @@
/// # `This is the text that will be sent to the tool as input.`
```
+### Injecting HTML
+
+It happens rarely, but sometimes what you really need is to inject some raw HTML
+into the dartdoc output, without it being subject to Markdown processing
+beforehand. This can be useful when the output of an external tool is HTML, for
+instance. This is where the `{@inject-html}...{@end-inject-html}` tags come in.
+
+For security reasons, the `{@inject-html}` directive will be ignored unless the
+`--inject-html` flag is given on the dartdoc command line.
+
+Since this HTML fragment doesn't undergo Markdown processing, reference links
+and other normal processing won't happen on the contained fragment.
+
+So, this:
+```dart
+ /// {@inject-html}
+ /// <p>[The HTML to inject.]()</p>
+ /// {@end-inject-html}
+```
+
+Will result in this be emitted in its place in the HTML output (notice that the
+markdown link isn't linked).
+```
+<p>[The HTML to inject.]()</p>
+```
+
+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.
+
### Auto including dependencies
If `--auto-include-dependencies` flag is provided, dartdoc tries to automatically add
diff --git a/lib/src/dartdoc_options.dart b/lib/src/dartdoc_options.dart
index 54cacdf..c4d6e9a 100644
--- a/lib/src/dartdoc_options.dart
+++ b/lib/src/dartdoc_options.dart
@@ -541,7 +541,7 @@
bool hide = false,
bool isDir = false,
bool isFile = false,
- bool negatable,
+ bool negatable = false,
bool splitCommas})
: super._(name, null, help, isDir, isFile, mustExist, null) {
_hide = hide;
@@ -672,7 +672,7 @@
bool hide = false,
bool isDir = false,
bool isFile = false,
- bool negatable,
+ bool negatable = false,
bool splitCommas})
: super._(name, defaultsTo, help, isDir, isFile, mustExist, null) {
_hide = hide;
@@ -707,7 +707,7 @@
bool hide = false,
bool isDir = false,
bool isFile = false,
- bool negatable,
+ bool negatable = false,
bool parentDirOverridesChild: false,
bool splitCommas})
: super._(name, defaultsTo, help, isDir, isFile, mustExist, null) {
@@ -1045,7 +1045,7 @@
defaultsTo: defaultsTo as bool,
help: help,
hide: hide,
- negatable: negatable);
+ negatable: negatable ?? false);
} else if (_isInt || _isDouble || _isString) {
argParser.addOption(argName,
abbr: abbr,
@@ -1140,6 +1140,7 @@
List<String> get includeExternal =>
optionSet['includeExternal'].valueAt(context);
bool get includeSource => optionSet['includeSource'].valueAt(context);
+ bool get injectHtml => optionSet['injectHtml'].valueAt(context);
ToolConfiguration get tools => optionSet['tools'].valueAt(context);
/// _input is only used to construct synthetic options.
@@ -1240,8 +1241,8 @@
mustExist: true),
new DartdocOptionArgOnly<bool>('hideSdkText', false,
hide: true,
- help:
- 'Drop all text for SDK components. Helpful for integration tests for dartdoc, probably not useful for anything else.',
+ help: 'Drop all text for SDK components. Helpful for integration '
+ 'tests for dartdoc, probably not useful for anything else.',
negatable: true),
new DartdocOptionArgFile<List<String>>('include', [],
help: 'Library names to generate docs for.', splitCommas: true),
@@ -1254,6 +1255,9 @@
splitCommas: true),
new DartdocOptionArgOnly<bool>('includeSource', true,
help: 'Show source code blocks.', negatable: true),
+ new DartdocOptionArgOnly<bool>('injectHtml', false,
+ help: 'Allow the use of the {@inject-html} directive to inject raw '
+ 'HTML into dartdoc output.'),
new DartdocOptionArgOnly<String>('input', Directory.current.path,
isDir: true, help: 'Path to source directory', mustExist: true),
new DartdocOptionSyntheticOnly<String>('inputDir',
@@ -1323,7 +1327,7 @@
'A list of package names to place first when grouping libraries in packages. '
'Unmentioned packages are sorted after these.'),
new DartdocOptionArgOnly<bool>('sdkDocs', false,
- help: 'Generate ONLY the docs for the Dart SDK.', negatable: false),
+ help: 'Generate ONLY the docs for the Dart SDK.'),
new DartdocOptionArgSynth<String>('sdkDir',
(DartdocSyntheticOption<String> option, Directory dir) {
if (!option.parent['sdkDocs'].valueAt(dir) &&
@@ -1341,7 +1345,7 @@
new DartdocOptionArgFile<bool>('showUndocumentedCategories', false,
help: "Label categories that aren't documented", negatable: true),
new DartdocOptionArgOnly<bool>('showWarnings', false,
- help: 'Display all warnings.', negatable: false),
+ help: 'Display all warnings.'),
new DartdocOptionSyntheticOnly<PackageMeta>('topLevelPackageMeta',
(DartdocSyntheticOption<PackageMeta> option, Directory dir) {
PackageMeta packageMeta = new PackageMeta.fromDir(
@@ -1357,8 +1361,7 @@
return packageMeta;
}, help: 'PackageMeta object for the default package.'),
new DartdocOptionArgOnly<bool>('useCategories', true,
- help: 'Display categories in the sidebar of packages',
- negatable: false),
+ help: 'Display categories in the sidebar of packages'),
new DartdocOptionArgOnly<bool>('validateLinks', true,
help:
'Runs the built-in link checker to display Dart context aware warnings for broken links (slow)',
diff --git a/lib/src/model.dart b/lib/src/model.dart
index 6a5d129..5c6ba0f 100644
--- a/lib/src/model.dart
+++ b/lib/src/model.dart
@@ -4088,6 +4088,7 @@
/// And the HTML fragment will not have been processed or changed by Markdown,
/// but just injected verbatim.
String _injectHtmlFragments(String rawDocs) {
+ if (!config.injectHtml) return rawDocs;
final macroRegExp = new RegExp(r'<dartdoc-html>([a-f0-9]+)</dartdoc-html>');
return rawDocs.replaceAllMapped(macroRegExp, (match) {
String fragment = packageGraph.getHtmlFragment(match[1]);
@@ -4166,6 +4167,7 @@
/// {@end-inject-html}
///
String _stripHtmlAndAddToIndex(String rawDocs) {
+ if (!config.injectHtml) return rawDocs;
final templateRegExp = new RegExp(
r'[ ]*{@inject-html\s*}([\s\S]+?){@end-inject-html}[ ]*\n?',
multiLine: true);
diff --git a/test/model_test.dart b/test/model_test.dart
index 3e68bf7..bd33c5b 100644
--- a/test/model_test.dart
+++ b/test/model_test.dart
@@ -116,22 +116,59 @@
});
});
- group('HTML Injection', () {
+ group('HTML Injection when allowed', () {
+ Class htmlInjection;
+ Method injectSimpleHtml;
+
+ PackageGraph injectionPackageGraph;
+ Library injectionExLibrary;
+
+ setUpAll(() async {
+ injectionPackageGraph = await utils.bootBasicPackage(
+ 'testing/test_package', ['css', 'code_in_comments', 'excluded'],
+ additionalArguments: ['--inject-html']);
+
+ injectionExLibrary =
+ injectionPackageGraph.libraries.firstWhere((lib) => lib.name == 'ex');
+
+ htmlInjection = injectionExLibrary.classes
+ .firstWhere((c) => c.name == 'HtmlInjection');
+ injectSimpleHtml = htmlInjection.allInstanceMethods
+ .firstWhere((m) => m.name == 'injectSimpleHtml');
+ injectionPackageGraph.allLocalModelElements
+ .forEach((m) => m.documentation);
+ });
+
+ test("can inject HTML", () {
+ expect(
+ injectSimpleHtml.documentation,
+ contains(
+ '\n<dartdoc-html>bad2bbdd4a5cf9efb3212afff4449904756851aa</dartdoc-html>\n'));
+ expect(injectSimpleHtml.documentation,
+ isNot(contains('\n{@inject-html}\n')));
+ expect(injectSimpleHtml.documentationAsHtml,
+ contains(' <div style="opacity: 0.5;">[HtmlInjection]</div>'));
+ });
+ });
+
+ group('HTML Injection when not allowed', () {
Class htmlInjection;
Method injectSimpleHtml;
setUp(() {
- htmlInjection = exLibrary.classes.firstWhere((c) => c.name == 'HtmlInjection');
- injectSimpleHtml =
- htmlInjection.allInstanceMethods.firstWhere((m) => m.name == 'injectSimpleHtml');
+ htmlInjection =
+ exLibrary.classes.firstWhere((c) => c.name == 'HtmlInjection');
+ injectSimpleHtml = htmlInjection.allInstanceMethods
+ .firstWhere((m) => m.name == 'injectSimpleHtml');
packageGraph.allLocalModelElements.forEach((m) => m.documentation);
});
- test("can inject HTML", () {
+ test("doesn't inject HTML if --inject-html option is not present", () {
expect(
injectSimpleHtml.documentation,
- contains('\n<dartdoc-html>bad2bbdd4a5cf9efb3212afff4449904756851aa</dartdoc-html>\n'));
- expect(injectSimpleHtml.documentationAsHtml,
- contains(' <div style="opacity: 0.5;">[HtmlInjection]</div>'));
+ isNot(contains(
+ '\n<dartdoc-html>bad2bbdd4a5cf9efb3212afff4449904756851aa</dartdoc-html>\n')));
+ expect(injectSimpleHtml.documentation, isNot(contains('<dartdoc-html>')));
+ expect(injectSimpleHtml.documentationAsHtml, contains('{@inject-html}'));
});
});
@@ -1995,8 +2032,9 @@
reason: "Can't find convertToMap function in ${fakePath}");
if (Platform.isWindows) fakePath = fakePath.replaceAll('/', r'\\');
- crossdartPackageGraph = await utils
- .bootBasicPackage(utils.testPackageDir.path, [], withCrossdart: true);
+ crossdartPackageGraph = await utils.bootBasicPackage(
+ utils.testPackageDir.path, [],
+ additionalArguments: ['--add-crossdart']);
crossdartFakeLibrary =
crossdartPackageGraph.libraries.firstWhere((l) => l.name == 'fake');
HasGenerics = crossdartFakeLibrary.classes
diff --git a/test/src/utils.dart b/test/src/utils.dart
index ed63e28..c14fe28 100644
--- a/test/src/utils.dart
+++ b/test/src/utils.dart
@@ -60,18 +60,22 @@
if (dir.existsSync()) dir.deleteSync(recursive: true);
}
-void init() async {
+void init({List<String> additionalArguments}) async {
sdkDir = defaultSdkDir;
sdkPackageMeta = new PackageMeta.fromDir(sdkDir);
+ additionalArguments ??= <String>[];
testPackageGraph = await bootBasicPackage(
- 'testing/test_package', ['css', 'code_in_comments', 'excluded']);
+ 'testing/test_package', ['css', 'code_in_comments', 'excluded'],
+ additionalArguments: additionalArguments);
testPackageGraphGinormous = await bootBasicPackage(
'testing/test_package', ['css', 'code_in_commnets', 'excluded'],
- withAutoIncludedDependencies: true);
+ additionalArguments:
+ additionalArguments + ['--auto-include-dependencies']);
- testPackageGraphSmall =
- await bootBasicPackage('testing/test_package_small', []);
+ testPackageGraphSmall = await bootBasicPackage(
+ 'testing/test_package_small', [],
+ additionalArguments: additionalArguments);
testPackageGraphSdk = await bootSdkPackage();
}
@@ -82,18 +86,17 @@
Future<PackageGraph> bootBasicPackage(
String dirPath, List<String> excludeLibraries,
- {bool withAutoIncludedDependencies = false,
- bool withCrossdart = false}) async {
+ {List<String> additionalArguments}) async {
Directory dir = new Directory(dirPath);
+ additionalArguments ??= <String>[];
return new PackageBuilder(await contextFromArgv([
- '--input',
- dir.path,
- '--sdk-dir',
- sdkDir.path,
- '--exclude',
- excludeLibraries.join(','),
- '--${withCrossdart ? "" : "no-"}add-crossdart',
- '--${withAutoIncludedDependencies ? "" : "no-"}auto-include-dependencies'
- ]))
+ '--input',
+ dir.path,
+ '--sdk-dir',
+ sdkDir.path,
+ '--exclude',
+ excludeLibraries.join(','),
+ ] +
+ additionalArguments))
.buildPackageGraph();
}
diff --git a/testing/test_package_docs/ex/HtmlInjection-class.html b/testing/test_package_docs/ex/HtmlInjection-class.html
index e51f9c8..71d1d02 100644
--- a/testing/test_package_docs/ex/HtmlInjection-class.html
+++ b/testing/test_package_docs/ex/HtmlInjection-class.html
@@ -159,7 +159,8 @@
</span>
</dt>
<dd>
- Injects some HTML. <a href="ex/HtmlInjection/injectSimpleHtml.html">[...]</a>
+ Injects some HTML.
+{@inject-html} <a href="ex/HtmlInjection/injectSimpleHtml.html">[...]</a>
</dd>
<dt id="noSuchMethod" class="callable inherited">
diff --git a/testing/test_package_docs/ex/HtmlInjection/injectSimpleHtml.html b/testing/test_package_docs/ex/HtmlInjection/injectSimpleHtml.html
index 155e724..015141a 100644
--- a/testing/test_package_docs/ex/HtmlInjection/injectSimpleHtml.html
+++ b/testing/test_package_docs/ex/HtmlInjection/injectSimpleHtml.html
@@ -70,10 +70,9 @@
(<wbr>)
</section>
<section class="desc markdown">
- <p>Injects some HTML.</p>
-<p>
- <div style="opacity: 0.5;">[HtmlInjection]</div>
-</p>
+ <p>Injects some HTML.
+{@inject-html}</p> <div style="opacity: 0.5;">[HtmlInjection]</div>
+{@end-inject-html}
</section>
diff --git a/testing/test_package_docs_dev/ex/HtmlInjection-class.html b/testing/test_package_docs_dev/ex/HtmlInjection-class.html
index e51f9c8..71d1d02 100644
--- a/testing/test_package_docs_dev/ex/HtmlInjection-class.html
+++ b/testing/test_package_docs_dev/ex/HtmlInjection-class.html
@@ -159,7 +159,8 @@
</span>
</dt>
<dd>
- Injects some HTML. <a href="ex/HtmlInjection/injectSimpleHtml.html">[...]</a>
+ Injects some HTML.
+{@inject-html} <a href="ex/HtmlInjection/injectSimpleHtml.html">[...]</a>
</dd>
<dt id="noSuchMethod" class="callable inherited">
diff --git a/testing/test_package_docs_dev/ex/HtmlInjection/injectSimpleHtml.html b/testing/test_package_docs_dev/ex/HtmlInjection/injectSimpleHtml.html
index 155e724..015141a 100644
--- a/testing/test_package_docs_dev/ex/HtmlInjection/injectSimpleHtml.html
+++ b/testing/test_package_docs_dev/ex/HtmlInjection/injectSimpleHtml.html
@@ -70,10 +70,9 @@
(<wbr>)
</section>
<section class="desc markdown">
- <p>Injects some HTML.</p>
-<p>
- <div style="opacity: 0.5;">[HtmlInjection]</div>
-</p>
+ <p>Injects some HTML.
+{@inject-html}</p> <div style="opacity: 0.5;">[HtmlInjection]</div>
+{@end-inject-html}
</section>