Skip to content

Commit 3925458

Browse files
Trottruyadorno
authored andcommitted
doc,tools: use only one level 1 header per page
Increment the header levels from markdown files when producing HTML documents. This is both better semantically (as the two h1 headers in current docs are not actually equivalent level semantically--the second belongs below/inside the first) and better for accessibility. (It is valid HTML to have multiple h1 headers in a document, but it can be bad for screen reader experience.) PR-URL: #37839 Reviewed-By: Benjamin Gruenbaum <[email protected]> Reviewed-By: James M Snell <[email protected]> Reviewed-By: Pooja D P <[email protected]> Reviewed-By: Antoine du Hamel <[email protected]>
1 parent e84252b commit 3925458

File tree

2 files changed

+32
-23
lines changed

2 files changed

+32
-23
lines changed

test/doctool/test-doctool-html.js

+19-19
Original file line numberDiff line numberDiff line change
@@ -60,25 +60,25 @@ function toHTML({ input, filename, nodeVersion, versions }) {
6060
const testData = [
6161
{
6262
file: fixtures.path('order_of_end_tags_5873.md'),
63-
html: '<h3>Static method: Buffer.from(array) <span> ' +
63+
html: '<h4>Static method: Buffer.from(array) <span> ' +
6464
'<a class="mark" href="#foo_static_method_buffer_from_array" ' +
65-
'id="foo_static_method_buffer_from_array">#</a> </span> </h3>' +
65+
'id="foo_static_method_buffer_from_array">#</a> </span> </h4>' +
6666
'<ul><li><code>array</code><a ' +
6767
'href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/' +
6868
'Reference/Global_Objects/Array" class="type">&#x3C;Array></a></li></ul>'
6969
},
7070
{
7171
file: fixtures.path('doc_with_yaml.md'),
72-
html: '<h1>Sample Markdown with YAML info' +
72+
html: '<h2>Sample Markdown with YAML info' +
7373
'<span><a class="mark" href="#foo_sample_markdown_with_yaml_info" ' +
74-
' id="foo_sample_markdown_with_yaml_info">#</a></span></h1>' +
75-
'<section><h2>Foobar<span><a class="mark" href="#foo_foobar" ' +
76-
'id="foo_foobar">#</a></span></h2>' +
74+
' id="foo_sample_markdown_with_yaml_info">#</a></span></h2>' +
75+
'<section><h3>Foobar<span><a class="mark" href="#foo_foobar" ' +
76+
'id="foo_foobar">#</a></span></h3>' +
7777
'<div class="api_metadata"><span>Added in: v1.0.0</span></div> ' +
7878
'<p>Describe <code>Foobar</code> in more detail here.</p>' +
7979
'</section><section>' +
80-
'<h2>Foobar II<span><a class="mark" href="#foo_foobar_ii" ' +
81-
'id="foo_foobar_ii">#</a></span></h2><div class="api_metadata">' +
80+
'<h3>Foobar II<span><a class="mark" href="#foo_foobar_ii" ' +
81+
'id="foo_foobar_ii">#</a></span></h3><div class="api_metadata">' +
8282
'<details class="changelog"><summary>History</summary>' +
8383
'<table><tbody><tr><th>Version</th><th>Changes</th></tr>' +
8484
'<tr><td>v5.3.0, v4.2.0</td>' +
@@ -88,15 +88,15 @@ const testData = [
8888
'<p>Describe <code>Foobar II</code> in more detail here.' +
8989
'<a href="http://man7.org/linux/man-pages/man1/fg.1.html"><code>fg(1)' +
9090
'</code></a></p></section><section>' +
91-
'<h2>Deprecated thingy<span><a class="mark" ' +
91+
'<h3>Deprecated thingy<span><a class="mark" ' +
9292
'href="#foo_deprecated_thingy" id="foo_deprecated_thingy">#</a>' +
93-
'</span></h2><div class="api_metadata"><span>Added in: v1.0.0</span>' +
93+
'</span></h3><div class="api_metadata"><span>Added in: v1.0.0</span>' +
9494
'<span>Deprecated since: v2.0.0</span></div><p>Describe ' +
9595
'<code>Deprecated thingy</code> in more detail here.' +
9696
'<a href="http://man7.org/linux/man-pages/man1/fg.1p.html"><code>fg(1p)' +
9797
'</code></a></p></section><section>' +
98-
'<h2>Something<span><a class="mark" href="#foo_something' +
99-
'" id="foo_something">#</a></span></h2> ' +
98+
'<h3>Something<span><a class="mark" href="#foo_something' +
99+
'" id="foo_something">#</a></span></h3> ' +
100100
'<!-- This is not a metadata comment --> ' +
101101
'<p>Describe <code>Something</code> in more detail here. </p></section>'
102102
},
@@ -111,19 +111,19 @@ const testData = [
111111
},
112112
{
113113
file: fixtures.path('document_with_links.md'),
114-
html: '<h1>Usage and Example<span><a class="mark"' +
114+
html: '<h2>Usage and Example<span><a class="mark"' +
115115
'href="#foo_usage_and_example" id="foo_usage_and_example">#</a>' +
116-
'</span></h1><section><h2>Usage<span><a class="mark" href="#foo_usage"' +
117-
'id="foo_usage">#</a></span></h2><p><code>node \\[options\\] index.js' +
116+
'</span></h2><section><h3>Usage<span><a class="mark" href="#foo_usage"' +
117+
'id="foo_usage">#</a></span></h3><p><code>node \\[options\\] index.js' +
118118
'</code></p><p>Please see the<a href="cli.html#cli-options">' +
119119
'Command Line Options</a>document for more information.</p>' +
120-
'</section><section><h2>' +
120+
'</section><section><h3>' +
121121
'Example<span><a class="mark" href="#foo_example" id="foo_example">' +
122-
'#</a></span></h2><p>An example of a<a href="example.html">' +
122+
'#</a></span></h3><p>An example of a<a href="example.html">' +
123123
'webserver</a>written with Node.js which responds with<code>' +
124124
'\'Hello, World!\'</code>:</p></section><section>' +
125-
'<h2>See also<span><a class="mark"' +
126-
'href="#foo_see_also" id="foo_see_also">#</a></span></h2><p>Check' +
125+
'<h3>See also<span><a class="mark"' +
126+
'href="#foo_see_also" id="foo_see_also">#</a></span></h3><p>Check' +
127127
'out also<a href="https://nodejs.org/">this guide</a></p></section>'
128128
},
129129
{

tools/doc/html.js

+13-4
Original file line numberDiff line numberDiff line change
@@ -66,10 +66,19 @@ const gtocHTML = unified()
6666
const templatePath = path.join(docPath, 'template.html');
6767
const template = fs.readFileSync(templatePath, 'utf8');
6868

69-
function wrapSections(content) {
69+
function processContent(content) {
70+
content = content.toString();
71+
// Increment header tag levels to avoid multiple h1 tags in a doc.
72+
// This means we can't already have an <h6>.
73+
if (content.includes('<h6>')) {
74+
throw new Error('Cannot increment a level 6 header');
75+
}
76+
// `++level` to convert the string to a number and increment it.
77+
content = content.replace(/(?<=<\/?h)[1-5](?=[^<>]*>)/g, (level) => ++level);
78+
// Wrap h3 tags in section tags.
7079
let firstTime = true;
71-
return content.toString()
72-
.replace(/<h2/g, (heading) => {
80+
return content
81+
.replace(/<h3/g, (heading) => {
7382
if (firstTime) {
7483
firstTime = false;
7584
return '<section>' + heading;
@@ -91,7 +100,7 @@ function toHTML({ input, content, filename, nodeVersion, versions }) {
91100
.replace('__GTOC__', gtocHTML.replace(
92101
`class="nav-${id}"`, `class="nav-${id} active"`))
93102
.replace('__EDIT_ON_GITHUB__', editOnGitHub(filename))
94-
.replace('__CONTENT__', wrapSections(content));
103+
.replace('__CONTENT__', processContent(content));
95104

96105
const docCreated = input.match(
97106
/<!--\s*introduced_in\s*=\s*v([0-9]+)\.([0-9]+)\.[0-9]+\s*-->/);

0 commit comments

Comments
 (0)