From f248bf0a9871e1577392076fcdd50bab87ecc2ea Mon Sep 17 00:00:00 2001 From: Sebastian Good <2230835+scagood@users.noreply.github.com> Date: Tue, 4 Mar 2025 19:27:58 +0000 Subject: [PATCH] =?UTF-8?q?Revert=20"feat:=20add=20support=20for=20ignorin?= =?UTF-8?q?g=20sync=20methods=20from=20certain=20locations=20(#=E2=80=A6"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit 5544f20f113e59d6789a249dc24df73fdc354fa1. --- docs/rules/no-sync.md | 57 ------ lib/rules/no-sync.js | 114 +----------- lib/util/get-full-type-name.js | 47 ----- lib/util/get-parser-services.js | 24 --- lib/util/get-type-of-node.js | 21 --- package.json | 10 +- tests/fixtures/no-sync/base/file.ts | 1 - tests/fixtures/no-sync/base/tsconfig.json | 10 - tests/fixtures/no-sync/file.ts | 1 - tests/fixtures/no-sync/ignore-package/file.ts | 1 - .../node_modules/aaa/index.d.ts | 1 - .../ignore-package/node_modules/aaa/index.js | 0 .../node_modules/aaa/package.json | 6 - .../no-sync/ignore-package/package.json | 7 - .../no-sync/ignore-package/tsconfig.json | 10 - tests/fixtures/no-sync/tsconfig.json | 10 - tests/lib/rules/no-sync.js | 172 +----------------- tests/test-helpers.js | 60 ------ 18 files changed, 9 insertions(+), 543 deletions(-) delete mode 100644 lib/util/get-full-type-name.js delete mode 100644 lib/util/get-parser-services.js delete mode 100644 lib/util/get-type-of-node.js delete mode 100644 tests/fixtures/no-sync/base/file.ts delete mode 100644 tests/fixtures/no-sync/base/tsconfig.json delete mode 100644 tests/fixtures/no-sync/file.ts delete mode 100644 tests/fixtures/no-sync/ignore-package/file.ts delete mode 100644 tests/fixtures/no-sync/ignore-package/node_modules/aaa/index.d.ts delete mode 100644 tests/fixtures/no-sync/ignore-package/node_modules/aaa/index.js delete mode 100644 tests/fixtures/no-sync/ignore-package/node_modules/aaa/package.json delete mode 100644 tests/fixtures/no-sync/ignore-package/package.json delete mode 100644 tests/fixtures/no-sync/ignore-package/tsconfig.json delete mode 100644 tests/fixtures/no-sync/tsconfig.json diff --git a/docs/rules/no-sync.md b/docs/rules/no-sync.md index 38dea638..dc400974 100644 --- a/docs/rules/no-sync.md +++ b/docs/rules/no-sync.md @@ -61,7 +61,6 @@ fs.readFileSync(somePath).toString(); #### ignores You can `ignore` specific function names using this option. -Additionally, if you are using TypeScript you can optionally specify where the function is declared. Examples of **incorrect** code for this rule with the `{ ignores: ['readFileSync'] }` option: @@ -79,62 +78,6 @@ Examples of **correct** code for this rule with the `{ ignores: ['readFileSync'] fs.readFileSync(somePath); ``` -##### Advanced (TypeScript only) - -You can provide a list of specifiers to ignore. Specifiers are typed as follows: - -```ts -type Specifier = -| string -| { - from: "file"; - path?: string; - name?: string[]; - } -| { - from: "package"; - package?: string; - name?: string[]; - } -| { - from: "lib"; - name?: string[]; - } -``` - -###### From a file - -Examples of **correct** code for this rule with the ignore file specifier: - -```js -/*eslint n/no-sync: ["error", { ignores: [{ from: 'file', path: './foo.ts' }]}] */ - -import { fooSync } from "./foo" -fooSync() -``` - -###### From a package - -Examples of **correct** code for this rule with the ignore package specifier: - -```js -/*eslint n/no-sync: ["error", { ignores: [{ from: 'package', package: 'effect' }]}] */ - -import { Effect } from "effect" -const value = Effect.runSync(Effect.succeed(42)) -``` - -###### From the TypeScript library - -Examples of **correct** code for this rule with the ignore lib specifier: - -```js -/*eslint n/no-sync: ["error", { ignores: [{ from: 'lib' }]}] */ - -const stylesheet = new CSSStyleSheet() -stylesheet.replaceSync("body { font-size: 1.4em; } p { color: red; }") -``` - ## 🔎 Implementation - [Rule source](../../lib/rules/no-sync.js) diff --git a/lib/rules/no-sync.js b/lib/rules/no-sync.js index 6e9529c8..fb0de8e6 100644 --- a/lib/rules/no-sync.js +++ b/lib/rules/no-sync.js @@ -4,14 +4,6 @@ */ "use strict" -const typeMatchesSpecifier = - /** @type {import('ts-declaration-location').default} */ ( - /** @type {unknown} */ (require("ts-declaration-location")) - ) -const getTypeOfNode = require("../util/get-type-of-node") -const getParserServices = require("../util/get-parser-services") -const getFullTypeName = require("../util/get-full-type-name") - const selectors = [ // fs.readFileSync() // readFileSync.call(null, 'path') @@ -40,56 +32,7 @@ module.exports = { }, ignores: { type: "array", - items: { - oneOf: [ - { type: "string" }, - { - type: "object", - properties: { - from: { const: "file" }, - path: { - type: "string", - }, - name: { - type: "array", - items: { - type: "string", - }, - }, - }, - additionalProperties: false, - }, - { - type: "object", - properties: { - from: { const: "lib" }, - name: { - type: "array", - items: { - type: "string", - }, - }, - }, - additionalProperties: false, - }, - { - type: "object", - properties: { - from: { const: "package" }, - package: { - type: "string", - }, - name: { - type: "array", - items: { - type: "string", - }, - }, - }, - additionalProperties: false, - }, - ], - }, + items: { type: "string" }, default: [], }, }, @@ -114,64 +57,15 @@ module.exports = { * @returns {void} */ [selector.join(",")](node) { - const parserServices = getParserServices(context) - - /** - * @type {import('typescript').Type | undefined | null} - */ - let type = undefined - - /** - * @type {string | undefined | null} - */ - let fullName = undefined - - for (const ignore of ignores) { - if (typeof ignore === "string") { - if (ignore === node.name) { - return - } - - continue - } - - if ( - parserServices === null || - parserServices.program === null - ) { - throw new Error( - 'TypeScript parser services not available. Rule "n/no-sync" is configured to use "ignores" option with a non-string value. This requires TypeScript parser services to be available.' - ) - } - - type = - type === undefined - ? getTypeOfNode(node, parserServices) - : type - - fullName = - fullName === undefined - ? getFullTypeName(type) - : fullName - - if ( - typeMatchesSpecifier( - parserServices.program, - ignore, - type - ) && - (ignore.name === undefined || - ignore.name.includes(fullName ?? node.name)) - ) { - return - } + if (ignores.includes(node.name)) { + return } context.report({ node: node.parent, messageId: "noSync", data: { - propertyName: fullName ?? node.name, + propertyName: node.name, }, }) }, diff --git a/lib/util/get-full-type-name.js b/lib/util/get-full-type-name.js deleted file mode 100644 index 9e5ee7bf..00000000 --- a/lib/util/get-full-type-name.js +++ /dev/null @@ -1,47 +0,0 @@ -"use strict" - -const ts = (() => { - try { - // eslint-disable-next-line n/no-unpublished-require - return require("typescript") - } catch { - return null - } -})() - -/** - * @param {import('typescript').Type | null} type - * @returns {string | null} - */ -module.exports = function getFullTypeName(type) { - if (ts === null || type === null) { - return null - } - - /** - * @type {string[]} - */ - let nameParts = [] - let currentSymbol = type.getSymbol() - while (currentSymbol !== undefined) { - if ( - currentSymbol.valueDeclaration?.kind === ts.SyntaxKind.SourceFile || - currentSymbol.valueDeclaration?.kind === - ts.SyntaxKind.ModuleDeclaration - ) { - break - } - - nameParts.unshift(currentSymbol.getName()) - currentSymbol = - /** @type {import('typescript').Symbol & {parent: import('typescript').Symbol | undefined}} */ ( - currentSymbol - ).parent - } - - if (nameParts.length === 0) { - return null - } - - return nameParts.join(".") -} diff --git a/lib/util/get-parser-services.js b/lib/util/get-parser-services.js deleted file mode 100644 index 1d0be646..00000000 --- a/lib/util/get-parser-services.js +++ /dev/null @@ -1,24 +0,0 @@ -"use strict" - -const { - getParserServices: getParserServicesFromTsEslint, -} = require("@typescript-eslint/utils/eslint-utils") - -/** - * Get the TypeScript parser services. - * If TypeScript isn't present, returns `null`. - * - * @param {import('eslint').Rule.RuleContext} context - rule context - * @returns {import('@typescript-eslint/parser').ParserServices | null} - */ -module.exports = function getParserServices(context) { - // Not using tseslint parser? - if ( - context.sourceCode.parserServices?.esTreeNodeToTSNodeMap == null || - context.sourceCode.parserServices.tsNodeToESTreeNodeMap == null - ) { - return null - } - - return getParserServicesFromTsEslint(/** @type {any} */ (context), true) -} diff --git a/lib/util/get-type-of-node.js b/lib/util/get-type-of-node.js deleted file mode 100644 index ca5050f0..00000000 --- a/lib/util/get-type-of-node.js +++ /dev/null @@ -1,21 +0,0 @@ -"use strict" - -/** - * Get the type of a node. - * If TypeScript isn't present, returns `null`. - * - * @param {import('estree').Node} node - A node - * @param {import('@typescript-eslint/parser').ParserServices} parserServices - A parserServices - * @returns {import('typescript').Type | null} - */ -module.exports = function getTypeOfNode(node, parserServices) { - const { esTreeNodeToTSNodeMap, program } = parserServices - if (program === null) { - return null - } - const tsNode = esTreeNodeToTSNodeMap.get(/** @type {any} */ (node)) - const checker = program.getTypeChecker() - const nodeType = checker.getTypeAtLocation(tsNode) - const constrained = checker.getBaseConstraintOfType(nodeType) - return constrained ?? nodeType -} diff --git a/package.json b/package.json index 4d891ccb..83a67a32 100644 --- a/package.json +++ b/package.json @@ -18,23 +18,21 @@ }, "dependencies": { "@eslint-community/eslint-utils": "^4.4.1", - "@typescript-eslint/utils": "^8.21.0", "enhanced-resolve": "^5.17.1", "eslint-plugin-es-x": "^7.8.0", "get-tsconfig": "^4.8.1", "globals": "^15.11.0", "ignore": "^5.3.2", "minimatch": "^9.0.5", - "semver": "^7.6.3", - "ts-declaration-location": "^1.0.5" + "semver": "^7.6.3" }, "devDependencies": { "@eslint/js": "^9.14.0", "@types/eslint": "^9.6.1", "@types/estree": "^1.0.6", "@types/node": "^20.17.5", - "@typescript-eslint/parser": "^8.21.0", - "@typescript-eslint/typescript-estree": "^8.21.0", + "@typescript-eslint/parser": "^8.12.2", + "@typescript-eslint/typescript-estree": "^8.12.2", "eslint": "^9.14.0", "eslint-config-prettier": "^9.1.0", "eslint-doc-generator": "^1.7.1", @@ -54,7 +52,7 @@ "rimraf": "^5.0.10", "ts-ignore-import": "^4.0.1", "type-fest": "^4.26.1", - "typescript": "^5.7" + "typescript": "~5.6" }, "scripts": { "build": "node scripts/update", diff --git a/tests/fixtures/no-sync/base/file.ts b/tests/fixtures/no-sync/base/file.ts deleted file mode 100644 index 182a8503..00000000 --- a/tests/fixtures/no-sync/base/file.ts +++ /dev/null @@ -1 +0,0 @@ -// File needs to exists diff --git a/tests/fixtures/no-sync/base/tsconfig.json b/tests/fixtures/no-sync/base/tsconfig.json deleted file mode 100644 index 5b217cb9..00000000 --- a/tests/fixtures/no-sync/base/tsconfig.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "compilerOptions": { - "target": "ESNext", - "module": "ESNext", - "moduleResolution": "Bundler", - "strict": true, - "skipLibCheck": true - }, - "include": ["**/*"] -} diff --git a/tests/fixtures/no-sync/file.ts b/tests/fixtures/no-sync/file.ts deleted file mode 100644 index 182a8503..00000000 --- a/tests/fixtures/no-sync/file.ts +++ /dev/null @@ -1 +0,0 @@ -// File needs to exists diff --git a/tests/fixtures/no-sync/ignore-package/file.ts b/tests/fixtures/no-sync/ignore-package/file.ts deleted file mode 100644 index 182a8503..00000000 --- a/tests/fixtures/no-sync/ignore-package/file.ts +++ /dev/null @@ -1 +0,0 @@ -// File needs to exists diff --git a/tests/fixtures/no-sync/ignore-package/node_modules/aaa/index.d.ts b/tests/fixtures/no-sync/ignore-package/node_modules/aaa/index.d.ts deleted file mode 100644 index 38f18aef..00000000 --- a/tests/fixtures/no-sync/ignore-package/node_modules/aaa/index.d.ts +++ /dev/null @@ -1 +0,0 @@ -export function fooSync(): void; diff --git a/tests/fixtures/no-sync/ignore-package/node_modules/aaa/index.js b/tests/fixtures/no-sync/ignore-package/node_modules/aaa/index.js deleted file mode 100644 index e69de29b..00000000 diff --git a/tests/fixtures/no-sync/ignore-package/node_modules/aaa/package.json b/tests/fixtures/no-sync/ignore-package/node_modules/aaa/package.json deleted file mode 100644 index 39437d0a..00000000 --- a/tests/fixtures/no-sync/ignore-package/node_modules/aaa/package.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "name": "aaa", - "version": "0.0.0", - "main": "./index.js", - "types": "./index.d.ts" -} diff --git a/tests/fixtures/no-sync/ignore-package/package.json b/tests/fixtures/no-sync/ignore-package/package.json deleted file mode 100644 index 5c6c2690..00000000 --- a/tests/fixtures/no-sync/ignore-package/package.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "name": "test", - "version": "0.0.0", - "dependencies": { - "aaa": "0.0.0" - } -} diff --git a/tests/fixtures/no-sync/ignore-package/tsconfig.json b/tests/fixtures/no-sync/ignore-package/tsconfig.json deleted file mode 100644 index 5b217cb9..00000000 --- a/tests/fixtures/no-sync/ignore-package/tsconfig.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "compilerOptions": { - "target": "ESNext", - "module": "ESNext", - "moduleResolution": "Bundler", - "strict": true, - "skipLibCheck": true - }, - "include": ["**/*"] -} diff --git a/tests/fixtures/no-sync/tsconfig.json b/tests/fixtures/no-sync/tsconfig.json deleted file mode 100644 index 5b217cb9..00000000 --- a/tests/fixtures/no-sync/tsconfig.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "compilerOptions": { - "target": "ESNext", - "module": "ESNext", - "moduleResolution": "Bundler", - "strict": true, - "skipLibCheck": true - }, - "include": ["**/*"] -} diff --git a/tests/lib/rules/no-sync.js b/tests/lib/rules/no-sync.js index 9fb8c33d..0c7141ee 100644 --- a/tests/lib/rules/no-sync.js +++ b/tests/lib/rules/no-sync.js @@ -4,7 +4,7 @@ */ "use strict" -const { RuleTester, TsRuleTester } = require("#test-helpers") +const RuleTester = require("#test-helpers").RuleTester const rule = require("../../../lib/rules/no-sync") new RuleTester().run("no-sync", rule, { @@ -149,173 +149,3 @@ new RuleTester().run("no-sync", rule, { }, ], }) - -new (TsRuleTester("no-sync/base").run)("no-sync", rule, { - valid: [ - { - code: ` -declare function fooSync(): void; -fooSync(); -`, - options: [ - { - ignores: [ - { - from: "file", - }, - ], - }, - ], - }, - { - code: ` -declare function fooSync(): void; -fooSync(); -`, - options: [ - { - ignores: [ - { - from: "file", - name: ["fooSync"], - }, - ], - }, - ], - }, - { - code: ` -const stylesheet = new CSSStyleSheet(); -stylesheet.replaceSync("body { font-size: 1.4em; } p { color: red; }"); -`, - options: [ - { - ignores: [ - { - from: "lib", - name: ["CSSStyleSheet.replaceSync"], - }, - ], - }, - ], - }, - ], - invalid: [ - { - code: ` -declare function fooSync(): void; -fooSync(); -`, - options: [ - { - ignores: [ - { - from: "file", - path: "**/bar.ts", - }, - ], - }, - ], - errors: [ - { - messageId: "noSync", - data: { propertyName: "fooSync" }, - type: "CallExpression", - }, - ], - }, - { - code: ` -declare function fooSync(): void; -fooSync(); -`, - options: [ - { - ignores: [ - { - from: "file", - name: ["barSync"], - }, - ], - }, - ], - errors: [ - { - messageId: "noSync", - data: { propertyName: "fooSync" }, - type: "CallExpression", - }, - ], - }, - { - code: ` -const stylesheet = new CSSStyleSheet(); -stylesheet.replaceSync("body { font-size: 1.4em; } p { color: red; }"); -`, - options: [ - { - ignores: [ - { - from: "file", - name: ["CSSStyleSheet.replaceSync"], - }, - ], - }, - ], - errors: [ - { - messageId: "noSync", - data: { propertyName: "CSSStyleSheet.replaceSync" }, - type: "MemberExpression", - }, - ], - }, - ], -}) - -new (TsRuleTester("no-sync/ignore-package").run)("no-sync", rule, { - valid: [ - { - code: ` -import { fooSync } from "aaa"; -fooSync(); -`, - options: [ - { - ignores: [ - { - from: "package", - package: "aaa", - name: ["fooSync"], - }, - ], - }, - ], - }, - ], - invalid: [ - { - code: ` -import { fooSync } from "aaa"; -fooSync(); -`, - options: [ - { - ignores: [ - { - from: "file", - name: ["fooSync"], - }, - ], - }, - ], - errors: [ - { - messageId: "noSync", - data: { propertyName: "fooSync" }, - type: "CallExpression", - }, - ], - }, - ], -}) diff --git a/tests/test-helpers.js b/tests/test-helpers.js index 69ce7abd..bff30126 100644 --- a/tests/test-helpers.js +++ b/tests/test-helpers.js @@ -3,15 +3,12 @@ * @author 唯然 */ "use strict" - -const path = require("path") const eslintVersion = require("eslint/package.json").version const { RuleTester } = require("eslint") const { FlatRuleTester } = require("eslint/use-at-your-own-risk") const globals = require("globals") const semverSatisfies = require("semver/functions/satisfies") const os = require("os") -const typescriptParser = require("@typescript-eslint/parser") // greater than or equal to ESLint v9 exports.gteEslintV9 = semverSatisfies(eslintVersion, ">=9", { @@ -36,26 +33,6 @@ const defaultConfig = { globals: { ...globals.es2015, ...globals.node }, }, } - -/** - * @param {string} fixturePath - Path to the fixture directory relative to the fixtures directory - * @returns - */ -function getTsConfig(fixturePath) { - return { - languageOptions: { - parser: typescriptParser, - parserOptions: { - tsconfigRootDir: path.join(__dirname, "fixtures", fixturePath), - projectService: { - // Ensure we're not using the default project - maximumDefaultProjectFileMatchCount_THIS_WILL_SLOW_DOWN_LINTING: 0, - }, - }, - }, - } -} - exports.RuleTester = function (config = defaultConfig) { if (config.languageOptions.env?.node === false) config.languageOptions.globals = config.languageOptions.globals || {} @@ -78,31 +55,6 @@ exports.RuleTester = function (config = defaultConfig) { return ruleTester } -/** - * @param {string | import('eslint').Linter.Config} configOrFixturePath - * @returns - */ -exports.TsRuleTester = function (configOrFixturePath) { - const config = - typeof configOrFixturePath === "object" - ? configOrFixturePath - : getTsConfig(configOrFixturePath) - - const ruleTester = exports.RuleTester.call(this, config) - const $run = ruleTester.run.bind(ruleTester) - ruleTester.run = function (name, rule, tests) { - tests.valid = tests.valid.map(setTsFilename) - tests.invalid = tests.invalid.map(setTsFilename) - - $run(name, rule, tests) - } - return ruleTester -} -Object.setPrototypeOf( - exports.TsRuleTester.prototype, - exports.RuleTester.prototype -) - // support skip in tests function shouldRun(item) { if (typeof item === "string") return true @@ -111,15 +63,3 @@ function shouldRun(item) { delete item.skip return skip === void 0 || skip === false } - -function setTsFilename(item) { - if (typeof item === "string") { - return { - code: item, - filename: "file.ts", - } - } - - item.filename ??= "file.ts" - return item -}