From aace6c262621fb47c15fb02acc3633bc90d6fe5f Mon Sep 17 00:00:00 2001 From: Antoine du Hamel Date: Sat, 19 Feb 2022 18:14:09 +0100 Subject: [PATCH] tools: lint deprecation codes Add a rule to make sure deprecation codes are in order. PR-URL: https://github.com/nodejs/node/pull/41992 Reviewed-By: Richard Lau Reviewed-By: James M Snell --- doc/api/deprecations.md | 12 ++- test/doctool/test-deprecation-codes.js | 28 ++++++ ...est-eslint-documented-deprecation-codes.js | 42 +++++++++ tools/doc/deprecationCodes.mjs | 92 +++++++++++++++++++ .../documented-deprecation-codes.js | 37 ++++++++ tools/eslint-rules/rules-utils.js | 8 ++ 6 files changed, 215 insertions(+), 4 deletions(-) create mode 100644 test/doctool/test-deprecation-codes.js create mode 100644 test/parallel/test-eslint-documented-deprecation-codes.js create mode 100644 tools/doc/deprecationCodes.mjs create mode 100644 tools/eslint-rules/documented-deprecation-codes.js diff --git a/doc/api/deprecations.md b/doc/api/deprecations.md index 6837217719c00e..e6fea6582d6156 100644 --- a/doc/api/deprecations.md +++ b/doc/api/deprecations.md @@ -1822,6 +1822,10 @@ Type: End-of-Life `runInAsyncIdScope` doesn't emit the `'before'` or `'after'` event and can thus cause a lot of issues. See . + + + + ### DEP0089: `require('assert')` +### DEP0115: `crypto.prng()`, `crypto.pseudoRandomBytes()`, `crypto.rng()` + - - Type: Documentation-only (supports [`--pending-deprecation`][]) + + In recent versions of Node.js, there is no difference between [`crypto.randomBytes()`][] and `crypto.pseudoRandomBytes()`. The latter is deprecated along with the undocumented aliases `crypto.prng()` and diff --git a/test/doctool/test-deprecation-codes.js b/test/doctool/test-deprecation-codes.js new file mode 100644 index 00000000000000..8e7ea37d242aa5 --- /dev/null +++ b/test/doctool/test-deprecation-codes.js @@ -0,0 +1,28 @@ +'use strict'; + +require('../common'); +const path = require('path'); +const { spawn } = require('child_process'); + +const script = path.join( + __dirname, + '..', + '..', + 'tools', + 'doc', + 'deprecationCodes.mjs' +); + +const mdPath = path.join( + __dirname, + '..', + '..', + 'doc', + 'api', + 'deprecations.md' +); + +const cp = spawn(process.execPath, [script, mdPath], { encoding: 'utf-8', stdio: 'inherit' }); + +cp.on('error', (err) => { throw err; }); +cp.on('exit', (code) => process.exit(code)); 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..45fec7786a28ac --- /dev/null +++ b/test/parallel/test-eslint-documented-deprecation-codes.js @@ -0,0 +1,42 @@ +'use strict'; + +const common = require('../common'); +if (!common.hasCrypto) + common.skip('missing crypto'); +if (!common.hasIntl) + common.skip('missing Intl'); +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 + }, + ] + }, + ] +}); diff --git a/tools/doc/deprecationCodes.mjs b/tools/doc/deprecationCodes.mjs new file mode 100644 index 00000000000000..6715bb04b60c26 --- /dev/null +++ b/tools/doc/deprecationCodes.mjs @@ -0,0 +1,92 @@ +import fs from 'fs'; +import { resolve } from 'path'; +import assert from 'assert'; + +import { unified } from 'unified'; +import remarkParse from 'remark-parse'; + +const source = resolve(process.argv[2]); + +const skipDeprecationComment = /^$/; + +const generateDeprecationCode = (codeAsNumber) => + `DEP${codeAsNumber.toString().padStart(4, '0')}`; + +const addMarkdownPathToErrorStack = (error, node) => { + const { line, column } = node.position.start; + const [header, ...lines] = error.stack.split('\n'); + error.stack = + header + + `\n at (${source}:${line}:${column})\n` + + lines.join('\n'); + return error; +}; + +const testHeading = (headingNode, expectedDeprecationCode) => { + try { + assert.strictEqual( + headingNode?.children[0]?.value.substring(0, 9), + `${expectedDeprecationCode}: `, + 'Ill-formed or out-of-order deprecation code.' + ); + } catch (e) { + throw addMarkdownPathToErrorStack(e, headingNode); + } +}; + +const testYAMLComment = (commentNode) => { + try { + assert.match( + commentNode?.value?.substring(0, 21), + /^