Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

doc,tools: use only one level 1 header per page #37839

Merged
merged 2 commits into from Mar 25, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
42 changes: 20 additions & 22 deletions doc/api/async_hooks.md
Expand Up @@ -25,9 +25,7 @@ as the abstract concept that is a resource.
If [`Worker`][]s are used, each thread has an independent `async_hooks`
interface, and each thread will use a new set of async IDs.

## Public API

### Overview
## Overview

Following is a simple overview of the public API.

Expand Down Expand Up @@ -79,7 +77,7 @@ function destroy(asyncId) { }
function promiseResolve(asyncId) { }
```

#### `async_hooks.createHook(callbacks)`
## `async_hooks.createHook(callbacks)`

<!-- YAML
added: v8.1.0
Expand Down Expand Up @@ -133,7 +131,7 @@ Because promises are asynchronous resources whose lifecycle is tracked
via the async hooks mechanism, the `init()`, `before()`, `after()`, and
`destroy()` callbacks *must not* be async functions that return promises.

##### Error handling
### Error handling

If any `AsyncHook` callbacks throw, the application will print the stack trace
and exit. The exit path does follow that of an uncaught exception, but
Expand All @@ -150,7 +148,7 @@ future. This is subject to change in the future if a comprehensive analysis is
performed to ensure an exception can follow the normal control flow without
unintentional side effects.

##### Printing in AsyncHooks callbacks
### Printing in AsyncHooks callbacks

Because printing to the console is an asynchronous operation, `console.log()`
will cause the AsyncHooks callbacks to be called. Using `console.log()` or
Expand All @@ -176,12 +174,12 @@ provided by AsyncHooks itself. The logging should then be skipped when
it was the logging itself that caused AsyncHooks callback to call. By
doing this the otherwise infinite recursion is broken.

### Class: `AsyncHook`
## Class: `AsyncHook`

The class `AsyncHook` exposes an interface for tracking lifetime events
of asynchronous operations.

#### `asyncHook.enable()`
### `asyncHook.enable()`

* Returns: {AsyncHook} A reference to `asyncHook`.

Expand All @@ -197,7 +195,7 @@ const async_hooks = require('async_hooks');
const hook = async_hooks.createHook(callbacks).enable();
```

#### `asyncHook.disable()`
### `asyncHook.disable()`

* Returns: {AsyncHook} A reference to `asyncHook`.

Expand All @@ -207,13 +205,13 @@ be called again until enabled.

For API consistency `disable()` also returns the `AsyncHook` instance.

#### Hook callbacks
### Hook callbacks

Key events in the lifetime of asynchronous events have been categorized into
four areas: instantiation, before/after the callback is called, and when the
instance is destroyed.

##### `init(asyncId, type, triggerAsyncId, resource)`
#### `init(asyncId, type, triggerAsyncId, resource)`

* `asyncId` {number} A unique ID for the async resource.
* `type` {string} The type of the async resource.
Expand All @@ -240,7 +238,7 @@ clearTimeout(setTimeout(() => {}, 10));
Every new resource is assigned an ID that is unique within the scope of the
current Node.js instance.

###### `type`
##### `type`

The `type` is a string identifying the type of resource that caused
`init` to be called. Generally, it will correspond to the name of the
Expand All @@ -263,7 +261,7 @@ It is possible to have type name collisions. Embedders are encouraged to use
unique prefixes, such as the npm package name, to prevent collisions when
listening to the hooks.

###### `triggerAsyncId`
##### `triggerAsyncId`

`triggerAsyncId` is the `asyncId` of the resource that caused (or "triggered")
the new resource to initialize and that caused `init` to call. This is different
Expand Down Expand Up @@ -302,7 +300,7 @@ that information, it would be impossible to link resources together in
terms of what caused them to be created, so `triggerAsyncId` is given the task
of propagating what resource is responsible for the new resource's existence.

###### `resource`
##### `resource`

`resource` is an object that represents the actual async resource that has
been initialized. This can contain useful information that can vary based on
Expand All @@ -316,7 +314,7 @@ could contain the SQL query being executed.
In some cases the resource object is reused for performance reasons, it is
thus not safe to use it as a key in a `WeakMap` or add properties to it.

###### Asynchronous context example
##### Asynchronous context example

The following is an example with additional information about the calls to
`init` between the `before` and `after` calls, specifically what the
Expand Down Expand Up @@ -415,7 +413,7 @@ TCPSERVERWRAP(5)
Timeout(7)
```

##### `before(asyncId)`
#### `before(asyncId)`

* `asyncId` {number}

Expand All @@ -432,7 +430,7 @@ asynchronous resources like a TCP server will typically call the `before`
callback multiple times, while other operations like `fs.open()` will call
it only once.

##### `after(asyncId)`
#### `after(asyncId)`

* `asyncId` {number}

Expand All @@ -442,7 +440,7 @@ If an uncaught exception occurs during execution of the callback, then `after`
will run *after* the `'uncaughtException'` event is emitted or a `domain`'s
handler runs.

##### `destroy(asyncId)`
#### `destroy(asyncId)`

* `asyncId` {number}

Expand All @@ -454,7 +452,7 @@ made to the `resource` object passed to `init` it is possible that `destroy`
will never be called, causing a memory leak in the application. If the resource
does not depend on garbage collection, then this will not be an issue.

##### `promiseResolve(asyncId)`
#### `promiseResolve(asyncId)`

<!-- YAML
added: v8.6.0
Expand Down Expand Up @@ -485,7 +483,7 @@ init for PROMISE with id 6, trigger id: 5 # the Promise returned by then()
after 6
```

#### `async_hooks.executionAsyncResource()`
### `async_hooks.executionAsyncResource()`

<!-- YAML
added:
Expand Down Expand Up @@ -543,7 +541,7 @@ const server = createServer((req, res) => {
}).listen(3000);
```

#### `async_hooks.executionAsyncId()`
### `async_hooks.executionAsyncId()`

<!-- YAML
added: v8.1.0
Expand Down Expand Up @@ -584,7 +582,7 @@ const server = net.createServer((conn) => {
Promise contexts may not get precise `executionAsyncIds` by default.
See the section on [promise execution tracking][].

#### `async_hooks.triggerAsyncId()`
### `async_hooks.triggerAsyncId()`

* Returns: {number} The ID of the resource responsible for calling the callback
that is currently being executed.
Expand Down
38 changes: 19 additions & 19 deletions test/doctool/test-doctool-html.js
Expand Up @@ -60,25 +60,25 @@ function toHTML({ input, filename, nodeVersion, versions }) {
const testData = [
{
file: fixtures.path('order_of_end_tags_5873.md'),
html: '<h3>Static method: Buffer.from(array) <span> ' +
html: '<h4>Static method: Buffer.from(array) <span> ' +
'<a class="mark" href="#foo_static_method_buffer_from_array" ' +
'id="foo_static_method_buffer_from_array">#</a> </span> </h3>' +
'id="foo_static_method_buffer_from_array">#</a> </span> </h4>' +
'<ul><li><code>array</code><a ' +
'href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/' +
'Reference/Global_Objects/Array" class="type">&#x3C;Array></a></li></ul>'
},
{
file: fixtures.path('doc_with_yaml.md'),
html: '<h1>Sample Markdown with YAML info' +
html: '<h2>Sample Markdown with YAML info' +
'<span><a class="mark" href="#foo_sample_markdown_with_yaml_info" ' +
' id="foo_sample_markdown_with_yaml_info">#</a></span></h1>' +
'<section><h2>Foobar<span><a class="mark" href="#foo_foobar" ' +
'id="foo_foobar">#</a></span></h2>' +
' id="foo_sample_markdown_with_yaml_info">#</a></span></h2>' +
'<section><h3>Foobar<span><a class="mark" href="#foo_foobar" ' +
'id="foo_foobar">#</a></span></h3>' +
'<div class="api_metadata"><span>Added in: v1.0.0</span></div> ' +
'<p>Describe <code>Foobar</code> in more detail here.</p>' +
'</section><section>' +
'<h2>Foobar II<span><a class="mark" href="#foo_foobar_ii" ' +
'id="foo_foobar_ii">#</a></span></h2><div class="api_metadata">' +
'<h3>Foobar II<span><a class="mark" href="#foo_foobar_ii" ' +
'id="foo_foobar_ii">#</a></span></h3><div class="api_metadata">' +
'<details class="changelog"><summary>History</summary>' +
'<table><tbody><tr><th>Version</th><th>Changes</th></tr>' +
'<tr><td>v5.3.0, v4.2.0</td>' +
Expand All @@ -88,15 +88,15 @@ const testData = [
'<p>Describe <code>Foobar II</code> in more detail here.' +
'<a href="http://man7.org/linux/man-pages/man1/fg.1.html"><code>fg(1)' +
'</code></a></p></section><section>' +
'<h2>Deprecated thingy<span><a class="mark" ' +
'<h3>Deprecated thingy<span><a class="mark" ' +
'href="#foo_deprecated_thingy" id="foo_deprecated_thingy">#</a>' +
'</span></h2><div class="api_metadata"><span>Added in: v1.0.0</span>' +
'</span></h3><div class="api_metadata"><span>Added in: v1.0.0</span>' +
'<span>Deprecated since: v2.0.0</span></div><p>Describe ' +
'<code>Deprecated thingy</code> in more detail here.' +
'<a href="http://man7.org/linux/man-pages/man1/fg.1p.html"><code>fg(1p)' +
'</code></a></p></section><section>' +
'<h2>Something<span><a class="mark" href="#foo_something' +
'" id="foo_something">#</a></span></h2> ' +
'<h3>Something<span><a class="mark" href="#foo_something' +
'" id="foo_something">#</a></span></h3> ' +
'<!-- This is not a metadata comment --> ' +
'<p>Describe <code>Something</code> in more detail here. </p></section>'
},
Expand All @@ -111,19 +111,19 @@ const testData = [
},
{
file: fixtures.path('document_with_links.md'),
html: '<h1>Usage and Example<span><a class="mark"' +
html: '<h2>Usage and Example<span><a class="mark"' +
'href="#foo_usage_and_example" id="foo_usage_and_example">#</a>' +
'</span></h1><section><h2>Usage<span><a class="mark" href="#foo_usage"' +
'id="foo_usage">#</a></span></h2><p><code>node \\[options\\] index.js' +
'</span></h2><section><h3>Usage<span><a class="mark" href="#foo_usage"' +
'id="foo_usage">#</a></span></h3><p><code>node \\[options\\] index.js' +
'</code></p><p>Please see the<a href="cli.html#cli-options">' +
'Command Line Options</a>document for more information.</p>' +
'</section><section><h2>' +
'</section><section><h3>' +
'Example<span><a class="mark" href="#foo_example" id="foo_example">' +
'#</a></span></h2><p>An example of a<a href="example.html">' +
'#</a></span></h3><p>An example of a<a href="example.html">' +
'webserver</a>written with Node.js which responds with<code>' +
'\'Hello, World!\'</code>:</p></section><section>' +
'<h2>See also<span><a class="mark"' +
'href="#foo_see_also" id="foo_see_also">#</a></span></h2><p>Check' +
'<h3>See also<span><a class="mark"' +
'href="#foo_see_also" id="foo_see_also">#</a></span></h3><p>Check' +
'out also<a href="https://nodejs.org/">this guide</a></p></section>'
},
{
Expand Down
17 changes: 13 additions & 4 deletions tools/doc/html.js
Expand Up @@ -66,10 +66,19 @@ const gtocHTML = unified()
const templatePath = path.join(docPath, 'template.html');
const template = fs.readFileSync(templatePath, 'utf8');

function wrapSections(content) {
function processContent(content) {
content = content.toString();
// Increment header tag levels to avoid multiple h1 tags in a doc.
// This means we can't already have an <h6>.
if (content.includes('<h6>')) {
throw new Error('Cannot increment a level 6 header');
}
Trott marked this conversation as resolved.
Show resolved Hide resolved
// `++level` to convert the string to a number and increment it.
content = content.replace(/(?<=<\/?h)[1-5](?=[^<>]*>)/g, (level) => ++level);
// Wrap h3 tags in section tags.
let firstTime = true;
return content.toString()
.replace(/<h2/g, (heading) => {
return content
.replace(/<h3/g, (heading) => {
if (firstTime) {
firstTime = false;
return '<section>' + heading;
Expand All @@ -91,7 +100,7 @@ function toHTML({ input, content, filename, nodeVersion, versions }) {
.replace('__GTOC__', gtocHTML.replace(
`class="nav-${id}"`, `class="nav-${id} active"`))
.replace('__EDIT_ON_GITHUB__', editOnGitHub(filename))
.replace('__CONTENT__', wrapSections(content));
.replace('__CONTENT__', processContent(content));

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