• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1import '../common/index.mjs';
2import * as fixtures from '../common/fixtures.mjs';
3
4import assert from 'assert';
5import { readFileSync } from 'fs';
6import { createRequire } from 'module';
7
8import * as html from '../../tools/doc/html.mjs';
9import { replaceLinks } from '../../tools/doc/markdown.mjs';
10
11const require = createRequire(new URL('../../tools/doc/', import.meta.url));
12const unified = require('unified');
13const markdown = require('remark-parse');
14const remark2rehype = require('remark-rehype');
15const raw = require('rehype-raw');
16const htmlStringify = require('rehype-stringify');
17
18// Test links mapper is an object of the following structure:
19// {
20//   [filename]: {
21//     [link definition identifier]: [url to the linked resource]
22//   }
23// }
24const testLinksMapper = {
25  'foo': {
26    'command line options': 'cli.html#cli-options',
27    'web server': 'example.html'
28  }
29};
30
31function toHTML({ input, filename, nodeVersion, versions }) {
32  const content = unified()
33    .use(replaceLinks, { filename, linksMapper: testLinksMapper })
34    .use(markdown)
35    .use(html.firstHeader)
36    .use(html.preprocessText, { nodeVersion })
37    .use(html.preprocessElements, { filename })
38    .use(html.buildToc, { filename, apilinks: {} })
39    .use(remark2rehype, { allowDangerousHtml: true })
40    .use(raw)
41    .use(htmlStringify)
42    .processSync(input);
43
44  return html.toHTML({ input, content, filename, nodeVersion, versions });
45}
46
47// Test data is a list of objects with two properties.
48// The file property is the file path.
49// The html property is some HTML which will be generated by the doctool.
50// This HTML will be stripped of all whitespace because we don't currently
51// have an HTML parser.
52const testData = [
53  {
54    file: fixtures.path('order_of_end_tags_5873.md'),
55    html: '<h4>Static method: Buffer.from(array) <span> ' +
56      '<a class="mark" href="#foo_static_method_buffer_from_array" ' +
57      'id="foo_static_method_buffer_from_array">#</a> </span> </h4>' +
58      '<ul><li><code>array</code><a ' +
59      'href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/' +
60      'Reference/Global_Objects/Array" class="type">&#x3C;Array></a></li></ul>'
61  },
62  {
63    file: fixtures.path('doc_with_yaml.md'),
64    html: '<h2>Sample Markdown with YAML info' +
65      '<span><a class="mark" href="#foo_sample_markdown_with_yaml_info" ' +
66      ' id="foo_sample_markdown_with_yaml_info">#</a></span></h2>' +
67      '<section><h3>Foobar<span><a class="mark" href="#foo_foobar" ' +
68      'id="foo_foobar">#</a></span></h3>' +
69      '<div class="api_metadata"><span>Added in: v1.0.0</span></div> ' +
70      '<p>Describe <code>Foobar</code> in more detail here.</p>' +
71      '</section><section>' +
72      '<h3>Foobar II<span><a class="mark" href="#foo_foobar_ii" ' +
73      'id="foo_foobar_ii">#</a></span></h3><div class="api_metadata">' +
74      '<details class="changelog"><summary>History</summary>' +
75      '<table><tbody><tr><th>Version</th><th>Changes</th></tr>' +
76      '<tr><td>v5.3.0, v4.2.0</td>' +
77      '<td><p><span>Added in: v5.3.0, v4.2.0</span></p></td></tr>' +
78      '<tr><td>v4.2.0</td><td><p>The <code>error</code> parameter can now be' +
79      'an arrow function.</p></td></tr></tbody></table></details></div> ' +
80      '<p>Describe <code>Foobar II</code> in more detail here.' +
81      '<a href="http://man7.org/linux/man-pages/man1/fg.1.html"><code>fg(1)' +
82      '</code></a></p></section><section>' +
83      '<h3>Deprecated thingy<span><a class="mark" ' +
84      'href="#foo_deprecated_thingy" id="foo_deprecated_thingy">#</a>' +
85      '</span></h3><div class="api_metadata"><span>Added in: v1.0.0</span>' +
86      '<span>Deprecated since: v2.0.0</span></div><p>Describe ' +
87      '<code>Deprecated thingy</code> in more detail here.' +
88      '<a href="http://man7.org/linux/man-pages/man1/fg.1p.html"><code>fg(1p)' +
89      '</code></a></p></section><section>' +
90      '<h3>Something<span><a class="mark" href="#foo_something' +
91      '" id="foo_something">#</a></span></h3> ' +
92      '<!-- This is not a metadata comment --> ' +
93      '<p>Describe <code>Something</code> in more detail here. </p></section>'
94  },
95  {
96    file: fixtures.path('sample_document.md'),
97    html: '<ol><li>fish</li><li>fish</li></ol>' +
98      '<ul><li>Red fish</li><li>Blue fish</li></ul>',
99  },
100  {
101    file: fixtures.path('altdocs.md'),
102    html: '<li><a href="https://nodejs.org/docs/latest-v8.x/api/foo.html">8.x',
103  },
104  {
105    file: fixtures.path('document_with_links.md'),
106    html: '<h2>Usage and Example<span><a class="mark"' +
107    'href="#foo_usage_and_example" id="foo_usage_and_example">#</a>' +
108    '</span></h2><section><h3>Usage<span><a class="mark" href="#foo_usage"' +
109    'id="foo_usage">#</a></span></h3><p><code>node \\[options\\] index.js' +
110    '</code></p><p>Please see the<a href="cli.html#cli-options">' +
111    'Command Line Options</a>document for more information.</p>' +
112    '</section><section><h3>' +
113    'Example<span><a class="mark" href="#foo_example" id="foo_example">' +
114    '#</a></span></h3><p>An example of a<a href="example.html">' +
115    'webserver</a>written with Node.js which responds with<code>' +
116    '\'Hello, World!\'</code>:</p></section><section>' +
117    '<h3>See also<span><a class="mark"' +
118    'href="#foo_see_also" id="foo_see_also">#</a></span></h3><p>Check' +
119    'out also<a href="https://nodejs.org/">this guide</a></p></section>'
120  },
121  {
122    file: fixtures.path('document_with_special_heading.md'),
123    html: '<title>Sample markdown with special heading |',
124  },
125  {
126    file: fixtures.path('document_with_esm_and_cjs_code_snippet.md'),
127    html: '<input class="js-flavor-selector" type="checkbox" checked',
128  },
129  {
130    file: fixtures.path('document_with_cjs_and_esm_code_snippet.md'),
131    html: '<input class="js-flavor-selector" type="checkbox" aria-label',
132  },
133];
134
135const spaces = /\s/g;
136const versions = [
137  { num: '10.x', lts: true },
138  { num: '9.x' },
139  { num: '8.x' },
140  { num: '7.x' },
141  { num: '6.x' },
142  { num: '5.x' },
143  { num: '4.x' },
144  { num: '0.12.x' },
145  { num: '0.10.x' }];
146
147testData.forEach(({ file, html }) => {
148  // Normalize expected data by stripping whitespace.
149  const expected = html.replace(spaces, '');
150
151  const input = readFileSync(file, 'utf8');
152
153  const output = toHTML({ input,
154                          filename: 'foo',
155                          nodeVersion: process.version,
156                          versions });
157
158  const actual = output.replace(spaces, '');
159  // Assert that the input stripped of all whitespace contains the
160  // expected markup.
161  assert(actual.includes(expected),
162         `ACTUAL: ${actual}\nEXPECTED: ${expected}`);
163});
164