Change Request: Autogenerated type definitions for rules
ESLint version
HEAD
What problem do you want to solve?
We inherited a lot of hardcoded rule configuration types from @types/eslint, but these were all handcoded and we've already seen that they are out of date. (https://github.com/eslint/eslint/pull/18902, https://github.com/eslint/eslint/pull/18906, https://github.com/eslint/eslint/pull/18905, https://github.com/eslint/eslint/pull/18903, https://github.com/eslint/eslint/pull/18901). Keeping the types in sync with rules is going to be a problem going forward.
What do you think is the correct solution?
We should create a script that automatically generates the rule config types based on the rule schemas.
Participation
- [ ] I am willing to submit a pull request for this change.
Additional comments
Looking for a volunteer for this.
Writing a script to generate types might be a better approach. I've made a basic implementation. Could you review it to see if it aligns with what you were expecting? If so, I would like to extend it to support other schema types as well. https://replit.com/@AmareshSuriya/Autogenerated-type-definitions
Writing a script to generate types might be a better approach.
I'm a bit confused, how is that different than what I said? "We should create a script that automatically generates the rule config types based on the rule schemas."
https://replit.com/@AmareshSuriya/Autogenerated-type-definitions
This looks pretty good! I don't think we need to have the separate files (best-practices.d.ts), we can just put everything into a rules.d.ts.
And we should run this on precommit to make sure new changes are always updated.
Writing a script to generate types might be a better approach.
I'm a bit confused, how is that different than what I said? "We should create a script that automatically generates the rule config types based on the rule schemas."
I was trying to say I agree with you like ya writing a script..
This looks pretty good! I don't think we need to have the separate files (
best-practices.d.ts), we can just put everything into arules.d.ts.And we should run this on precommit to make sure new changes are always updated.
Sure. I will look at this. I will to extend it to support other schema types as well.
The typescript-eslint team has an internal package which may be leveraged.
Speaking as a typescript-eslint team member: that internal package could probably be split out into something more public. We'd be happy to take an issue if folks would find it useful!
Speaking just in general: I wonder if there's something that already exists & can be pulled in? "AJV schema to TypeScript types" feels like a general problem other folks would have wanted solved by now.
- https://github.com/ajv-validator/ajv-cli/issues/192 mentions this.
- https://www.npmjs.com/package/json-schema-to-typescript looks pretty promising itself.
I tried using typescript-eslint's internal package with ESLint rules. It creates type declarations for rule options as TypeScript code (no syntax tree) without JSDoc comments. For instance, this is what the output for the no-unused-vars rule looks like:
type Options = [
| "all"
| "local"
| {
args?: "after-used" | "all" | "none";
argsIgnorePattern?: string;
caughtErrors?: "all" | "none";
caughtErrorsIgnorePattern?: string;
destructuredArrayIgnorePattern?: string;
ignoreClassWithStaticInitBlock?: boolean;
ignoreRestSiblings?: boolean;
reportUsedIgnorePattern?: boolean;
vars?: "all" | "local";
varsIgnorePattern?: string;
},
];
Compare this to how the rule type is currently defined (which is also roughly what should be autogenerated):
https://github.com/eslint/eslint/blob/064c8b612e2e4b773d6b25867f2045e3ceaa9d66/lib/types/rules/variables.d.ts#L159-L203
For reference, here is the code I run to get the output from @typescript-eslint/rule-schema-to-typescript-types after building the package locally:
const { compile } = require("@typescript-eslint/rule-schema-to-typescript-types");
const path = require("node:path");
const eslintRulesPath = path.join(require.resolve("eslint"), "../rules");
const filepath = path.join(eslintRulesPath, "no-unused-vars.js");
const rule = require(filepath);
compile(rule.meta.schema, { filepath: ".ts" })
.then(text => console.log(text));
I'm not sure how valuable the comments are. I think it's much more important that the types are up-to-date.
Speaking as a typescript-eslint team member: that internal package could probably be split out into something more public.
Another problem of @typescript-eslint/rule-schema-to-typescript-types is that it doesn't support all rule schemas used in ESLint. For example, it runs into an error when trying to generate option types for logical-assignment-operators:
.../typescript-eslint/packages/rule-schema-to-typescript-types/dist/generateType.js:60
throw new errors_1.NotSupportedError('untyped schemas without one of [$ref, enum, oneOf]', schema);
^
NotSupportedError: Generating a type for untyped schemas without one of [$ref, enum, oneOf] is not currently supported:
{
"items": [
{
"const": "always"
},
{
"type": "object",
"properties": {
"enforceForIfStatements": {
"type": "boolean"
}
},
"additionalProperties": false
}
],
"minItems": 0,
"maxItems": 2
}
at generateType (.../typescript-eslint/packages/rule-schema-to-typescript-types/dist/generateType.js:60:15)
at .../typescript-eslint/packages/rule-schema-to-typescript-types/dist/generateUnionType.js:31:60
at generateUnionType (.../typescript-eslint/packages/rule-schema-to-typescript-types/dist/generateUnionType.js:33:11)
at generateType (.../typescript-eslint/packages/rule-schema-to-typescript-types/dist/generateType.js:55:58)
at compileSchema (.../typescript-eslint/packages/rule-schema-to-typescript-types/dist/index.js:69:50)
at compile (.../typescript-eslint/packages/rule-schema-to-typescript-types/dist/index.js:31:24)
at Object.<anonymous> (.../test/test.js:10:1)
at Module._compile (node:internal/modules/cjs/loader:1565:14)
at Object..js (node:internal/modules/cjs/loader:1708:10)
at Module.load (node:internal/modules/cjs/loader:1318:32)
Node.js v22.12.0
It's an interesting tool anyway, so we could fork it and update it to make it work for us. Not sure about making it a public package as that would be clearly more work.
https://www.npmjs.com/package/json-schema-to-typescript looks pretty promising itself.
Could it be that that tool simply ignores schemas it doesn't understand rather than throwing an error? Here is the whole output produced by json-schema-to-typescript for the complexity rule:
/* eslint-disable */
/**
* This file was automatically generated by json-schema-to-typescript.
* DO NOT MODIFY IT BY HAND. Instead, modify the source JSONSchema file,
* and run json-schema-to-typescript to regenerate this file.
*/
For most other rules the output is disappointing as well, with unknown types, unions of empty tuples, etc.
I just filed https://github.com/typescript-eslint/typescript-eslint/issues/10469 to track making @typescript-eslint/rule-schema-to-typescript-types public.
comments
Having at least the @default tags added is a nice idea... I think I'd like that in typescript-eslint too. 🙂
@amareshsm are you still working on this?
@amareshsm are you still working on this?
Apologies for this. I had started working on it but didn’t get the time to complete the implementation, so I’ve unassigned it from myself now.
I will take this.
@Tanujkanti4441 are you still working on this?
@Tanujkanti4441 ping
Sorry for the delays, somehow missed this, got engaged in other PR's and stuffs, working on it.
Thanks!
Thanks for the update @Tanujkanti4441. When do you think you'll be able to open a pull request?
Thanks for the update @Tanujkanti4441. When do you think you'll be able to open a pull request?
Within a week i guess.
👋 Hi! This issue is being addressed in pull request https://github.com/eslint/eslint/pull/20061. Thanks, @Tanujkanti4441!