Skip to content

Enhancement: [no-deprecated] Add 'allow' option for specific types or values #9899

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
4 tasks done
BurningEnlightenment opened this issue Aug 28, 2024 · 11 comments · Fixed by #10585
Closed
4 tasks done
Labels
accepting prs Go ahead, send a pull request that resolves this issue enhancement: plugin rule option New rule option for an existing eslint-plugin rule locked due to age Please open a new issue if you'd like to say more. See https://typescript-eslint.io/contributing. package: eslint-plugin Issues related to @typescript-eslint/eslint-plugin

Comments

@BurningEnlightenment
Copy link

Before You File a Proposal Please Confirm You Have Done The Following...

My proposal is suitable for this project

  • I believe my proposal would be useful to the broader TypeScript community (meaning it is not a niche proposal).

Link to the rule's documentation

https://typescript-eslint.io/rules/no-deprecated/

Description

I find it very useful to flag and address deprecated API usage during the dependency upgrade cycle. Whence I'd like to enforce the rule for the usage of my dependencies.
However, for my own code base I want to follow a gradual deprecation cycle, i.e. I want to introduce an updated API and inform users writing new code about the updated API via a @deprecated JSDoc comment. Afterwards I'd phase the deprecated API out and remove it in the end.
The current rule is unsuited for the combined requirements, so I propose a boolean option ignoreUserDeprecations.

Fail

/** @deprecated Use apiV2 instead. */
async function apiV1(): Promise<void> { /*…*/ }

async function apiV2(): Promise<void> { /*…*/ }

await apiV1();

/* >===================================< */

import { parse } from 'node:url';

// 'parse' is deprecated. Use the WHATWG URL API instead.
const url = parse('/foo');

Pass

/** @deprecated Use apiV2 instead. */
async function apiV1(): Promise<void> { /*…*/ }

async function apiV2(): Promise<void> { /*…*/ }

// apiV1 has been defined in the current code base and is therefore not flagged
await apiV1();

/* >===================================< */

// Modern Node.js API, uses `new URL()`
const url2 = new URL('/foo', 'http://www.example.com');

Additional Info

Originally proposed in the [no-deprecated] issue #8988 (comment)

@BurningEnlightenment BurningEnlightenment added enhancement: plugin rule option New rule option for an existing eslint-plugin rule package: eslint-plugin Issues related to @typescript-eslint/eslint-plugin triage Waiting for team members to take a look labels Aug 28, 2024
@bradzacher
Copy link
Member

What is the difference between "user code" and "dependency code"?
How can we tell the difference between the two?

We can't use the import path and say "it has to have a ./ or a ../ for the import path" because tsconfig path mapping is a very commonly used thing.

You can't even really say "it's in node_modules" because yarn/pnpm monorepo workspaces are another very commonly used thing and those work via node_modules.

The key to considering this feature request is understanding how we can generically make this distinction.

@BurningEnlightenment
Copy link
Author

What is the difference between "user code" and "dependency code"?
The key to considering this feature request is understanding how we can generically make this distinction.

My initial suggestion would have solely been: Everything in the purview of the current typescript project is user code. Whereas purview is defined as the files, include, exclude settings of the tsconfig applicable to the file being linted.

However, as you noted this falls flat for yarn/pnpm monorepos. So maybe it makes sense to additionally define a package name exclusion list (perhaps as a regex). If a package matches the list, it won't be considered as a source for deprecation annotations. This should be enough for monorepo use cases as their packages usually live under a common few prefixes.

My initial suggestion also needs some further thought wrt unit tests. They usually live in a different typescript project and usually don't refer to the code under test by its official package name.

The exclusion mechanism also needs to be based on information readily available to the linter, otherwise this'll likely result in an unacceptable performance hit. Given that I've no experience with this codebase, I can't make this judgement and would need some feedback with regards to my suggestions. Thanks for considering it!

@kirkwaiblinger
Copy link
Member

Idea 💡 - what if we just create an allowlist like for no-floating-promises? This gives users control over what to consider internal (or whether to allow specific externally deprecated types if they so choose) rather than forcing us to infer it.

(more detailed docs for specifier format are on their way in #9587)

@kirkwaiblinger
Copy link
Member

My initial suggestion also needs some further thought wrt unit tests. They usually live in a different typescript project and usually don't refer to the code under test by its official package name.

I think this can be at least partially addressed by specifying different configurations for the rule applying to different files (at the eslint config level, rather than within the rule), right?

@bradzacher
Copy link
Member

The spec we designed was for ignoring specific types - we would need to extend it for values I believe.

@BurningEnlightenment
Copy link
Author

Idea 💡 - what if we just create an allowlist like for no-floating-promises? This gives users control over what to consider internal (or whether to allow specific externally deprecated types if they so choose) rather than forcing us to infer it.

That does sound rather tedious, I'd prefer something less granular.

I think this can be at least partially addressed by specifying different configurations for the rule applying to different files (at the eslint config level, rather than within the rule), right?

I had the following case in mind: The tests have their own tsconfig.spec.json e.g. to allow different "module" settings as jest has (had?) trouble with ES modules. Thus they wouldn't be in the same tsconfig purview as the library code. Of course you could set no-deprecated to warn for the tests, but that is a comparatively blunt fix.

@JoshuaKGoldberg
Copy link
Member

+1 from me on using the TypeOrValueSpecifier format as previously used in no-floating-promises and other rules. Blanket-ignoring all constructs in a particular folder is pretty heavyweight. I think we'd want to try out the same standard format as other rules before adding in something big like that.

@JoshuaKGoldberg JoshuaKGoldberg added evaluating community engagement we're looking for community engagement on this issue to show that this problem is widely important and removed triage Waiting for team members to take a look labels Sep 13, 2024
@JoshuaKGoldberg
Copy link
Member

Marking as evaluating community engagement to see if a lot of folks ask for this. Specifically, what's under consideration is adding an allow option using our standard TypeOrValueSpecifier format.

@JoshuaKGoldberg JoshuaKGoldberg changed the title Enhancement: [no-deprecated] Ignore deprecations from user code Enhancement: [no-deprecated] Add 'allow' option for specific types or values Sep 13, 2024
@github-staff github-staff deleted a comment from ViniciusSCG Oct 1, 2024
@github-staff github-staff deleted a comment from ViniciusSCG Oct 1, 2024
@Josh-Cena
Copy link
Member

Strong +1. Enabled it for several projects and there are many reasons for disabling the rule on a per-API basis:

  • Platform APIs that need graceful fallback for old envs
  • Using our own API like the OP

@kirkwaiblinger
Copy link
Member

This would be super useful to me right now in #10496. I want to deprecate our API externally, and gradually replace it internally.

@JoshuaKGoldberg
Copy link
Member

I'm also +1 on this. So given that we have three team members in favor and an internal use case, marking as accepting PRs. 🚀

@JoshuaKGoldberg JoshuaKGoldberg added accepting prs Go ahead, send a pull request that resolves this issue and removed evaluating community engagement we're looking for community engagement on this issue to show that this problem is widely important labels Dec 14, 2024
@github-actions github-actions bot added the locked due to age Please open a new issue if you'd like to say more. See https://typescript-eslint.io/contributing. label Jan 21, 2025
@github-actions github-actions bot locked as resolved and limited conversation to collaborators Jan 21, 2025
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
accepting prs Go ahead, send a pull request that resolves this issue enhancement: plugin rule option New rule option for an existing eslint-plugin rule locked due to age Please open a new issue if you'd like to say more. See https://typescript-eslint.io/contributing. package: eslint-plugin Issues related to @typescript-eslint/eslint-plugin
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants