From 5e5af2947f3ddbdde208a19e8a0d16ebdd123d2c Mon Sep 17 00:00:00 2001 From: Antoine du Hamel Date: Thu, 17 Oct 2024 12:37:54 +0200 Subject: [PATCH] tools: add `polyfilled` option to `prefer-primordials` rule MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PR-URL: https://github.com/nodejs/node/pull/55318 Reviewed-By: Michaƫl Zasso --- .../test-eslint-prefer-primordials.js | 16 ++++++++++++++ tools/eslint-rules/prefer-primordials.js | 22 +++++++++++++++++++ 2 files changed, 38 insertions(+) diff --git a/test/parallel/test-eslint-prefer-primordials.js b/test/parallel/test-eslint-prefer-primordials.js index 61c84cbaddf..b6633c08e56 100644 --- a/test/parallel/test-eslint-prefer-primordials.js +++ b/test/parallel/test-eslint-prefer-primordials.js @@ -177,6 +177,22 @@ new RuleTester({ options: [{ name: 'Symbol' }], errors: [{ message: /const { SymbolIterator } = primordials/ }] }, + { + code: ` + const { SymbolAsyncDispose } = primordials; + const a = { [SymbolAsyncDispose] () {} } + `, + options: [{ name: 'Symbol', polyfilled: ['asyncDispose', 'dispose'] }], + errors: [{ message: /const { SymbolAsyncDispose } = require\("internal\/util"\)/ }] + }, + { + code: ` + const { SymbolDispose } = primordials; + const a = { [SymbolDispose] () {} } + `, + options: [{ name: 'Symbol', polyfilled: ['asyncDispose', 'dispose'] }], + errors: [{ message: /const { SymbolDispose } = require\("internal\/util"\)/ }] + }, { code: ` const { ObjectDefineProperty, Symbol } = primordials; diff --git a/tools/eslint-rules/prefer-primordials.js b/tools/eslint-rules/prefer-primordials.js index 48b351b46ae..4f109748716 100644 --- a/tools/eslint-rules/prefer-primordials.js +++ b/tools/eslint-rules/prefer-primordials.js @@ -74,6 +74,7 @@ module.exports = { meta: { messages: { error: 'Use `const { {{name}} } = primordials;` instead of the global.', + errorPolyfill: 'Use `const { {{name}} } = require("internal/util");` instead of the primordial.', }, schema: { type: 'array', @@ -88,6 +89,10 @@ module.exports = { items: { type: 'string' }, }, into: { type: 'string' }, + polyfilled: { + type: 'array', + items: { type: 'string' }, + }, }, additionalProperties: false, }, @@ -99,6 +104,7 @@ module.exports = { const nameMap = new Map(); const renameMap = new Map(); + const polyfilledSet = new Set(); for (const option of context.options) { const names = option.ignore || []; @@ -109,6 +115,11 @@ module.exports = { if (option.into) { renameMap.set(option.name, option.into); } + if (option.polyfilled) { + for (const propertyName of option.polyfilled) { + polyfilledSet.add(`${option.name}${propertyName[0].toUpperCase()}${propertyName.slice(1)}`); + } + } } let reported; @@ -186,6 +197,17 @@ module.exports = { }, VariableDeclarator(node) { const name = node.init?.name; + if (name === 'primordials' && node.id.type === 'ObjectPattern') { + const name = node.id.properties.find(({ key }) => polyfilledSet.has(key.name))?.key.name; + if (name) { + context.report({ + node, + messageId: 'errorPolyfill', + data: { name }, + }); + return; + } + } if (name !== undefined && isTarget(nameMap, name) && node.id.type === 'Identifier' && !globalScope.set.get(name)?.defs.length) {