From 8efa5a868fc7d7deef9ec45e519654312d317790 Mon Sep 17 00:00:00 2001 From: Adam Jones Date: Sat, 22 Apr 2023 14:11:00 +0100 Subject: [PATCH 1/7] fix(eslint-plugin): fix schemas across several rules and add schema tests --- packages/eslint-plugin/package.json | 1 + .../src/rules/no-restricted-imports.ts | 175 +++++++++++------- .../src/rules/parameter-properties.ts | 1 - .../tests/areOptionsValid.test.ts | 32 ++++ .../eslint-plugin/tests/areOptionsValid.ts | 43 +++++ .../tests/rules/array-type.test.ts | 17 ++ .../parameter-properties.shot | 3 +- packages/eslint-plugin/tests/schemas.test.ts | 32 ++++ .../tools/integration-test-base.ts | 10 +- yarn.lock | 2 +- 10 files changed, 246 insertions(+), 70 deletions(-) create mode 100644 packages/eslint-plugin/tests/areOptionsValid.test.ts create mode 100644 packages/eslint-plugin/tests/areOptionsValid.ts diff --git a/packages/eslint-plugin/package.json b/packages/eslint-plugin/package.json index 3b0e219f74f..4d0d0efb882 100644 --- a/packages/eslint-plugin/package.json +++ b/packages/eslint-plugin/package.json @@ -72,6 +72,7 @@ "@types/natural-compare": "*", "@types/prettier": "*", "@typescript-eslint/rule-schema-to-typescript-types": "5.59.0", + "ajv": "^6.12.6", "cross-fetch": "*", "jest-specific-snapshot": "*", "json-schema": "*", diff --git a/packages/eslint-plugin/src/rules/no-restricted-imports.ts b/packages/eslint-plugin/src/rules/no-restricted-imports.ts index 17e93f7feba..7291081093b 100644 --- a/packages/eslint-plugin/src/rules/no-restricted-imports.ts +++ b/packages/eslint-plugin/src/rules/no-restricted-imports.ts @@ -19,6 +19,66 @@ const baseRule = getESLintCoreRule('no-restricted-imports'); export type Options = InferOptionsTypeFromRule; export type MessageIds = InferMessageIdsTypeFromRule; +// In some versions of eslint, the base rule has a completely incompatible schema +// This helper function is to safely try to get parts of the schema. If it's not +// possible, we'll fallback to less strict checks. +const tryAccess = (getter: () => T, fallback: T): T => { + try { + return getter(); + } catch { + return fallback; + } +}; + +const baseSchema = baseRule.meta.schema as { + anyOf: [ + unknown, + { + type: 'array'; + items: [ + { + type: 'object'; + properties: { + paths: { + type: 'array'; + items: { + anyOf: [ + { type: 'string' }, + { + type: 'object'; + properties: JSONSchema4['properties']; + required: string[]; + }, + ]; + }; + }; + patterns: { + anyOf: [ + { type: 'array'; items: { type: 'string' } }, + { + type: 'array'; + items: { + type: 'object'; + properties: JSONSchema4['properties']; + required: string[]; + }; + }, + ]; + }; + }; + }, + ]; + }, + ]; +}; + +const allowTypeImportsOptionSchema: JSONSchema4['properties'] = { + allowTypeImports: { + type: 'boolean', + description: 'Disallow value imports, but allow type-only imports.', + }, +}; + const arrayOfStringsOrObjects: JSONSchema4 = { type: 'array', items: { @@ -26,30 +86,28 @@ const arrayOfStringsOrObjects: JSONSchema4 = { { type: 'string' }, { type: 'object', + additionalProperties: false, properties: { - name: { type: 'string' }, - message: { - type: 'string', - minLength: 1, - }, - importNames: { - type: 'array', - items: { - type: 'string', - }, - }, - allowTypeImports: { - type: 'boolean', - description: 'Disallow value imports, but allow type-only imports.', - }, + ...tryAccess( + () => + baseSchema.anyOf[1].items[0].properties.paths.items.anyOf[1] + .properties, + undefined, + ), + ...allowTypeImportsOptionSchema, }, - additionalProperties: false, - required: ['name'], + required: tryAccess( + () => + baseSchema.anyOf[1].items[0].properties.paths.items.anyOf[1] + .required, + undefined, + ), }, ], }, uniqueItems: true, }; + const arrayOfStringsOrObjectPatterns: JSONSchema4 = { anyOf: [ { @@ -63,43 +121,48 @@ const arrayOfStringsOrObjectPatterns: JSONSchema4 = { type: 'array', items: { type: 'object', + additionalProperties: false, properties: { - importNames: { - type: 'array', - items: { - type: 'string', - }, - minItems: 1, - uniqueItems: true, - }, - group: { - type: 'array', - items: { - type: 'string', - }, - minItems: 1, - uniqueItems: true, - }, - message: { - type: 'string', - minLength: 1, - }, - caseSensitive: { - type: 'boolean', - }, - allowTypeImports: { - type: 'boolean', - description: 'Disallow value imports, but allow type-only imports.', - }, + ...tryAccess( + () => + baseSchema.anyOf[1].items[0].properties.patterns.anyOf[1].items + .properties, + undefined, + ), + ...allowTypeImportsOptionSchema, }, - additionalProperties: false, - required: ['group'], + required: tryAccess( + () => + baseSchema.anyOf[1].items[0].properties.patterns.anyOf[1].items + .required, + [], + ), }, uniqueItems: true, }, ], }; +const schema: JSONSchema4 = { + anyOf: [ + arrayOfStringsOrObjects, + { + type: 'array', + items: [ + { + type: 'object', + properties: { + paths: arrayOfStringsOrObjects, + patterns: arrayOfStringsOrObjectPatterns, + }, + additionalProperties: false, + }, + ], + additionalItems: false, + }, + ], +}; + function isObjectOfPaths( obj: unknown, ): obj is { paths: ArrayOfStringOrObject } { @@ -153,25 +216,7 @@ export default createRule({ }, messages: baseRule.meta.messages, fixable: baseRule.meta.fixable, - schema: { - anyOf: [ - arrayOfStringsOrObjects, - { - type: 'array', - items: [ - { - type: 'object', - properties: { - paths: arrayOfStringsOrObjects, - patterns: arrayOfStringsOrObjectPatterns, - }, - additionalProperties: false, - }, - ], - additionalItems: false, - }, - ], - }, + schema, }, defaultOptions: [], create(context) { diff --git a/packages/eslint-plugin/src/rules/parameter-properties.ts b/packages/eslint-plugin/src/rules/parameter-properties.ts index 10c15b06177..9da84f13c41 100644 --- a/packages/eslint-plugin/src/rules/parameter-properties.ts +++ b/packages/eslint-plugin/src/rules/parameter-properties.ts @@ -59,7 +59,6 @@ export default util.createRule({ items: { $ref: '#/items/0/$defs/modifier', }, - minItems: 1, }, prefer: { enum: ['class-property', 'parameter-property'], diff --git a/packages/eslint-plugin/tests/areOptionsValid.test.ts b/packages/eslint-plugin/tests/areOptionsValid.test.ts new file mode 100644 index 00000000000..1c3decf81a6 --- /dev/null +++ b/packages/eslint-plugin/tests/areOptionsValid.test.ts @@ -0,0 +1,32 @@ +import * as util from '../src/util'; +import { areOptionsValid } from './areOptionsValid'; + +const exampleRule = util.createRule<['value-a' | 'value-b'], never>({ + name: 'my-example-rule', + meta: { + type: 'layout', + docs: { + description: 'Detects something or other', + }, + schema: [{ enum: ['value-a', 'value-b'] }], + messages: {}, + }, + defaultOptions: ['value-a'], + create() { + return {}; + }, +}); + +test('returns true for valid options', () => { + expect(areOptionsValid(exampleRule, ['value-a'])).toBe(true); +}); + +describe('returns false for invalid options', () => { + test('bad enum value', () => { + expect(areOptionsValid(exampleRule, ['value-c'])).toBe(false); + }); + + test('bad type', () => { + expect(areOptionsValid(exampleRule, [true])).toBe(false); + }); +}); diff --git a/packages/eslint-plugin/tests/areOptionsValid.ts b/packages/eslint-plugin/tests/areOptionsValid.ts new file mode 100644 index 00000000000..80186124757 --- /dev/null +++ b/packages/eslint-plugin/tests/areOptionsValid.ts @@ -0,0 +1,43 @@ +import { RuleModule } from '@typescript-eslint/utils/ts-eslint'; +import Ajv from 'ajv'; +import type { JSONSchema4 } from 'json-schema'; + +const ajv = new Ajv({ async: false }); + +export function areOptionsValid( + rule: RuleModule, + options: unknown, +): boolean { + const normalizedSchema = normalizeSchema(rule.meta.schema); + + const valid = ajv.validate(normalizedSchema, options); + if (typeof valid !== 'boolean') { + // Schema could not validate options synchronously. This is not allowed for ESLint rules. + return false; + } + + return valid; +} + +function normalizeSchema( + schema: JSONSchema4 | readonly JSONSchema4[], +): JSONSchema4 { + if (!Array.isArray(schema)) { + return schema; + } + + if (schema.length === 0) { + return { + type: 'array', + minItems: 0, + maxItems: 0, + }; + } + + return { + type: 'array', + items: schema, + minItems: 0, + maxItems: schema.length, + }; +} diff --git a/packages/eslint-plugin/tests/rules/array-type.test.ts b/packages/eslint-plugin/tests/rules/array-type.test.ts index 04ab47d0b8a..8706417251a 100644 --- a/packages/eslint-plugin/tests/rules/array-type.test.ts +++ b/packages/eslint-plugin/tests/rules/array-type.test.ts @@ -4,6 +4,7 @@ import { TSESLint } from '@typescript-eslint/utils'; import type { OptionString } from '../../src/rules/array-type'; import rule from '../../src/rules/array-type'; import { RuleTester } from '../RuleTester'; +import { areOptionsValid } from '../areOptionsValid'; const ruleTester = new RuleTester({ parser: '@typescript-eslint/parser', @@ -2156,3 +2157,19 @@ type BrokenArray = { ); }); }); + +describe('schema validation', () => { + // https://github.com/typescript-eslint/typescript-eslint/issues/6852 + test("array-type does not accept 'simple-array' option", () => { + if (areOptionsValid(rule, [{ default: 'simple-array' }])) { + throw new Error(`Options succeeded validation for bad options`); + } + }); + + // https://github.com/typescript-eslint/typescript-eslint/issues/6892 + test('array-type does not accept non object option', () => { + if (areOptionsValid(rule, ['array'])) { + throw new Error(`Options succeeded validation for bad options`); + } + }); +}); diff --git a/packages/eslint-plugin/tests/schema-snapshots/parameter-properties.shot b/packages/eslint-plugin/tests/schema-snapshots/parameter-properties.shot index f317443ca00..8782e431b6d 100644 --- a/packages/eslint-plugin/tests/schema-snapshots/parameter-properties.shot +++ b/packages/eslint-plugin/tests/schema-snapshots/parameter-properties.shot @@ -25,7 +25,6 @@ exports[`Rule schemas should be convertible to TS types for documentation purpos "items": { "$ref": "#/items/0/$defs/modifier" }, - "minItems": 1, "type": "array" }, "prefer": { @@ -50,7 +49,7 @@ type Modifier = type Options = [ { - allow?: [Modifier, ...Modifier[]]; + allow?: Modifier[]; prefer?: 'class-property' | 'parameter-property'; }, ]; diff --git a/packages/eslint-plugin/tests/schemas.test.ts b/packages/eslint-plugin/tests/schemas.test.ts index 19cf8280c5b..97620f474e2 100644 --- a/packages/eslint-plugin/tests/schemas.test.ts +++ b/packages/eslint-plugin/tests/schemas.test.ts @@ -7,6 +7,7 @@ import path from 'path'; import { format, resolveConfig } from 'prettier'; import rules from '../src/rules/index'; +import { areOptionsValid } from './areOptionsValid'; const snapshotFolder = path.resolve(__dirname, 'schema-snapshots'); try { @@ -153,3 +154,34 @@ describe('Rules should only define valid keys on schemas', () => { }); } }); + +describe('Rule schemas should validate options correctly', () => { + // Normally, we use the rule's default options as an example of valid options. + // However, the defaults might not actually be valid (especially in the case + // where the defaults have to cover multiple incompatible options). + // This override allows providing example valid options for rules which don't + // accept their defaults. + const overrideValidOptions: Record = { + semi: ['never'], + 'func-call-spacing': ['never'], + }; + + for (const [ruleName, rule] of Object.entries(rules)) { + test(`${ruleName} must accept valid options`, () => { + if ( + !areOptionsValid( + rule, + overrideValidOptions[ruleName] ?? rule.defaultOptions, + ) + ) { + throw new Error(`Options failed validation against rule's schema`); + } + }); + + test(`${ruleName} rejects arbitrary options`, () => { + if (areOptionsValid(rule, [{ 'arbitrary-schemas.test.ts': true }])) { + throw new Error(`Options succeeded validation for arbitrary options`); + } + }); + } +}); diff --git a/packages/integration-tests/tools/integration-test-base.ts b/packages/integration-tests/tools/integration-test-base.ts index 6cd59d1856d..e148aee966d 100644 --- a/packages/integration-tests/tools/integration-test-base.ts +++ b/packages/integration-tests/tools/integration-test-base.ts @@ -98,6 +98,7 @@ export function integrationTest(testFilename: string, filesGlob: string): void { // lint, outputting to a JSON file const outFile = await tmpFile(); + let stderr = ''; try { await execFile( 'yarn', @@ -118,6 +119,11 @@ export function integrationTest(testFilename: string, filesGlob: string): void { ); } catch (ex) { // we expect eslint will "fail" because we have intentional lint errors + + // useful for debugging + if (typeof ex === 'object' && ex != null && 'stderr' in ex) { + stderr = String(ex.stderr); + } } // console.log('Lint complete.'); @@ -132,7 +138,9 @@ export function integrationTest(testFilename: string, filesGlob: string): void { const lintOutput = JSON.parse(lintOutputRAW); expect(lintOutput).toMatchSnapshot(); } catch { - throw lintOutputRAW; + throw new Error( + `Lint output could not be parsed as JSON: \`${lintOutputRAW}\`. The error logs from eslint were: \`${stderr}\``, + ); } }); diff --git a/yarn.lock b/yarn.lock index 03195b91279..bfafcc2bf4e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4321,7 +4321,7 @@ ajv-keywords@^5.0.0: dependencies: fast-deep-equal "^3.1.3" -ajv@^6.10.0, ajv@^6.12.2, ajv@^6.12.4, ajv@^6.12.5, ajv@~6.12.6: +ajv@^6.10.0, ajv@^6.12.2, ajv@^6.12.4, ajv@^6.12.5, ajv@^6.12.6, ajv@~6.12.6: version "6.12.6" resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== From 509b162438299ff5a54937871950d46f1772b55e Mon Sep 17 00:00:00 2001 From: Adam Jones Date: Sat, 22 Apr 2023 15:33:30 +0100 Subject: [PATCH 2/7] Fix typecheck --- packages/eslint-plugin/tests/areOptionsValid.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/eslint-plugin/tests/areOptionsValid.ts b/packages/eslint-plugin/tests/areOptionsValid.ts index 80186124757..198387a6e77 100644 --- a/packages/eslint-plugin/tests/areOptionsValid.ts +++ b/packages/eslint-plugin/tests/areOptionsValid.ts @@ -1,4 +1,4 @@ -import { RuleModule } from '@typescript-eslint/utils/ts-eslint'; +import type { RuleModule } from '@typescript-eslint/utils/ts-eslint'; import Ajv from 'ajv'; import type { JSONSchema4 } from 'json-schema'; @@ -23,7 +23,7 @@ function normalizeSchema( schema: JSONSchema4 | readonly JSONSchema4[], ): JSONSchema4 { if (!Array.isArray(schema)) { - return schema; + return schema as JSONSchema4; } if (schema.length === 0) { From d716278c1a8d02a4f8f8ea5ee00029df21fe5e0c Mon Sep 17 00:00:00 2001 From: Adam Jones Date: Sat, 22 Apr 2023 16:39:56 +0100 Subject: [PATCH 3/7] Fix lint --- packages/eslint-plugin/tests/rules/array-type.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/eslint-plugin/tests/rules/array-type.test.ts b/packages/eslint-plugin/tests/rules/array-type.test.ts index 8706417251a..0e0e6a99264 100644 --- a/packages/eslint-plugin/tests/rules/array-type.test.ts +++ b/packages/eslint-plugin/tests/rules/array-type.test.ts @@ -3,8 +3,8 @@ import { TSESLint } from '@typescript-eslint/utils'; import type { OptionString } from '../../src/rules/array-type'; import rule from '../../src/rules/array-type'; -import { RuleTester } from '../RuleTester'; import { areOptionsValid } from '../areOptionsValid'; +import { RuleTester } from '../RuleTester'; const ruleTester = new RuleTester({ parser: '@typescript-eslint/parser', From ccab82e12d95edb5ab0920f57deeee5670866e4a Mon Sep 17 00:00:00 2001 From: Adam Jones Date: Mon, 1 May 2023 20:27:28 +0100 Subject: [PATCH 4/7] Address review feedback --- packages/eslint-plugin/tests/areOptionsValid.ts | 5 +++-- packages/rule-schema-to-typescript-types/package.json | 1 + .../src/generateArrayType.ts | 10 +++++++--- .../src/generateObjectType.ts | 6 ++++-- .../src/generateType.ts | 4 ++-- packages/rule-schema-to-typescript-types/src/index.ts | 4 ++-- packages/rule-schema-to-typescript-types/tsconfig.json | 2 +- packages/utils/src/index.ts | 3 ++- packages/utils/src/ts-utils/index.ts | 1 + .../src => utils/src/ts-utils}/isArray.ts | 0 10 files changed, 23 insertions(+), 13 deletions(-) create mode 100644 packages/utils/src/ts-utils/index.ts rename packages/{rule-schema-to-typescript-types/src => utils/src/ts-utils}/isArray.ts (100%) diff --git a/packages/eslint-plugin/tests/areOptionsValid.ts b/packages/eslint-plugin/tests/areOptionsValid.ts index 198387a6e77..2909fb3ecfd 100644 --- a/packages/eslint-plugin/tests/areOptionsValid.ts +++ b/packages/eslint-plugin/tests/areOptionsValid.ts @@ -1,3 +1,4 @@ +import { TSUtils } from '@typescript-eslint/utils'; import type { RuleModule } from '@typescript-eslint/utils/ts-eslint'; import Ajv from 'ajv'; import type { JSONSchema4 } from 'json-schema'; @@ -22,8 +23,8 @@ export function areOptionsValid( function normalizeSchema( schema: JSONSchema4 | readonly JSONSchema4[], ): JSONSchema4 { - if (!Array.isArray(schema)) { - return schema as JSONSchema4; + if (!TSUtils.isArray(schema)) { + return schema; } if (schema.length === 0) { diff --git a/packages/rule-schema-to-typescript-types/package.json b/packages/rule-schema-to-typescript-types/package.json index a1fd1d7ea4b..5fd8a219db5 100644 --- a/packages/rule-schema-to-typescript-types/package.json +++ b/packages/rule-schema-to-typescript-types/package.json @@ -35,6 +35,7 @@ "dependencies": { "@types/prettier": "*", "@typescript-eslint/type-utils": "5.59.0", + "@typescript-eslint/utils": "5.59.0", "natural-compare": "^1.4.0", "prettier": "*" }, diff --git a/packages/rule-schema-to-typescript-types/src/generateArrayType.ts b/packages/rule-schema-to-typescript-types/src/generateArrayType.ts index cece1fa4025..865803b3041 100644 --- a/packages/rule-schema-to-typescript-types/src/generateArrayType.ts +++ b/packages/rule-schema-to-typescript-types/src/generateArrayType.ts @@ -1,9 +1,9 @@ +import { TSUtils } from '@typescript-eslint/utils'; import type { JSONSchema4 } from '@typescript-eslint/utils/json-schema'; import { NotSupportedError, UnexpectedError } from './errors'; import { generateType } from './generateType'; import { getCommentLines } from './getCommentLines'; -import { isArray } from './isArray'; import type { ArrayAST, AST, RefMap, TupleAST, UnionAST } from './types'; /** @@ -21,7 +21,11 @@ export function generateArrayType( // but that's obviously dumb and loose so let's not even bother with it throw new UnexpectedError('Unexpected missing items', schema); } - if (schema.items && !isArray(schema.items) && schema.additionalItems) { + if ( + schema.items && + !TSUtils.isArray(schema.items) && + schema.additionalItems + ) { throw new NotSupportedError( 'singlely-typed array with additionalItems', schema, @@ -41,7 +45,7 @@ export function generateArrayType( let items: JSONSchema4[]; let spreadItemSchema: JSONSchema4 | null = null; - if (!isArray(schema.items)) { + if (!TSUtils.isArray(schema.items)) { if (hasMinItems || hasMaxItems) { // treat as a tuple items = Array( diff --git a/packages/rule-schema-to-typescript-types/src/generateObjectType.ts b/packages/rule-schema-to-typescript-types/src/generateObjectType.ts index c0de43699d3..e91eb18dc81 100644 --- a/packages/rule-schema-to-typescript-types/src/generateObjectType.ts +++ b/packages/rule-schema-to-typescript-types/src/generateObjectType.ts @@ -1,9 +1,9 @@ import { requiresQuoting } from '@typescript-eslint/type-utils'; +import { TSUtils } from '@typescript-eslint/utils'; import type { JSONSchema4 } from 'json-schema'; import { generateType } from './generateType'; import { getCommentLines } from './getCommentLines'; -import { isArray } from './isArray'; import type { AST, ObjectAST, RefMap } from './types'; export function generateObjectType( @@ -28,7 +28,9 @@ export function generateObjectType( } const properties: ObjectAST['properties'] = []; - const required = new Set(isArray(schema.required) ? schema.required : []); + const required = new Set( + TSUtils.isArray(schema.required) ? schema.required : [], + ); if (schema.properties) { const propertyDefs = Object.entries(schema.properties); for (const [propName, propSchema] of propertyDefs) { diff --git a/packages/rule-schema-to-typescript-types/src/generateType.ts b/packages/rule-schema-to-typescript-types/src/generateType.ts index d6c0efa2890..d87cb754e20 100644 --- a/packages/rule-schema-to-typescript-types/src/generateType.ts +++ b/packages/rule-schema-to-typescript-types/src/generateType.ts @@ -1,3 +1,4 @@ +import { TSUtils } from '@typescript-eslint/utils'; import type { JSONSchema4 } from '@typescript-eslint/utils/json-schema'; import { NotSupportedError, UnexpectedError } from './errors'; @@ -5,7 +6,6 @@ import { generateArrayType } from './generateArrayType'; import { generateObjectType } from './generateObjectType'; import { generateUnionType } from './generateUnionType'; import { getCommentLines } from './getCommentLines'; -import { isArray } from './isArray'; import type { AST, RefMap } from './types'; // keywords we probably should support but currently do not support @@ -68,7 +68,7 @@ export function generateType(schema: JSONSchema4, refMap: RefMap): AST { }; } - if (isArray(schema.type)) { + if (TSUtils.isArray(schema.type)) { throw new NotSupportedError('schemas with multiple types', schema); } if (schema.type == null) { diff --git a/packages/rule-schema-to-typescript-types/src/index.ts b/packages/rule-schema-to-typescript-types/src/index.ts index 3100f122f2d..6db931c7740 100644 --- a/packages/rule-schema-to-typescript-types/src/index.ts +++ b/packages/rule-schema-to-typescript-types/src/index.ts @@ -1,9 +1,9 @@ +import { TSUtils } from '@typescript-eslint/utils'; import type { JSONSchema4 } from 'json-schema'; import path from 'path'; import { format as prettierFormat, resolveConfig } from 'prettier'; import { generateType } from './generateType'; -import { isArray } from './isArray'; import { optimizeAST } from './optimizeAST'; import { printTypeAlias } from './printAST'; import type { AST } from './types'; @@ -17,7 +17,7 @@ export function compile( schemaIn: JSONSchema4 | readonly JSONSchema4[], ): string { const { schema, isArraySchema } = (() => { - if (isArray(schemaIn)) { + if (TSUtils.isArray(schemaIn)) { return { schema: schemaIn, isArraySchema: true, diff --git a/packages/rule-schema-to-typescript-types/tsconfig.json b/packages/rule-schema-to-typescript-types/tsconfig.json index 06b94d057fa..8d711bc36c1 100644 --- a/packages/rule-schema-to-typescript-types/tsconfig.json +++ b/packages/rule-schema-to-typescript-types/tsconfig.json @@ -4,6 +4,6 @@ "composite": false, "rootDir": "." }, - "include": ["src", "tests", "typings"], + "include": ["src", "tests", "typings", "../utils/src/ts-utils/isArray.ts"], "references": [] } diff --git a/packages/utils/src/index.ts b/packages/utils/src/index.ts index c2c366379a0..e604617af99 100644 --- a/packages/utils/src/index.ts +++ b/packages/utils/src/index.ts @@ -2,6 +2,7 @@ import * as ASTUtils from './ast-utils'; import * as ESLintUtils from './eslint-utils'; import * as JSONSchema from './json-schema'; import * as TSESLint from './ts-eslint'; +import * as TSUtils from './ts-utils'; -export { ASTUtils, ESLintUtils, JSONSchema, TSESLint }; +export { ASTUtils, ESLintUtils, JSONSchema, TSESLint, TSUtils }; export * from './ts-estree'; diff --git a/packages/utils/src/ts-utils/index.ts b/packages/utils/src/ts-utils/index.ts new file mode 100644 index 00000000000..7561f2d5376 --- /dev/null +++ b/packages/utils/src/ts-utils/index.ts @@ -0,0 +1 @@ +export * from './isArray'; diff --git a/packages/rule-schema-to-typescript-types/src/isArray.ts b/packages/utils/src/ts-utils/isArray.ts similarity index 100% rename from packages/rule-schema-to-typescript-types/src/isArray.ts rename to packages/utils/src/ts-utils/isArray.ts From f2e3cdae3842ef8d63e4bad66d6e24e54d45a36b Mon Sep 17 00:00:00 2001 From: Adam Jones Date: Wed, 31 May 2023 14:44:03 +0100 Subject: [PATCH 5/7] Fix CI --- packages/eslint-plugin/tests/areOptionsValid.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/eslint-plugin/tests/areOptionsValid.ts b/packages/eslint-plugin/tests/areOptionsValid.ts index 2909fb3ecfd..807653deb2f 100644 --- a/packages/eslint-plugin/tests/areOptionsValid.ts +++ b/packages/eslint-plugin/tests/areOptionsValid.ts @@ -6,7 +6,7 @@ import type { JSONSchema4 } from 'json-schema'; const ajv = new Ajv({ async: false }); export function areOptionsValid( - rule: RuleModule, + rule: RuleModule, options: unknown, ): boolean { const normalizedSchema = normalizeSchema(rule.meta.schema); @@ -37,7 +37,7 @@ function normalizeSchema( return { type: 'array', - items: schema, + items: schema as JSONSchema4[], minItems: 0, maxItems: schema.length, }; From 730821b2e4c0604eb57ca404d9b402dc0082e588 Mon Sep 17 00:00:00 2001 From: Adam Jones Date: Wed, 31 May 2023 16:38:41 +0100 Subject: [PATCH 6/7] Revert accidental change --- packages/rule-schema-to-typescript-types/tsconfig.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/rule-schema-to-typescript-types/tsconfig.json b/packages/rule-schema-to-typescript-types/tsconfig.json index 8d711bc36c1..06b94d057fa 100644 --- a/packages/rule-schema-to-typescript-types/tsconfig.json +++ b/packages/rule-schema-to-typescript-types/tsconfig.json @@ -4,6 +4,6 @@ "composite": false, "rootDir": "." }, - "include": ["src", "tests", "typings", "../utils/src/ts-utils/isArray.ts"], + "include": ["src", "tests", "typings"], "references": [] } From 55a5ffbbfe05d3616b9164e565adc555790a90b6 Mon Sep 17 00:00:00 2001 From: Adam Jones Date: Sat, 8 Jul 2023 00:48:25 +0100 Subject: [PATCH 7/7] Fix tests --- packages/eslint-plugin/tests/areOptionsValid.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/eslint-plugin/tests/areOptionsValid.test.ts b/packages/eslint-plugin/tests/areOptionsValid.test.ts index 1c3decf81a6..6ec3fd4dfca 100644 --- a/packages/eslint-plugin/tests/areOptionsValid.test.ts +++ b/packages/eslint-plugin/tests/areOptionsValid.test.ts @@ -8,7 +8,7 @@ const exampleRule = util.createRule<['value-a' | 'value-b'], never>({ docs: { description: 'Detects something or other', }, - schema: [{ enum: ['value-a', 'value-b'] }], + schema: [{ type: 'string', enum: ['value-a', 'value-b'] }], messages: {}, }, defaultOptions: ['value-a'],