From db384d13ada7d9f48a7f8bf2ae92f76a4e3789aa Mon Sep 17 00:00:00 2001 From: Sebastian Good <2230835+scagood@users.noreply.github.com> Date: Tue, 10 Dec 2024 02:08:10 +0000 Subject: [PATCH] fix(no-unsupported): Correctly handle recursive objects on a per module basis (#396) --- lib/util/enumerate-property-names.js | 22 +++-- .../no-unsupported-features/node-builtins.js | 90 ++++++++++++++++++- 2 files changed, 98 insertions(+), 14 deletions(-) diff --git a/lib/util/enumerate-property-names.js b/lib/util/enumerate-property-names.js index de802c46..54fcc455 100644 --- a/lib/util/enumerate-property-names.js +++ b/lib/util/enumerate-property-names.js @@ -15,15 +15,16 @@ const unprefixNodeColon = require("./unprefix-node-colon") * Enumerate property names of a given object recursively. * @param {TraceMap} traceMap The map for APIs to enumerate. * @param {string[]} [path] The path to the current map. - * @param {WeakSet} [recursionSet] A WeakSet used to block recursion (eg Module, Module.Module, Module.Module.Module) + * @param {{ [key: string]: WeakSet }} [recursion] An object to block recursion (per module) * @returns {IterableIterator} The property names of the map. */ -function* enumeratePropertyNames( - traceMap, - path = [], - recursionSet = new WeakSet() -) { - if (recursionSet.has(traceMap)) { +function* enumeratePropertyNames(traceMap, path = [], recursion = {}) { + const recursionSet = + typeof path[0] === "string" + ? (recursion[path[0]] ??= new WeakSet()) + : undefined + + if (recursionSet?.has(traceMap)) { return } @@ -48,11 +49,8 @@ function* enumeratePropertyNames( yield childName } - yield* enumeratePropertyNames( - childValue, - childPath, - recursionSet.add(traceMap) - ) + recursionSet?.add(traceMap) + yield* enumeratePropertyNames(childValue, childPath, recursion) } } diff --git a/tests/lib/rules/no-unsupported-features/node-builtins.js b/tests/lib/rules/no-unsupported-features/node-builtins.js index 1c8295d8..626f518d 100644 --- a/tests/lib/rules/no-unsupported-features/node-builtins.js +++ b/tests/lib/rules/no-unsupported-features/node-builtins.js @@ -4,13 +4,58 @@ */ "use strict" +/** @import { Linter } from 'eslint' */ + const RuleTester = require("../../../test-helpers").RuleTester const rule = require("../../../../lib/rules/no-unsupported-features/node-builtins") +/** + * @typedef ValidTestCase + * @property {string} [name] + * @property {string} code + * @property {any} [options] + * @property {string | undefined} [filename] + * @property {boolean} [only] + * @property {Linter.LanguageOptions | undefined} [languageOptions] + * @property {{ [name: string]: any } | undefined} [settings] + */ +/** + * @typedef SuggestionOutput + * @property {string} [messageId] + * @property {string} [desc] + * @property {Record | undefined} [data] + * @property {string} output + */ +/** + * @typedef InvalidTestExtras + * @property {number | Array} errors + * @property {string | null | undefined} [output] + */ +/** + * @typedef {ValidTestCase & InvalidTestExtras} InvalidTestCase + */ +/** + * @typedef TestCaseError + * @property {string | RegExp} [message] + * @property {string} [messageId] + * @property {string | undefined} [type] + * @property {any} [data] + * @property {number | undefined} [line] + * @property {number | undefined} [column] + * @property {number | undefined} [endLine] + * @property {number | undefined} [endColumn] + * @property {SuggestionOutput[] | undefined} [suggestions] + */ +/** + * @typedef Pattern + * @property {ValidTestCase[]} [valid] + * @property {InvalidTestCase[]} [invalid] + */ + /** * Concatenate patterns. - * @param {Array<{valid:Array,invalid:Array}>} patterns The patterns to concat. - * @returns {{valid:Array,invalid:Array}} The concatenated patterns. + * @param {Pattern[]} patterns The patterns to concat. + * @returns {Pattern} The concatenated patterns. */ function concat(patterns) { const ret = { @@ -5372,6 +5417,47 @@ new RuleTester({ languageOptions: { sourceType: "module" } }).run( ], }, + //---------------------------------------------------------------------- + // timers/promises + //---------------------------------------------------------------------- + { + valid: [ + { + code: ` + import { scheduler } from 'node:timers/promises'; + await scheduler.wait( 1000 ); + `, + options: [ + { + version: ">= 20.0.0", + ignores: ["timers/promises.scheduler.wait"], + }, + ], + languageOptions: { ecmaVersion: "latest" }, + }, + ], + invalid: [ + { + code: ` + import { scheduler } from 'node:timers/promises'; + await scheduler.wait( 1000 ); + `, + options: [{ version: ">= 20.0.0" }], + languageOptions: { ecmaVersion: "latest" }, + + errors: [ + { + messageId: "not-supported-yet", + data: { + name: "timers/promises.scheduler.wait", + version: ">= 20.0.0", + }, + }, + ], + }, + ], + }, + { valid: [ {