Skip to content

Commit d27fb46

Browse files
committed
feat: linter
Signed-off-by: flakey5 <[email protected]>
1 parent 1c86005 commit d27fb46

File tree

9 files changed

+180
-7
lines changed

9 files changed

+180
-7
lines changed

bin/cli.mjs

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
#!/usr/bin/env node
22

33
import { resolve } from 'node:path';
4-
import { argv } from 'node:process';
4+
import { argv, exit } from 'node:process';
55

66
import { Command, Option } from 'commander';
77

@@ -12,6 +12,8 @@ import generators from '../src/generators/index.mjs';
1212
import createLoader from '../src/loader.mjs';
1313
import createParser from '../src/parser.mjs';
1414
import createNodeReleases from '../src/releases.mjs';
15+
import { Linter } from '../src/linter/index.mjs';
16+
import reporters from '../src/linter/reporters/index.mjs';
1517

1618
const availableGenerators = Object.keys(generators);
1719

@@ -50,6 +52,12 @@ program
5052
'Set the processing target modes'
5153
).choices(availableGenerators)
5254
)
55+
.addOption(new Option('--skip-validation', 'TODO').default(false))
56+
.addOption(
57+
new Option('--reporter', 'TODO')
58+
.choices(Object.keys(reporters))
59+
.default('console')
60+
)
5361
.parse(argv);
5462

5563
/**
@@ -66,10 +74,20 @@ program
6674
* @type {Options}
6775
* @description The return type for values sent to the program from the CLI.
6876
*/
69-
const { input, output, target = [], version, changelog } = program.opts();
77+
const {
78+
input,
79+
output,
80+
target = [],
81+
version,
82+
changelog,
83+
skipValidation,
84+
reporter,
85+
} = program.opts();
86+
87+
const linter = skipValidation ? undefined : new Linter();
7088

7189
const { loadFiles } = createLoader();
72-
const { parseApiDocs } = createParser();
90+
const { parseApiDocs } = createParser(linter);
7391

7492
const apiDocFiles = loadFiles(input);
7593

@@ -89,4 +107,13 @@ await runGenerators({
89107
version: coerce(version),
90108
// A list of all Node.js major versions with LTS status
91109
releases: await getAllMajors(),
110+
linter,
92111
});
112+
113+
if (linter) {
114+
linter.report(reporter);
115+
116+
if (linter.hasError) {
117+
exit(1);
118+
}
119+
}

src/generators/legacy-html/assets/style.css

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -137,8 +137,8 @@ code,
137137
.pre,
138138
span.type,
139139
a.type {
140-
font-family: SFMono-Regular, Menlo, Consolas, 'Liberation Mono', 'Courier New',
141-
monospace;
140+
font-family: SFMono-Regular, Menlo, Consolas, 'Liberation Mono',
141+
'Courier New', monospace;
142142
font-size: 0.9em;
143143
}
144144

src/generators/types.d.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import type { SemVer } from 'semver';
22
import type availableGenerators from './index.mjs';
33
import type { ApiDocReleaseEntry } from '../types';
4+
import type { Linter } from '../linter/index.mjs';
45

56
declare global {
67
// All available generators as an inferable type, to allow Generator interfaces
@@ -26,6 +27,8 @@ declare global {
2627

2728
// A list of all Node.js major versions and their respective release information
2829
releases: Array<ApiDocReleaseEntry>;
30+
31+
linter: Linter | undefined;
2932
}
3033

3134
export interface GeneratorMetadata<I extends any, O extends any> {

src/linter/index.mjs

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
// @ts-check
2+
'use strict';
3+
4+
import reporters from './reporters/index.mjs';
5+
6+
/**
7+
*
8+
*/
9+
export class Linter {
10+
#_hasError = false;
11+
12+
/**
13+
* @type {Array<import('./types.d.ts').LintMessage>}
14+
*/
15+
#messages = [];
16+
17+
/**
18+
*
19+
*/
20+
get hasError() {
21+
return this.#_hasError;
22+
}
23+
24+
/**
25+
* @param {import('./types.d.ts').LintMessage} msg
26+
*/
27+
log(msg) {
28+
if (msg.level === 'error') {
29+
this.#_hasError = true;
30+
}
31+
32+
this.#messages.push(msg);
33+
}
34+
35+
/**
36+
* @param {keyof reporters} reporterName
37+
*/
38+
report(reporterName) {
39+
const reporter = reporters[reporterName];
40+
41+
for (const message of this.#messages) {
42+
reporter(message);
43+
}
44+
}
45+
46+
/**
47+
* @param {string} msg
48+
* @param {import('./types.d.ts').LintMessageLocation | undefined} location
49+
*/
50+
info(msg, location) {
51+
this.log({
52+
level: 'info',
53+
msg,
54+
location,
55+
});
56+
}
57+
58+
/**
59+
* @param {string} msg
60+
* @param {import('./types.d.ts').LintMessageLocation | undefined} location
61+
*/
62+
warn(msg, location) {
63+
this.log({
64+
level: 'warn',
65+
msg,
66+
location,
67+
});
68+
}
69+
70+
/**
71+
* @param {string} msg
72+
* @param {import('./types.d.ts').LintMessageLocation | undefined} location
73+
*/
74+
error(msg, location) {
75+
this.log({
76+
level: 'error',
77+
msg,
78+
location,
79+
});
80+
}
81+
}

src/linter/reporters/console.mjs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// @ts-check
2+
3+
'use strict';
4+
5+
import { styleText } from 'node:util';
6+
7+
/**
8+
* TODO is there a way to grab the parameter type for styleText since the types aren't exported
9+
* @type {Record<import('../types.d.ts').LintLevel, string>}
10+
*/
11+
const levelToColorMap = {
12+
info: 'gray',
13+
warn: 'yellow',
14+
error: 'red',
15+
};
16+
17+
/**
18+
* @type {import('../types.d.ts').Reporter}
19+
*/
20+
export default msg => {
21+
console.log(styleText(levelToColorMap[msg.level], msg.msg));
22+
};

src/linter/reporters/github.mjs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// @ts-check
2+
3+
'use strict';
4+
5+
/**
6+
* GitHub action reporter for
7+
*
8+
* @type {import('../types.d.ts').Reporter}
9+
*/
10+
export default msg => {
11+
// TODO
12+
console.log(msg);
13+
};

src/linter/reporters/index.mjs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
'use strict';
2+
3+
import console from './console.mjs';
4+
import github from './github.mjs';
5+
6+
export default /** @type {const} */ ({
7+
console,
8+
github,
9+
});

src/linter/types.d.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
export type LintLevel = 'info' | 'warn' | 'error';
2+
3+
export interface LintMessageLocation {
4+
// The absolute path to the file
5+
path: string;
6+
line: number;
7+
column: number;
8+
}
9+
10+
export interface LintMessage {
11+
level: LintLevel;
12+
msg: string;
13+
location?: LintMessageLocation;
14+
}
15+
16+
export type Reporter = (msg: LintMessage) => void;

src/parser.mjs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,14 @@ import { createNodeSlugger } from './utils/slugger.mjs';
1414

1515
/**
1616
* Creates an API doc parser for a given Markdown API doc file
17+
*
18+
* @param {import('./linter/index.mjs').Linter | undefined} linter
1719
*/
18-
const createParser = () => {
20+
const createParser = linter => {
1921
// Creates an instance of the Remark processor with GFM support
2022
// which is used for stringifying the AST tree back to Markdown
2123
const remarkProcessor = getRemark();
22-
24+
linter?.info('asd123');
2325
const {
2426
setHeadingMetadata,
2527
addYAMLMetadata,

0 commit comments

Comments
 (0)