Skip to content

Commit e9139b6

Browse files
committed
Add lint rule for runtime deprecations
1 parent ca5f40f commit e9139b6

File tree

3 files changed

+98
-0
lines changed

3 files changed

+98
-0
lines changed
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
'use strict';
2+
3+
const common = require('../common');
4+
if (!common.hasCrypto)
5+
common.skip('missing crypto');
6+
common.skipIfEslintMissing();
7+
8+
const RuleTester = require('../../tools/node_modules/eslint').RuleTester;
9+
const rule = require('../../tools/eslint-rules/documented-deprecation-codes');
10+
11+
const mdFile = 'doc/api/deprecations.md';
12+
13+
const invalidCode = 'UNDOCUMENTED INVALID CODE';
14+
15+
new RuleTester().run('documented-deprecation-codes', rule, {
16+
valid: [
17+
`
18+
deprecate(function() {
19+
return this.getHeaders();
20+
}, 'OutgoingMessage.prototype._headers is deprecated', 'DEP0066')
21+
`
22+
],
23+
invalid: [
24+
{
25+
code: `
26+
deprecate(function foo(){}, 'bar', '${invalidCode}');
27+
`,
28+
errors: [
29+
{
30+
message: `"${invalidCode}" does not match the expected pattern`,
31+
line: 2
32+
},
33+
{
34+
message: `"${invalidCode}" is not documented in ${mdFile}`,
35+
line: 2
36+
},
37+
{
38+
message:
39+
`${mdFile} does not have an anchor for "${invalidCode}"`,
40+
line: 2
41+
}
42+
]
43+
}
44+
]
45+
});
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
'use strict';
2+
3+
const fs = require('fs');
4+
const path = require('path');
5+
const { isDefiningDeprecation } = require('./rules-utils.js');
6+
7+
const patternToMatch = /^DEP\d+$/;
8+
9+
const mdFile = 'doc/api/deprecations.md';
10+
const doc = fs.readFileSync(path.resolve(__dirname, '../..', mdFile), 'utf8');
11+
12+
function isInDoc(code) {
13+
return doc.includes(`### ${code}:`);
14+
}
15+
16+
function includesAnchor(code) {
17+
return doc.includes(`<a id="${code}"></a>`);
18+
}
19+
20+
function getDeprecationCode(node) {
21+
return node.expression.arguments[2].value;
22+
}
23+
24+
module.exports = {
25+
create: function(context) {
26+
return {
27+
ExpressionStatement: function(node) {
28+
if (!isDefiningDeprecation(node) || !getDeprecationCode(node)) return;
29+
const code = getDeprecationCode(node);
30+
if (!patternToMatch.test(code)) {
31+
const message = `"${code}" does not match the expected pattern`;
32+
context.report({ node, message });
33+
}
34+
if (!isInDoc(code)) {
35+
const message = `"${code}" is not documented in ${mdFile}`;
36+
context.report({ node, message });
37+
}
38+
if (!includesAnchor(code)) {
39+
const message = `${mdFile} does not have an anchor for "${code}"`;
40+
context.report({ node, message });
41+
}
42+
},
43+
};
44+
},
45+
};

tools/eslint-rules/rules-utils.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,14 @@ module.exports.isDefiningError = function(node) {
2020
node.expression.arguments.length !== 0;
2121
};
2222

23+
module.exports.isDefiningDeprecation = function(node) {
24+
return node.expression &&
25+
node.expression.type === 'CallExpression' &&
26+
node.expression.callee &&
27+
node.expression.callee.name.endsWith('deprecate') &&
28+
node.expression.arguments.length !== 0;
29+
};
30+
2331
/**
2432
* Returns true if any of the passed in modules are used in
2533
* require calls.

0 commit comments

Comments
 (0)