From f5883ede5a7ad2167d381ac16ec1ae81ba7bef78 Mon Sep 17 00:00:00 2001 From: James M Snell Date: Tue, 24 Oct 2017 10:57:21 -0700 Subject: [PATCH] tools: add eslint rule for documented errors PR-URL: https://github.com/nodejs/node/pull/16450 Reviewed-By: Anatoli Papirovski Reviewed-By: Refael Ackermann Reviewed-By: Colin Ihrig Reviewed-By: Teddy Katz --- lib/internal/errors.js | 1 + .../parallel/test-eslint-documented-errors.js | 34 ++++++++++++++ tools/eslint-rules/documented-errors.js | 46 +++++++++++++++++++ 3 files changed, 81 insertions(+) create mode 100644 test/parallel/test-eslint-documented-errors.js create mode 100644 tools/eslint-rules/documented-errors.js diff --git a/lib/internal/errors.js b/lib/internal/errors.js index 33560d0865..f539cdc955 100644 --- a/lib/internal/errors.js +++ b/lib/internal/errors.js @@ -1,3 +1,4 @@ +/* eslint documented-errors: "error" */ /* eslint alphabetize-errors: "error" */ 'use strict'; diff --git a/test/parallel/test-eslint-documented-errors.js b/test/parallel/test-eslint-documented-errors.js new file mode 100644 index 0000000000..94e81ff3ab --- /dev/null +++ b/test/parallel/test-eslint-documented-errors.js @@ -0,0 +1,34 @@ +'use strict'; + +require('../common'); + +const RuleTester = require('../../tools/eslint').RuleTester; +const rule = require('../../tools/eslint-rules/documented-errors'); + +const invalidCode = 'UNDOCUMENTED ERROR CODE'; + +new RuleTester().run('documented-errors', rule, { + valid: [ + ` + E('ERR_ASSERTION', 'foo'); + ` + ], + invalid: [ + { + code: ` + E('${invalidCode}', 'bar'); + `, + errors: [ + { + message: `"${invalidCode}" is not documented in doc/api/errors.md`, + line: 2 + }, + { + message: + `doc/api/errors.md does not have an anchor for "${invalidCode}"`, + line: 2 + } + ] + } + ] +}); diff --git a/tools/eslint-rules/documented-errors.js b/tools/eslint-rules/documented-errors.js new file mode 100644 index 0000000000..471452d67a --- /dev/null +++ b/tools/eslint-rules/documented-errors.js @@ -0,0 +1,46 @@ +'use strict'; + +const fs = require('fs'); +const path = require('path'); + +const doc = fs.readFileSync(path.resolve(__dirname, '../../doc/api/errors.md'), + 'utf8'); + +function isInDoc(code) { + return doc.match(`### ${code}`) != null; +} + +function includesAnchor(code) { + return doc.match(``) != null; +} + +function errorForNode(node) { + return node.expression.arguments[0].value; +} + +function isDefiningError(node) { + return node.expression && + node.expression.type === 'CallExpression' && + node.expression.callee && + node.expression.callee.name === 'E'; +} + +module.exports = { + create: function(context) { + return { + ExpressionStatement: function(node) { + if (!isDefiningError(node)) return; + const code = errorForNode(node); + if (!isInDoc(code)) { + const message = `"${code}" is not documented in doc/api/errors.md`; + context.report({ node, message }); + } + if (!includesAnchor(code)) { + const message = + `doc/api/errors.md does not have an anchor for "${code}"`; + context.report({ node, message }); + } + } + }; + } +};