Skip to content

Enhancement(eslint-plugin): Export types of rules option for flat config #8571

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

Open
3 tasks done
linlinyang opened this issue Feb 28, 2024 · 8 comments
Open
3 tasks done
Labels
enhancement New feature or request package: eslint-plugin Issues related to @typescript-eslint/eslint-plugin team assigned A member of the typescript-eslint team should work on this.

Comments

@linlinyang
Copy link

linlinyang commented Feb 28, 2024

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

Description

I hope I can define ts lint rules in my flat eslint.config.ts which will be compared to eslint.config.js like this:

import type { Linter } from 'eslint';
import type {ruleOptions} from '@typescript-eslint/eslint-plugin';

type TSRules = {
  [K in keyof ruleOptions]?: Linter.RuleEntry<ruleOptions[K]>;
};
// Than those rules has hints
const rules: TSRules = {
  'accessor-pairs': 'error',
  'array-type': ['error', {
     readonly: 'array'
   }]
};

And It helpful for define rule with prefix:

import type { Linter } from 'eslint';
import type {ruleOptions} from '@typescript-eslint/eslint-plugin';

type TSRules = {
  [K in keyof ruleOptions as `ts/${K}`]?: Linter.RuleEntry<ruleOptions[K]>;
};
// Than those rules has hints
const rules: TSRules = {
  'ts/accessor-pairs': 'error',
  'ts/array-type': ['error', {
     readonly: 'array'
   }]
};

In use of:

import type { Linter } from 'eslint';
import parseTs from '@typescript-eslint/parser';
import pluginTs from '@typescript-eslint/eslint-plugin';

const flatconfig: Linter.FlatConfig[] = [{
  plugins: {
    ts: pluginTs as any
  },
  files: ['**/*.?([cm])ts'],
  languageOptions: {
    parser: parseTs as any,
    parserOptions: {
      project: true,
      sourceType: 'module',
      // extraFileExtensions: ['.vue']
    }
  },
  
  rules: {
    ...rules
  }
}]
@linlinyang linlinyang added enhancement: new plugin rule New rule request for eslint-plugin package: eslint-plugin Issues related to @typescript-eslint/eslint-plugin triage Waiting for team members to take a look labels Feb 28, 2024
@linlinyang
Copy link
Author

And so I raise this PR

@JoshuaKGoldberg
Copy link
Member

Personally I think could be a good and reasonable idea. Now that configs can be typed and are generally made in JS/TS land, folks will want to have nice typing around their rule options.

cc @bradzacher as this goes pretty directly against:

We purposely don't generate types for our plugin because TL;DR:
1) there's no real reason that anyone should do a typed import of our rules,
2) it would require us to change our code so there aren't as many inferred types

See the rest of that long comment. It has a lot of good info for why this isn't easy or straightforward to do. I think it could be made to work by just keying the rule names and their types, rather than the rules themselves - but it might be tricky.

In order to get this to work, I think we have a couple of blockers:

  • Rule proposal: Export all types used in exports #7670: it'll be much easier to work with type exports once we have that rule created and enabled internally
  • We'd want to be sure the implementation wouldn't add a huge amount of overhead. We'd have to see a real proposal (read: a draft PR) showing how to get it to work

A few tangential notes, by the way...

in my flat eslint.config.ts

Err, ESLint that I know of doesn't support eslint.config.ts. Where are you seeing this as being supported? That doesn't block this issue as folks can always // @ts-check in the file. Just curious if there's useful context to learn. 🙂

rule with prefix
ts/accessor-pairs

We strongly recommend not doing this. If you refer to rules from the same plugin with a different prefix than another shared config, then they can get configured twice. 😬

@JoshuaKGoldberg JoshuaKGoldberg added blocked by another issue Issues which are not ready because another issue needs to be resolved first and removed triage Waiting for team members to take a look labels Mar 25, 2024
@bradzacher
Copy link
Member

This is something I have wanted to do for a while and is one of the reasons that I built the type generator for json schema (that we use for tests and docs).

Flat config does give us a good way to do it now - but it is quite complicated to get the types working safely.

We don't really want to just do global type augmentation and instead we would want something using generics. But the generics are hard because the user can do whatever they want with plugin namespaces. Shareable configs also complicate things cos they can do the same, but obfuscated.

If you remember this was the genesis behind this idea for an API - we could make the types safe if we make the user declare the canonical form up-front. Would also make the generics easy.

@bradzacher
Copy link
Member

Side note that because we chose not to do anything with legacy configs there was this project that spun up.

https://github.com/eslint-types/eslint-define-config

@JoshuaKGoldberg
Copy link
Member

Yeah maybe this would be a good first step towards an API? We can treat this issue as tracking just the exposure of the canonical rule names & options, and use that as a basis to work on more scaffolding next.

@bradzacher
Copy link
Member

as this goes pretty directly against:

We purposely don't generate types for our plugin because TL;DR:
1) there's no real reason that anyone should do a typed import of our rules,
2) it would require us to change our code so there aren't as many inferred types

It doesn't go against it.

We still won't want to generate declarations via tsc for this feature cos those declarations would be wrong. Instead we'd need to build codegen on top of our json schema to type package that would emit a signature per rule.

Ideally this would be a new tool that we'd release for the ecosystem!

@Josh-Cena Josh-Cena added enhancement New feature or request and removed enhancement: new plugin rule New rule request for eslint-plugin labels Jun 5, 2024
@JoshuaKGoldberg JoshuaKGoldberg added team assigned A member of the typescript-eslint team should work on this. and removed blocked by another issue Issues which are not ready because another issue needs to be resolved first labels Aug 1, 2024
@kirkwaiblinger
Copy link
Member

@linlinyang With the current direction of eslint/rfcs#126, static analysis of rule options looks like a possibility to be proposed upstream in eslint, and I'd like to see such a proposal happen. I'm happy to adapt your POC to make sense for eslint and give you co-author credit. Or, if you'd like to initiate the proposal yourself, you're welcome to. Let
me know!

@haoqunjiang
Copy link

I'm trying to provide similar functionalities for my shared config package via https://github.com/antfu/eslint-typegen.

But there's an issue that prevents me from doing so:
eslint-typegen tries to augment the RulesRecord type to provide type informations for rules, it is an interface in ESLint core, but becomes a type in typescript-eslint
Interfaces can be extended via declaration merging but types cannot, making it impossible to augment typescript-eslint's RulesRecord type in userland.

Would the team be open to a pull request that refactors this type and makes userland solutions like eslint-typegen possible?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request package: eslint-plugin Issues related to @typescript-eslint/eslint-plugin team assigned A member of the typescript-eslint team should work on this.
Projects
None yet
Development

No branches or pull requests

6 participants