Skip to content

Commit

Permalink
feat: improve rule schemas, add test to validate schemas, add tooling…
Browse files Browse the repository at this point in the history
… to generate schema types (#6899)
  • Loading branch information
bradzacher committed Apr 20, 2023
1 parent 4bc7571 commit acc1a43
Show file tree
Hide file tree
Showing 181 changed files with 10,410 additions and 713 deletions.
1 change: 1 addition & 0 deletions .github/workflows/ci.yml
Expand Up @@ -145,6 +145,7 @@ jobs:
'eslint-plugin-tslint',
'parser',
'repo-tools',
'rule-schema-to-typescript-types',
'scope-manager',
'type-utils',
'typescript-estree',
Expand Down
36 changes: 36 additions & 0 deletions docs/linting/Troubleshooting.mdx
Expand Up @@ -71,6 +71,42 @@ See our docs on [type aware linting](./Typed_Linting.mdx) for more information.
You're using an outdated version of `@typescript-eslint/parser`.
Update to the latest version to see a more informative version of this error message, explained [above](#i-get-errors-telling-me-eslint-was-configured-to-run--however-that-tsconfig-does-not--none-of-those-tsconfigs-include-this-file 'backlink to I get errors telling me ESLint was configured to run ...').

## How do I turn on a `@typescript-eslint` rule?

First make sure you've read the docs and understand ESLint configuration files:

- [Read our getting started guide](../Getting_Started.mdx) to ensure your config is properly setup to start configuring our rules.
- [Checkout ESLint's documentation on configuring rules](https://eslint.org/docs/latest/use/configure/rules) to ensure you understand how to configure rules.

Our [rule docs](/rules) detail the options each rule supports under the "Options" heading.
We use TypeScript types to describe an `Options` tuple type for the rule which you can use to configure the a rule.
In your config file the keys of the `rules` object are the names of the rules you wish to configure and the values follow the following form:

```ts
type Severity = 'off' | 'warn' | 'error';
type RuleConfig =
| Severity
| [Severity]
| [
Severiy,
// Options is the tuple type from the rule docs
...Options,
];
```

Some examples

```js title=".eslintrc.js"
module.exports = {
rules: {
// turns a rule on with no configuration (i.e. uses the default configuration)
'@typescript-eslint/array-type': 'error',
// turns on a rule with configuration
'@typescript-eslint/no-explicit-any': ['warn', { ignoreRestArgs: true }],
},
};
```

## I use a framework (like Vue) that requires custom file extensions, and I get errors like "You should add `parserOptions.extraFileExtensions` to your config"

You can use `parserOptions.extraFileExtensions` to specify an array of non-TypeScript extensions to allow, for example:
Expand Down
1 change: 1 addition & 0 deletions package.json
Expand Up @@ -71,6 +71,7 @@
"@types/jest": "^29.0.2",
"@types/jest-specific-snapshot": "^0.5.5",
"@types/marked": "^4.0.3",
"@types/natural-compare": "^1.4.0",
"@types/node": "^18.11.9",
"@types/prettier": "^2.6.0",
"@types/rimraf": "^3.0.2",
Expand Down
4 changes: 3 additions & 1 deletion packages/eslint-plugin/package.json
Expand Up @@ -69,9 +69,11 @@
"@types/debug": "*",
"@types/json-schema": "*",
"@types/marked": "*",
"@types/natural-compare": "^1.4.0",
"@types/natural-compare": "*",
"@types/prettier": "*",
"@typescript-eslint/rule-schema-to-typescript-types": "5.59.0",
"cross-fetch": "*",
"jest-specific-snapshot": "*",
"json-schema": "*",
"markdown-table": "^3.0.2",
"marked": "^4.0.15",
Expand Down
39 changes: 18 additions & 21 deletions packages/eslint-plugin/src/rules/array-type.ts
Expand Up @@ -105,30 +105,27 @@ export default util.createRule<Options, MessageIds>({
errorStringGenericSimple:
"Array type using '{{readonlyPrefix}}{{type}}[]' is forbidden for non-simple types. Use '{{className}}<{{type}}>' instead.",
},
schema: {
$defs: {
arrayOption: {
enum: ['array', 'generic', 'array-simple'],
schema: [
{
$defs: {
arrayOption: {
enum: ['array', 'generic', 'array-simple'],
},
},
},
prefixItems: [
{
properties: {
default: {
$ref: '#/$defs/arrayOption',
description: 'The array type expected for mutable cases...',
},
readonly: {
$ref: '#/$defs/arrayOption',
description:
'The array type expected for readonly cases. If omitted, the value for `default` will be used.',
},
properties: {
default: {
$ref: '#/items/0/$defs/arrayOption',
description: 'The array type expected for mutable cases.',
},
readonly: {
$ref: '#/items/0/$defs/arrayOption',
description:
'The array type expected for readonly cases. If omitted, the value for `default` will be used.',
},
type: 'object',
},
],
type: 'array',
},
type: 'object',
},
],
},
defaultOptions: [
{
Expand Down
66 changes: 31 additions & 35 deletions packages/eslint-plugin/src/rules/ban-ts-comment.ts
Expand Up @@ -39,45 +39,41 @@ export default util.createRule<[Options], MessageIds>({
tsDirectiveCommentDescriptionNotMatchPattern:
'The description for the "@ts-{{directive}}" directive must match the {{format}} format.',
},
schema: {
$defs: {
directiveConfigSchema: {
oneOf: [
{
type: 'boolean',
default: true,
},
{
enum: ['allow-with-description'],
},
{
type: 'object',
properties: {
descriptionFormat: { type: 'string' },
schema: [
{
$defs: {
directiveConfigSchema: {
oneOf: [
{
type: 'boolean',
default: true,
},
},
],
{
enum: ['allow-with-description'],
},
{
type: 'object',
properties: {
descriptionFormat: { type: 'string' },
},
},
],
},
},
},
prefixItems: [
{
properties: {
'ts-expect-error': {
$ref: '#/$defs/directiveConfigSchema',
},
'ts-ignore': { $ref: '#/$defs/directiveConfigSchema' },
'ts-nocheck': { $ref: '#/$defs/directiveConfigSchema' },
'ts-check': { $ref: '#/$defs/directiveConfigSchema' },
minimumDescriptionLength: {
type: 'number',
default: defaultMinimumDescriptionLength,
},
properties: {
'ts-expect-error': { $ref: '#/items/0/$defs/directiveConfigSchema' },
'ts-ignore': { $ref: '#/items/0/$defs/directiveConfigSchema' },
'ts-nocheck': { $ref: '#/items/0/$defs/directiveConfigSchema' },
'ts-check': { $ref: '#/items/0/$defs/directiveConfigSchema' },
minimumDescriptionLength: {
type: 'number',
default: defaultMinimumDescriptionLength,
},
additionalProperties: false,
},
],
type: 'array',
},
type: 'object',
additionalProperties: false,
},
],
},
defaultOptions: [
{
Expand Down
69 changes: 49 additions & 20 deletions packages/eslint-plugin/src/rules/ban-types.ts
Expand Up @@ -6,7 +6,7 @@ import * as util from '../util';
type Types = Record<
string,
| null
| false
| boolean
| string
| {
message: string;
Expand Down Expand Up @@ -35,9 +35,9 @@ function stringifyNode(
}

function getCustomMessage(
bannedType: null | string | { message?: string; fixWith?: string },
bannedType: null | true | string | { message?: string; fixWith?: string },
): string {
if (bannedType == null) {
if (bannedType == null || bannedType === true) {
return '';
}

Expand Down Expand Up @@ -140,28 +140,57 @@ export default util.createRule<Options, MessageIds>({
},
schema: [
{
$defs: {
banConfig: {
oneOf: [
{
type: 'null',
description: 'Bans the type with the default message',
},
{
enum: [false],
description:
'Un-bans the type (useful when paired with `extendDefaults`)',
},
{
enum: [true],
description: 'Bans the type with the default message',
},
{
type: 'string',
description: 'Bans the type with a custom message',
},
{
type: 'object',
description: 'Bans a type',
properties: {
message: {
type: 'string',
description: 'Custom error message',
},
fixWith: {
type: 'string',
description:
'Type to autofix replace with. Note that autofixers can be applied automatically - so you need to be careful with this option.',
},
suggest: {
type: 'array',
items: { type: 'string' },
description: 'Types to suggest replacing with.',
additionalItems: false,
},
},
additionalProperties: false,
},
],
},
},
type: 'object',
properties: {
types: {
type: 'object',
additionalProperties: {
oneOf: [
{ type: 'null' },
{ type: 'boolean' },
{ type: 'string' },
{
type: 'object',
properties: {
message: { type: 'string' },
fixWith: { type: 'string' },
suggest: {
type: 'array',
items: { type: 'string' },
},
},
additionalProperties: false,
},
],
$ref: '#/items/0/$defs/banConfig',
},
},
extendDefaults: {
Expand Down

0 comments on commit acc1a43

Please sign in to comment.