diff --git a/docs/architecture/Utils.mdx b/docs/architecture/Utils.mdx index 7c4fd674d70..4b307f4db42 100644 --- a/docs/architecture/Utils.mdx +++ b/docs/architecture/Utils.mdx @@ -15,14 +15,14 @@ Any custom rules you write generally will be as well. ## Exports -| Name | Description | -| ----------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `AST_NODE_TYPES` | An enum with the names of every single _node_ found in `TSESTree`. | -| `AST_TOKEN_TYPES` | An enum with the names of every single _token_ found in `TSESTree`. | -| `ASTUtils` | Tools for operating on the ESTree AST. Also includes the [`@eslint-community/eslint-utils`](https://www.npmjs.com/package/@eslint-community/eslint-utils) package, correctly typed to work with the types found in `TSESTree` | -| `ESLintUtils` | Tools for creating ESLint rules with TypeScript. | -| `JSONSchema` | Types from the [`@types/json-schema`](https://www.npmjs.com/package/@types/json-schema) package, re-exported to save you having to manually import them. Also ensures you're using the same version of the types as this package. | -| `ParserServices` | Typing for the parser services provided when parsing a file using `@typescript-eslint/typescript-estree`. | -| `TSESLint` | Types for ESLint, correctly typed to work with the types found in `TSESTree`. | -| `TSESLintScope` | The [`eslint-scope`](https://www.npmjs.com/package/eslint-scope) package, correctly typed to work with the types found in both `TSESTree` and `TSESLint` | -| `TSESTree` | Types for the TypeScript flavor of ESTree created by `@typescript-eslint/typescript-estree`. | +| Name | Description | +| ----------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `AST_NODE_TYPES` | An enum with the names of every single _node_ found in `TSESTree`. | +| `AST_TOKEN_TYPES` | An enum with the names of every single _token_ found in `TSESTree`. | +| `ASTUtils` | Tools for operating on the ESTree AST. Also includes the [`@eslint-community/eslint-utils`](https://www.npmjs.com/package/@eslint-community/eslint-utils) package, correctly typed to work with the types found in `TSESTree` | +| `ESLintUtils` | Tools for creating ESLint rules with TypeScript. | +| `JSONSchema` | Strict types for the JSON Schema v4 spec - the version that ESLint uses to validate all rules with. | +| `ParserServices` | Typing for the parser services provided when parsing a file using `@typescript-eslint/typescript-estree`. | +| `TSESLint` | Types for ESLint, correctly typed to work with the types found in `TSESTree`. | +| `TSESLintScope` | The [`eslint-scope`](https://www.npmjs.com/package/eslint-scope) package, correctly typed to work with the types found in both `TSESTree` and `TSESLint` | +| `TSESTree` | Types for the TypeScript flavor of ESTree created by `@typescript-eslint/typescript-estree`. | diff --git a/packages/eslint-plugin/package.json b/packages/eslint-plugin/package.json index 756fba6e3b1..b8c6e6f4dd8 100644 --- a/packages/eslint-plugin/package.json +++ b/packages/eslint-plugin/package.json @@ -66,6 +66,10 @@ "ts-api-utils": "^1.0.0" }, "devDependencies": { + "@types/debug": "*", + "@types/marked": "*", + "@types/natural-compare": "*", + "@types/prettier": "*", "@typescript-eslint/rule-schema-to-typescript-types": "5.59.11", "@typescript-eslint/rule-tester": "5.59.11", "cross-fetch": "*", diff --git a/packages/eslint-plugin/src/rules/array-type.ts b/packages/eslint-plugin/src/rules/array-type.ts index 1e3b978a281..08ff550a141 100644 --- a/packages/eslint-plugin/src/rules/array-type.ts +++ b/packages/eslint-plugin/src/rules/array-type.ts @@ -109,6 +109,7 @@ export default util.createRule({ { $defs: { arrayOption: { + type: 'string', enum: ['array', 'generic', 'array-simple'], }, }, diff --git a/packages/eslint-plugin/src/rules/ban-ts-comment.ts b/packages/eslint-plugin/src/rules/ban-ts-comment.ts index f3622c693ac..3f9c60bdb8d 100644 --- a/packages/eslint-plugin/src/rules/ban-ts-comment.ts +++ b/packages/eslint-plugin/src/rules/ban-ts-comment.ts @@ -49,6 +49,7 @@ export default util.createRule<[Options], MessageIds>({ default: true, }, { + type: 'string', enum: ['allow-with-description'], }, { diff --git a/packages/eslint-plugin/src/rules/ban-types.ts b/packages/eslint-plugin/src/rules/ban-types.ts index 688164c5f6c..b2912dc8302 100644 --- a/packages/eslint-plugin/src/rules/ban-types.ts +++ b/packages/eslint-plugin/src/rules/ban-types.ts @@ -148,11 +148,13 @@ export default util.createRule({ description: 'Bans the type with the default message', }, { + type: 'boolean', enum: [false], description: 'Un-bans the type (useful when paired with `extendDefaults`)', }, { + type: 'boolean', enum: [true], description: 'Bans the type with the default message', }, diff --git a/packages/eslint-plugin/src/rules/class-literal-property-style.ts b/packages/eslint-plugin/src/rules/class-literal-property-style.ts index 7e4d6b2d6b1..7563c6b97fc 100644 --- a/packages/eslint-plugin/src/rules/class-literal-property-style.ts +++ b/packages/eslint-plugin/src/rules/class-literal-property-style.ts @@ -50,7 +50,12 @@ export default util.createRule({ preferFieldStyle: 'Literals should be exposed using readonly fields.', preferGetterStyle: 'Literals should be exposed using getters.', }, - schema: [{ enum: ['fields', 'getters'] }], + schema: [ + { + type: 'string', + enum: ['fields', 'getters'], + }, + ], }, defaultOptions: ['fields'], create(context, [style]) { diff --git a/packages/eslint-plugin/src/rules/comma-dangle.ts b/packages/eslint-plugin/src/rules/comma-dangle.ts index 119907db762..029e9e3e651 100644 --- a/packages/eslint-plugin/src/rules/comma-dangle.ts +++ b/packages/eslint-plugin/src/rules/comma-dangle.ts @@ -49,9 +49,11 @@ export default util.createRule({ schema: { $defs: { value: { + type: 'string', enum: OPTION_VALUE_SCHEME, }, valueWithIgnore: { + type: 'string', enum: [...OPTION_VALUE_SCHEME, 'ignore'], }, }, @@ -79,7 +81,7 @@ export default util.createRule({ ], }, ], - additionalProperties: false, + additionalItems: false, }, fixable: 'code', hasSuggestions: baseRule.meta.hasSuggestions, diff --git a/packages/eslint-plugin/src/rules/consistent-generic-constructors.ts b/packages/eslint-plugin/src/rules/consistent-generic-constructors.ts index ed842628d9e..e437bc38d76 100644 --- a/packages/eslint-plugin/src/rules/consistent-generic-constructors.ts +++ b/packages/eslint-plugin/src/rules/consistent-generic-constructors.ts @@ -24,6 +24,7 @@ export default createRule({ fixable: 'code', schema: [ { + type: 'string', enum: ['type-annotation', 'constructor'], }, ], diff --git a/packages/eslint-plugin/src/rules/consistent-indexed-object-style.ts b/packages/eslint-plugin/src/rules/consistent-indexed-object-style.ts index d8ae71bec1d..268946ae463 100644 --- a/packages/eslint-plugin/src/rules/consistent-indexed-object-style.ts +++ b/packages/eslint-plugin/src/rules/consistent-indexed-object-style.ts @@ -21,6 +21,7 @@ export default createRule({ fixable: 'code', schema: [ { + type: 'string', enum: ['record', 'index-signature'], }, ], diff --git a/packages/eslint-plugin/src/rules/consistent-type-assertions.ts b/packages/eslint-plugin/src/rules/consistent-type-assertions.ts index d8f84fb583e..cce706c8eff 100644 --- a/packages/eslint-plugin/src/rules/consistent-type-assertions.ts +++ b/packages/eslint-plugin/src/rules/consistent-type-assertions.ts @@ -48,6 +48,7 @@ export default util.createRule({ type: 'object', properties: { assertionStyle: { + type: 'string', enum: ['never'], }, }, @@ -58,9 +59,11 @@ export default util.createRule({ type: 'object', properties: { assertionStyle: { + type: 'string', enum: ['as', 'angle-bracket'], }, objectLiteralTypeAssertions: { + type: 'string', enum: ['allow', 'allow-as-parameter', 'never'], }, }, diff --git a/packages/eslint-plugin/src/rules/consistent-type-definitions.ts b/packages/eslint-plugin/src/rules/consistent-type-definitions.ts index a28f07529b5..b504081ee4a 100644 --- a/packages/eslint-plugin/src/rules/consistent-type-definitions.ts +++ b/packages/eslint-plugin/src/rules/consistent-type-definitions.ts @@ -18,6 +18,7 @@ export default util.createRule({ }, schema: [ { + type: 'string', enum: ['interface', 'type'], }, ], diff --git a/packages/eslint-plugin/src/rules/consistent-type-imports.ts b/packages/eslint-plugin/src/rules/consistent-type-imports.ts index 3b9de8bad83..701c53b2541 100644 --- a/packages/eslint-plugin/src/rules/consistent-type-imports.ts +++ b/packages/eslint-plugin/src/rules/consistent-type-imports.ts @@ -65,12 +65,14 @@ export default util.createRule({ type: 'object', properties: { prefer: { + type: 'string', enum: ['type-imports', 'no-type-imports'], }, disallowTypeAnnotations: { type: 'boolean', }, fixStyle: { + type: 'string', enum: ['separate-type-imports', 'inline-type-imports'], }, }, diff --git a/packages/eslint-plugin/src/rules/explicit-member-accessibility.ts b/packages/eslint-plugin/src/rules/explicit-member-accessibility.ts index 71a85b4e701..9670659c975 100644 --- a/packages/eslint-plugin/src/rules/explicit-member-accessibility.ts +++ b/packages/eslint-plugin/src/rules/explicit-member-accessibility.ts @@ -51,14 +51,17 @@ export default util.createRule({ accessibilityLevel: { oneOf: [ { + type: 'string', enum: ['explicit'], description: 'Always require an accessor.', }, { + type: 'string', enum: ['no-public'], description: 'Require an accessor except when public.', }, { + type: 'string', enum: ['off'], description: 'Never check whether there is an accessor.', }, diff --git a/packages/eslint-plugin/src/rules/func-call-spacing.ts b/packages/eslint-plugin/src/rules/func-call-spacing.ts index cbb2bba5939..fd0b50a65fd 100644 --- a/packages/eslint-plugin/src/rules/func-call-spacing.ts +++ b/packages/eslint-plugin/src/rules/func-call-spacing.ts @@ -29,6 +29,7 @@ export default util.createRule({ type: 'array', items: [ { + type: 'string', enum: ['never'], }, ], @@ -39,6 +40,7 @@ export default util.createRule({ type: 'array', items: [ { + type: 'string', enum: ['always'], }, { diff --git a/packages/eslint-plugin/src/rules/keyword-spacing.ts b/packages/eslint-plugin/src/rules/keyword-spacing.ts index 0ec1d17ec38..893c70db767 100644 --- a/packages/eslint-plugin/src/rules/keyword-spacing.ts +++ b/packages/eslint-plugin/src/rules/keyword-spacing.ts @@ -1,5 +1,6 @@ import type { TSESTree } from '@typescript-eslint/utils'; import { AST_NODE_TYPES, AST_TOKEN_TYPES } from '@typescript-eslint/utils'; +import type { JSONSchema4 } from '@typescript-eslint/utils/json-schema'; import * as util from '../util'; import { getESLintCoreRule } from '../util/getESLintCoreRule'; @@ -26,7 +27,7 @@ const schema = util.deepMerge( }, }, }, -); +) as unknown as JSONSchema4; export default util.createRule({ name: 'keyword-spacing', diff --git a/packages/eslint-plugin/src/rules/member-delimiter-style.ts b/packages/eslint-plugin/src/rules/member-delimiter-style.ts index fb14ad32910..ac2d9e1aea4 100644 --- a/packages/eslint-plugin/src/rules/member-delimiter-style.ts +++ b/packages/eslint-plugin/src/rules/member-delimiter-style.ts @@ -150,9 +150,15 @@ export default util.createRule({ schema: [ { $defs: { - multiLineOption: { enum: ['none', 'semi', 'comma'] }, + multiLineOption: { + type: 'string', + enum: ['none', 'semi', 'comma'], + }, // note can't have "none" for single line delimiter as it's invalid syntax - singleLineOption: { enum: ['semi', 'comma'] }, + singleLineOption: { + type: 'string', + enum: ['semi', 'comma'], + }, // note - need to define this last as it references the enums delimiterConfig: BASE_SCHEMA, }, @@ -172,6 +178,7 @@ export default util.createRule({ additionalProperties: false, }, multilineDetection: { + type: 'string', enum: ['brackets', 'last-member'], }, }, diff --git a/packages/eslint-plugin/src/rules/member-ordering.ts b/packages/eslint-plugin/src/rules/member-ordering.ts index 97a5bd24c8d..ee2093a19ed 100644 --- a/packages/eslint-plugin/src/rules/member-ordering.ts +++ b/packages/eslint-plugin/src/rules/member-ordering.ts @@ -644,7 +644,7 @@ export default util.createRule({ }, allItems: { type: 'string', - enum: allMemberTypes, + enum: allMemberTypes as string[], }, typeItems: { type: 'string', diff --git a/packages/eslint-plugin/src/rules/method-signature-style.ts b/packages/eslint-plugin/src/rules/method-signature-style.ts index 3cc8773159c..e9db86cd687 100644 --- a/packages/eslint-plugin/src/rules/method-signature-style.ts +++ b/packages/eslint-plugin/src/rules/method-signature-style.ts @@ -22,6 +22,7 @@ export default util.createRule({ }, schema: [ { + type: 'string', enum: ['property', 'method'], }, ], diff --git a/packages/eslint-plugin/src/rules/no-empty-function.ts b/packages/eslint-plugin/src/rules/no-empty-function.ts index b908b6c6d88..8113ee6ce55 100644 --- a/packages/eslint-plugin/src/rules/no-empty-function.ts +++ b/packages/eslint-plugin/src/rules/no-empty-function.ts @@ -1,5 +1,6 @@ import type { TSESTree } from '@typescript-eslint/utils'; import { AST_NODE_TYPES } from '@typescript-eslint/utils'; +import type { JSONSchema4 } from '@typescript-eslint/utils/json-schema'; import * as util from '../util'; import { getESLintCoreRule } from '../util/getESLintCoreRule'; @@ -18,6 +19,7 @@ const schema = util.deepMerge( properties: { allow: { items: { + type: 'string', enum: [ 'functions', 'arrowFunctions', @@ -38,7 +40,7 @@ const schema = util.deepMerge( }, }, }, -); +) as unknown as JSONSchema4; export default util.createRule({ name: 'no-empty-function', diff --git a/packages/eslint-plugin/src/rules/no-invalid-void-type.ts b/packages/eslint-plugin/src/rules/no-invalid-void-type.ts index e367c3928be..38872f499ca 100644 --- a/packages/eslint-plugin/src/rules/no-invalid-void-type.ts +++ b/packages/eslint-plugin/src/rules/no-invalid-void-type.ts @@ -47,7 +47,7 @@ export default util.createRule<[Options], MessageIds>({ { type: 'array', items: { type: 'string' }, - minLength: 1, + minItems: 1, }, ], }, diff --git a/packages/eslint-plugin/src/rules/no-magic-numbers.ts b/packages/eslint-plugin/src/rules/no-magic-numbers.ts index 18ae31abea0..92a03c9078d 100644 --- a/packages/eslint-plugin/src/rules/no-magic-numbers.ts +++ b/packages/eslint-plugin/src/rules/no-magic-numbers.ts @@ -1,5 +1,6 @@ import type { TSESTree } from '@typescript-eslint/utils'; import { AST_NODE_TYPES } from '@typescript-eslint/utils'; +import type { JSONSchema4 } from '@typescript-eslint/utils/json-schema'; import * as util from '../util'; import { getESLintCoreRule } from '../util/getESLintCoreRule'; @@ -31,7 +32,7 @@ const schema = util.deepMerge( }, }, }, -); +) as unknown as JSONSchema4; export default util.createRule({ name: 'no-magic-numbers', diff --git a/packages/eslint-plugin/src/rules/no-shadow.ts b/packages/eslint-plugin/src/rules/no-shadow.ts index 991beb9f1eb..f40ea991dba 100644 --- a/packages/eslint-plugin/src/rules/no-shadow.ts +++ b/packages/eslint-plugin/src/rules/no-shadow.ts @@ -43,6 +43,7 @@ export default util.createRule({ type: 'boolean', }, hoist: { + type: 'string', enum: ['all', 'functions', 'never'], }, allow: { diff --git a/packages/eslint-plugin/src/rules/no-type-alias.ts b/packages/eslint-plugin/src/rules/no-type-alias.ts index 7356f00fbc5..cc41d65f78e 100644 --- a/packages/eslint-plugin/src/rules/no-type-alias.ts +++ b/packages/eslint-plugin/src/rules/no-type-alias.ts @@ -50,6 +50,7 @@ export default util.createRule({ { $defs: { expandedOptions: { + type: 'string', enum: [ 'always', 'never', @@ -59,6 +60,7 @@ export default util.createRule({ ] satisfies Values[], }, simpleOptions: { + type: 'string', enum: ['always', 'never'], }, }, diff --git a/packages/eslint-plugin/src/rules/no-unused-vars.ts b/packages/eslint-plugin/src/rules/no-unused-vars.ts index edb07bce0cc..a847294a52d 100644 --- a/packages/eslint-plugin/src/rules/no-unused-vars.ts +++ b/packages/eslint-plugin/src/rules/no-unused-vars.ts @@ -44,18 +44,21 @@ export default util.createRule({ { oneOf: [ { + type: 'string', enum: ['all', 'local'], }, { type: 'object', properties: { vars: { + type: 'string', enum: ['all', 'local'], }, varsIgnorePattern: { type: 'string', }, args: { + type: 'string', enum: ['all', 'after-used', 'none'], }, ignoreRestSiblings: { @@ -65,6 +68,7 @@ export default util.createRule({ type: 'string', }, caughtErrors: { + type: 'string', enum: ['all', 'none'], }, caughtErrorsIgnorePattern: { diff --git a/packages/eslint-plugin/src/rules/no-use-before-define.ts b/packages/eslint-plugin/src/rules/no-use-before-define.ts index eccbb320db3..8cca3042691 100644 --- a/packages/eslint-plugin/src/rules/no-use-before-define.ts +++ b/packages/eslint-plugin/src/rules/no-use-before-define.ts @@ -251,6 +251,7 @@ export default util.createRule({ { oneOf: [ { + type: 'string', enum: ['nofunc'], }, { diff --git a/packages/eslint-plugin/src/rules/padding-line-between-statements.ts b/packages/eslint-plugin/src/rules/padding-line-between-statements.ts index b1e974e1b86..deeeafadad5 100644 --- a/packages/eslint-plugin/src/rules/padding-line-between-statements.ts +++ b/packages/eslint-plugin/src/rules/padding-line-between-statements.ts @@ -598,14 +598,21 @@ export default util.createRule({ schema: { $defs: { paddingType: { + type: 'string', enum: Object.keys(PaddingTypes), }, statementType: { anyOf: [ - { enum: Object.keys(StatementTypes) }, + { + type: 'string', + enum: Object.keys(StatementTypes), + }, { type: 'array', - items: { enum: Object.keys(StatementTypes) }, + items: { + type: 'string', + enum: Object.keys(StatementTypes), + }, minItems: 1, uniqueItems: true, additionalItems: false, diff --git a/packages/eslint-plugin/src/rules/parameter-properties.ts b/packages/eslint-plugin/src/rules/parameter-properties.ts index 10c15b06177..f70bdb8b81b 100644 --- a/packages/eslint-plugin/src/rules/parameter-properties.ts +++ b/packages/eslint-plugin/src/rules/parameter-properties.ts @@ -41,6 +41,7 @@ export default util.createRule({ { $defs: { modifier: { + type: 'string', enum: [ 'readonly', 'private', @@ -62,6 +63,7 @@ export default util.createRule({ minItems: 1, }, prefer: { + type: 'string', enum: ['class-property', 'parameter-property'], }, }, diff --git a/packages/eslint-plugin/src/rules/return-await.ts b/packages/eslint-plugin/src/rules/return-await.ts index 89422a32db0..f9d6584d13f 100644 --- a/packages/eslint-plugin/src/rules/return-await.ts +++ b/packages/eslint-plugin/src/rules/return-await.ts @@ -37,6 +37,7 @@ export default util.createRule({ }, schema: [ { + type: 'string', enum: ['in-try-catch', 'always', 'never'], }, ], diff --git a/packages/eslint-plugin/src/rules/space-before-function-paren.ts b/packages/eslint-plugin/src/rules/space-before-function-paren.ts index 369ae43d880..d82e8a94b26 100644 --- a/packages/eslint-plugin/src/rules/space-before-function-paren.ts +++ b/packages/eslint-plugin/src/rules/space-before-function-paren.ts @@ -29,18 +29,22 @@ export default util.createRule({ { oneOf: [ { + type: 'string', enum: ['always', 'never'], }, { type: 'object', properties: { anonymous: { + type: 'string', enum: ['always', 'never', 'ignore'], }, named: { + type: 'string', enum: ['always', 'never', 'ignore'], }, asyncArrow: { + type: 'string', enum: ['always', 'never', 'ignore'], }, }, diff --git a/packages/eslint-plugin/src/rules/triple-slash-reference.ts b/packages/eslint-plugin/src/rules/triple-slash-reference.ts index 0eef1368505..10f85b6cc6e 100644 --- a/packages/eslint-plugin/src/rules/triple-slash-reference.ts +++ b/packages/eslint-plugin/src/rules/triple-slash-reference.ts @@ -30,12 +30,15 @@ export default util.createRule({ type: 'object', properties: { lib: { + type: 'string', enum: ['always', 'never'], }, path: { + type: 'string', enum: ['always', 'never'], }, types: { + type: 'string', enum: ['always', 'never', 'prefer-import'], }, }, diff --git a/packages/eslint-plugin/tests/schema-snapshots/array-type.shot b/packages/eslint-plugin/tests/schema-snapshots/array-type.shot index 4fef7c8ec97..4f46cb9a726 100644 --- a/packages/eslint-plugin/tests/schema-snapshots/array-type.shot +++ b/packages/eslint-plugin/tests/schema-snapshots/array-type.shot @@ -8,7 +8,8 @@ exports[`Rule schemas should be convertible to TS types for documentation purpos { "$defs": { "arrayOption": { - "enum": ["array", "array-simple", "generic"] + "enum": ["array", "array-simple", "generic"], + "type": "string" } }, "additionalProperties": false, diff --git a/packages/eslint-plugin/tests/schema-snapshots/ban-ts-comment.shot b/packages/eslint-plugin/tests/schema-snapshots/ban-ts-comment.shot index ee076d804da..a39ac4e59b3 100644 --- a/packages/eslint-plugin/tests/schema-snapshots/ban-ts-comment.shot +++ b/packages/eslint-plugin/tests/schema-snapshots/ban-ts-comment.shot @@ -14,7 +14,8 @@ exports[`Rule schemas should be convertible to TS types for documentation purpos "type": "boolean" }, { - "enum": ["allow-with-description"] + "enum": ["allow-with-description"], + "type": "string" }, { "additionalProperties": false, diff --git a/packages/eslint-plugin/tests/schema-snapshots/ban-types.shot b/packages/eslint-plugin/tests/schema-snapshots/ban-types.shot index 68f35c203ee..a7fe2d555cd 100644 --- a/packages/eslint-plugin/tests/schema-snapshots/ban-types.shot +++ b/packages/eslint-plugin/tests/schema-snapshots/ban-types.shot @@ -15,11 +15,13 @@ exports[`Rule schemas should be convertible to TS types for documentation purpos }, { "description": "Un-bans the type (useful when paired with \`extendDefaults\`)", - "enum": [false] + "enum": [false], + "type": "boolean" }, { "description": "Bans the type with the default message", - "enum": [true] + "enum": [true], + "type": "boolean" }, { "description": "Bans the type with a custom message", diff --git a/packages/eslint-plugin/tests/schema-snapshots/class-literal-property-style.shot b/packages/eslint-plugin/tests/schema-snapshots/class-literal-property-style.shot index 1bf67927f61..ab5b34c1d89 100644 --- a/packages/eslint-plugin/tests/schema-snapshots/class-literal-property-style.shot +++ b/packages/eslint-plugin/tests/schema-snapshots/class-literal-property-style.shot @@ -6,7 +6,8 @@ exports[`Rule schemas should be convertible to TS types for documentation purpos [ { - "enum": ["fields", "getters"] + "enum": ["fields", "getters"], + "type": "string" } ] diff --git a/packages/eslint-plugin/tests/schema-snapshots/comma-dangle.shot b/packages/eslint-plugin/tests/schema-snapshots/comma-dangle.shot index a5b0ca54a31..645b7ce040f 100644 --- a/packages/eslint-plugin/tests/schema-snapshots/comma-dangle.shot +++ b/packages/eslint-plugin/tests/schema-snapshots/comma-dangle.shot @@ -7,7 +7,8 @@ exports[`Rule schemas should be convertible to TS types for documentation purpos { "$defs": { "value": { - "enum": ["always", "always-multiline", "never", "only-multiline"] + "enum": ["always", "always-multiline", "never", "only-multiline"], + "type": "string" }, "valueWithIgnore": { "enum": [ @@ -16,10 +17,11 @@ exports[`Rule schemas should be convertible to TS types for documentation purpos "ignore", "never", "only-multiline" - ] + ], + "type": "string" } }, - "additionalProperties": false, + "additionalItems": false, "items": [ { "oneOf": [ diff --git a/packages/eslint-plugin/tests/schema-snapshots/consistent-generic-constructors.shot b/packages/eslint-plugin/tests/schema-snapshots/consistent-generic-constructors.shot index 540eea55862..339f564088a 100644 --- a/packages/eslint-plugin/tests/schema-snapshots/consistent-generic-constructors.shot +++ b/packages/eslint-plugin/tests/schema-snapshots/consistent-generic-constructors.shot @@ -6,7 +6,8 @@ exports[`Rule schemas should be convertible to TS types for documentation purpos [ { - "enum": ["constructor", "type-annotation"] + "enum": ["constructor", "type-annotation"], + "type": "string" } ] diff --git a/packages/eslint-plugin/tests/schema-snapshots/consistent-indexed-object-style.shot b/packages/eslint-plugin/tests/schema-snapshots/consistent-indexed-object-style.shot index 5befaa24e0c..d498aa9d357 100644 --- a/packages/eslint-plugin/tests/schema-snapshots/consistent-indexed-object-style.shot +++ b/packages/eslint-plugin/tests/schema-snapshots/consistent-indexed-object-style.shot @@ -6,7 +6,8 @@ exports[`Rule schemas should be convertible to TS types for documentation purpos [ { - "enum": ["index-signature", "record"] + "enum": ["index-signature", "record"], + "type": "string" } ] diff --git a/packages/eslint-plugin/tests/schema-snapshots/consistent-type-assertions.shot b/packages/eslint-plugin/tests/schema-snapshots/consistent-type-assertions.shot index 04acdfde423..b50dc807a9b 100644 --- a/packages/eslint-plugin/tests/schema-snapshots/consistent-type-assertions.shot +++ b/packages/eslint-plugin/tests/schema-snapshots/consistent-type-assertions.shot @@ -11,7 +11,8 @@ exports[`Rule schemas should be convertible to TS types for documentation purpos "additionalProperties": false, "properties": { "assertionStyle": { - "enum": ["never"] + "enum": ["never"], + "type": "string" } }, "required": ["assertionStyle"], @@ -21,10 +22,12 @@ exports[`Rule schemas should be convertible to TS types for documentation purpos "additionalProperties": false, "properties": { "assertionStyle": { - "enum": ["angle-bracket", "as"] + "enum": ["angle-bracket", "as"], + "type": "string" }, "objectLiteralTypeAssertions": { - "enum": ["allow", "allow-as-parameter", "never"] + "enum": ["allow", "allow-as-parameter", "never"], + "type": "string" } }, "required": ["assertionStyle"], diff --git a/packages/eslint-plugin/tests/schema-snapshots/consistent-type-definitions.shot b/packages/eslint-plugin/tests/schema-snapshots/consistent-type-definitions.shot index 130f2ac3c9c..0a721742384 100644 --- a/packages/eslint-plugin/tests/schema-snapshots/consistent-type-definitions.shot +++ b/packages/eslint-plugin/tests/schema-snapshots/consistent-type-definitions.shot @@ -6,7 +6,8 @@ exports[`Rule schemas should be convertible to TS types for documentation purpos [ { - "enum": ["interface", "type"] + "enum": ["interface", "type"], + "type": "string" } ] diff --git a/packages/eslint-plugin/tests/schema-snapshots/consistent-type-imports.shot b/packages/eslint-plugin/tests/schema-snapshots/consistent-type-imports.shot index 4f8ad794909..7164fbdd367 100644 --- a/packages/eslint-plugin/tests/schema-snapshots/consistent-type-imports.shot +++ b/packages/eslint-plugin/tests/schema-snapshots/consistent-type-imports.shot @@ -12,10 +12,12 @@ exports[`Rule schemas should be convertible to TS types for documentation purpos "type": "boolean" }, "fixStyle": { - "enum": ["inline-type-imports", "separate-type-imports"] + "enum": ["inline-type-imports", "separate-type-imports"], + "type": "string" }, "prefer": { - "enum": ["no-type-imports", "type-imports"] + "enum": ["no-type-imports", "type-imports"], + "type": "string" } }, "type": "object" diff --git a/packages/eslint-plugin/tests/schema-snapshots/explicit-member-accessibility.shot b/packages/eslint-plugin/tests/schema-snapshots/explicit-member-accessibility.shot index f0a2dc9a4fb..5a33d7fca21 100644 --- a/packages/eslint-plugin/tests/schema-snapshots/explicit-member-accessibility.shot +++ b/packages/eslint-plugin/tests/schema-snapshots/explicit-member-accessibility.shot @@ -11,15 +11,18 @@ exports[`Rule schemas should be convertible to TS types for documentation purpos "oneOf": [ { "description": "Always require an accessor.", - "enum": ["explicit"] + "enum": ["explicit"], + "type": "string" }, { "description": "Require an accessor except when public.", - "enum": ["no-public"] + "enum": ["no-public"], + "type": "string" }, { "description": "Never check whether there is an accessor.", - "enum": ["off"] + "enum": ["off"], + "type": "string" } ] } diff --git a/packages/eslint-plugin/tests/schema-snapshots/func-call-spacing.shot b/packages/eslint-plugin/tests/schema-snapshots/func-call-spacing.shot index 3c9d0f7ed23..d3192bbdc54 100644 --- a/packages/eslint-plugin/tests/schema-snapshots/func-call-spacing.shot +++ b/packages/eslint-plugin/tests/schema-snapshots/func-call-spacing.shot @@ -9,7 +9,8 @@ exports[`Rule schemas should be convertible to TS types for documentation purpos { "items": [ { - "enum": ["never"] + "enum": ["never"], + "type": "string" } ], "maxItems": 1, @@ -19,7 +20,8 @@ exports[`Rule schemas should be convertible to TS types for documentation purpos { "items": [ { - "enum": ["always"] + "enum": ["always"], + "type": "string" }, { "additionalProperties": false, diff --git a/packages/eslint-plugin/tests/schema-snapshots/member-delimiter-style.shot b/packages/eslint-plugin/tests/schema-snapshots/member-delimiter-style.shot index 6b5cf0a4a41..a1c9dcc17ee 100644 --- a/packages/eslint-plugin/tests/schema-snapshots/member-delimiter-style.shot +++ b/packages/eslint-plugin/tests/schema-snapshots/member-delimiter-style.shot @@ -38,10 +38,12 @@ exports[`Rule schemas should be convertible to TS types for documentation purpos "type": "object" }, "multiLineOption": { - "enum": ["comma", "none", "semi"] + "enum": ["comma", "none", "semi"], + "type": "string" }, "singleLineOption": { - "enum": ["comma", "semi"] + "enum": ["comma", "semi"], + "type": "string" } }, "additionalProperties": false, @@ -59,7 +61,8 @@ exports[`Rule schemas should be convertible to TS types for documentation purpos "type": "object" }, "multilineDetection": { - "enum": ["brackets", "last-member"] + "enum": ["brackets", "last-member"], + "type": "string" }, "overrides": { "additionalProperties": false, diff --git a/packages/eslint-plugin/tests/schema-snapshots/method-signature-style.shot b/packages/eslint-plugin/tests/schema-snapshots/method-signature-style.shot index d03573a0898..b66647bd92d 100644 --- a/packages/eslint-plugin/tests/schema-snapshots/method-signature-style.shot +++ b/packages/eslint-plugin/tests/schema-snapshots/method-signature-style.shot @@ -6,7 +6,8 @@ exports[`Rule schemas should be convertible to TS types for documentation purpos [ { - "enum": ["method", "property"] + "enum": ["method", "property"], + "type": "string" } ] diff --git a/packages/eslint-plugin/tests/schema-snapshots/no-empty-function.shot b/packages/eslint-plugin/tests/schema-snapshots/no-empty-function.shot index e863a0f81cc..c7660d3ec1e 100644 --- a/packages/eslint-plugin/tests/schema-snapshots/no-empty-function.shot +++ b/packages/eslint-plugin/tests/schema-snapshots/no-empty-function.shot @@ -25,7 +25,8 @@ exports[`Rule schemas should be convertible to TS types for documentation purpos "private-constructors", "protected-constructors", "setters" - ] + ], + "type": "string" }, "type": "array", "uniqueItems": true diff --git a/packages/eslint-plugin/tests/schema-snapshots/no-invalid-void-type.shot b/packages/eslint-plugin/tests/schema-snapshots/no-invalid-void-type.shot index 61f32fe43a8..a6d271f1a0f 100644 --- a/packages/eslint-plugin/tests/schema-snapshots/no-invalid-void-type.shot +++ b/packages/eslint-plugin/tests/schema-snapshots/no-invalid-void-type.shot @@ -20,7 +20,7 @@ exports[`Rule schemas should be convertible to TS types for documentation purpos "items": { "type": "string" }, - "minLength": 1, + "minItems": 1, "type": "array" } ] @@ -36,7 +36,7 @@ exports[`Rule schemas should be convertible to TS types for documentation purpos type Options = [ { allowAsThisParameter?: boolean; - allowInGenericTypeArguments?: boolean | string[]; + allowInGenericTypeArguments?: [string, ...string[]] | boolean; }, ]; " diff --git a/packages/eslint-plugin/tests/schema-snapshots/no-shadow.shot b/packages/eslint-plugin/tests/schema-snapshots/no-shadow.shot index d16291030d6..78b85fbadc0 100644 --- a/packages/eslint-plugin/tests/schema-snapshots/no-shadow.shot +++ b/packages/eslint-plugin/tests/schema-snapshots/no-shadow.shot @@ -18,7 +18,8 @@ exports[`Rule schemas should be convertible to TS types for documentation purpos "type": "boolean" }, "hoist": { - "enum": ["all", "functions", "never"] + "enum": ["all", "functions", "never"], + "type": "string" }, "ignoreFunctionTypeParameterNameValueShadow": { "type": "boolean" diff --git a/packages/eslint-plugin/tests/schema-snapshots/no-type-alias.shot b/packages/eslint-plugin/tests/schema-snapshots/no-type-alias.shot index 16653ab2565..f2c6920de9c 100644 --- a/packages/eslint-plugin/tests/schema-snapshots/no-type-alias.shot +++ b/packages/eslint-plugin/tests/schema-snapshots/no-type-alias.shot @@ -14,10 +14,12 @@ exports[`Rule schemas should be convertible to TS types for documentation purpos "in-unions", "in-unions-and-intersections", "never" - ] + ], + "type": "string" }, "simpleOptions": { - "enum": ["always", "never"] + "enum": ["always", "never"], + "type": "string" } }, "additionalProperties": false, diff --git a/packages/eslint-plugin/tests/schema-snapshots/no-unused-vars.shot b/packages/eslint-plugin/tests/schema-snapshots/no-unused-vars.shot index 802a33bfade..a87d2016784 100644 --- a/packages/eslint-plugin/tests/schema-snapshots/no-unused-vars.shot +++ b/packages/eslint-plugin/tests/schema-snapshots/no-unused-vars.shot @@ -8,19 +8,22 @@ exports[`Rule schemas should be convertible to TS types for documentation purpos { "oneOf": [ { - "enum": ["all", "local"] + "enum": ["all", "local"], + "type": "string" }, { "additionalProperties": false, "properties": { "args": { - "enum": ["after-used", "all", "none"] + "enum": ["after-used", "all", "none"], + "type": "string" }, "argsIgnorePattern": { "type": "string" }, "caughtErrors": { - "enum": ["all", "none"] + "enum": ["all", "none"], + "type": "string" }, "caughtErrorsIgnorePattern": { "type": "string" @@ -32,7 +35,8 @@ exports[`Rule schemas should be convertible to TS types for documentation purpos "type": "boolean" }, "vars": { - "enum": ["all", "local"] + "enum": ["all", "local"], + "type": "string" }, "varsIgnorePattern": { "type": "string" diff --git a/packages/eslint-plugin/tests/schema-snapshots/no-use-before-define.shot b/packages/eslint-plugin/tests/schema-snapshots/no-use-before-define.shot index cfe91c2c7b7..624448da333 100644 --- a/packages/eslint-plugin/tests/schema-snapshots/no-use-before-define.shot +++ b/packages/eslint-plugin/tests/schema-snapshots/no-use-before-define.shot @@ -8,7 +8,8 @@ exports[`Rule schemas should be convertible to TS types for documentation purpos { "oneOf": [ { - "enum": ["nofunc"] + "enum": ["nofunc"], + "type": "string" }, { "additionalProperties": false, diff --git a/packages/eslint-plugin/tests/schema-snapshots/padding-line-between-statements.shot b/packages/eslint-plugin/tests/schema-snapshots/padding-line-between-statements.shot index 7e87a4e6856..63acbd25d50 100644 --- a/packages/eslint-plugin/tests/schema-snapshots/padding-line-between-statements.shot +++ b/packages/eslint-plugin/tests/schema-snapshots/padding-line-between-statements.shot @@ -7,7 +7,8 @@ exports[`Rule schemas should be convertible to TS types for documentation purpos { "$defs": { "paddingType": { - "enum": ["always", "any", "never"] + "enum": ["always", "any", "never"], + "type": "string" }, "statementType": { "anyOf": [ @@ -53,7 +54,8 @@ exports[`Rule schemas should be convertible to TS types for documentation purpos "var", "while", "with" - ] + ], + "type": "string" }, { "additionalItems": false, @@ -99,7 +101,8 @@ exports[`Rule schemas should be convertible to TS types for documentation purpos "var", "while", "with" - ] + ], + "type": "string" }, "minItems": 1, "type": "array", diff --git a/packages/eslint-plugin/tests/schema-snapshots/parameter-properties.shot b/packages/eslint-plugin/tests/schema-snapshots/parameter-properties.shot index f317443ca00..461b50d919e 100644 --- a/packages/eslint-plugin/tests/schema-snapshots/parameter-properties.shot +++ b/packages/eslint-plugin/tests/schema-snapshots/parameter-properties.shot @@ -16,7 +16,8 @@ exports[`Rule schemas should be convertible to TS types for documentation purpos "public", "public readonly", "readonly" - ] + ], + "type": "string" } }, "additionalProperties": false, @@ -29,7 +30,8 @@ exports[`Rule schemas should be convertible to TS types for documentation purpos "type": "array" }, "prefer": { - "enum": ["class-property", "parameter-property"] + "enum": ["class-property", "parameter-property"], + "type": "string" } }, "type": "object" diff --git a/packages/eslint-plugin/tests/schema-snapshots/return-await.shot b/packages/eslint-plugin/tests/schema-snapshots/return-await.shot index 7d0a6d5e142..5d79a331bf3 100644 --- a/packages/eslint-plugin/tests/schema-snapshots/return-await.shot +++ b/packages/eslint-plugin/tests/schema-snapshots/return-await.shot @@ -6,7 +6,8 @@ exports[`Rule schemas should be convertible to TS types for documentation purpos [ { - "enum": ["always", "in-try-catch", "never"] + "enum": ["always", "in-try-catch", "never"], + "type": "string" } ] diff --git a/packages/eslint-plugin/tests/schema-snapshots/space-before-function-paren.shot b/packages/eslint-plugin/tests/schema-snapshots/space-before-function-paren.shot index 67ca6e24371..08a6df9b902 100644 --- a/packages/eslint-plugin/tests/schema-snapshots/space-before-function-paren.shot +++ b/packages/eslint-plugin/tests/schema-snapshots/space-before-function-paren.shot @@ -8,19 +8,23 @@ exports[`Rule schemas should be convertible to TS types for documentation purpos { "oneOf": [ { - "enum": ["always", "never"] + "enum": ["always", "never"], + "type": "string" }, { "additionalProperties": false, "properties": { "anonymous": { - "enum": ["always", "ignore", "never"] + "enum": ["always", "ignore", "never"], + "type": "string" }, "asyncArrow": { - "enum": ["always", "ignore", "never"] + "enum": ["always", "ignore", "never"], + "type": "string" }, "named": { - "enum": ["always", "ignore", "never"] + "enum": ["always", "ignore", "never"], + "type": "string" } }, "type": "object" diff --git a/packages/eslint-plugin/tests/schema-snapshots/triple-slash-reference.shot b/packages/eslint-plugin/tests/schema-snapshots/triple-slash-reference.shot index c5b400712bf..330be71ffe1 100644 --- a/packages/eslint-plugin/tests/schema-snapshots/triple-slash-reference.shot +++ b/packages/eslint-plugin/tests/schema-snapshots/triple-slash-reference.shot @@ -9,13 +9,16 @@ exports[`Rule schemas should be convertible to TS types for documentation purpos "additionalProperties": false, "properties": { "lib": { - "enum": ["always", "never"] + "enum": ["always", "never"], + "type": "string" }, "path": { - "enum": ["always", "never"] + "enum": ["always", "never"], + "type": "string" }, "types": { - "enum": ["always", "never", "prefer-import"] + "enum": ["always", "never", "prefer-import"], + "type": "string" } }, "type": "object" diff --git a/packages/eslint-plugin/tests/schemas.test.ts b/packages/eslint-plugin/tests/schemas.test.ts index 19cf8280c5b..08221924026 100644 --- a/packages/eslint-plugin/tests/schemas.test.ts +++ b/packages/eslint-plugin/tests/schemas.test.ts @@ -1,16 +1,16 @@ import 'jest-specific-snapshot'; +import fs from 'node:fs'; +import path from 'node:path'; + import { compile } from '@typescript-eslint/rule-schema-to-typescript-types'; -import type { JSONSchema4 } from '@typescript-eslint/utils/json-schema'; -import fs, { mkdirSync } from 'fs'; -import path from 'path'; import { format, resolveConfig } from 'prettier'; import rules from '../src/rules/index'; const snapshotFolder = path.resolve(__dirname, 'schema-snapshots'); try { - mkdirSync(snapshotFolder); + fs.mkdirSync(snapshotFolder); } catch { // ignore failure as it means it already exists probably } @@ -129,7 +129,7 @@ const VALID_SCHEMA_PROPS = new Set([ 'title', 'type', 'uniqueItems', -] satisfies (keyof JSONSchema4)[]); +]); describe('Rules should only define valid keys on schemas', () => { for (const [ruleName, ruleDef] of Object.entries(rules)) { (ruleName === ONLY ? it.only : it)(ruleName, () => { diff --git a/packages/rule-schema-to-typescript-types/src/generateArrayType.ts b/packages/rule-schema-to-typescript-types/src/generateArrayType.ts index cece1fa4025..1165ec7dbc4 100644 --- a/packages/rule-schema-to-typescript-types/src/generateArrayType.ts +++ b/packages/rule-schema-to-typescript-types/src/generateArrayType.ts @@ -1,4 +1,7 @@ -import type { JSONSchema4 } from '@typescript-eslint/utils/json-schema'; +import type { + JSONSchema4, + JSONSchema4ArraySchema, +} from '@typescript-eslint/utils/json-schema'; import { NotSupportedError, UnexpectedError } from './errors'; import { generateType } from './generateType'; @@ -13,7 +16,7 @@ import type { ArrayAST, AST, RefMap, TupleAST, UnionAST } from './types'; const MAX_ITEMS_TO_TUPLIZE = 20; export function generateArrayType( - schema: JSONSchema4, + schema: JSONSchema4ArraySchema, refMap: RefMap, ): ArrayAST | TupleAST | UnionAST { if (!schema.items) { diff --git a/packages/rule-schema-to-typescript-types/src/generateObjectType.ts b/packages/rule-schema-to-typescript-types/src/generateObjectType.ts index c0de43699d3..30ece46cdf3 100644 --- a/packages/rule-schema-to-typescript-types/src/generateObjectType.ts +++ b/packages/rule-schema-to-typescript-types/src/generateObjectType.ts @@ -1,5 +1,5 @@ import { requiresQuoting } from '@typescript-eslint/type-utils'; -import type { JSONSchema4 } from 'json-schema'; +import type { JSONSchema4ObjectSchema } from '@typescript-eslint/utils/json-schema'; import { generateType } from './generateType'; import { getCommentLines } from './getCommentLines'; @@ -7,7 +7,7 @@ import { isArray } from './isArray'; import type { AST, ObjectAST, RefMap } from './types'; export function generateObjectType( - schema: JSONSchema4, + schema: JSONSchema4ObjectSchema, refMap: RefMap, ): ObjectAST { const commentLines = getCommentLines(schema); diff --git a/packages/rule-schema-to-typescript-types/src/generateType.ts b/packages/rule-schema-to-typescript-types/src/generateType.ts index d6c0efa2890..e077926c34b 100644 --- a/packages/rule-schema-to-typescript-types/src/generateType.ts +++ b/packages/rule-schema-to-typescript-types/src/generateType.ts @@ -9,7 +9,7 @@ import { isArray } from './isArray'; import type { AST, RefMap } from './types'; // keywords we probably should support but currently do not support -const UNSUPPORTED_KEYWORDS = new Set([ +const UNSUPPORTED_KEYWORDS = new Set([ 'allOf', 'dependencies', 'extends', @@ -18,7 +18,7 @@ const UNSUPPORTED_KEYWORDS = new Set([ 'multipleOf', 'not', 'patternProperties', -] satisfies (keyof JSONSchema4)[]); +]); export function generateType(schema: JSONSchema4, refMap: RefMap): AST { const unsupportedProps = Object.keys(schema).filter(key => @@ -46,13 +46,13 @@ export function generateType(schema: JSONSchema4, refMap: RefMap): AST { commentLines, }; } - if (schema.enum) { + if ('enum' in schema && schema.enum) { return { ...generateUnionType(schema.enum, refMap), commentLines, }; } - if (schema.anyOf) { + if ('anyOf' in schema && schema.anyOf) { return { // a union isn't *TECHNICALLY* correct - technically anyOf is actually // anyOf: [T, U, V] -> T | U | V | T & U | T & V | U & V @@ -61,22 +61,22 @@ export function generateType(schema: JSONSchema4, refMap: RefMap): AST { commentLines, }; } - if (schema.oneOf) { + if ('oneOf' in schema && schema.oneOf) { return { ...generateUnionType(schema.oneOf, refMap), commentLines, }; } - if (isArray(schema.type)) { - throw new NotSupportedError('schemas with multiple types', schema); - } - if (schema.type == null) { + if (!('type' in schema) || schema.type == null) { throw new NotSupportedError( 'untyped schemas without one of [$ref, enum, oneOf]', schema, ); } + if (isArray(schema.type)) { + throw new NotSupportedError('schemas with multiple types', schema); + } switch (schema.type) { case 'any': diff --git a/packages/rule-schema-to-typescript-types/src/index.ts b/packages/rule-schema-to-typescript-types/src/index.ts index 3100f122f2d..43d16826ab3 100644 --- a/packages/rule-schema-to-typescript-types/src/index.ts +++ b/packages/rule-schema-to-typescript-types/src/index.ts @@ -1,4 +1,4 @@ -import type { JSONSchema4 } from 'json-schema'; +import type { JSONSchema4 } from '@typescript-eslint/utils/json-schema'; import path from 'path'; import { format as prettierFormat, resolveConfig } from 'prettier'; diff --git a/packages/rule-tester/src/utils/config-schema.ts b/packages/rule-tester/src/utils/config-schema.ts index 8261ac8749c..8aaa46d4cac 100644 --- a/packages/rule-tester/src/utils/config-schema.ts +++ b/packages/rule-tester/src/utils/config-schema.ts @@ -1,8 +1,8 @@ // Forked from https://github.com/eslint/eslint/blob/ad9dd6a933fd098a0d99c6a9aa059850535c23ee/conf/config-schema.js -import type { JSONSchema } from '@typescript-eslint/utils'; +import type { JSONSchema4 } from '@typescript-eslint/utils/json-schema'; -const baseConfigProperties: JSONSchema.JSONSchema4['properties'] = { +const baseConfigProperties: Record = { $schema: { type: 'string' }, defaultFilenames: { type: 'object', @@ -39,7 +39,7 @@ const baseConfigProperties: JSONSchema.JSONSchema4['properties'] = { ecmaFeatures: { type: 'object' }, // deprecated; logs a warning when used }; -export const configSchema: JSONSchema.JSONSchema4 = { +export const configSchema: JSONSchema4 = { definitions: { stringOrStrings: { oneOf: [ diff --git a/packages/rule-tester/tests/RuleTester.test.ts b/packages/rule-tester/tests/RuleTester.test.ts index dbbaf85ef7a..93f9f6d35d2 100644 --- a/packages/rule-tester/tests/RuleTester.test.ts +++ b/packages/rule-tester/tests/RuleTester.test.ts @@ -125,7 +125,7 @@ const NOOP_RULE: RuleModule<'error', []> = { error: 'error', }, type: 'problem', - schema: {}, + schema: [], }, defaultOptions: [], create() { diff --git a/packages/utils/src/json-schema.ts b/packages/utils/src/json-schema.ts index c6b1ccacd71..f022791c2f8 100644 --- a/packages/utils/src/json-schema.ts +++ b/packages/utils/src/json-schema.ts @@ -1,2 +1,498 @@ -// eslint-disable-next-line import/no-extraneous-dependencies -export type * from 'json-schema'; +/** + * This is a fork of https://github.com/DefinitelyTyped/DefinitelyTyped/blob/13f63c2eb8d7479caf01ab8d72f9e3683368a8f5/types/json-schema/index.d.ts + * We intentionally fork this because: + * - ESLint ***ONLY*** supports JSONSchema v4 + * - We want to provide stricter types + */ + +//================================================================================================== +// JSON Schema Draft 04 +//================================================================================================== + +/** + * @see https://tools.ietf.org/html/draft-zyp-json-schema-03#section-5.1 + */ +export type JSONSchema4TypeName = + | 'string' + | 'number' + | 'integer' + | 'boolean' + | 'object' + | 'array' + | 'null' + | 'any'; + +/** + * @see https://tools.ietf.org/html/draft-zyp-json-schema-04#section-3.5 + */ +export type JSONSchema4Type = string | number | boolean | null; + +/** + * Meta schema + * + * Recommended values: + * - 'http://json-schema.org/schema#' + * - 'http://json-schema.org/hyper-schema#' + * - 'http://json-schema.org/draft-04/schema#' + * - 'http://json-schema.org/draft-04/hyper-schema#' + * - 'http://json-schema.org/draft-03/schema#' + * - 'http://json-schema.org/draft-03/hyper-schema#' + * + * @see https://tools.ietf.org/html/draft-handrews-json-schema-validation-01#section-5 + */ +export type JSONSchema4Version = string; + +/** + * JSON Schema V4 + * @see https://tools.ietf.org/html/draft-zyp-json-schema-04 + */ +export type JSONSchema4 = + | JSONSchema4ObjectSchema + | JSONSchema4ArraySchema + | JSONSchema4StringSchema + | JSONSchema4NumberSchema + | JSONSchema4BoleanSchema + | JSONSchema4NullSchema + | JSONSchema4AnySchema + | JSONSchema4RefSchema + | JSONSchema4AllOfSchema + | JSONSchema4AnyOfSchema + | JSONSchema4OneOfSchema + | JSONSchema4MultiSchema; + +interface JSONSchema4Base { + id?: string | undefined; + + $schema?: JSONSchema4Version | undefined; + + /** + * A single type, or a union of simple types + */ + type?: JSONSchema4TypeName | JSONSchema4TypeName[] | undefined; + + /** + * Path to a schema defined in `definitions`/`$defs` that will form the base + * for this schema. + * + * If you are defining an "array" schema (`schema: [ ... ]`) for your rule + * then you should prefix this with `items/0` so that the validator can find + * your definitions. + * + * eg: `'#/items/0/definitions/myDef'` + * + * Otherwise if you are defining an "object" schema (`schema: { ... }`) for + * your rule you can directly reference your definitions + * + * eg: `'#/definitions/myDef'` + */ + $ref?: string | undefined; + + /** + * This attribute is a string that provides a short description of the + * instance property. + * + * @see https://tools.ietf.org/html/draft-zyp-json-schema-03#section-5.21 + */ + title?: string | undefined; + + /** + * This attribute is a string that provides a full description of the of + * purpose the instance property. + * + * @see https://tools.ietf.org/html/draft-zyp-json-schema-03#section-5.22 + */ + description?: string | undefined; + + /** + * Reusable definitions that can be referenced via `$ref` + */ + definitions?: + | { + [k: string]: JSONSchema4; + } + | undefined; + /** + * Reusable definitions that can be referenced via `$ref` + */ + $defs?: + | { + [k: string]: JSONSchema4; + } + | undefined; + + /** + * The value of this property MUST be another schema which will provide + * a base schema which the current schema will inherit from. The + * inheritance rules are such that any instance that is valid according + * to the current schema MUST be valid according to the referenced + * schema. This MAY also be an array, in which case, the instance MUST + * be valid for all the schemas in the array. A schema that extends + * another schema MAY define additional attributes, constrain existing + * attributes, or add other constraints. + * + * Conceptually, the behavior of extends can be seen as validating an + * instance against all constraints in the extending schema as well as + * the extended schema(s). + * + * @see https://tools.ietf.org/html/draft-zyp-json-schema-03#section-5.26 + */ + extends?: string | string[] | undefined; + + /** + * The default value for the item if not present + */ + default?: JSONSchema4Type | undefined; + + /** + * This attribute indicates if the instance must have a value, and not + * be undefined. This is false by default, making the instance + * optional. + * + * @see https://tools.ietf.org/html/draft-zyp-json-schema-03#section-5.7 + */ + required?: boolean | string[] | undefined; + + /** + * (NOT) Must not be valid against the given schema + */ + not?: JSONSchema4 | undefined; + /** + * (AND) Must be valid against all of the sub-schemas + */ + allOf?: JSONSchema4[] | undefined; + /** + * (OR) Must be valid against any of the sub-schemas + */ + anyOf?: JSONSchema4[] | undefined; + /** + * (XOR) Must be valid against exactly one of the sub-schemas + */ + oneOf?: JSONSchema4[] | undefined; +} + +export interface JSONSchema4RefSchema extends JSONSchema4Base { + type?: undefined; + $ref: string; +} + +export interface JSONSchema4AllOfSchema extends JSONSchema4Base { + type?: undefined; + allOf: JSONSchema4[]; +} + +export interface JSONSchema4AnyOfSchema extends JSONSchema4Base { + type?: undefined; + anyOf: JSONSchema4[]; +} + +export interface JSONSchema4OneOfSchema extends JSONSchema4Base { + type?: undefined; + oneOf: JSONSchema4[]; +} + +export interface JSONSchema4MultiSchema + extends Omit, + Omit, + Omit, + Omit, + Omit, + Omit, + Omit { + type: JSONSchema4TypeName[]; + /** + * This provides an enumeration of all possible values that are valid + * for the instance property. This MUST be an array, and each item in + * the array represents a possible value for the instance value. If + * this attribute is defined, the instance value MUST be one of the + * values in the array in order for the schema to be valid. + * + * @see https://tools.ietf.org/html/draft-zyp-json-schema-03#section-5.19 + */ + enum?: JSONSchema4Type[]; +} + +/** + * @see https://json-schema.org/understanding-json-schema/reference/object.html + */ +export interface JSONSchema4ObjectSchema extends JSONSchema4Base { + type: 'object'; + + /** + * This attribute defines a schema for all properties that are not + * explicitly defined in an object type definition. If specified, the + * value MUST be a schema or a boolean. If false is provided, no + * additional properties are allowed beyond the properties defined in + * the schema. The default value is an empty schema which allows any + * value for additional properties. + * + * @see https://tools.ietf.org/html/draft-zyp-json-schema-03#section-5.4 + */ + additionalProperties?: boolean | JSONSchema4 | undefined; + + /** + * This attribute is an object with property definitions that define the + * valid values of instance object property values. When the instance + * value is an object, the property values of the instance object MUST + * conform to the property definitions in this object. In this object, + * each property definition's value MUST be a schema, and the property's + * name MUST be the name of the instance property that it defines. The + * instance property value MUST be valid according to the schema from + * the property definition. Properties are considered unordered, the + * order of the instance properties MAY be in any order. + * + * @see https://tools.ietf.org/html/draft-zyp-json-schema-03#section-5.2 + */ + properties?: + | { + [k: string]: JSONSchema4; + } + | undefined; + + /** + * This attribute is an object that defines the schema for a set of + * property names of an object instance. The name of each property of + * this attribute's object is a regular expression pattern in the ECMA + * 262/Perl 5 format, while the value is a schema. If the pattern + * matches the name of a property on the instance object, the value of + * the instance's property MUST be valid against the pattern name's + * schema value. + * + * @see https://tools.ietf.org/html/draft-zyp-json-schema-03#section-5.3 + */ + patternProperties?: + | { + [k: string]: JSONSchema4; + } + | undefined; + + /** + * The `dependencies` keyword conditionally applies a sub-schema when a given + * property is present. This schema is applied in the same way `allOf` applies + * schemas. Nothing is merged or extended. Both schemas apply independently. + */ + dependencies?: + | { + [k: string]: JSONSchema4 | string[]; + } + | undefined; + + /** + * The maximum number of properties allowed for record-style schemas + */ + maxProperties?: number | undefined; + /** + * The minimum number of properties required for record-style schemas + */ + minProperties?: number | undefined; +} + +/** + * @see https://json-schema.org/understanding-json-schema/reference/array.html + */ +export interface JSONSchema4ArraySchema extends JSONSchema4Base { + type: 'array'; + + /** + * May only be defined when "items" is defined, and is a tuple of JSONSchemas. + * + * This provides a definition for additional items in an array instance + * when tuple definitions of the items is provided. This can be false + * to indicate additional items in the array are not allowed, or it can + * be a schema that defines the schema of the additional items. + * + * @see https://tools.ietf.org/html/draft-zyp-json-schema-03#section-5.6 + */ + additionalItems?: boolean | JSONSchema4 | undefined; + + /** + * This attribute defines the allowed items in an instance array, and + * MUST be a schema or an array of schemas. The default value is an + * empty schema which allows any value for items in the instance array. + * + * When this attribute value is a schema and the instance value is an + * array, then all the items in the array MUST be valid according to the + * schema. + * + * When this attribute value is an array of schemas and the instance + * value is an array, each position in the instance array MUST conform + * to the schema in the corresponding position for this array. This + * called tuple typing. When tuple typing is used, additional items are + * allowed, disallowed, or constrained by the "additionalItems" + * (Section 5.6) attribute using the same rules as + * "additionalProperties" (Section 5.4) for objects. + * + * @see https://tools.ietf.org/html/draft-zyp-json-schema-03#section-5.5 + */ + items?: JSONSchema4 | JSONSchema4[] | undefined; + + /** + * Defines the maximum length of an array + */ + maxItems?: number | undefined; + + /** + * Defines the minimum length of an array + */ + minItems?: number | undefined; + + /** + * Enforces that all items in the array are unique + */ + uniqueItems?: boolean | undefined; +} + +/** + * @see https://json-schema.org/understanding-json-schema/reference/string.html + */ +export interface JSONSchema4StringSchema extends JSONSchema4Base { + type: 'string'; + + /** + * The maximum allowed length for the string + */ + maxLength?: number | undefined; + + /** + * The minimum allowed length for the string + */ + minLength?: number | undefined; + + /** + * The `pattern` keyword is used to restrict a string to a particular regular + * expression. The regular expression syntax is the one defined in JavaScript + * (ECMA 262 specifically) with Unicode support. + * + * When defining the regular expressions, it’s important to note that the + * string is considered valid if the expression matches anywhere within the + * string. For example, the regular expression "p" will match any string with + * a p in it, such as "apple" not just a string that is simply "p". Therefore, + * it is usually less confusing, as a matter of course, to surround the + * regular expression in ^...$, for example, "^p$", unless there is a good + * reason not to do so. + */ + pattern?: string | undefined; + + /** + * The `format` keyword allows for basic semantic identification of certain + * kinds of string values that are commonly used. + * + * For example, because JSON doesn’t have a “DateTime” type, dates need to be + * encoded as strings. `format` allows the schema author to indicate that the + * string value should be interpreted as a date. + * + * ajv v6 provides a few built-in formats - all other strings will cause AJV + * to throw during schema compilation + */ + format?: + | 'date' + | 'time' + | 'date-time' + | 'uri' + | 'uri-reference' + | 'uri-template' + | 'url' + | 'email' + | 'hostname' + | 'ipv4' + | 'ipv6' + | 'regex' + | 'uuid' + | 'json-pointer' + | 'json-pointer-uri-fragment' + | 'relative-json-pointer' + | undefined; + + enum?: string[] | undefined; +} + +/** + * @see https://json-schema.org/understanding-json-schema/reference/numeric.html + */ +export interface JSONSchema4NumberSchema extends JSONSchema4Base { + type: 'number' | 'integer'; + + /** + * Numbers can be restricted to a multiple of a given number, using the + * `multipleOf` keyword. It may be set to any positive number. + */ + multipleOf?: number | undefined; + + /** + * The maximum allowed value for the number + */ + maximum?: number | undefined; + + /** + * The minimum allowed value for the number + */ + minimum?: number | undefined; + + /** + * The exclusive minimum allowed value for the number + * - `true` = `x < maximum` + * - `false` = `x <= maximum` + * + * Default is `false` + */ + exclusiveMaximum?: boolean | undefined; + + /** + * Indicates whether or not `minimum` is the inclusive or exclusive minimum + * - `true` = `x > minimum` + * - `false` = `x ≥ minimum` + * + * Default is `false` + */ + exclusiveMinimum?: boolean | undefined; + + /** + * This provides an enumeration of all possible values that are valid + * for the instance property. This MUST be an array, and each item in + * the array represents a possible value for the instance value. If + * this attribute is defined, the instance value MUST be one of the + * values in the array in order for the schema to be valid. + * + * @see https://tools.ietf.org/html/draft-zyp-json-schema-03#section-5.19 + */ + enum?: number[] | undefined; +} + +/** + * @see https://json-schema.org/understanding-json-schema/reference/boolean.html + */ +export interface JSONSchema4BoleanSchema extends JSONSchema4Base { + type: 'boolean'; + + /** + * This provides an enumeration of all possible values that are valid + * for the instance property. This MUST be an array, and each item in + * the array represents a possible value for the instance value. If + * this attribute is defined, the instance value MUST be one of the + * values in the array in order for the schema to be valid. + * + * @see https://tools.ietf.org/html/draft-zyp-json-schema-03#section-5.19 + */ + enum?: boolean[] | undefined; +} + +/** + * @see https://json-schema.org/understanding-json-schema/reference/null.html + */ +export interface JSONSchema4NullSchema extends JSONSchema4Base { + type: 'null'; + + /** + * This provides an enumeration of all possible values that are valid + * for the instance property. This MUST be an array, and each item in + * the array represents a possible value for the instance value. If + * this attribute is defined, the instance value MUST be one of the + * values in the array in order for the schema to be valid. + * + * @see https://tools.ietf.org/html/draft-zyp-json-schema-03#section-5.19 + */ + enum?: null[] | undefined; +} + +export interface JSONSchema4AnySchema extends JSONSchema4Base { + type: 'any'; +} diff --git a/packages/website/blog/2023-03-13-announcing-typescript-eslint-v6-beta.md b/packages/website/blog/2023-03-13-announcing-typescript-eslint-v6-beta.md index 615a99907dd..43647637bef 100644 --- a/packages/website/blog/2023-03-13-announcing-typescript-eslint-v6-beta.md +++ b/packages/website/blog/2023-03-13-announcing-typescript-eslint-v6-beta.md @@ -332,6 +332,7 @@ For more information on the package, [see the `rule-tester` package documentatio - [feat(typescript-estree): remove optionality from AST boolean properties](https://github.com/typescript-eslint/typescript-eslint/pull/6274): Switches most AST properties marked as `?: boolean` to `: boolean`, as well as some properties marked as `?:` optional to `| undefined`. This results in more predictable AST node object shapes. - [chore(typescript-estree): remove visitor-keys backwards compat export](https://github.com/typescript-eslint/typescript-eslint/pull/6242): `visitorKeys` can now only be imported from `@typescript-eslint/visitor-keys`. Previously it was also re-exported by `@typescript-eslint/utils`. - [feat: add package.json exports for public packages](https://github.com/typescript-eslint/typescript-eslint/pull/6458): `@typescript-eslint/*` packages now use `exports` to prevent importing internal file paths. +- [feat: fork json schema types for better compat with ESLint rule validation #6963](https://github.com/typescript-eslint/typescript-eslint/pull/6963): `@typescript-eslint/utils` now exports a more strict version of `JSONSchema4` types, which are more strict in type checking rule options types ## Appreciation diff --git a/packages/website/src/components/lib/jsonSchema.ts b/packages/website/src/components/lib/jsonSchema.ts index 124b85e7342..cc68b440163 100644 --- a/packages/website/src/components/lib/jsonSchema.ts +++ b/packages/website/src/components/lib/jsonSchema.ts @@ -37,24 +37,27 @@ export function getRuleJsonSchemaWithErrorLevel( additionalItems: false, }; } - // example: explicit-member-accessibility - if (isArray(ruleSchema.items)) { - return { - ...ruleSchema, - items: [defaultRuleSchema, ...ruleSchema.items], - maxItems: ruleSchema.maxItems ? ruleSchema.maxItems + 1 : undefined, - minItems: ruleSchema.minItems ? ruleSchema.minItems + 1 : 1, - additionalItems: false, - }; - } - // example: naming-convention rule - if (typeof ruleSchema.items === 'object' && ruleSchema.items) { - return { - ...ruleSchema, - items: [defaultRuleSchema], - additionalItems: ruleSchema.items, - }; + if (ruleSchema.type === 'array') { + // example: explicit-member-accessibility + if (isArray(ruleSchema.items)) { + return { + ...ruleSchema, + items: [defaultRuleSchema, ...ruleSchema.items], + maxItems: ruleSchema.maxItems ? ruleSchema.maxItems + 1 : undefined, + minItems: ruleSchema.minItems ? ruleSchema.minItems + 1 : 1, + additionalItems: false, + }; + } + // example: naming-convention rule + if (typeof ruleSchema.items === 'object' && ruleSchema.items) { + return { + ...ruleSchema, + items: [defaultRuleSchema], + additionalItems: ruleSchema.items, + }; + } } + // example eqeqeq if (isArray(ruleSchema.anyOf)) { return { diff --git a/patches/@types+json-schema+7.0.11.patch b/patches/@types+json-schema+7.0.11.patch deleted file mode 100644 index 33f3206e1ac..00000000000 --- a/patches/@types+json-schema+7.0.11.patch +++ /dev/null @@ -1,35 +0,0 @@ -diff --git a/node_modules/@types/json-schema/index.d.ts b/node_modules/@types/json-schema/index.d.ts -index 7a92dec..44d9691 100755 ---- a/node_modules/@types/json-schema/index.d.ts -+++ b/node_modules/@types/json-schema/index.d.ts -@@ -154,9 +154,18 @@ export interface JSONSchema4 { - */ - additionalProperties?: boolean | JSONSchema4 | undefined; - -+ /** -+ * Reusable definitions that can be referenced via `$ref` -+ */ - definitions?: { - [k: string]: JSONSchema4; - } | undefined; -+ /** -+ * Reusable definitions that can be referenced via `$ref` -+ */ -+ $defs?: { -+ [k: string]: JSONSchema4; -+ } | undefined; - - /** - * This attribute is an object with property definitions that define the -@@ -232,11 +241,6 @@ export interface JSONSchema4 { - */ - extends?: string | string[] | undefined; - -- /** -- * @see https://tools.ietf.org/html/draft-zyp-json-schema-04#section-5.6 -- */ -- [k: string]: any; -- - format?: string | undefined; - } - diff --git a/yarn.lock b/yarn.lock index 1f151cb9c53..2007a9a2114 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4352,6 +4352,13 @@ dependencies: "@types/node" "*" +"@types/debug@*": + version "4.1.8" + resolved "https://registry.yarnpkg.com/@types/debug/-/debug-4.1.8.tgz#cef723a5d0a90990313faec2d1e22aee5eecb317" + integrity sha512-/vPO1EPOs306Cvhwv7KfVfYvOJqA/S/AXjaHQiJboCZzcNDb+TIJFN9/2C9DZ//ijSKWioNyUxD792QmDJ+HKQ== + dependencies: + "@types/ms" "*" + "@types/debug@^4.1.7": version "4.1.7" resolved "https://registry.yarnpkg.com/@types/debug/-/debug-4.1.7.tgz#7cc0ea761509124709b8b2d1090d8f6c17aadb82" @@ -4518,6 +4525,11 @@ resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.195.tgz#bafc975b252eb6cea78882ce8a7b6bf22a6de632" integrity sha512-Hwx9EUgdwf2GLarOjQp5ZH8ZmblzcbTBC2wtQWNKARBSxM9ezRIAUpeDTgoQRAFB0+8CNWXVA9+MaSOzOF3nPg== +"@types/marked@*": + version "5.0.0" + resolved "https://registry.yarnpkg.com/@types/marked/-/marked-5.0.0.tgz#3235b9133054e6586eedabfb77aa7d4a4bafbfcf" + integrity sha512-YcZe50jhltsCq7rc9MNZC/4QB/OnA2Pd6hrOSTOFajtabN+38slqgDDCeE/0F83SjkKBQcsZUj7VLWR0H5cKRA== + "@types/marked@^4.0.8": version "4.0.8" resolved "https://registry.yarnpkg.com/@types/marked/-/marked-4.0.8.tgz#b316887ab3499d0a8f4c70b7bd8508f92d477955" @@ -4555,7 +4567,7 @@ resolved "https://registry.yarnpkg.com/@types/ms/-/ms-0.7.31.tgz#31b7ca6407128a3d2bbc27fe2d21b345397f6197" integrity sha512-iiUgKzV9AuaEkZqkOLDIvlQiL6ltuZd9tGcW3gwpnX8JbuiuhFlEGmmFXEXkN50Cvq7Os88IY2v0dkDqXYWVgA== -"@types/natural-compare@^1.4.1": +"@types/natural-compare@*", "@types/natural-compare@^1.4.1": version "1.4.1" resolved "https://registry.yarnpkg.com/@types/natural-compare/-/natural-compare-1.4.1.tgz#fc2b11ea100d380b0de7af15768bef209157bfb9" integrity sha512-9dr4UakpvN0QUvwNefk9+o14Sr1pPPIDWkgCxPkHcg3kyjtc9eKK1ng6dZ23vRwByloCqXYtZ1T5nJxkk3Ib3A==