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"><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