Skip to content

Commit 2b8e295

Browse files
gspencergoogjcollins-g
authored andcommitted
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
1 parent eeb5893 commit 2b8e295

File tree

9 files changed

+120
-45
lines changed

9 files changed

+120
-45
lines changed

README.md

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -301,6 +301,35 @@ the equivalent of having the following comment in the code:
301301
/// # `This is the text that will be sent to the tool as input.`
302302
```
303303

304+
### Injecting HTML
305+
306+
It happens rarely, but sometimes what you really need is to inject some raw HTML
307+
into the dartdoc output, without it being subject to Markdown processing
308+
beforehand. This can be useful when the output of an external tool is HTML, for
309+
instance. This is where the `{@inject-html}...{@end-inject-html}` tags come in.
310+
311+
For security reasons, the `{@inject-html}` directive will be ignored unless the
312+
`--inject-html` flag is given on the dartdoc command line.
313+
314+
Since this HTML fragment doesn't undergo Markdown processing, reference links
315+
and other normal processing won't happen on the contained fragment.
316+
317+
So, this:
318+
```dart
319+
/// {@inject-html}
320+
/// <p>[The HTML to inject.]()</p>
321+
/// {@end-inject-html}
322+
```
323+
324+
Will result in this be emitted in its place in the HTML output (notice that the
325+
markdown link isn't linked).
326+
```
327+
<p>[The HTML to inject.]()</p>
328+
```
329+
330+
It's best to only inject HTML that is self-contained and doesn't depend upon
331+
other elements on the page, since those may change in future versions of Dartdoc.
332+
304333
### Auto including dependencies
305334

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

lib/src/dartdoc_options.dart

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -541,7 +541,7 @@ class DartdocOptionArgSynth<T> extends DartdocOption<T>
541541
bool hide = false,
542542
bool isDir = false,
543543
bool isFile = false,
544-
bool negatable,
544+
bool negatable = false,
545545
bool splitCommas})
546546
: super._(name, null, help, isDir, isFile, mustExist, null) {
547547
_hide = hide;
@@ -672,7 +672,7 @@ class DartdocOptionArgOnly<T> extends DartdocOption<T>
672672
bool hide = false,
673673
bool isDir = false,
674674
bool isFile = false,
675-
bool negatable,
675+
bool negatable = false,
676676
bool splitCommas})
677677
: super._(name, defaultsTo, help, isDir, isFile, mustExist, null) {
678678
_hide = hide;
@@ -707,7 +707,7 @@ class DartdocOptionArgFile<T> extends DartdocOption<T>
707707
bool hide = false,
708708
bool isDir = false,
709709
bool isFile = false,
710-
bool negatable,
710+
bool negatable = false,
711711
bool parentDirOverridesChild: false,
712712
bool splitCommas})
713713
: super._(name, defaultsTo, help, isDir, isFile, mustExist, null) {
@@ -1045,7 +1045,7 @@ abstract class _DartdocArgOption<T> implements DartdocOption<T> {
10451045
defaultsTo: defaultsTo as bool,
10461046
help: help,
10471047
hide: hide,
1048-
negatable: negatable);
1048+
negatable: negatable ?? false);
10491049
} else if (_isInt || _isDouble || _isString) {
10501050
argParser.addOption(argName,
10511051
abbr: abbr,
@@ -1140,6 +1140,7 @@ class DartdocOptionContext {
11401140
List<String> get includeExternal =>
11411141
optionSet['includeExternal'].valueAt(context);
11421142
bool get includeSource => optionSet['includeSource'].valueAt(context);
1143+
bool get injectHtml => optionSet['injectHtml'].valueAt(context);
11431144
ToolConfiguration get tools => optionSet['tools'].valueAt(context);
11441145

11451146
/// _input is only used to construct synthetic options.
@@ -1240,8 +1241,8 @@ Future<List<DartdocOption>> createDartdocOptions() async {
12401241
mustExist: true),
12411242
new DartdocOptionArgOnly<bool>('hideSdkText', false,
12421243
hide: true,
1243-
help:
1244-
'Drop all text for SDK components. Helpful for integration tests for dartdoc, probably not useful for anything else.',
1244+
help: 'Drop all text for SDK components. Helpful for integration '
1245+
'tests for dartdoc, probably not useful for anything else.',
12451246
negatable: true),
12461247
new DartdocOptionArgFile<List<String>>('include', [],
12471248
help: 'Library names to generate docs for.', splitCommas: true),
@@ -1254,6 +1255,9 @@ Future<List<DartdocOption>> createDartdocOptions() async {
12541255
splitCommas: true),
12551256
new DartdocOptionArgOnly<bool>('includeSource', true,
12561257
help: 'Show source code blocks.', negatable: true),
1258+
new DartdocOptionArgOnly<bool>('injectHtml', false,
1259+
help: 'Allow the use of the {@inject-html} directive to inject raw '
1260+
'HTML into dartdoc output.'),
12571261
new DartdocOptionArgOnly<String>('input', Directory.current.path,
12581262
isDir: true, help: 'Path to source directory', mustExist: true),
12591263
new DartdocOptionSyntheticOnly<String>('inputDir',
@@ -1323,7 +1327,7 @@ Future<List<DartdocOption>> createDartdocOptions() async {
13231327
'A list of package names to place first when grouping libraries in packages. '
13241328
'Unmentioned packages are sorted after these.'),
13251329
new DartdocOptionArgOnly<bool>('sdkDocs', false,
1326-
help: 'Generate ONLY the docs for the Dart SDK.', negatable: false),
1330+
help: 'Generate ONLY the docs for the Dart SDK.'),
13271331
new DartdocOptionArgSynth<String>('sdkDir',
13281332
(DartdocSyntheticOption<String> option, Directory dir) {
13291333
if (!option.parent['sdkDocs'].valueAt(dir) &&
@@ -1341,7 +1345,7 @@ Future<List<DartdocOption>> createDartdocOptions() async {
13411345
new DartdocOptionArgFile<bool>('showUndocumentedCategories', false,
13421346
help: "Label categories that aren't documented", negatable: true),
13431347
new DartdocOptionArgOnly<bool>('showWarnings', false,
1344-
help: 'Display all warnings.', negatable: false),
1348+
help: 'Display all warnings.'),
13451349
new DartdocOptionSyntheticOnly<PackageMeta>('topLevelPackageMeta',
13461350
(DartdocSyntheticOption<PackageMeta> option, Directory dir) {
13471351
PackageMeta packageMeta = new PackageMeta.fromDir(
@@ -1357,8 +1361,7 @@ Future<List<DartdocOption>> createDartdocOptions() async {
13571361
return packageMeta;
13581362
}, help: 'PackageMeta object for the default package.'),
13591363
new DartdocOptionArgOnly<bool>('useCategories', true,
1360-
help: 'Display categories in the sidebar of packages',
1361-
negatable: false),
1364+
help: 'Display categories in the sidebar of packages'),
13621365
new DartdocOptionArgOnly<bool>('validateLinks', true,
13631366
help:
13641367
'Runs the built-in link checker to display Dart context aware warnings for broken links (slow)',

lib/src/model.dart

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4088,6 +4088,7 @@ abstract class ModelElement extends Canonicalization
40884088
/// And the HTML fragment will not have been processed or changed by Markdown,
40894089
/// but just injected verbatim.
40904090
String _injectHtmlFragments(String rawDocs) {
4091+
if (!config.injectHtml) return rawDocs;
40914092
final macroRegExp = new RegExp(r'<dartdoc-html>([a-f0-9]+)</dartdoc-html>');
40924093
return rawDocs.replaceAllMapped(macroRegExp, (match) {
40934094
String fragment = packageGraph.getHtmlFragment(match[1]);
@@ -4166,6 +4167,7 @@ abstract class ModelElement extends Canonicalization
41664167
/// &#123;@end-inject-html&#125;
41674168
///
41684169
String _stripHtmlAndAddToIndex(String rawDocs) {
4170+
if (!config.injectHtml) return rawDocs;
41694171
final templateRegExp = new RegExp(
41704172
r'[ ]*{@inject-html\s*}([\s\S]+?){@end-inject-html}[ ]*\n?',
41714173
multiLine: true);

test/model_test.dart

Lines changed: 47 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -116,25 +116,62 @@ void main() {
116116
});
117117
});
118118

119-
group('HTML Injection', () {
119+
group('HTML Injection when allowed', () {
120120
Class htmlInjection;
121121
Method injectSimpleHtml;
122122

123-
setUp(() {
124-
htmlInjection = exLibrary.classes.firstWhere((c) => c.name == 'HtmlInjection');
125-
injectSimpleHtml =
126-
htmlInjection.allInstanceMethods.firstWhere((m) => m.name == 'injectSimpleHtml');
127-
packageGraph.allLocalModelElements.forEach((m) => m.documentation);
123+
PackageGraph injectionPackageGraph;
124+
Library injectionExLibrary;
125+
126+
setUpAll(() async {
127+
injectionPackageGraph = await utils.bootBasicPackage(
128+
'testing/test_package', ['css', 'code_in_comments', 'excluded'],
129+
additionalArguments: ['--inject-html']);
130+
131+
injectionExLibrary =
132+
injectionPackageGraph.libraries.firstWhere((lib) => lib.name == 'ex');
133+
134+
htmlInjection = injectionExLibrary.classes
135+
.firstWhere((c) => c.name == 'HtmlInjection');
136+
injectSimpleHtml = htmlInjection.allInstanceMethods
137+
.firstWhere((m) => m.name == 'injectSimpleHtml');
138+
injectionPackageGraph.allLocalModelElements
139+
.forEach((m) => m.documentation);
128140
});
141+
129142
test("can inject HTML", () {
130143
expect(
131144
injectSimpleHtml.documentation,
132-
contains('\n<dartdoc-html>bad2bbdd4a5cf9efb3212afff4449904756851aa</dartdoc-html>\n'));
145+
contains(
146+
'\n<dartdoc-html>bad2bbdd4a5cf9efb3212afff4449904756851aa</dartdoc-html>\n'));
147+
expect(injectSimpleHtml.documentation,
148+
isNot(contains('\n{@inject-html}\n')));
133149
expect(injectSimpleHtml.documentationAsHtml,
134150
contains(' <div style="opacity: 0.5;">[HtmlInjection]</div>'));
135151
});
136152
});
137153

154+
group('HTML Injection when not allowed', () {
155+
Class htmlInjection;
156+
Method injectSimpleHtml;
157+
158+
setUp(() {
159+
htmlInjection =
160+
exLibrary.classes.firstWhere((c) => c.name == 'HtmlInjection');
161+
injectSimpleHtml = htmlInjection.allInstanceMethods
162+
.firstWhere((m) => m.name == 'injectSimpleHtml');
163+
packageGraph.allLocalModelElements.forEach((m) => m.documentation);
164+
});
165+
test("doesn't inject HTML if --inject-html option is not present", () {
166+
expect(
167+
injectSimpleHtml.documentation,
168+
isNot(contains(
169+
'\n<dartdoc-html>bad2bbdd4a5cf9efb3212afff4449904756851aa</dartdoc-html>\n')));
170+
expect(injectSimpleHtml.documentation, isNot(contains('<dartdoc-html>')));
171+
expect(injectSimpleHtml.documentationAsHtml, contains('{@inject-html}'));
172+
});
173+
});
174+
138175
group('Missing and Remote', () {
139176
test('Verify that SDK libraries are not canonical when missing', () {
140177
expect(
@@ -1995,8 +2032,9 @@ String topLevelFunction(int param1, bool param2, Cool coolBeans,
19952032
reason: "Can't find convertToMap function in ${fakePath}");
19962033
if (Platform.isWindows) fakePath = fakePath.replaceAll('/', r'\\');
19972034

1998-
crossdartPackageGraph = await utils
1999-
.bootBasicPackage(utils.testPackageDir.path, [], withCrossdart: true);
2035+
crossdartPackageGraph = await utils.bootBasicPackage(
2036+
utils.testPackageDir.path, [],
2037+
additionalArguments: ['--add-crossdart']);
20002038
crossdartFakeLibrary =
20012039
crossdartPackageGraph.libraries.firstWhere((l) => l.name == 'fake');
20022040
HasGenerics = crossdartFakeLibrary.classes

test/src/utils.dart

Lines changed: 19 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -60,18 +60,22 @@ void delete(Directory dir) {
6060
if (dir.existsSync()) dir.deleteSync(recursive: true);
6161
}
6262

63-
void init() async {
63+
void init({List<String> additionalArguments}) async {
6464
sdkDir = defaultSdkDir;
6565
sdkPackageMeta = new PackageMeta.fromDir(sdkDir);
66+
additionalArguments ??= <String>[];
6667

6768
testPackageGraph = await bootBasicPackage(
68-
'testing/test_package', ['css', 'code_in_comments', 'excluded']);
69+
'testing/test_package', ['css', 'code_in_comments', 'excluded'],
70+
additionalArguments: additionalArguments);
6971
testPackageGraphGinormous = await bootBasicPackage(
7072
'testing/test_package', ['css', 'code_in_commnets', 'excluded'],
71-
withAutoIncludedDependencies: true);
73+
additionalArguments:
74+
additionalArguments + ['--auto-include-dependencies']);
7275

73-
testPackageGraphSmall =
74-
await bootBasicPackage('testing/test_package_small', []);
76+
testPackageGraphSmall = await bootBasicPackage(
77+
'testing/test_package_small', [],
78+
additionalArguments: additionalArguments);
7579
testPackageGraphSdk = await bootSdkPackage();
7680
}
7781

@@ -82,18 +86,17 @@ Future<PackageGraph> bootSdkPackage() async {
8286

8387
Future<PackageGraph> bootBasicPackage(
8488
String dirPath, List<String> excludeLibraries,
85-
{bool withAutoIncludedDependencies = false,
86-
bool withCrossdart = false}) async {
89+
{List<String> additionalArguments}) async {
8790
Directory dir = new Directory(dirPath);
91+
additionalArguments ??= <String>[];
8892
return new PackageBuilder(await contextFromArgv([
89-
'--input',
90-
dir.path,
91-
'--sdk-dir',
92-
sdkDir.path,
93-
'--exclude',
94-
excludeLibraries.join(','),
95-
'--${withCrossdart ? "" : "no-"}add-crossdart',
96-
'--${withAutoIncludedDependencies ? "" : "no-"}auto-include-dependencies'
97-
]))
93+
'--input',
94+
dir.path,
95+
'--sdk-dir',
96+
sdkDir.path,
97+
'--exclude',
98+
excludeLibraries.join(','),
99+
] +
100+
additionalArguments))
98101
.buildPackageGraph();
99102
}

testing/test_package_docs/ex/HtmlInjection-class.html

Lines changed: 2 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

testing/test_package_docs/ex/HtmlInjection/injectSimpleHtml.html

Lines changed: 3 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

testing/test_package_docs_dev/ex/HtmlInjection-class.html

Lines changed: 2 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

testing/test_package_docs_dev/ex/HtmlInjection/injectSimpleHtml.html

Lines changed: 3 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)