Skip to content
Merged
Show file tree
Hide file tree
Changes from 9 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
34 changes: 32 additions & 2 deletions bin/cli.mjs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#!/usr/bin/env node

import { resolve } from 'node:path';
import { argv } from 'node:process';
import { argv, exit } from 'node:process';

import { Command, Option } from 'commander';

Expand All @@ -12,6 +12,8 @@ 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 { Linter } from '../src/linter/index.mjs';
Comment thread
araujogui marked this conversation as resolved.
Outdated
import reporters from '../src/linter/reporters/index.mjs';

const availableGenerators = Object.keys(generators);

Expand Down Expand Up @@ -50,6 +52,12 @@ program
'Set the processing target modes'
).choices(availableGenerators)
)
.addOption(new Option('--skip-linting', 'Skip linting').default(false))
.addOption(
new Option('-r, --reporter [reporter]', 'Specify the linter reporter')
.choices(Object.keys(reporters))
.default('console')
)
.parse(argv);

/**
Expand All @@ -61,12 +69,24 @@ program
* @property {Target[]} target Specifies the generator target mode.
* @property {string} version Specifies the target Node.js version.
* @property {string} changelog Specifies the path to the Node.js CHANGELOG.md file
* @property {boolean} skipLinting Specifies whether to skip linting
* @property {keyof reporters} reporter Specifies the linter reporter
*
* @name ProgramOptions
* @type {Options}
* @description The return type for values sent to the program from the CLI.
*/
const { input, output, target = [], version, changelog } = program.opts();
const {
input,
output,
target = [],
version,
changelog,
skipLinting,
reporter,
} = program.opts();

const linter = skipLinting ? undefined : new Linter();
Comment thread
araujogui marked this conversation as resolved.
Outdated

const { loadFiles } = createMarkdownLoader();
const { parseApiDocs } = createMarkdownParser();
Expand All @@ -80,6 +100,8 @@ const { runGenerators } = createGenerator(parsedApiDocs);
// Retrieves Node.js release metadata from a given Node.js version and CHANGELOG.md file
const { getAllMajors } = createNodeReleases(changelog);

linter?.lintAll(parsedApiDocs);

await runGenerators({
// A list of target modes for the API docs parser
generators: target,
Expand All @@ -92,3 +114,11 @@ await runGenerators({
// A list of all Node.js major versions with LTS status
releases: await getAllMajors(),
});

if (linter) {
Comment thread
araujogui marked this conversation as resolved.
Outdated
linter.report(reporter);

if (linter.hasError) {
exit(1);
}
}
66 changes: 66 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
},
"dependencies": {
"acorn": "^8.14.0",
"@actions/core": "^1.11.1",
Comment thread
ovflowd marked this conversation as resolved.
"commander": "^13.1.0",
"estree-util-visit": "^2.0.0",
"dedent": "^1.5.3",
Expand Down
56 changes: 45 additions & 11 deletions src/constants.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -125,17 +125,45 @@ export const DOC_SLUG_ENVIRONMENT = 'environment-variables-1';
// JavaScript globals types within the MDN JavaScript docs
// @see DOC_MDN_BASE_URL_JS_GLOBALS
export const DOC_TYPES_MAPPING_GLOBALS = {
...Object.fromEntries([
'AggregateError', 'Array', 'ArrayBuffer', 'DataView', 'Date', 'Error',
'EvalError', 'Function', 'Map', 'NaN', 'Object', 'Promise', 'Proxy', 'RangeError',
'ReferenceError', 'RegExp', 'Set', 'SharedArrayBuffer', 'SyntaxError', 'Symbol',
'TypeError', 'URIError', 'WeakMap', 'WeakSet',

'TypedArray',
'Float32Array', 'Float64Array',
'Int8Array', 'Int16Array', 'Int32Array',
'Uint8Array', 'Uint8ClampedArray', 'Uint16Array', 'Uint32Array',
].map(e => [e, e])),
...Object.fromEntries(
Comment thread
ovflowd marked this conversation as resolved.
[
'AggregateError',
'Array',
'ArrayBuffer',
'DataView',
'Date',
'Error',
'EvalError',
'Function',
'Map',
'NaN',
'Object',
'Promise',
'Proxy',
'RangeError',
'ReferenceError',
'RegExp',
'Set',
'SharedArrayBuffer',
'SyntaxError',
'Symbol',
'TypeError',
'URIError',
'WeakMap',
'WeakSet',

'TypedArray',
'Float32Array',
'Float64Array',
'Int8Array',
'Int16Array',
'Int32Array',
'Uint8Array',
'Uint8ClampedArray',
'Uint16Array',
'Uint32Array',
].map(e => [e, e])
),
bigint: 'BigInt',
'WebAssembly.Instance': 'WebAssembly/Instance',
};
Expand Down Expand Up @@ -392,3 +420,9 @@ export const DOC_TYPES_MAPPING_OTHER = {
Response: `${DOC_MDN_BASE_URL}/API/Response`,
Request: `${DOC_MDN_BASE_URL}/API/Request`,
};

export const LINT_MESSAGES = {
missingIntroducedIn: "Missing 'introduced_in' field in the API doc entry",
missingChangeVersion: 'Missing version field in the API doc entry',
invalidChangeVersion: 'Invalid version number: {{version}}',
};
3 changes: 3 additions & 0 deletions src/generators/types.d.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type { SemVer } from 'semver';
import type availableGenerators from './index.mjs';
import type { ApiDocReleaseEntry } from '../types';
import type { Linter } from '../linter/index.mjs';

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

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

linter: Linter | undefined;
Comment thread
araujogui marked this conversation as resolved.
Outdated
}

export interface GeneratorMetadata<I extends any, O extends any> {
Expand Down
65 changes: 65 additions & 0 deletions src/linter/index.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
'use strict';

import reporters from './reporters/index.mjs';
import { invalidChangeVersion } from './rules/invalid-change-version.mjs';
import { missingChangeVersion } from './rules/missing-change-version.mjs';
import { missingIntroducedIn } from './rules/missing-introduced-in.mjs';

/**
* Lint issues in ApiDocMetadataEntry entries
*/
export class Linter {
/**
* @type {Array<import('./types.d.ts').LintIssue>}
*/
#issues = [];

/**
* @type {Array<import('./types.d.ts').LintRule>}
*/
#rules = [missingIntroducedIn, missingChangeVersion, invalidChangeVersion];

/**
* @param {ApiDocMetadataEntry} entry
* @returns {void}
*/
lint(entry) {
for (const rule of this.#rules) {
const issues = rule(entry);

if (issues.length > 0) {
this.#issues.push(...issues);
}
}
}

/**
* @param {ApiDocMetadataEntry[]} entries
* @returns {void}
*/
lintAll(entries) {
for (const entry of entries) {
this.lint(entry);
}
}

/**
* @param {keyof reporters} reporterName
*/
report(reporterName) {
const reporter = reporters[reporterName];

for (const issue of this.#issues) {
reporter(issue);
}
}

/**
* Returns whether there are any issues with a level of 'error'
*
* @returns {boolean}
*/
get hasError() {
return this.#issues.some(issue => issue.level === 'error');
}
}
29 changes: 29 additions & 0 deletions src/linter/reporters/console.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
'use strict';

import { styleText } from 'node:util';

/**
* @type {Record<import('../types.d.ts').IssueLevel, string>}
*/
const levelToColorMap = {
info: 'gray',
warn: 'yellow',
error: 'red',
};

/**
* @type {import('../types.d.ts').Reporter}
*/
export default issue => {
const position = issue.location.position
? ` (${issue.location.position.start.line}:${issue.location.position.end.line})`
: '';

console.log(
styleText(
// @ts-expect-error ForegroundColors is not exported
Comment thread
araujogui marked this conversation as resolved.
Outdated
levelToColorMap[issue.level],
`${issue.message} at ${issue.location.path}${position}`
)
);
};
24 changes: 24 additions & 0 deletions src/linter/reporters/github.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
'use strict';

import * as core from '@actions/core';

const actions = {
warn: core.warning,
error: core.error,
info: core.notice,
};

/**
* GitHub action reporter for
*
* @type {import('../types.d.ts').Reporter}
*/
export default issue => {
const logFn = actions[issue.level] || core.notice;

logFn(issue.message, {
file: issue.location.path,
startLine: issue.location.position?.start.line,
endLine: issue.location.position?.end.line,
});
};
Loading