PR-URL: https://github.com/nodejs/node/pull/62395 Reviewed-By: Jacob Smith <jacob@frende.me> Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: Chengzhong Wu <legendecas@gmail.com> Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Joyee Cheung <joyeec9h3@gmail.com> Reviewed-By: Gerhard Stöbich <deb2001-github@yahoo.de> Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com>
163 lines
4.9 KiB
JavaScript
163 lines
4.9 KiB
JavaScript
import * as common from '../common/index.mjs';
|
|
|
|
import assert from 'node:assert';
|
|
import { existsSync } from 'node:fs';
|
|
import fs from 'node:fs/promises';
|
|
import path from 'node:path';
|
|
|
|
// This tests that `make doc` generates the JSON documentation properly.
|
|
// Note that for this test to pass, `make doc` must be run first.
|
|
|
|
if (common.isWindows) {
|
|
common.skip('`make doc` does not run on Windows');
|
|
}
|
|
|
|
function validateModule(module) {
|
|
assert.strictEqual(typeof module, 'object');
|
|
assert.strictEqual(module.type, 'module');
|
|
assert.ok(module.name);
|
|
assert.ok(module.textRaw);
|
|
}
|
|
|
|
function validateMisc(misc) {
|
|
assert.strictEqual(typeof misc, 'object');
|
|
assert.strictEqual(misc.type, 'misc');
|
|
assert.ok(misc.name);
|
|
assert.strictEqual(typeof misc.name, 'string');
|
|
assert.ok(misc.textRaw);
|
|
assert.strictEqual(typeof misc.textRaw, 'string');
|
|
}
|
|
|
|
let numberOfDeprecatedSections = 0;
|
|
let numberOfRemovedAPIs = 0;
|
|
|
|
const metaExpectedKeys = new Set([
|
|
'added',
|
|
'changes',
|
|
'deprecated',
|
|
'napiVersion',
|
|
'removed',
|
|
]);
|
|
|
|
function validateMeta(meta) {
|
|
assert.partialDeepStrictEqual(metaExpectedKeys, new Set(Object.keys(meta)));
|
|
assert.ok(!Object.hasOwn(meta, 'added') || Array.isArray(meta.added) || typeof meta.added === 'string');
|
|
if (meta.deprecated) {
|
|
numberOfDeprecatedSections++;
|
|
assert.ok(Array.isArray(meta.deprecated) || typeof meta.deprecated === 'string');
|
|
}
|
|
if (meta.removed) {
|
|
numberOfRemovedAPIs++;
|
|
assert.ok(Array.isArray(meta.removed) || typeof meta.removed === 'string');
|
|
}
|
|
|
|
assert.ok(!Object.hasOwn(meta, 'napiVersion') || Number(meta.napiVersion));
|
|
assert.ok(Array.isArray(meta.changes));
|
|
}
|
|
|
|
function findAllKeys(obj, allKeys = new Set()) {
|
|
for (const [key, value] of Object.entries(obj)) {
|
|
if (Number.isNaN(Number(key))) allKeys.add(key);
|
|
if (typeof value === 'object') findAllKeys(value, allKeys);
|
|
|
|
if (key === 'miscs') {
|
|
assert.ok(Array.isArray(value));
|
|
assert.ok(value.length);
|
|
value.forEach(validateMisc);
|
|
} else if (key === 'modules') {
|
|
assert.ok(Array.isArray(value));
|
|
assert.ok(value.length);
|
|
value.forEach(validateModule);
|
|
} else if (key === 'meta') {
|
|
validateMeta(value);
|
|
}
|
|
}
|
|
return allKeys;
|
|
}
|
|
|
|
const allExpectedKeys = new Set([
|
|
'added',
|
|
'changes',
|
|
'classes',
|
|
'classMethods',
|
|
'commit',
|
|
'ctors',
|
|
'default',
|
|
'deprecated',
|
|
'desc',
|
|
'description',
|
|
'displayName',
|
|
'events',
|
|
'examples',
|
|
'globals',
|
|
'introduced_in',
|
|
'meta',
|
|
'methods',
|
|
'miscs',
|
|
'modules',
|
|
'name',
|
|
'napiVersion',
|
|
'optional',
|
|
'options',
|
|
'params',
|
|
'pr-url',
|
|
'properties',
|
|
'removed',
|
|
'return',
|
|
'shortDesc',
|
|
'signatures',
|
|
'source',
|
|
'stability',
|
|
'stabilityText',
|
|
'textRaw',
|
|
'type',
|
|
'version',
|
|
]);
|
|
|
|
for await (const dirent of await fs.opendir(new URL('../../out/doc/api/', import.meta.url))) {
|
|
if (!dirent.name.endsWith('.md')) continue;
|
|
|
|
const jsonPath = path.join(dirent.parentPath, dirent.name.slice(0, -2) + 'json');
|
|
const expectedSource = `doc/api/${dirent.name}`;
|
|
if (dirent.name === 'quic.md') {
|
|
assert.ok(!existsSync(jsonPath)); // QUIC documentation is not public yet
|
|
continue;
|
|
}
|
|
|
|
console.log('testing', jsonPath, 'based on', expectedSource);
|
|
|
|
const fileContent = await fs.readFile(jsonPath, 'utf8');
|
|
// A proxy to check if the file is human readable is to count if it contains
|
|
// at least 3 line return.
|
|
assert.strictEqual(fileContent.split('\n', 3).length, 3);
|
|
|
|
const json = JSON.parse(fileContent);
|
|
|
|
assert.strictEqual(json.type, 'module');
|
|
assert.strictEqual(json.source, expectedSource);
|
|
if (dirent.name !== 'index.md') {
|
|
assert.ok(json.introduced_in || Object.values(json).at(-1)?.[0].introduced_in);
|
|
}
|
|
assert.deepStrictEqual(Object.keys(json), ['type', 'source', ...({
|
|
'addons.md': ['introduced_in', 'miscs'],
|
|
'cli.md': ['introduced_in', 'miscs'],
|
|
'debugger.md': ['introduced_in', 'stability', 'stabilityText', 'miscs'],
|
|
'deprecations.md': ['introduced_in', 'miscs'],
|
|
'documentation.md': ['introduced_in', 'miscs'],
|
|
'errors.md': ['introduced_in', 'classes', 'miscs'],
|
|
'esm.md': ['introduced_in', 'meta', 'stability', 'stabilityText', 'properties', 'miscs'],
|
|
'globals.md': ['introduced_in', 'stability', 'stabilityText', 'classes', 'methods', 'miscs'],
|
|
'index.md': [],
|
|
'intl.md': ['introduced_in', 'miscs'],
|
|
'n-api.md': ['introduced_in', 'stability', 'stabilityText', 'miscs'],
|
|
'packages.md': ['introduced_in', 'meta', 'miscs'],
|
|
'process.md': ['globals'],
|
|
'report.md': ['introduced_in', 'meta', 'stability', 'stabilityText', 'miscs'],
|
|
'synopsis.md': ['introduced_in', 'miscs'],
|
|
}[dirent.name] ?? ['modules'])]);
|
|
|
|
assert.partialDeepStrictEqual(allExpectedKeys, findAllKeys(json));
|
|
}
|
|
|
|
assert.strictEqual(numberOfDeprecatedSections, 45); // Increase this number every time a new API is deprecated.
|
|
assert.strictEqual(numberOfRemovedAPIs, 46); // Increase this number every time a section is marked as removed.
|