Skip to content

Commit 9be04e0

Browse files
authored
Allow ID attributes on headings when running with --sanitize-html (#3358)
* Allow ID attributes on headings when running with --sanitize-html * Organize imports * Additional tests
1 parent 8785dd2 commit 9be04e0

File tree

3 files changed

+50
-3
lines changed

3 files changed

+50
-3
lines changed

lib/src/render/documentation_renderer.dart

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -307,6 +307,20 @@ final _citeAttributeValidator = <String, bool Function(String)>{
307307
'cite': _validUrl,
308308
};
309309

310+
/// Allow the `id` attribute for `h1`, `h2`, ... `h6`.
311+
final _headingAttributeValidator = <String, bool Function(String)>{
312+
'id': (id) {
313+
// This id property is generated by package:markdown in:
314+
// https://github.com/dart-lang/markdown/blob/ecbffa9bf9109d490b9388e9cb1f2bb801aee63c/lib/src/block_syntaxes/block_syntax.dart#L57-L63
315+
316+
// Cannot contain anything but a-z0-9_-
317+
if (id.contains(RegExp('[^a-z0-9_-]'))) {
318+
return false;
319+
}
320+
return true;
321+
},
322+
};
323+
310324
final _elementAttributeValidators =
311325
<String, Map<String, bool Function(String)>>{
312326
'A': {
@@ -324,4 +338,12 @@ final _elementAttributeValidators =
324338
'DEL': _citeAttributeValidator,
325339
'INS': _citeAttributeValidator,
326340
'Q': _citeAttributeValidator,
341+
'H1': _headingAttributeValidator,
342+
'H2': _headingAttributeValidator,
343+
'H3': _headingAttributeValidator,
344+
'H4': _headingAttributeValidator,
345+
'H5': _headingAttributeValidator,
346+
'H6': _headingAttributeValidator,
347+
'H7': _headingAttributeValidator,
348+
'H8': _headingAttributeValidator,
327349
};

test/end2end/model_special_cases_test.dart

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import 'package:dartdoc/src/model/model.dart';
1515
import 'package:dartdoc/src/package_config_provider.dart';
1616
import 'package:dartdoc/src/package_meta.dart';
1717
import 'package:dartdoc/src/special_elements.dart';
18+
import 'package:html/parser.dart' as html;
1819
import 'package:test/test.dart';
1920

2021
import '../src/utils.dart' as utils;
@@ -211,9 +212,8 @@ void main() {
211212
Class classWithHtml;
212213
late final Method blockHtml;
213214
late final Method inlineHtml;
214-
215-
PackageGraph packageGraph;
216-
Library exLibrary;
215+
late final PackageGraph packageGraph;
216+
late final Library exLibrary;
217217

218218
setUpAll(() async {
219219
packageGraph = await utils.bootBasicPackage(
@@ -237,6 +237,21 @@ void main() {
237237
}
238238
});
239239

240+
test('can have auto-generated id attributes on headings', () {
241+
final dom = html.parseFragment(exLibrary.documentationAsHtml);
242+
expect(dom.querySelector('h1[id="heading-with-id"]'), isNotNull);
243+
});
244+
245+
test('can have id attributes on headings', () {
246+
final dom = html.parseFragment(exLibrary.documentationAsHtml);
247+
expect(dom.querySelector('h1[id="my-id"]'), isNotNull);
248+
});
249+
250+
test('cannot have capital id attributes on headings', () {
251+
final dom = html.parseFragment(exLibrary.documentationAsHtml);
252+
expect(dom.querySelector('h1[id="MY-ID"]'), isNull);
253+
});
254+
240255
test('can have inline HTML', () {
241256
expect(inlineHtml.documentationAsHtml, contains('<small>'));
242257
});

testing/test_package_sanitize_html/lib/test_package_sanitize_html.dart

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,13 @@
1+
/// My library
2+
///
3+
/// See [heading](#heading-with-id).
4+
///
5+
/// <h1 id="my-id">headline with custom id</h1>
6+
///
7+
/// <h1 id="MY-ID">headline with disallowed id</h1>
8+
///
9+
/// # Heading with id
10+
/// * what a topic
111
library ex;
212

313
abstract class SanitizableHtml {

0 commit comments

Comments
 (0)