Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .github/dependabot.yml
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,8 @@ updates:
semver-minor-days: 5
semver-patch-days: 5
exclude:
- '@node-core/doc-kit'
- '@doc-kit/*'
- '@node-core/*'
commit-message:
prefix: tools
open-pull-requests-limit: 10
Expand Down
5 changes: 5 additions & 0 deletions .github/workflows/build-tarball.yml
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ env:
PYTHON_VERSION: '3.15'
FLAKY_TESTS: keep_retrying
CLANG_VERSION: '19'
NODE_VERSION: lts/*

permissions:
contents: read
Expand All @@ -84,6 +85,10 @@ jobs:
with:
python-version: ${{ env.PYTHON_VERSION }}
allow-prereleases: true
- name: Use Node.js ${{ env.NODE_VERSION }}
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version: ${{ env.NODE_VERSION }}
- name: Make tarball
run: |
export DISTTYPE=nightly
Expand Down
42 changes: 23 additions & 19 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -402,7 +402,12 @@ ifeq ($(OSTYPE),os400)
DOCBUILDSTAMP_PREREQS := $(DOCBUILDSTAMP_PREREQS) out/$(BUILDTYPE)/node.exp
endif

DOC_KIT ?= tools/doc/node_modules/@node-core/doc-kit/bin/cli.mjs
DOC_KIT ?= tools/doc/node_modules/@doc-kit/cli/bin/cli.mjs
ifeq ($(V),1)
DOC_KIT_LOG_LEVEL ?= debug
else
DOC_KIT_LOG_LEVEL ?= info
endif

node_use_openssl_and_icu = $(call available-node,"-p" \
"process.versions.openssl != undefined && process.versions.icu != undefined")
Expand Down Expand Up @@ -886,8 +891,10 @@ out/doc/api: doc/api
mkdir -p $@
cp -r doc/api out/doc

# Generate all doc files (individual and all.html/all.json) in a single doc-kit call
# Using grouped targets (&:) so Make knows one command produces all outputs
# Generate all doc files (individual and all.html/all.json) in a single doc-kit call.
# A stamp tells Make that one command produces them all; a grouped target (&:)
# needs GNU Make 4.3, and older ones (4.2.1 on RHEL 8) rerun the whole build for
# every output that's still missing.
ifeq ($(OSTYPE),aix)
# TODO(@nodejs/web-infra): AIX is currently hanging during HTML minification
$(apidocs_html) $(apidocs_json) out/doc/api/all.html out/doc/api/all.json:
Expand All @@ -902,23 +909,22 @@ else ifeq ($(ARCHTYPE),riscv64)
$(apidocs_html) $(apidocs_json) out/doc/api/all.html out/doc/api/all.json:
@echo "Skipping $@ (not currently supported by $(DESTCPU) machines)"
else
$(apidocs_html) $(apidocs_json) out/doc/api/all.html out/doc/api/all.json &: $(apidoc_sources) tools/doc/node_modules | out/doc/api
out/doc/.docbuildstamp: $(apidoc_sources) tools/doc/node_modules | out/doc/api
@if [ "$(shell $(node_use_openssl_and_icu))" != "true" ]; then \
echo "Skipping $@ (no crypto and/or no ICU)"; \
else \
$(call available-node, \
$(DOC_KIT) generate \
-t legacy-html-all \
-t legacy-json-all \
-i doc/api/*.md \
--ignore $(skip_apidoc_files) \
--log-level $(DOC_KIT_LOG_LEVEL) \
--config-file tools/doc/web.doc-kit.config.mjs \
-o out/doc/api \
-c ./CHANGELOG.md \
-v $(VERSION) \
--index doc/api/index.md \
--type-map doc/type-map.json \
$(if $(JOBS),-p $(JOBS)) \
) \
fi
@touch $@

$(apidocs_html) $(apidocs_json) out/doc/api/all.html out/doc/api/all.json: out/doc/.docbuildstamp
endif

out/doc/llms.txt: $(apidoc_sources) tools/doc/node_modules | out/doc
Expand All @@ -927,13 +933,11 @@ out/doc/llms.txt: $(apidoc_sources) tools/doc/node_modules | out/doc
else \
$(call available-node, \
$(DOC_KIT) generate \
--log-level $(DOC_KIT_LOG_LEVEL) \
--config-file tools/doc/web.doc-kit.config.mjs \
-t llms-txt \
-i doc/api/*.md \
--ignore $(skip_apidoc_files) \
-o $(@D) \
-c ./CHANGELOG.md \
-v $(VERSION) \
--type-map doc/type-map.json \
) \
fi

Expand All @@ -943,12 +947,10 @@ out/doc/apilinks.json: $(wildcard lib/*.js) tools/doc/node_modules | out/doc
else \
$(call available-node, \
$(DOC_KIT) generate \
-t api-links \
-i lib/*.js \
--log-level $(DOC_KIT_LOG_LEVEL) \
--config-file tools/doc/api-links.doc-kit.config.mjs \
-o $(@D) \
-c ./CHANGELOG.md \
-v $(VERSION) \
--type-map doc/type-map.json \
) \
fi

Expand All @@ -962,6 +964,7 @@ node.1: doc/api/cli.md tools/doc/node_modules
else \
$(call available-node, \
$(DOC_KIT) generate \
--log-level $(DOC_KIT_LOG_LEVEL) \
-v $(VERSION) \
--config-file tools/doc/man-page.doc-kit.config.mjs \
-o doc \
Expand Down Expand Up @@ -1505,6 +1508,7 @@ tools/.manpagelintstamp: doc/node.1 doc/api/cli.md tools/doc/node_modules
$(RM) -r tools/doc/.manpagecheck && \
$(call available-node, \
$(DOC_KIT) generate \
--log-level $(DOC_KIT_LOG_LEVEL) \
-v $(VERSION) \
--config-file tools/doc/man-page.doc-kit.config.mjs \
) \
Expand Down
14 changes: 7 additions & 7 deletions doc/node.1
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
.\"
.\" This file was generated automatically by the @node-core/doc-kit tool.
.\" This file was generated automatically by Node.js's doc-kit tool.
.\" Please do not edit this file manually. Make any updates to cli.md
.\" and regenerate the file afterward.
.\"
.\" To regenerate this file, run `make doc/node.1`.
.\" To regenerate this file, run `make node.1`.
.\"
.\"======================================================================
.Dd $Mdocdate$
Expand Down Expand Up @@ -274,7 +274,7 @@ Error: connect ERR_ACCESS_DENIED Access to this API has been restricted. Use --a
.It Fl -allow-openssl-store
When using the Permission Model, the process will not be able to use
OpenSSL STORE loaders by default, for example to load a private key from a
\fB<URL>\fR passed to \fBcrypto.createPrivateKey()\fR. Attempts to do so will throw
\fB{URL}\fR passed to \fBcrypto.createPrivateKey()\fR. Attempts to do so will throw
an \fBERR_ACCESS_DENIED\fR unless the user explicitly passes the
\fB--allow-openssl-store\fR flag. This permission can be dropped at runtime via
\fBpermission.drop()\fR.
Expand Down Expand Up @@ -452,11 +452,11 @@ creation behavior.
The following options are currently supported:
.Bl -bullet
.It
\fBbuilder\fR \fB<string>\fR Required. Provides the name to the script that is executed
before building the snapshot, as if \fB--build-snapshot\fR had been passed
\fBbuilder\fR \fB{string}\fR Required. Provides the name to the script that is executed
before building the snapshot, as if \fB--build-snapshot\fR had been passed
with \fBbuilder\fR as the main script name.
.It
\fBwithoutCodeCache\fR \fB<boolean>\fR Optional. Including the code cache reduces the
\fBwithoutCodeCache\fR \fB{boolean}\fR Optional. Including the code cache reduces the
time spent on compiling functions included in the snapshot at the expense
of a bigger snapshot size and potentially breaking portability of the
snapshot.
Expand Down Expand Up @@ -1993,7 +1993,7 @@ Print node's version.
.It Fl -vfs-load Ns = Ns Ar source
.Bl -bullet
.It
\fBsource\fR \fB<string>\fR A directory or an archive file to mount and run.
\fBsource\fR \fB{string}\fR A directory or an archive file to mount and run.
.El
May be given at most once.
Mounts \fBsource\fR as a virtual file system (\fBnode:vfs\fR), and runs the entry
Expand Down
106 changes: 52 additions & 54 deletions test/doctool/test-make-doc.mjs
Original file line number Diff line number Diff line change
@@ -1,74 +1,72 @@
import * as common from '../common/index.mjs';

import assert from 'assert';
import fs from 'fs';
import path from 'path';
import assert from 'node:assert';
import fs from 'node:fs';
import path from 'node: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.
// This tests that `make doc` generates the documentation properly: an HTML
// page and a JSON file for every Markdown file under `doc/api`, and nothing
// for anything else. 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.') || name === 'apilinks.json') continue;

assert.ok(
allMD.includes(name.replace(/\.\w+$/, '.md')),
`Unexpected output: out/doc/api/${name}, remove and rerun.`,
);
// Not all files under `doc/api` are expected in the generated output.
// Parse out list of excluded files.
let skippedDocs = [];
const makefile = await fs.open(new URL('../../Makefile', import.meta.url));
try {
// Find the `skip_apidoc_files = ` line and parse out the list of files.
for await (const line of makefile.readLines()) {
if (line.startsWith('skip_apidoc_files')) {
skippedDocs = line.split('=')[1]?.trim().split(/\s/).map((n) => path.basename(n));
}
}
} finally {
makefile.close();
}

const toc = fs.readFileSync(new URL('./index.html', apiURL), 'utf8');
const re = /href=("([^/]+\.html)"|([^/]+\.html))/;
const globalRe = new RegExp(re, 'g');
const links = toc.match(globalRe);
assert.notStrictEqual(links, null);
const sources = fs.readdirSync(mdURL)
.filter((name) => path.extname(name) === '.md')
.map((name) => path.basename(name, '.md'));
const generated = fs.readdirSync(apiURL);

// 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 = ['policy.json', 'policy.html'];
const skipedDocs = ['dtls.json', 'dtls.html', 'quic.json', 'quic.html'];
// These have no Markdown source of their own.
const expectedExtras = ['index.html', 'all.html', 'all.json'];
for (const name of expectedExtras) {
assert.ok(generated.includes(name), `${name} was not generated`);
}

// 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`);
for (const name of sources) {
for (const extension of ['.html', '.json']) {
const file = `${name}${extension}`;
if (skippedDocs.includes(name)) {
assert.ok(!generated.includes(file), `${file} was unexpectedly generated`);
continue;
}
assert.ok(generated.includes(file), `${file} was not generated`);
assert.notStrictEqual(
fs.statSync(new URL(`./${file}`, apiURL)).size,
0,
`${file} is empty`,
);
}
}

// 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) || skipedDocs.includes(actualDoc) ||
actualDoc === 'apilinks.json') continue;
// Every generated page must come from a current Markdown file, so a stale
// `out/doc/api` (e.g. from a renamed document) is noticed.
const expectedPages = ['404.html', 'apilinks.json', ...expectedExtras];
for (const name of generated) {
const extension = path.extname(name);
if (extension !== '.html' && extension !== '.json') continue;
if (expectedPages.includes(name)) continue;
assert.ok(
expectedDocs.includes(actualDoc), `${actualDoc} does not match TOC`);

assert.notStrictEqual(
fs.statSync(new URL(`./${actualDoc}`, apiURL)).size,
0,
`${actualDoc} is empty`,
sources.includes(path.basename(name, extension)),
`Unexpected output: out/doc/api/${name}, remove and rerun.`,
);
}
22 changes: 22 additions & 0 deletions tools/doc/api-links.doc-kit.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { fileURLToPath } from 'node:url';

const root = new URL('../../', import.meta.url);

const fromRoot = (path) =>
fileURLToPath(new URL(path, root)).replaceAll('\\', '/');

const urlFromRoot = (path) => new URL(path, root).href;

export default {
extends: '@node-core/doc-kit/config',

target: ['api-links'],

global: {
input: [fromRoot('lib/*.js')],
output: fromRoot('out/doc'),

// Point every loadable URL at its local file so no network request is made.
changelog: urlFromRoot('CHANGELOG.md'),
},
};
Loading
Loading