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