Upload Kmake

This commit is contained in:
Gorochu
2026-05-26 23:36:42 -07:00
parent ba051b2f74
commit 555ec72358
41615 changed files with 13344630 additions and 1 deletions

View File

@ -0,0 +1,43 @@
import '../common/index.mjs';
import * as fixtures from '../common/fixtures.mjs';
import tmpdir from '../common/tmpdir.js';
import assert from 'assert';
import { execFileSync } from 'child_process';
import fs from 'fs';
import path from 'path';
import { fileURLToPath } from 'url';
const script = fileURLToPath(
new URL('../../tools/doc/apilinks.mjs', import.meta.url));
const apilinks = fixtures.path('apilinks');
tmpdir.refresh();
fs.readdirSync(apilinks).forEach((fixture) => {
if (!fixture.endsWith('.js')) return;
const input = path.join(apilinks, fixture);
const expectedContent = fs.readFileSync(`${input}on`, 'utf8');
const outputPath = tmpdir.resolve(`${fixture}on`);
execFileSync(
process.execPath,
[script, outputPath, input],
{ encoding: 'utf-8' },
);
const expectedLinks = JSON.parse(expectedContent);
const actualLinks = JSON.parse(fs.readFileSync(outputPath));
for (const [k, v] of Object.entries(expectedLinks)) {
assert.ok(k in actualLinks, `link not found: ${k}`);
assert.ok(actualLinks[k].endsWith('/' + v),
`link ${actualLinks[k]} expected to end with ${v}`);
delete actualLinks[k];
}
assert.strictEqual(
Object.keys(actualLinks).length, 0,
`unexpected links returned ${JSON.stringify(actualLinks)}`,
);
});

View File

@ -0,0 +1,28 @@
'use strict';
require('../common');
const path = require('path');
const { spawn } = require('child_process');
const script = path.join(
__dirname,
'..',
'..',
'tools',
'doc',
'deprecationCodes.mjs',
);
const mdPath = path.join(
__dirname,
'..',
'..',
'doc',
'api',
'deprecations.md',
);
const cp = spawn(process.execPath, [script, mdPath], { encoding: 'utf-8', stdio: 'inherit' });
cp.on('error', (err) => { throw err; });
cp.on('exit', (code) => process.exit(code));

View File

@ -0,0 +1,177 @@
import '../common/index.mjs';
import * as fixtures from '../common/fixtures.mjs';
import assert from 'assert';
import { readFileSync } from 'fs';
import * as html from '../../tools/doc/html.mjs';
import { replaceLinks } from '../../tools/doc/markdown.mjs';
import {
rehypeRaw,
rehypeStringify,
remarkParse,
remarkRehype,
unified,
} from '../../tools/doc/deps.mjs';
// Test links mapper is an object of the following structure:
// {
// [filename]: {
// [link definition identifier]: [url to the linked resource]
// }
// }
const testLinksMapper = {
'foo': {
'command line options': 'cli.html#cli-options',
'web server': 'example.html',
},
};
function toHTML({ input, filename, nodeVersion, versions }) {
const content = unified()
.use(replaceLinks, { filename, linksMapper: testLinksMapper })
.use(remarkParse)
.use(html.firstHeader)
.use(html.preprocessText, { nodeVersion })
.use(html.preprocessElements, { filename })
.use(html.buildToc, { filename, apilinks: {} })
.use(remarkRehype, { allowDangerousHtml: true })
.use(rehypeRaw)
.use(rehypeStringify)
.processSync(input);
return html.toHTML({ input, content, filename, nodeVersion, versions });
}
// Test data is a list of objects with two properties.
// The file property is the file path.
// The html property is some HTML which will be generated by the doctool.
// This HTML will be stripped of all whitespace because we don't currently
// have an HTML parser.
const testData = [
{
file: fixtures.path('order_of_end_tags_5873.md'),
html: '<h4>Static method: Buffer.from(array) <span> ' +
'<a class="mark" href="#static-method-bufferfromarray" ' +
'id="static-method-bufferfromarray">#</a> </span> ' +
'<a aria-hidden="true" class="legacy" ' +
'id="foo_static_method_buffer_from_array"></a></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: '<h2>Sample Markdown with YAML info' +
'<span><a class="mark" href="#sample-markdown-with-yaml-info" ' +
' id="sample-markdown-with-yaml-info">#</a></span>' +
'<a aria-hidden="true" class="legacy" ' +
'id="foo_sample_markdown_with_yaml_info"></a></h2>' +
'<section><h3>Foobar<span><a class="mark" href="#foobar" ' +
'id="foobar">#</a></span>' +
'<a aria-hidden="true" class="legacy" id="foo_foobar"></a></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>' +
'<h3>Foobar II<span><a class="mark" href="#foobar-ii" ' +
'id="foobar-ii">#</a></span>' +
'<a aria-hidden="true" class="legacy" id="foo_foobar_ii"></a></h3>' +
'<div class="api_metadata">' +
'<details class="changelog"><summary>History</summary>' +
'<table><tbody><tr><th>Version</th><th>Changes</th></tr>' +
'<tr><td>v4.2.0</td><td><p>The <code>error</code> parameter can now be' +
'an arrow function.</p></td></tr>' +
'<tr><td>v5.3.0, v4.2.0</td>' +
'<td><p><span>Added in: v5.3.0, v4.2.0</span></p></td></tr>' +
'</tbody></table></details></div> ' +
'<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>' +
'<h3>Deprecated thingy<span><a class="mark" ' +
'href="#deprecated-thingy" id="deprecated-thingy">#</a>' +
'</span><a aria-hidden="true" class="legacy"' +
'id="foo_deprecated_thingy"></a>' +
'</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>' +
'<h3>Something<span><a class="mark" href="#something' +
'" id="something">#</a></span>' +
'<a aria-hidden="true" class="legacy" id="foo_something"></a></h3>' +
'<!-- This is not a metadata comment --> ' +
'<p>Describe <code>Something</code> in more detail here. </p></section>',
},
{
file: fixtures.path('sample_document.md'),
html: '<ol><li>fish</li><li>fish</li></ol>' +
'<ul><li>Red fish</li><li>Blue fish</li></ul>',
},
{
file: fixtures.path('altdocs.md'),
html: '<li><a href="https://nodejs.org/docs/latest-v8.x/api/foo.html">8.x',
},
{
file: fixtures.path('document_with_links.md'),
html: '<h2>Usage and Example<span><a class="mark"' +
'href="#usage-and-example" id="usage-and-example">#</a>' +
'</span><a aria-hidden="true" class="legacy" id="foo_usage_and_example">' +
'</a></h2><section><h3>Usage<span><a class="mark" href="#usage"' +
'id="usage">#</a></span><a aria-hidden="true" class="legacy"' +
'id="foo_usage"></a></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><h3>' +
'Example<span><a class="mark" href="#example" id="example">' +
'#</a></span><a aria-hidden="true" class="legacy" id="foo_example">' +
'</a></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>' +
'<h3>See also<span><a class="mark"' +
'href="#see-also" id="see-also">#</a></span><a aria-hidden="true"' +
'class="legacy" id="foo_see_also"></a></h3><p>Check' +
'out also<a href="https://nodejs.org/">this guide</a></p></section>',
},
{
file: fixtures.path('document_with_special_heading.md'),
html: '<title>Sample markdown with special heading |',
},
{
file: fixtures.path('document_with_esm_and_cjs_code_snippet.md'),
html: '<input class="js-flavor-toggle" type="checkbox" checked',
},
{
file: fixtures.path('document_with_cjs_and_esm_code_snippet.md'),
html: '<input class="js-flavor-toggle" type="checkbox" aria-label',
},
];
const spaces = /\s/g;
const versions = [
{ num: '10.x', lts: true },
{ num: '9.x' },
{ num: '8.x' },
{ num: '7.x' },
{ num: '6.x' },
{ num: '5.x' },
{ num: '4.x' },
{ num: '0.12.x' },
{ num: '0.10.x' }];
testData.forEach(({ file, html }) => {
// Normalize expected data by stripping whitespace.
const expected = html.replace(spaces, '');
const input = readFileSync(file, 'utf8');
const output = toHTML({ input,
filename: 'foo',
nodeVersion: process.version,
versions });
const actual = output.replace(spaces, '');
// Assert that the input stripped of all whitespace contains the
// expected markup.
assert(actual.includes(expected),
`ACTUAL: ${actual}\nEXPECTED: ${expected}`);
});

View File

@ -0,0 +1,227 @@
import * as common from '../common/index.mjs';
import * as fixtures from '../common/fixtures.mjs';
import assert from 'assert';
import fs from 'fs';
import * as json from '../../tools/doc/json.mjs';
import {
remarkParse,
unified,
} from '../../tools/doc/deps.mjs';
function toJSON(input, filename, cb) {
function nullCompiler() {
this.Compiler = (tree) => tree;
}
unified()
.use(remarkParse)
.use(json.jsonAPI, { filename })
.use(nullCompiler)
.process(input, cb);
}
// Outputs valid json with the expected fields when given simple markdown
// Test data is a list of objects with two properties.
// The file property is the file path.
// The json property is some json which will be generated by the doctool.
const testData = [
{
file: fixtures.path('sample_document.md'),
json: {
type: 'module',
source: 'foo',
modules: [{
textRaw: 'Sample Markdown',
name: 'sample_markdown',
modules: [{
textRaw: 'Seussian Rhymes',
name: 'seussian_rhymes',
desc: '<ol>\n<li>fish</li>\n<li>fish</li>\n</ol>\n' +
'<ul>\n<li>Red fish</li>\n<li>Blue fish</li>\n</ul>',
type: 'module',
displayName: 'Seussian Rhymes',
}],
type: 'module',
displayName: 'Sample Markdown',
}],
},
},
{
file: fixtures.path('order_of_end_tags_5873.md'),
json: {
type: 'module',
source: 'foo',
modules: [{
textRaw: 'Title',
name: 'title',
modules: [{
textRaw: 'Subsection',
name: 'subsection',
classMethods: [{
textRaw: 'Static method: Buffer.from(array)',
type: 'classMethod',
name: 'from',
signatures: [
{
params: [{
textRaw: '`array` {Array}',
name: 'array',
type: 'Array',
}],
},
],
}],
type: 'module',
displayName: 'Subsection',
}],
type: 'module',
displayName: 'Title',
}],
},
},
{
file: fixtures.path('doc_with_yaml.md'),
json: {
type: 'module',
source: 'foo',
modules: [
{
textRaw: 'Sample Markdown with YAML info',
name: 'sample_markdown_with_yaml_info',
modules: [
{
textRaw: 'Foobar',
name: 'foobar',
meta: {
added: ['v1.0.0'],
changes: [],
},
desc: '<p>Describe <code>Foobar</code> in more detail ' +
'here.</p>',
type: 'module',
displayName: 'Foobar',
},
{
textRaw: 'Foobar II',
name: 'foobar_ii',
meta: {
added: ['v5.3.0', 'v4.2.0'],
changes: [
{ 'version': 'v4.2.0',
'pr-url': 'https://github.com/nodejs/node/pull/3276',
'description': 'The `error` parameter can now be ' +
'an arrow function.' },
],
},
desc: '<p>Describe <code>Foobar II</code> in more detail ' +
'here. fg(1)</p>',
type: 'module',
displayName: 'Foobar II',
},
{
textRaw: 'Deprecated thingy',
name: 'deprecated_thingy',
meta: {
added: ['v1.0.0'],
deprecated: ['v2.0.0'],
changes: [],
},
desc: '<p>Describe <code>Deprecated thingy</code> in more ' +
'detail here. fg(1p)</p>',
type: 'module',
displayName: 'Deprecated thingy',
},
{
textRaw: 'Something',
name: 'something',
desc: '<!-- This is not a metadata comment -->\n<p>' +
'Describe <code>Something</code> in more detail here.</p>',
type: 'module',
displayName: 'Something',
},
],
type: 'module',
displayName: 'Sample Markdown with YAML info',
},
],
},
},
{
file: fixtures.path('doc_with_backticks_in_headings.md'),
json: {
type: 'module',
source: 'foo',
modules: [
{
textRaw: 'Fhqwhgads',
name: 'fhqwhgads',
properties: [
{
name: 'fullName',
textRaw: '`Fqhqwhgads.fullName`',
},
],
classMethods: [
{
name: 'again',
signatures: [
{
params: [],
},
],
textRaw: 'Static method: `Fhqwhgads.again()`',
type: 'classMethod',
},
],
classes: [
{
textRaw: 'Class: `ComeOn`',
type: 'class',
name: 'ComeOn',
},
],
ctors: [
{
name: 'Fhqwhgads',
signatures: [
{
params: [],
},
],
textRaw: 'Constructor: `new Fhqwhgads()`',
type: 'ctor',
},
],
methods: [
{
textRaw: '`everybody.to(limit)`',
type: 'method',
name: 'to',
signatures: [{ params: [] }],
},
],
events: [
{
textRaw: "Event: `'FHQWHfest'`",
type: 'event',
name: 'FHQWHfest',
params: [],
},
],
type: 'module',
displayName: 'Fhqwhgads',
},
],
},
},
];
testData.forEach((item) => {
fs.readFile(item.file, 'utf8', common.mustSucceed((input) => {
toJSON(input, 'foo', common.mustSucceed((output) => {
assert.deepStrictEqual(output.json, item.json);
}));
}));
});

View File

@ -0,0 +1,74 @@
import '../common/index.mjs';
import tmpdir from '../common/tmpdir.js';
import assert from 'assert';
import { spawnSync } from 'child_process';
import fs from 'fs';
import { fileURLToPath } from 'url';
import util from 'util';
const debuglog = util.debuglog('test');
const versionsTool = fileURLToPath(
new URL('../../tools/doc/versions.mjs', import.meta.url));
// At the time of writing these are the minimum expected versions.
// New versions of Node.js do not have to be explicitly added here.
const expected = [
'12.x',
'11.x',
'10.x',
'9.x',
'8.x',
'7.x',
'6.x',
'5.x',
'4.x',
'0.12.x',
'0.10.x',
];
tmpdir.refresh();
const versionsFile = tmpdir.resolve('versions.json');
debuglog(`${process.execPath} ${versionsTool} ${versionsFile}`);
const opts = { cwd: tmpdir.path, encoding: 'utf8' };
const cp = spawnSync(process.execPath, [ versionsTool, versionsFile ], opts);
debuglog(cp.stderr);
debuglog(cp.stdout);
assert.strictEqual(cp.stdout, '');
assert.strictEqual(cp.signal, null);
assert.strictEqual(cp.status, 0);
const versions = JSON.parse(fs.readFileSync(versionsFile));
debuglog(versions);
// Coherence checks for each returned version.
for (const version of versions) {
const tested = util.inspect(version);
const parts = version.num.split('.');
const expectedLength = parts[0] === '0' ? 3 : 2;
assert.strictEqual(parts.length, expectedLength,
`'num' from ${tested} should be '<major>.x'.`);
assert.strictEqual(parts[parts.length - 1], 'x',
`'num' from ${tested} doesn't end in '.x'.`);
const isEvenRelease = Number.parseInt(parts[expectedLength - 2]) % 2 === 0;
const hasLtsProperty = Object.hasOwn(version, 'lts');
if (hasLtsProperty) {
// Odd-numbered versions of Node.js are never LTS.
assert.ok(isEvenRelease, `${tested} should not be an 'lts' release.`);
assert.ok(version.lts, `'lts' from ${tested} should 'true'.`);
}
}
// Check that the minimum number of versions were returned.
// Later versions are allowed, but not checked for here (they were checked
// above).
// Also check for the previous semver major -- From the main branch this will be
// the most recent major release.
const thisMajor = Number.parseInt(process.versions.node.split('.')[0]);
const prevMajorString = `${thisMajor - 1}.x`;
if (!expected.includes(prevMajorString)) {
expected.unshift(prevMajorString);
}
for (const version of expected) {
assert.ok(versions.find((x) => x.num === version),
`Did not find entry for '${version}' in ${util.inspect(versions)}`);
}

View File

@ -0,0 +1,46 @@
import '../common/index.mjs';
import assert from 'assert';
import { referenceToLocalMdFile } from '../../tools/doc/markdown.mjs';
{
const shouldBeSpotted = [
'test.md',
'TEST.MD',
'test.js.md',
'.test.md',
'./test.md',
'subfolder/test.md',
'../test.md',
'test.md#anchor',
'subfolder/test.md#anchor',
'/test.md',
];
shouldBeSpotted.forEach((url) => {
assert.match(url, referenceToLocalMdFile);
});
}
{
const shouldNotBeSpotted = [
'https://example.com/test.md',
'HTTPS://EXAMPLE.COM/TEST.MD',
'git+https://example.com/test.md',
'ftp://1.1.1.1/test.md',
'urn:isbn:9780307476463.md',
'file://./test.md',
'/dev/null',
'test.html',
'test.html#anchor.md',
'test.html?anchor.md',
'test.md5',
'testmd',
'.md',
];
shouldNotBeSpotted.forEach((url) => {
assert.doesNotMatch(url, referenceToLocalMdFile);
});
}

View File

@ -0,0 +1,73 @@
import * as common from '../common/index.mjs';
import assert from 'assert';
import fs from 'fs';
import path from 'path';
if (common.isWindows) {
common.skip('`make doc` does not run on Windows');
}
// This tests that `make doc` generates the documentation properly.
// Note that for this test to pass, `make doc` must be run first.
const apiURL = new URL('../../out/doc/api/', import.meta.url);
const mdURL = new URL('../../doc/api/', import.meta.url);
const allMD = fs.readdirSync(mdURL);
const allDocs = fs.readdirSync(apiURL);
assert.ok(allDocs.includes('index.html'));
const actualDocs = allDocs.filter(
(name) => {
const extension = path.extname(name);
return extension === '.html' || extension === '.json';
},
);
for (const name of actualDocs) {
if (name.startsWith('all.')) continue;
assert.ok(
allMD.includes(name.replace(/\.\w+$/, '.md')),
`Unexpected output: out/doc/api/${name}, remove and rerun.`,
);
}
const toc = fs.readFileSync(new URL('./index.html', apiURL), 'utf8');
const re = /href="([^/]+\.html)"/;
const globalRe = new RegExp(re, 'g');
const links = toc.match(globalRe);
assert.notStrictEqual(links, null);
// Filter out duplicate links, leave just filenames, add expected JSON files.
const linkedHtmls = [...new Set(links)].map((link) => link.match(re)[1])
.concat(['index.html']);
const expectedJsons = linkedHtmls
.map((name) => name.replace('.html', '.json'));
const expectedDocs = linkedHtmls.concat(expectedJsons);
const renamedDocs = ['corepack.json', 'corepack.html', 'policy.json', 'policy.html'];
const skipedDocs = ['quic.json', 'quic.html'];
// Test that all the relative links in the TOC match to the actual documents.
for (const expectedDoc of expectedDocs) {
if (skipedDocs.includes(expectedDoc)) continue;
assert.ok(actualDocs.includes(expectedDoc), `${expectedDoc} does not exist`);
}
// Test that all the actual documents match to the relative links in the TOC
// and that they are not empty files.
for (const actualDoc of actualDocs) {
// When renaming the documentation, the old url is lost
// Unless the old file is still available pointing to the correct location
// 301 redirects are not yet automated. So keeping the old URL is a
// reasonable workaround.
if (renamedDocs.includes(actualDoc)) continue;
assert.ok(
expectedDocs.includes(actualDoc), `${actualDoc} does not match TOC`);
assert.notStrictEqual(
fs.statSync(new URL(`./${actualDoc}`, apiURL)).size,
0,
`${actualDoc} is empty`,
);
}

7
test/doctool/testcfg.py Normal file
View File

@ -0,0 +1,7 @@
import os
import sys
sys.path.append(os.path.join(os.path.dirname(__file__), '..'))
import testpy
def GetConfiguration(context, root):
return testpy.ParallelTestConfiguration(context, root, 'doctool')