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