Skip to content

Commit

Permalink
feat: fork json schema types for better compat with ESLint rule valid…
Browse files Browse the repository at this point in the history
…ation (#6963)

* feat: fork json schema types for better compat with ESLint rule validation

* make the schema types a discriminated union

* Also update blog

---------

Co-authored-by: Josh Goldberg <git@joshuakgoldberg.com>
  • Loading branch information
bradzacher and JoshuaKGoldberg committed Jun 17, 2023
1 parent c456f8c commit a4967f2
Show file tree
Hide file tree
Showing 67 changed files with 740 additions and 149 deletions.
22 changes: 11 additions & 11 deletions docs/architecture/Utils.mdx
Expand Up @@ -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`. |
4 changes: 4 additions & 0 deletions packages/eslint-plugin/package.json
Expand Up @@ -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": "*",
Expand Down
1 change: 1 addition & 0 deletions packages/eslint-plugin/src/rules/array-type.ts
Expand Up @@ -109,6 +109,7 @@ export default util.createRule<Options, MessageIds>({
{
$defs: {
arrayOption: {
type: 'string',
enum: ['array', 'generic', 'array-simple'],
},
},
Expand Down
1 change: 1 addition & 0 deletions packages/eslint-plugin/src/rules/ban-ts-comment.ts
Expand Up @@ -49,6 +49,7 @@ export default util.createRule<[Options], MessageIds>({
default: true,
},
{
type: 'string',
enum: ['allow-with-description'],
},
{
Expand Down
2 changes: 2 additions & 0 deletions packages/eslint-plugin/src/rules/ban-types.ts
Expand Up @@ -148,11 +148,13 @@ export default util.createRule<Options, MessageIds>({
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',
},
Expand Down
Expand Up @@ -50,7 +50,12 @@ export default util.createRule<Options, MessageIds>({
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]) {
Expand Down
4 changes: 3 additions & 1 deletion packages/eslint-plugin/src/rules/comma-dangle.ts
Expand Up @@ -49,9 +49,11 @@ export default util.createRule<Options, MessageIds>({
schema: {
$defs: {
value: {
type: 'string',
enum: OPTION_VALUE_SCHEME,
},
valueWithIgnore: {
type: 'string',
enum: [...OPTION_VALUE_SCHEME, 'ignore'],
},
},
Expand Down Expand Up @@ -79,7 +81,7 @@ export default util.createRule<Options, MessageIds>({
],
},
],
additionalProperties: false,
additionalItems: false,
},
fixable: 'code',
hasSuggestions: baseRule.meta.hasSuggestions,
Expand Down
Expand Up @@ -24,6 +24,7 @@ export default createRule<Options, MessageIds>({
fixable: 'code',
schema: [
{
type: 'string',
enum: ['type-annotation', 'constructor'],
},
],
Expand Down
Expand Up @@ -21,6 +21,7 @@ export default createRule<Options, MessageIds>({
fixable: 'code',
schema: [
{
type: 'string',
enum: ['record', 'index-signature'],
},
],
Expand Down
Expand Up @@ -48,6 +48,7 @@ export default util.createRule<Options, MessageIds>({
type: 'object',
properties: {
assertionStyle: {
type: 'string',
enum: ['never'],
},
},
Expand All @@ -58,9 +59,11 @@ export default util.createRule<Options, MessageIds>({
type: 'object',
properties: {
assertionStyle: {
type: 'string',
enum: ['as', 'angle-bracket'],
},
objectLiteralTypeAssertions: {
type: 'string',
enum: ['allow', 'allow-as-parameter', 'never'],
},
},
Expand Down
Expand Up @@ -18,6 +18,7 @@ export default util.createRule({
},
schema: [
{
type: 'string',
enum: ['interface', 'type'],
},
],
Expand Down
2 changes: 2 additions & 0 deletions packages/eslint-plugin/src/rules/consistent-type-imports.ts
Expand Up @@ -65,12 +65,14 @@ export default util.createRule<Options, MessageIds>({
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'],
},
},
Expand Down
Expand Up @@ -51,14 +51,17 @@ export default util.createRule<Options, MessageIds>({
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.',
},
Expand Down
2 changes: 2 additions & 0 deletions packages/eslint-plugin/src/rules/func-call-spacing.ts
Expand Up @@ -29,6 +29,7 @@ export default util.createRule<Options, MessageIds>({
type: 'array',
items: [
{
type: 'string',
enum: ['never'],
},
],
Expand All @@ -39,6 +40,7 @@ export default util.createRule<Options, MessageIds>({
type: 'array',
items: [
{
type: 'string',
enum: ['always'],
},
{
Expand Down
3 changes: 2 additions & 1 deletion 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';
Expand All @@ -26,7 +27,7 @@ const schema = util.deepMerge(
},
},
},
);
) as unknown as JSONSchema4;

export default util.createRule<Options, MessageIds>({
name: 'keyword-spacing',
Expand Down
11 changes: 9 additions & 2 deletions packages/eslint-plugin/src/rules/member-delimiter-style.ts
Expand Up @@ -150,9 +150,15 @@ export default util.createRule<Options, MessageIds>({
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,
},
Expand All @@ -172,6 +178,7 @@ export default util.createRule<Options, MessageIds>({
additionalProperties: false,
},
multilineDetection: {
type: 'string',
enum: ['brackets', 'last-member'],
},
},
Expand Down
2 changes: 1 addition & 1 deletion packages/eslint-plugin/src/rules/member-ordering.ts
Expand Up @@ -644,7 +644,7 @@ export default util.createRule<Options, MessageIds>({
},
allItems: {
type: 'string',
enum: allMemberTypes,
enum: allMemberTypes as string[],
},
typeItems: {
type: 'string',
Expand Down
1 change: 1 addition & 0 deletions packages/eslint-plugin/src/rules/method-signature-style.ts
Expand Up @@ -22,6 +22,7 @@ export default util.createRule<Options, MessageIds>({
},
schema: [
{
type: 'string',
enum: ['property', 'method'],
},
],
Expand Down
4 changes: 3 additions & 1 deletion 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';
Expand All @@ -18,6 +19,7 @@ const schema = util.deepMerge(
properties: {
allow: {
items: {
type: 'string',
enum: [
'functions',
'arrowFunctions',
Expand All @@ -38,7 +40,7 @@ const schema = util.deepMerge(
},
},
},
);
) as unknown as JSONSchema4;

export default util.createRule<Options, MessageIds>({
name: 'no-empty-function',
Expand Down
2 changes: 1 addition & 1 deletion packages/eslint-plugin/src/rules/no-invalid-void-type.ts
Expand Up @@ -47,7 +47,7 @@ export default util.createRule<[Options], MessageIds>({
{
type: 'array',
items: { type: 'string' },
minLength: 1,
minItems: 1,
},
],
},
Expand Down
3 changes: 2 additions & 1 deletion 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';
Expand Down Expand Up @@ -31,7 +32,7 @@ const schema = util.deepMerge(
},
},
},
);
) as unknown as JSONSchema4;

export default util.createRule<Options, MessageIds>({
name: 'no-magic-numbers',
Expand Down
1 change: 1 addition & 0 deletions packages/eslint-plugin/src/rules/no-shadow.ts
Expand Up @@ -43,6 +43,7 @@ export default util.createRule<Options, MessageIds>({
type: 'boolean',
},
hoist: {
type: 'string',
enum: ['all', 'functions', 'never'],
},
allow: {
Expand Down
2 changes: 2 additions & 0 deletions packages/eslint-plugin/src/rules/no-type-alias.ts
Expand Up @@ -50,6 +50,7 @@ export default util.createRule<Options, MessageIds>({
{
$defs: {
expandedOptions: {
type: 'string',
enum: [
'always',
'never',
Expand All @@ -59,6 +60,7 @@ export default util.createRule<Options, MessageIds>({
] satisfies Values[],
},
simpleOptions: {
type: 'string',
enum: ['always', 'never'],
},
},
Expand Down
4 changes: 4 additions & 0 deletions packages/eslint-plugin/src/rules/no-unused-vars.ts
Expand Up @@ -44,18 +44,21 @@ export default util.createRule<Options, MessageIds>({
{
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: {
Expand All @@ -65,6 +68,7 @@ export default util.createRule<Options, MessageIds>({
type: 'string',
},
caughtErrors: {
type: 'string',
enum: ['all', 'none'],
},
caughtErrorsIgnorePattern: {
Expand Down
1 change: 1 addition & 0 deletions packages/eslint-plugin/src/rules/no-use-before-define.ts
Expand Up @@ -251,6 +251,7 @@ export default util.createRule<Options, MessageIds>({
{
oneOf: [
{
type: 'string',
enum: ['nofunc'],
},
{
Expand Down
Expand Up @@ -598,14 +598,21 @@ export default util.createRule<Options, MessageIds>({
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,
Expand Down

0 comments on commit a4967f2

Please sign in to comment.