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 Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -876,7 +876,7 @@ VERSION=v$(RAWVER)

.PHONY: doc-only
.NOTPARALLEL: doc-only
doc-only: $(apidoc_dirs) $(apidocs_html) $(apidocs_json) out/doc/api/all.json out/doc/llms.txt out/doc/apilinks.json ## Builds the docs with the local or the global Node.js binary.
doc-only: $(apidoc_dirs) $(apidocs_html) $(apidocs_json) out/doc/api/all.html out/doc/api/all.json out/doc/llms.txt out/doc/apilinks.json ## Builds the docs with the local or the global Node.js binary.

.PHONY: doc
doc: $(NODE_EXE) doc-only ## Build Node.js, and then build the documentation with the new binary.
Expand Down Expand Up @@ -915,6 +915,7 @@ $(apidocs_html) $(apidocs_json) out/doc/api/all.html out/doc/api/all.json &: $(a
$(DOC_KIT) generate \
--log-level $(DOC_KIT_LOG_LEVEL) \
--config-file tools/doc/web.doc-kit.config.mjs \
-o out/doc/api \
-v $(VERSION) \
$(if $(JOBS),-p $(JOBS)) \
) \
Expand Down
72 changes: 72 additions & 0 deletions test/doctool/test-make-doc.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import * as common from '../common/index.mjs';

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: 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);

// 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 sources = fs.readdirSync(mdURL)
.filter((name) => path.extname(name) === '.md')
.map((name) => path.basename(name, '.md'));
const generated = fs.readdirSync(apiURL);

// 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`);
}

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`,
);
}
}

// 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(
sources.includes(path.basename(name, extension)),
`Unexpected output: out/doc/api/${name}, remove and rerun.`,
);
}
15 changes: 10 additions & 5 deletions tools/doc/api-links.doc-kit.config.mjs
Original file line number Diff line number Diff line change
@@ -1,17 +1,22 @@
import { join } from 'node:path';
import { pathToFileURL } from 'node:url';
import { fileURLToPath } from 'node:url';

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

const fromRoot = (path) =>
pathToFileURL(join(import.meta.dirname, '..', '..', path)).href;
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: ['lib/*.js'],
input: [fromRoot('lib/*.js')],
output: fromRoot('out/doc'),

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