From e9139b6883f83983092a7a7c3116d847343cbc80 Mon Sep 17 00:00:00 2001 From: Antoine du HAMEL Date: Fri, 29 May 2020 11:41:36 +0200 Subject: [PATCH] Add lint rule for runtime deprecations --- ...est-eslint-documented-deprecation-codes.js | 45 +++++++++++++++++++ .../documented-deprecation-codes.js | 45 +++++++++++++++++++ tools/eslint-rules/rules-utils.js | 8 ++++ 3 files changed, 98 insertions(+) create mode 100644 test/parallel/test-eslint-documented-deprecation-codes.js create mode 100644 tools/eslint-rules/documented-deprecation-codes.js diff --git a/test/parallel/test-eslint-documented-deprecation-codes.js b/test/parallel/test-eslint-documented-deprecation-codes.js new file mode 100644 index 00000000000000..30cb214e666695 --- /dev/null +++ b/test/parallel/test-eslint-documented-deprecation-codes.js @@ -0,0 +1,45 @@ +'use strict'; + +const common = require('../common'); +if (!common.hasCrypto) + common.skip('missing crypto'); +common.skipIfEslintMissing(); + +const RuleTester = require('../../tools/node_modules/eslint').RuleTester; +const rule = require('../../tools/eslint-rules/documented-deprecation-codes'); + +const mdFile = 'doc/api/deprecations.md'; + +const invalidCode = 'UNDOCUMENTED INVALID CODE'; + +new RuleTester().run('documented-deprecation-codes', rule, { + valid: [ + ` + deprecate(function() { + return this.getHeaders(); + }, 'OutgoingMessage.prototype._headers is deprecated', 'DEP0066') + ` + ], + invalid: [ + { + code: ` + deprecate(function foo(){}, 'bar', '${invalidCode}'); + `, + errors: [ + { + message: `"${invalidCode}" does not match the expected pattern`, + line: 2 + }, + { + message: `"${invalidCode}" is not documented in ${mdFile}`, + line: 2 + }, + { + message: + `${mdFile} does not have an anchor for "${invalidCode}"`, + line: 2 + } + ] + } + ] +}); diff --git a/tools/eslint-rules/documented-deprecation-codes.js b/tools/eslint-rules/documented-deprecation-codes.js new file mode 100644 index 00000000000000..b950f4553be74f --- /dev/null +++ b/tools/eslint-rules/documented-deprecation-codes.js @@ -0,0 +1,45 @@ +'use strict'; + +const fs = require('fs'); +const path = require('path'); +const { isDefiningDeprecation } = require('./rules-utils.js'); + +const patternToMatch = /^DEP\d+$/; + +const mdFile = 'doc/api/deprecations.md'; +const doc = fs.readFileSync(path.resolve(__dirname, '../..', mdFile), 'utf8'); + +function isInDoc(code) { + return doc.includes(`### ${code}:`); +} + +function includesAnchor(code) { + return doc.includes(``); +} + +function getDeprecationCode(node) { + return node.expression.arguments[2].value; +} + +module.exports = { + create: function(context) { + return { + ExpressionStatement: function(node) { + if (!isDefiningDeprecation(node) || !getDeprecationCode(node)) return; + const code = getDeprecationCode(node); + if (!patternToMatch.test(code)) { + const message = `"${code}" does not match the expected pattern`; + context.report({ node, message }); + } + if (!isInDoc(code)) { + const message = `"${code}" is not documented in ${mdFile}`; + context.report({ node, message }); + } + if (!includesAnchor(code)) { + const message = `${mdFile} does not have an anchor for "${code}"`; + context.report({ node, message }); + } + }, + }; + }, +}; diff --git a/tools/eslint-rules/rules-utils.js b/tools/eslint-rules/rules-utils.js index 462ab7c2ff3ab8..5bfefccb99be4c 100644 --- a/tools/eslint-rules/rules-utils.js +++ b/tools/eslint-rules/rules-utils.js @@ -20,6 +20,14 @@ module.exports.isDefiningError = function(node) { node.expression.arguments.length !== 0; }; +module.exports.isDefiningDeprecation = function(node) { + return node.expression && + node.expression.type === 'CallExpression' && + node.expression.callee && + node.expression.callee.name.endsWith('deprecate') && + node.expression.arguments.length !== 0; +}; + /** * Returns true if any of the passed in modules are used in * require calls.