Skip to content

Commit ca5f40f

Browse files
committed
doc: lint deprecation codes
Add a rule to make sure deprecation codes are in order.
1 parent ef1eb8d commit ca5f40f

File tree

3 files changed

+134
-1
lines changed

3 files changed

+134
-1
lines changed

doc/api/deprecations.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1129,7 +1129,7 @@ Type: Documentation-only
11291129
The [`util.isNumber()`][] API is deprecated.
11301130

11311131
<a id="DEP0053"></a>
1132-
### DEP0053 `util.isObject()`
1132+
### DEP0053: `util.isObject()`
11331133
<!-- YAML
11341134
changes:
11351135
- version:
@@ -1795,6 +1795,9 @@ Type: End-of-Life
17951795
`runInAsyncIdScope` doesn't emit the `'before'` or `'after'` event and can thus
17961796
cause a lot of issues. See <https://github.com/nodejs/node/issues/14328>.
17971797
1798+
<!-- md-lint skip-deprecation DEP0087 -->
1799+
<!-- md-lint skip-deprecation DEP0088 -->
1800+
17981801
<a id="DEP0089"></a>
17991802
### DEP0089: `require('assert')`
18001803
<!-- YAML
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
'use strict';
2+
3+
require('../common');
4+
const path = require('path');
5+
const { execFileSync } = require('child_process');
6+
7+
const script = path.join(
8+
__dirname,
9+
'..',
10+
'..',
11+
'tools',
12+
'doc',
13+
'deprecationCodes.js'
14+
);
15+
16+
const mdPath = path.join(
17+
__dirname,
18+
'..',
19+
'..',
20+
'doc',
21+
'api',
22+
'deprecations.md'
23+
);
24+
25+
execFileSync(process.execPath, [script, mdPath], { encoding: 'utf-8' });

tools/doc/deprecationCodes.js

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
'use strict';
2+
3+
const fs = require('fs');
4+
const { resolve } = require('path');
5+
6+
const unified = require('unified');
7+
const assert = require('assert');
8+
const source = resolve(process.argv[2]);
9+
10+
const skipDeprecationComment = /^<!-- md-lint skip-deprecation (DEP\d{4}) -->$/;
11+
12+
const generateDeprecationCode = (codeAsNumber) =>
13+
`DEP${codeAsNumber.toString().padStart(4, '0')}`;
14+
15+
const addMarkdownPathToErrorStack = (error, node) => {
16+
const { line, column } = node.position.start;
17+
const [header, ...lines] = error.stack.split('\n');
18+
error.stack =
19+
header +
20+
`\n at <anonymous> (${source}:${line}:${column})\n` +
21+
lines.join('\n');
22+
return error;
23+
};
24+
25+
const testAnchor = (anchorNode, expectedDeprecationCode) => {
26+
try {
27+
assert.strictEqual(
28+
anchorNode?.children[0]?.value,
29+
`<a id="${expectedDeprecationCode}">`,
30+
`Missing or ill-formed anchor for ${expectedDeprecationCode}.`
31+
);
32+
} catch (e) {
33+
throw addMarkdownPathToErrorStack(e, anchorNode);
34+
}
35+
};
36+
37+
const testHeading = (headingNode, expectedDeprecationCode) => {
38+
try {
39+
assert.strictEqual(
40+
headingNode?.children[0]?.value.substring(0, 9),
41+
`${expectedDeprecationCode}: `,
42+
'Ill-formed or out-of-order deprecation code.'
43+
);
44+
} catch (e) {
45+
throw addMarkdownPathToErrorStack(e, headingNode);
46+
}
47+
};
48+
49+
const testYAMLComment = (commentNode) => {
50+
try {
51+
assert.strictEqual(
52+
commentNode?.value?.substring(0, 19),
53+
'<!-- YAML\nchanges:\n',
54+
'Missing or ill-formed YAML comment.'
55+
);
56+
} catch (e) {
57+
throw addMarkdownPathToErrorStack(e, commentNode);
58+
}
59+
};
60+
61+
const testDeprecationType = (paragraphNode) => {
62+
try {
63+
assert.strictEqual(
64+
paragraphNode?.children[0]?.value?.substring(0, 6),
65+
'Type: ',
66+
'Missing deprecation type.'
67+
);
68+
} catch (e) {
69+
throw addMarkdownPathToErrorStack(e, paragraphNode);
70+
}
71+
};
72+
73+
const tree = unified()
74+
.use(require('remark-parse'))
75+
.parse(fs.readFileSync(source));
76+
77+
let expectedDeprecationCodeNumber = 0;
78+
for (let i = 0; i < tree.children.length; i++) {
79+
const node = tree.children[i];
80+
if (node.type === 'html' && skipDeprecationComment.test(node.value)) {
81+
const expectedDeprecationCode =
82+
generateDeprecationCode(++expectedDeprecationCodeNumber);
83+
const deprecationCodeAsText = node.value.match(skipDeprecationComment)[1];
84+
85+
try {
86+
assert.strictEqual(
87+
deprecationCodeAsText,
88+
expectedDeprecationCode,
89+
'Deprecation codes are not ordered correctly.'
90+
);
91+
} catch (e) {
92+
throw addMarkdownPathToErrorStack(e, node);
93+
}
94+
}
95+
if (node.type === 'heading' && node.depth === 3) {
96+
const expectedDeprecationCode =
97+
generateDeprecationCode(++expectedDeprecationCodeNumber);
98+
99+
testHeading(node, expectedDeprecationCode);
100+
101+
testAnchor(tree.children[i - 1], expectedDeprecationCode);
102+
testYAMLComment(tree.children[i + 1]);
103+
testDeprecationType(tree.children[i + 2]);
104+
}
105+
}

0 commit comments

Comments
 (0)