Skip to content
Merged
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
15 changes: 11 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,17 @@ CLI tool to generate API documentation of a Node.js project.

Options:
-i, --input [patterns...] Specify input file patterns using glob syntax
--ignore [patterns...] Specify files to be ignored from the input using glob syntax
--ignore [patterns...] Specify which input files to ignore using glob syntax
-o, --output <path> Specify the relative or absolute output directory
-v, --version <semver> Specify the target version of Node.js, semver compliant (default: "v22.6.0")
-c, --changelog <url> Specify the path (file: or https://) to the CHANGELOG.md file (default: "https://raw.githubusercontent.com/nodejs/node/HEAD/CHANGELOG.md")
-t, --target [mode...] Set the processing target modes (choices: "json-simple", "legacy-html", "legacy-html-all", "man-page", "legacy-json", "legacy-json-all", "addon-verify", "api-links", "orama-db")
-v, --version <semver> Specify the target version of Node.js, semver compliant (default: "v22.11.0")
-c, --changelog <url> Specify the path (file: or https://) to the CHANGELOG.md file (default:
"https://raw.githubusercontent.com/nodejs/node/HEAD/CHANGELOG.md")
-t, --target [mode...] Set the processing target modes (choices: "json-simple", "legacy-html", "legacy-html-all",
"man-page", "legacy-json", "legacy-json-all", "addon-verify", "api-links", "orama-db")
--disable-rule [rule...] Disable a specific linter rule (choices: "invalid-change-version",
"missing-change-version", "missing-introduced-in", default: [])
--lint-dry-run Run linter in dry-run mode (default: false)
--git-ref A git ref/commit URL pointing to Node.js
-r, --reporter [reporter] Specify the linter reporter (choices: "console", "github", default: "console")
-h, --help display help for command
```
22 changes: 17 additions & 5 deletions bin/cli.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,12 @@ import { coerce } from 'semver';
import { DOC_NODE_CHANGELOG_URL, DOC_NODE_VERSION } from '../src/constants.mjs';
import createGenerator from '../src/generators.mjs';
import generators from '../src/generators/index.mjs';
import createMarkdownLoader from '../src/loaders/markdown.mjs';
import createMarkdownParser from '../src/parsers/markdown.mjs';
import createNodeReleases from '../src/releases.mjs';
import createLinter from '../src/linter/index.mjs';
import reporters from '../src/linter/reporters/index.mjs';
import rules from '../src/linter/rules/index.mjs';
import createMarkdownLoader from '../src/loaders/markdown.mjs';
import createMarkdownParser from '../src/parsers/markdown.mjs';
import createNodeReleases from '../src/releases.mjs';

const availableGenerators = Object.keys(generators);

Expand Down Expand Up @@ -67,6 +67,11 @@ program
.addOption(
new Option('--lint-dry-run', 'Run linter in dry-run mode').default(false)
)
.addOption(
new Option('--git-ref', 'A git ref/commit URL pointing to Node.js').default(
'https://github.com/nodejs/node/tree/HEAD'
)
)
.addOption(
new Option('-r, --reporter [reporter]', 'Specify the linter reporter')
.choices(Object.keys(reporters))
Expand All @@ -85,6 +90,7 @@ program
* @property {string} changelog Specifies the path to the Node.js CHANGELOG.md file.
* @property {string[]} disableRule Specifies the linter rules to disable.
* @property {boolean} lintDryRun Specifies whether the linter should run in dry-run mode.
* @property {boolean} useGit Specifies whether the parser should execute optional git commands. (Should only be used within a git repo)
* @property {keyof reporters} reporter Specifies the linter reporter.
*
* @name ProgramOptions
Expand All @@ -100,6 +106,7 @@ const {
changelog,
disableRule,
lintDryRun,
gitRef,
reporter,
} = program.opts();

Expand All @@ -117,23 +124,28 @@ const { runGenerators } = createGenerator(parsedApiDocs);
// Retrieves Node.js release metadata from a given Node.js version and CHANGELOG.md file
const { getAllMajors } = createNodeReleases(changelog);

// Runs the Linter on the parsed API docs
linter.lintAll(parsedApiDocs);

if (target && output) {
if (target) {
await runGenerators({
// A list of target modes for the API docs parser
generators: target,
// Resolved `input` to be used
input: input,
// Resolved `output` path to be used
output: resolve(output),
output: output && resolve(output),
// Resolved SemVer of current Node.js version
version: coerce(version),
// A list of all Node.js major versions with LTS status
releases: await getAllMajors(),
// An URL containing a git ref URL pointing to the commit or ref that was used
// to generate the API docs. This is used to link to the source code of the
gitRef,
});
}

// Reports Lint Content
linter.report(reporter);

exit(Number(linter.hasError()));
10 changes: 4 additions & 6 deletions src/generators.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ const availableGenerators = {
};

/**
* @typedef {{ ast: import('./generators/types.d.ts').GeneratorMetadata<ApiDocMetadataEntry, ApiDocMetadataEntry>}} AstGenerator The AST "generator" is a facade for the AST tree and it isn't really a generator
* @typedef {import('./generators/types.d.ts').AvailableGenerators & AstGenerator} AllGenerators A complete set of the available generators, including the AST one
* @typedef {{ ast: GeneratorMetadata<ApiDocMetadataEntry, ApiDocMetadataEntry>}} AstGenerator The AST "generator" is a facade for the AST tree and it isn't really a generator
* @typedef {AvailableGenerators & AstGenerator} AllGenerators A complete set of the available generators, including the AST one
* @param markdownInput
* @param jsInput
*
Expand All @@ -41,14 +41,12 @@ const createGenerator = markdownInput => {
*
* @type {{ [K in keyof AllGenerators]: ReturnType<AllGenerators[K]['generate']> }}
*/
const cachedGenerators = {
ast: Promise.resolve(markdownInput),
};
const cachedGenerators = { ast: Promise.resolve(markdownInput) };

/**
* Runs the Generator engine with the provided top-level input and the given generator options
*
* @param {import('./generators/types.d.ts').GeneratorOptions} options The options for the generator runtime
* @param {GeneratorOptions} options The options for the generator runtime
*/
const runGenerators = async ({ generators, ...extra }) => {
// Note that this method is blocking, and will only execute one generator per-time
Expand Down
2 changes: 1 addition & 1 deletion src/generators/addon-verify/index.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import {
*
* @typedef {Array<ApiDocMetadataEntry>} Input
*
* @type {import('../types.d.ts').GeneratorMetadata<Input, string>}
* @type {GeneratorMetadata<Input, string>}
*/
export default {
name: 'addon-verify',
Expand Down
41 changes: 9 additions & 32 deletions src/generators/api-links/index.mjs
Original file line number Diff line number Diff line change
@@ -1,11 +1,7 @@
'use strict';

import { basename, dirname, join } from 'node:path';
import { basename, join } from 'node:path';
import { writeFile } from 'node:fs/promises';
import {
getBaseGitHubUrl,
getCurrentGitHash,
} from './utils/getBaseGitHubUrl.mjs';
import { extractExports } from './utils/extractExports.mjs';
import { findDefinitions } from './utils/findDefinitions.mjs';
import { checkIndirectReferences } from './utils/checkIndirectReferences.mjs';
Expand All @@ -20,7 +16,7 @@ import { checkIndirectReferences } from './utils/checkIndirectReferences.mjs';
*
* @typedef {Array<JsProgram>} Input
*
* @type {import('../types.d.ts').GeneratorMetadata<Input, Record<string, string>>}
* @type {GeneratorMetadata<Input, Record<string, string>>}
*/
export default {
name: 'api-links',
Expand All @@ -40,56 +36,37 @@ export default {
* @param {Input} input
* @param {Partial<GeneratorOptions>} options
*/
async generate(input, { output }) {
async generate(input, { output, gitRef }) {
/**
* @type Record<string, string>
*/
const definitions = {};

/**
* @type {string}
*/
let baseGithubLink;

if (input.length > 0) {
const repositoryDirectory = dirname(input[0].path);

const repository = getBaseGitHubUrl(repositoryDirectory);

const tag = getCurrentGitHash(repositoryDirectory);

baseGithubLink = `${repository}/blob/${tag}`;
}

input.forEach(program => {
/**
* Mapping of definitions to their line number
*
* @type {Record<string, number>}
* @example { 'someclass.foo': 10 }
*/
const nameToLineNumberMap = {};

// `http.js` -> `http`
const programBasename = basename(program.path, '.js');
const baseName = basename(program.path, '.js');

const exports = extractExports(
program,
programBasename,
nameToLineNumberMap
);
const exports = extractExports(program, baseName, nameToLineNumberMap);

findDefinitions(program, programBasename, nameToLineNumberMap, exports);
findDefinitions(program, baseName, nameToLineNumberMap, exports);

checkIndirectReferences(program, exports, nameToLineNumberMap);

const githubLink =
`${baseGithubLink}/lib/${programBasename}.js`.replaceAll('\\', '/');
const fullGitUrl = `${gitRef}/lib/${baseName}.js`;

// Add the exports we found in this program to our output
Object.keys(nameToLineNumberMap).forEach(key => {
const lineNumber = nameToLineNumberMap[key];

definitions[key] = `${githubLink}#L${lineNumber}`;
definitions[key] = `${fullGitUrl}#L${lineNumber}`;
});
});

Expand Down
4 changes: 3 additions & 1 deletion src/generators/api-links/test/fixtures.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,9 @@ describe('api links', () => {
input: [sourceFile],
});

const actualOutput = await apiLinks.generate(astJsResult, {});
const actualOutput = await apiLinks.generate(astJsResult, {
gitRef: 'https://github.com/nodejs/node/tree/HEAD',
});

for (const [k, v] of Object.entries(actualOutput)) {
actualOutput[k] = v.replace(/.*(?=lib\/)/, '');
Expand Down
35 changes: 0 additions & 35 deletions src/generators/api-links/utils/getBaseGitHubUrl.mjs

This file was deleted.

2 changes: 1 addition & 1 deletion src/generators/ast-js/index.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import createJsParser from '../../parsers/javascript.mjs';
*
* @typedef {unknown} Input
*
* @type {import('../types.d.ts').GeneratorMetadata<Input, Array<JsProgram>>}
* @type {GeneratorMetadata<Input, Array<JsProgram>>}
*/
export default {
name: 'ast-js',
Expand Down
2 changes: 1 addition & 1 deletion src/generators/json-simple/index.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import { getRemark } from '../../utils/remark.mjs';
*
* @typedef {Array<ApiDocMetadataEntry>} Input
*
* @type {import('../types.d.ts').GeneratorMetadata<Input, string>}
* @type {GeneratorMetadata<Input, string>}
*/
export default {
name: 'json-simple',
Expand Down
2 changes: 1 addition & 1 deletion src/generators/legacy-html-all/index.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ import { getRemarkRehype } from '../../utils/remark.mjs';
*
* @typedef {Array<TemplateValues>} Input
*
* @type {import('../types.d.ts').GeneratorMetadata<Input, string>}
* @type {GeneratorMetadata<Input, string>}
*/
export default {
name: 'legacy-html-all',
Expand Down
2 changes: 1 addition & 1 deletion src/generators/legacy-html/index.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ import { getRemarkRehype } from '../../utils/remark.mjs';
*
* @typedef {Array<ApiDocMetadataEntry>} Input
*
* @type {import('../types.d.ts').GeneratorMetadata<Input, Array<TemplateValues>>}
* @type {GeneratorMetadata<Input, Array<TemplateValues>>}
*/
export default {
name: 'legacy-html',
Expand Down
2 changes: 1 addition & 1 deletion src/generators/legacy-json-all/index.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { join } from 'node:path';
*
* @typedef {Array<import('../legacy-json/types.d.ts').Section>} Input
*
* @type {import('../types.d.ts').GeneratorMetadata<Input, import('./types.d.ts').Output>}
* @type {GeneratorMetadata<Input, import('./types.d.ts').Output>}
*/
export default {
name: 'legacy-json-all',
Expand Down
2 changes: 1 addition & 1 deletion src/generators/legacy-json/index.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import { createSectionBuilder } from './utils/buildSection.mjs';
*
* @typedef {Array<ApiDocMetadataEntry>} Input
*
* @type {import('../types.d.ts').GeneratorMetadata<Input, import('./types.d.ts').Section[]>}
* @type {GeneratorMetadata<Input, import('./types.d.ts').Section[]>}
*/
export default {
name: 'legacy-json',
Expand Down
2 changes: 1 addition & 1 deletion src/generators/man-page/index.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import { DOC_SLUG_ENVIRONMENT, DOC_SLUG_OPTIONS } from '../../constants.mjs';
*
* @typedef {Array<ApiDocMetadataEntry>} Input
*
* @type {import('../types.d.ts').GeneratorMetadata<Input, string>}
* @type {GeneratorMetadata<Input, string>}
*/
export default {
name: 'man-page',
Expand Down
2 changes: 1 addition & 1 deletion src/generators/orama-db/index.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import { createSectionBuilder } from '../legacy-json/utils/buildSection.mjs';
*
* @typedef {Array<ApiDocMetadataEntry>} Input
*
* @type {import('../types.d.ts').GeneratorMetadata<Input, import('./types.d.ts').OramaDb>}
* @type {GeneratorMetadata<Input, import('./types.d.ts').OramaDb>}
*/
export default {
name: 'orama-db',
Expand Down
8 changes: 7 additions & 1 deletion src/generators/types.d.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type { SemVer } from 'semver';
import type availableGenerators from './index.mjs';
import type { ApiDocReleaseEntry } from '../types';
import type availableGenerators from './index.mjs';

declare global {
// All available generators as an inferable type, to allow Generator interfaces
Expand Down Expand Up @@ -30,6 +30,12 @@ declare global {

// A list of all Node.js major versions and their respective release information
releases: Array<ApiDocReleaseEntry>;

// An URL containing a git ref URL pointing to the commit or ref that was used
// to generate the API docs. This is used to link to the source code of the
// i.e. https://github.com/nodejs/node/tree/2cb1d07e0f6d9456438016bab7db4688ab354fd2
// i.e. https://gitlab.com/someone/node/tree/HEAD
gitRef: string;
}

export interface GeneratorMetadata<I extends any, O extends any> {
Expand Down
Loading