diff --git a/lib/internal/errors.js b/lib/internal/errors.js index 48eb6b89356ac8..5ac0fb9a5457f8 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 00000000000000..94e81ff3abaecc --- /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 00000000000000..471452d67a04f2 --- /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 }); + } + } + }; + } +};