Skip to content

Commit 246cc34

Browse files
committed
chore(lint): report error on invalid change versions, except when REPLACEME
1 parent e991c6f commit 246cc34

File tree

4 files changed

+90
-52
lines changed

4 files changed

+90
-52
lines changed
+31-35
Original file line numberDiff line numberDiff line change
@@ -1,42 +1,38 @@
11
import { LINT_MESSAGES } from '../constants.mjs';
22
import { valid } from 'semver';
3+
import { env } from 'node:process';
4+
5+
const NODE_RELEASED_VERSIONS = env.NODE_RELEASED_VERSIONS?.split(',');
36

47
/**
5-
* Checks if any change version is invalid
8+
* Determines if a given version is invalid.
69
*
7-
* @param {ApiDocMetadataEntry[]} entries
8-
* @returns {Array<import('../types').LintIssue>}
10+
* @param {string} version - The version to check.
11+
* @returns {boolean} True if the version is invalid, false otherwise.
912
*/
10-
export const invalidChangeVersion = entries => {
11-
const issues = [];
12-
13-
for (const entry of entries) {
14-
if (entry.changes.length === 0) continue;
15-
16-
const allVersions = entry.changes
17-
.filter(change => change.version)
18-
.flatMap(change =>
19-
Array.isArray(change.version) ? change.version : [change.version]
20-
);
21-
22-
const invalidVersions = allVersions.filter(
23-
version => valid(version) === null
24-
);
13+
const isInvalid = NODE_RELEASED_VERSIONS
14+
? version =>
15+
version !== 'REPLACEME' && !NODE_RELEASED_VERSIONS.includes(version)
16+
: version => version !== 'REPLACEME' && !valid(version);
2517

26-
issues.push(
27-
...invalidVersions.map(version => ({
28-
level: 'warn',
29-
message: LINT_MESSAGES.invalidChangeVersion.replace(
30-
'{{version}}',
31-
version
32-
),
33-
location: {
34-
path: entry.api_doc_source,
35-
position: entry.yaml_position,
36-
},
37-
}))
38-
);
39-
}
40-
41-
return issues;
42-
};
18+
/**
19+
* Checks if any change version is invalid.
20+
*
21+
* @param {ApiDocMetadataEntry[]} entries - The metadata entries to check.
22+
* @returns {Array<import('../types').LintIssue>} List of lint issues found.
23+
*/
24+
export const invalidChangeVersion = entries =>
25+
entries.flatMap(({ changes, api_doc_source, yaml_position }) =>
26+
changes.flatMap(({ version }) =>
27+
(Array.isArray(version) ? version : [version])
28+
.filter(isInvalid)
29+
.map(version => ({
30+
level: 'error',
31+
message: LINT_MESSAGES.invalidChangeVersion.replace(
32+
'{{version}}',
33+
version
34+
),
35+
location: { path: api_doc_source, position: yaml_position },
36+
}))
37+
)
38+
);

src/linter/tests/fixtures/entries.mjs

+5
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,11 @@ export const assertEntry = {
3939
'pr-url': 'https://github.com/nodejs/node/pull/34001',
4040
description: "Exposed as `require('node:assert/strict')`.",
4141
},
42+
{
43+
version: 'REPLACEME',
44+
'pr-url': 'https://github.com/nodejs/node/pull/12345',
45+
description: 'This is a test entry.',
46+
},
4247
],
4348
heading: {
4449
type: 'heading',
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import { invalidChangeVersion } from '../../rules/invalid-change-version.mjs';
2+
import { deepEqual } from 'node:assert';
3+
import { assertEntry } from './entries.mjs';
4+
5+
const issues = invalidChangeVersion([
6+
{
7+
...assertEntry,
8+
changes: [
9+
...assertEntry.changes,
10+
{ version: ['SOME_OTHER_RELEASED_VERSION'] },
11+
],
12+
},
13+
]);
14+
15+
deepEqual(issues, []);

src/linter/tests/rules/invalid-change-version.test.mjs

+39-17
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,43 @@
11
import { describe, it } from 'node:test';
22
import { invalidChangeVersion } from '../../rules/invalid-change-version.mjs';
3-
import { deepEqual } from 'node:assert';
3+
import { deepEqual, strictEqual } from 'node:assert';
44
import { assertEntry } from '../fixtures/entries.mjs';
5+
import { spawnSync } from 'node:child_process';
6+
import { fileURLToPath } from 'node:url';
7+
import { execPath } from 'node:process';
58

69
describe('invalidChangeVersion', () => {
7-
it('should return an empty array if all change versions are valid', () => {
8-
const issues = invalidChangeVersion([assertEntry]);
10+
it('should work with NODE_RELEASED_VERSIONS', () => {
11+
const result = spawnSync(
12+
execPath,
13+
[
14+
fileURLToPath(
15+
new URL(
16+
'../fixtures/invalidChangeVersion-environment.mjs',
17+
import.meta.url
18+
)
19+
),
20+
],
21+
{
22+
env: {
23+
NODE_RELEASED_VERSIONS: [
24+
'v9.9.0',
25+
'v13.9.0',
26+
'v12.16.2',
27+
'v15.0.0',
28+
'REPLACEME',
29+
'SOME_OTHER_RELEASED_VERSION',
30+
].join(','),
31+
},
32+
}
33+
);
934

10-
deepEqual(issues, []);
35+
strictEqual(result.status, 0);
36+
strictEqual(result.error, undefined);
37+
});
38+
39+
it('should return an empty array if all change versions are valid', () => {
40+
deepEqual(invalidChangeVersion([assertEntry]), []);
1141
});
1242

1343
it('should return an issue if a change version is invalid', () => {
@@ -16,30 +46,22 @@ describe('invalidChangeVersion', () => {
1646
...assertEntry,
1747
changes: [
1848
...assertEntry.changes,
19-
{ version: ['v13.9.0', 'REPLACEME'] },
49+
{ version: ['v13.9.0', 'INVALID_VERSION'] },
2050
],
2151
},
2252
]);
2353

2454
deepEqual(issues, [
2555
{
26-
level: 'warn',
56+
level: 'error',
2757
location: {
2858
path: 'doc/api/assert.md',
2959
position: {
30-
end: {
31-
column: 35,
32-
line: 7,
33-
offset: 137,
34-
},
35-
start: {
36-
column: 1,
37-
line: 7,
38-
offset: 103,
39-
},
60+
start: { column: 1, line: 7, offset: 103 },
61+
end: { column: 35, line: 7, offset: 137 },
4062
},
4163
},
42-
message: 'Invalid version number: REPLACEME',
64+
message: 'Invalid version number: INVALID_VERSION',
4365
},
4466
]);
4567
});

0 commit comments

Comments
 (0)