diff --git a/eslint.config.mjs b/eslint.config.mjs index d31a648c0327..b299e7140604 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -36,6 +36,7 @@ const vitestFiles = [ 'packages/parser/tests/lib/**/*.test.{ts,tsx,cts,mts}', 'packages/parser/tests/test-utils/**/*.{ts,tsx,cts,mts}', 'packages/utils/tests/**/*.test?(-d).{ts,tsx,cts,mts}', + 'packages/type-utils/tests/**/*.test.{ts,tsx,cts,mts}', ]; export default tseslint.config( diff --git a/nx.json b/nx.json index 6f69941fe0d4..ac7a356e5991 100644 --- a/nx.json +++ b/nx.json @@ -103,12 +103,11 @@ "{workspaceRoot}/vitest.config.base.mts", "{projectRoot}/vitest.config.mts" ], - "outputs": ["{options.reportsDirectory}"], + "outputs": ["{projectRoot}/coverage"], "cache": true, "options": { "config": "{projectRoot}/vitest.config.mts", - "watch": false, - "reportsDirectory": "{projectRoot}/coverage" + "watch": false } }, "lint": { @@ -132,7 +131,7 @@ }, "typecheck": { "dependsOn": ["types:copy-ast-spec"], - "outputs": ["{workspaceRoot}/dist/out-tsc/{projectRoot}"], + "outputs": ["{workspaceRoot}/dist"], "cache": true } }, diff --git a/packages/ast-spec/project.json b/packages/ast-spec/project.json index bb045ad1f6be..a46843d6def3 100644 --- a/packages/ast-spec/project.json +++ b/packages/ast-spec/project.json @@ -1,21 +1,21 @@ { "name": "ast-spec", "$schema": "../../node_modules/nx/schemas/project-schema.json", - "type": "library", + "projectType": "library", "implicitDependencies": ["!typescript-estree"], + "root": "packages/ast-spec", + "sourceRoot": "packages/ast-spec/src", "targets": { "build": { - "executor": "nx:run-commands", - "options": { - "cwd": "packages/ast-spec", - "commands": ["yarn build"] - }, "outputs": ["{projectRoot}/dist/**/*.ts"] }, "lint": { "executor": "@nx/eslint:lint", "outputs": ["{options.outputFile}"] }, + "test": { + "dependsOn": ["typecheck"] + }, "typecheck": { "dependsOn": ["typescript-estree:build"] } diff --git a/packages/type-utils/jest.config.js b/packages/type-utils/jest.config.js deleted file mode 100644 index 910991b20cff..000000000000 --- a/packages/type-utils/jest.config.js +++ /dev/null @@ -1,7 +0,0 @@ -'use strict'; - -// @ts-check -/** @type {import('@jest/types').Config.InitialOptions} */ -module.exports = { - ...require('../../jest.config.base.js'), -}; diff --git a/packages/type-utils/package.json b/packages/type-utils/package.json index 0b27cc760a3f..5e3b42a78d34 100644 --- a/packages/type-utils/package.json +++ b/packages/type-utils/package.json @@ -40,10 +40,10 @@ "build": "tsc -b tsconfig.build.json", "postbuild": "downlevel-dts dist _ts4.3/dist --to=4.3", "clean": "tsc -b tsconfig.build.json --clean", - "postclean": "rimraf dist && rimraf _ts3.4 && rimraf _ts4.3 && rimraf coverage", + "postclean": "rimraf dist/ _ts4.3/ coverage/", "format": "prettier --write \"./**/*.{ts,mts,cts,tsx,js,mjs,cjs,jsx,json,md,css}\" --ignore-path ../../.prettierignore", "lint": "npx nx lint", - "test": "jest", + "test": "vitest --run --config=$INIT_CWD/vitest.config.mts", "check-types": "npx nx typecheck" }, "dependencies": { @@ -57,14 +57,14 @@ "typescript": ">=4.8.4 <5.9.0" }, "devDependencies": { - "@jest/types": "29.6.3", "@typescript-eslint/parser": "8.29.1", + "@vitest/coverage-v8": "^3.1.1", "ajv": "^6.12.6", "downlevel-dts": "*", - "jest": "29.7.0", "prettier": "^3.2.5", "rimraf": "*", - "typescript": "*" + "typescript": "*", + "vitest": "^3.1.1" }, "funding": { "type": "opencollective", diff --git a/packages/type-utils/project.json b/packages/type-utils/project.json index 4ac211280e6b..8c91c0ace943 100644 --- a/packages/type-utils/project.json +++ b/packages/type-utils/project.json @@ -1,12 +1,16 @@ { "name": "type-utils", "$schema": "../../node_modules/nx/schemas/project-schema.json", - "type": "library", - "implicitDependencies": [], + "projectType": "library", + "root": "packages/type-utils", + "sourceRoot": "packages/type-utils/src", "targets": { "lint": { "executor": "@nx/eslint:lint", "outputs": ["{options.outputFile}"] + }, + "test": { + "executor": "@nx/vite:test" } } } diff --git a/packages/type-utils/tests/TypeOrValueSpecifier.test.ts b/packages/type-utils/tests/TypeOrValueSpecifier.test.ts index b58ae80df8d2..70ae2bda9313 100644 --- a/packages/type-utils/tests/TypeOrValueSpecifier.test.ts +++ b/packages/type-utils/tests/TypeOrValueSpecifier.test.ts @@ -1,4 +1,5 @@ import type { TSESTree } from '@typescript-eslint/utils'; +import type { TestContext } from 'vitest'; import { parseForESLint } from '@typescript-eslint/parser'; import Ajv from 'ajv'; @@ -8,41 +9,51 @@ import type { TypeOrValueSpecifier } from '../src/TypeOrValueSpecifier'; import { typeMatchesSpecifier, typeOrValueSpecifiersSchema } from '../src'; +const ROOT_DIR = path.posix.join( + ...path.relative(process.cwd(), path.join(__dirname, '..')).split(path.sep), +); + describe('TypeOrValueSpecifier', () => { describe('Schema', () => { const ajv = new Ajv(); const validate = ajv.compile(typeOrValueSpecifiersSchema); - function runTestPositive(typeOrValueSpecifier: unknown): void { + function runTestPositive( + [typeOrValueSpecifier]: readonly [typeOrValueSpecifier: unknown], + { expect }: TestContext, + ): void { expect(validate([typeOrValueSpecifier])).toBe(true); } - function runTestNegative(typeOrValueSpecifier: unknown): void { + function runTestNegative( + [typeOrValueSpecifier]: readonly [typeOrValueSpecifier: unknown], + { expect }: TestContext, + ): void { expect(validate([typeOrValueSpecifier])).toBe(false); } - it.each([['MyType'], ['myValue'], ['any'], ['void'], ['never']])( + it.for([['MyType'], ['myValue'], ['any'], ['void'], ['never']] as const)( 'matches a simple string specifier %s', runTestPositive, ); - it.each([ + it.for([ [42], [false], [null], [undefined], [['MyType']], [(): void => {}], - ])("doesn't match any non-string basic type: %s", runTestNegative); + ] as const)("doesn't match any non-string basic type: %s", runTestNegative); - it.each([ + it.for([ [{ from: 'file', name: 'MyType' }], [{ from: 'file', name: ['MyType', 'myValue'] }], [{ from: 'file', name: 'MyType', path: './filename.js' }], [{ from: 'file', name: ['MyType', 'myValue'], path: './filename.js' }], - ])('matches a file specifier: %s', runTestPositive); + ] as const)('matches a file specifier: %s', runTestPositive); - it.each([ + it.for([ [{ from: 'file', name: 42 }], [{ from: 'file', name: ['MyType', 42] }], [{ from: 'file', name: ['MyType', 'MyType'] }], @@ -59,23 +70,26 @@ describe('TypeOrValueSpecifier', () => { }, ], [{ from: 'file', name: 'MyType', unrelatedProperty: '' }], - ])("doesn't match a malformed file specifier: %s", runTestNegative); + ] as const)( + "doesn't match a malformed file specifier: %s", + runTestNegative, + ); - it.each([ + it.for([ [{ from: 'lib', name: 'MyType' }], [{ from: 'lib', name: ['MyType', 'myValue'] }], - ])('matches a lib specifier: %s', runTestPositive); + ] as const)('matches a lib specifier: %s', runTestPositive); - it.each([ + it.for([ [{ from: 'lib', name: 42 }], [{ from: 'lib', name: ['MyType', 42] }], [{ from: 'lib', name: ['MyType', 'MyType'] }], [{ from: 'lib', name: [] }], [{ from: 'lib' }], [{ from: 'lib', name: 'MyType', unrelatedProperty: '' }], - ])("doesn't match a malformed lib specifier: %s", runTestNegative); + ] as const)("doesn't match a malformed lib specifier: %s", runTestNegative); - it.each([ + it.for([ [{ from: 'package', name: 'MyType', package: 'jquery' }], [ { @@ -84,9 +98,9 @@ describe('TypeOrValueSpecifier', () => { package: 'jquery', }, ], - ])('matches a package specifier: %s', runTestPositive); + ] as const)('matches a package specifier: %s', runTestPositive); - it.each([ + it.for([ [{ from: 'package', name: 42, package: 'jquery' }], [{ from: 'package', name: ['MyType', 42], package: 'jquery' }], [ @@ -119,14 +133,18 @@ describe('TypeOrValueSpecifier', () => { unrelatedProperty: '', }, ], - ])("doesn't match a malformed package specifier: %s", runTestNegative); + ] as const)( + "doesn't match a malformed package specifier: %s", + runTestNegative, + ); }); - describe('typeMatchesSpecifier', () => { + describe(typeMatchesSpecifier, () => { function runTests( code: string, specifier: TypeOrValueSpecifier, expected: boolean, + expect: TestContext['expect'], ): void { const rootDir = path.join(__dirname, 'fixtures'); const { ast, services } = parseForESLint(code, { @@ -149,35 +167,48 @@ describe('TypeOrValueSpecifier', () => { } function runTestPositive( - code: string, - specifier: TypeOrValueSpecifier, + [code, specifier]: readonly [ + code: string, + specifier: TypeOrValueSpecifier, + ], + testContext: Partial & Pick = { + expect, + }, ): void { - runTests(code, specifier, true); + runTests(code, specifier, true, testContext.expect); } function runTestNegative( - code: string, - specifier: TypeOrValueSpecifier, + [code, specifier]: readonly [ + code: string, + specifier: TypeOrValueSpecifier, + ], + testContext: Partial & Pick = { + expect, + }, ): void { - runTests(code, specifier, false); + runTests(code, specifier, false, testContext.expect); } - it.each<[string, TypeOrValueSpecifier]>([ + it.for([ ['interface Foo {prop: string}; type Test = Foo;', 'Foo'], ['type Test = RegExp;', 'RegExp'], - ])('matches a matching universal string specifier', runTestPositive); + ] as const satisfies [string, TypeOrValueSpecifier][])( + 'matches a matching universal string specifier', + runTestPositive, + ); - it.each<[string, TypeOrValueSpecifier]>([ + it.for([ ['interface Foo {prop: string}; type Test = Foo;', 'Bar'], ['interface Foo {prop: string}; type Test = Foo;', 'RegExp'], ['type Test = RegExp;', 'Foo'], ['type Test = RegExp;', 'BigInt'], - ])( + ] as const satisfies [string, TypeOrValueSpecifier][])( "doesn't match a mismatched universal string specifier", runTestNegative, ); - it.each<[string, TypeOrValueSpecifier]>([ + it.for([ [ 'interface Foo {prop: string}; type Test = Foo;', { from: 'file', name: 'Foo' }, @@ -196,11 +227,19 @@ describe('TypeOrValueSpecifier', () => { ], [ 'interface Foo {prop: string}; type Test = Foo;', - { from: 'file', name: 'Foo', path: 'tests/fixtures/file.ts' }, + { + from: 'file', + name: 'Foo', + path: `${ROOT_DIR}/tests/fixtures/file.ts`, + }, ], [ 'type Foo = {prop: string}; type Test = Foo;', - { from: 'file', name: 'Foo', path: 'tests/fixtures/file.ts' }, + { + from: 'file', + name: 'Foo', + path: `${ROOT_DIR}/tests/fixtures/file.ts`, + }, ], [ 'type Foo = Promise & {hey?: string}; let foo: Foo = Promise.resolve(5); type Test = typeof foo;', @@ -211,7 +250,7 @@ describe('TypeOrValueSpecifier', () => { { from: 'file', name: 'Foo', - path: 'tests/../tests/fixtures/////file.ts', + path: `${ROOT_DIR}/tests/../tests/fixtures/////file.ts`, }, ], [ @@ -219,7 +258,7 @@ describe('TypeOrValueSpecifier', () => { { from: 'file', name: 'Foo', - path: 'tests/../tests/fixtures/////file.ts', + path: `${ROOT_DIR}/tests/../tests/fixtures/////file.ts`, }, ], [ @@ -227,7 +266,7 @@ describe('TypeOrValueSpecifier', () => { { from: 'file', name: ['Foo', 'Bar'], - path: 'tests/fixtures/file.ts', + path: `${ROOT_DIR}/tests/fixtures/file.ts`, }, ], [ @@ -235,12 +274,15 @@ describe('TypeOrValueSpecifier', () => { { from: 'file', name: ['Foo', 'Bar'], - path: 'tests/fixtures/file.ts', + path: `${ROOT_DIR}/tests/fixtures/file.ts`, }, ], - ])('matches a matching file specifier: %s', runTestPositive); + ] as const satisfies [string, TypeOrValueSpecifier][])( + 'matches a matching file specifier: %s', + runTestPositive, + ); - it.each<[string, TypeOrValueSpecifier]>([ + it.for([ [ 'interface Foo {prop: string}; type Test = Foo;', { from: 'file', name: 'Bar' }, @@ -261,32 +303,44 @@ describe('TypeOrValueSpecifier', () => { path: 'tests/fixtures/wrong-file.ts', }, ], - ])("doesn't match a mismatched file specifier: %s", runTestNegative); + ] as const satisfies [string, TypeOrValueSpecifier][])( + "doesn't match a mismatched file specifier: %s", + runTestNegative, + ); - it.each<[string, TypeOrValueSpecifier]>([ + it.for([ ['type Test = RegExp;', { from: 'lib', name: 'RegExp' }], ['type Test = RegExp;', { from: 'lib', name: ['RegExp', 'BigInt'] }], - ])('matches a matching lib specifier: %s', runTestPositive); + ] as const satisfies [string, TypeOrValueSpecifier][])( + 'matches a matching lib specifier: %s', + runTestPositive, + ); - it.each<[string, TypeOrValueSpecifier]>([ + it.for([ ['type Test = RegExp;', { from: 'lib', name: 'BigInt' }], ['type Test = RegExp;', { from: 'lib', name: ['BigInt', 'Date'] }], - ])("doesn't match a mismatched lib specifier: %s", runTestNegative); + ] as const satisfies [string, TypeOrValueSpecifier][])( + "doesn't match a mismatched lib specifier: %s", + runTestNegative, + ); - it.each<[string, TypeOrValueSpecifier]>([ + it.for([ ['type Test = string;', { from: 'lib', name: 'string' }], ['type Test = string;', { from: 'lib', name: ['string', 'number'] }], - ])('matches a matching intrinsic type specifier: %s', runTestPositive); + ] as const satisfies [string, TypeOrValueSpecifier][])( + 'matches a matching intrinsic type specifier: %s', + runTestPositive, + ); - it.each<[string, TypeOrValueSpecifier]>([ + it.for([ ['type Test = string;', { from: 'lib', name: 'number' }], ['type Test = string;', { from: 'lib', name: ['number', 'boolean'] }], - ])( + ] as const satisfies [string, TypeOrValueSpecifier][])( "doesn't match a mismatched intrinsic type specifier: %s", runTestNegative, ); - it.each<[string, TypeOrValueSpecifier]>([ + it.for([ [ 'import type {Node} from "typescript"; type Test = Node;', { from: 'package', name: 'Node', package: 'typescript' }, @@ -366,9 +420,12 @@ describe('TypeOrValueSpecifier', () => { package: 'node:test', }, ], - ])('matches a matching package specifier: %s', runTestPositive); + ] as const satisfies [string, TypeOrValueSpecifier][])( + 'matches a matching package specifier: %s', + runTestPositive, + ); - it.each<[string, TypeOrValueSpecifier]>([ + it.for([ [ ` type Other = { __otherBrand: true }; @@ -386,12 +443,12 @@ describe('TypeOrValueSpecifier', () => { `, { from: 'file', name: ['SafePromise'] }, ], - ])( + ] as const satisfies [string, TypeOrValueSpecifier][])( "doesn't match a mismatched type specifier for an intersection type: %s", runTestNegative, ); - it.each<[string, TypeOrValueSpecifier]>([ + it.for([ [ ` type SafePromise = Promise & { __safeBrand: string }; @@ -400,12 +457,12 @@ describe('TypeOrValueSpecifier', () => { `, { from: 'file', name: ['ResultType'] }, ], - ])( + ] as const satisfies [string, TypeOrValueSpecifier][])( 'matches a matching type specifier for an intersection type: %s', runTestPositive, ); - it.each<[string, TypeOrValueSpecifier]>([ + it.for([ [ ` declare module "node:test" { @@ -425,12 +482,12 @@ describe('TypeOrValueSpecifier', () => { package: 'node:test', }, ], - ])( + ] as const satisfies [string, TypeOrValueSpecifier][])( 'matches a matching package specifier for an intersection type: %s', runTestPositive, ); - it.each<[string, TypeOrValueSpecifier]>([ + it.for([ [ ` declare module "node:test" { @@ -450,13 +507,13 @@ describe('TypeOrValueSpecifier', () => { package: 'node:test', }, ], - ])( + ] as const satisfies [string, TypeOrValueSpecifier][])( "doesn't match a mismatched package specifier for an intersection type: %s", runTestNegative, ); it("does not match a `declare global` with the 'global' package name", () => { - runTestNegative( + runTestNegative([ ` declare global { export type URL = {}; @@ -469,10 +526,10 @@ describe('TypeOrValueSpecifier', () => { name: 'URL', package: 'global', }, - ); + ]); }); - it.each<[string, TypeOrValueSpecifier]>([ + it.for([ [ 'import type {Node} from "typescript"; type Test = Node;', { from: 'package', name: 'Symbol', package: 'typescript' }, @@ -497,9 +554,12 @@ describe('TypeOrValueSpecifier', () => { 'import type {Node as TsNode} from "typescript"; type Test = TsNode;', { from: 'package', name: 'TsNode', package: 'typescript' }, ], - ])("doesn't match a mismatched package specifier: %s", runTestNegative); + ] as const satisfies [string, TypeOrValueSpecifier][])( + "doesn't match a mismatched package specifier: %s", + runTestNegative, + ); - it.each<[string, TypeOrValueSpecifier]>([ + it.for([ [ 'interface Foo {prop: string}; type Test = Foo;', { from: 'lib', name: 'Foo' }, @@ -528,18 +588,25 @@ describe('TypeOrValueSpecifier', () => { package: 'foo-package', }, ], - ['type Test = RegExp;', { from: 'file', name: 'RegExp' }], - ['type Test = RegExp;', { from: 'file', name: ['RegExp', 'BigInt'] }], + ['type Test = RegExp;', { from: 'file', name: 'RegExp', path: ROOT_DIR }], + [ + 'type Test = RegExp;', + { from: 'file', name: ['RegExp', 'BigInt'], path: ROOT_DIR }, + ], [ 'type Test = RegExp;', - { from: 'file', name: 'RegExp', path: 'tests/fixtures/file.ts' }, + { + from: 'file', + name: 'RegExp', + path: `${ROOT_DIR}/tests/fixtures/file.ts`, + }, ], [ 'type Test = RegExp;', { from: 'file', name: ['RegExp', 'BigInt'], - path: 'tests/fixtures/file.ts', + path: `${ROOT_DIR}/tests/fixtures/file.ts`, }, ], [ @@ -550,11 +617,17 @@ describe('TypeOrValueSpecifier', () => { 'type Test = RegExp;', { from: 'package', name: ['RegExp', 'BigInt'], package: 'foo-package' }, ], - ])("doesn't match a mismatched specifier type: %s", runTestNegative); + ] as const satisfies [string, TypeOrValueSpecifier][])( + "doesn't match a mismatched specifier type: %s", + runTestNegative, + ); - it.each<[string, TypeOrValueSpecifier]>([ + it.for([ ['type Test = Foo;', { from: 'lib', name: 'Foo' }], ['type Test = Foo;', { from: 'lib', name: ['Foo', 'number'] }], - ])("doesn't match an error type: %s", runTestNegative); + ] as const satisfies [string, TypeOrValueSpecifier][])( + "doesn't match an error type: %s", + runTestNegative, + ); }); }); diff --git a/packages/type-utils/tests/containsAllTypesByName.test.ts b/packages/type-utils/tests/containsAllTypesByName.test.ts index 46933b01f092..351e5fb84c91 100644 --- a/packages/type-utils/tests/containsAllTypesByName.test.ts +++ b/packages/type-utils/tests/containsAllTypesByName.test.ts @@ -1,5 +1,6 @@ import type { TSESTree } from '@typescript-eslint/typescript-estree'; import type * as ts from 'typescript'; +import type { TestContext } from 'vitest'; import { parseForESLint } from '@typescript-eslint/parser'; import path from 'node:path'; @@ -7,7 +8,7 @@ import path from 'node:path'; import { containsAllTypesByName } from '../src'; import { expectToHaveParserServices } from './test-utils/expectToHaveParserServices'; -describe('containsAllTypesByName', () => { +describe(containsAllTypesByName, () => { const rootDir = path.join(__dirname, 'fixtures'); function getType(code: string): ts.Type { @@ -27,6 +28,7 @@ describe('containsAllTypesByName', () => { code: string, allowAny: boolean, expected: boolean, + { expect }: TestContext, ): void { const type = getType(code); const result = containsAllTypesByName(type, allowAny, new Set()); @@ -34,27 +36,33 @@ describe('containsAllTypesByName', () => { } describe('is true', () => { - function runTest(code: string, expected: boolean): void { - runTestForAliasDeclaration(code, true, expected); + function runTest( + [code, expected]: readonly [code: string, expected: boolean], + testContext: TestContext, + ): void { + runTestForAliasDeclaration(code, true, expected, testContext); } - it.each([ + it.for([ ['type Test = unknown;', false], ['type Test = any;', false], ['type Test = string;', false], - ])('when code is "%s" expected is %s', runTest); + ] as const)('when code is "%s" expected is %s', runTest); }); describe('is false', () => { - function runTest(code: string, expected: boolean): void { - runTestForAliasDeclaration(code, false, expected); + function runTest( + [code, expected]: readonly [code: string, expected: boolean], + testContext: TestContext, + ): void { + runTestForAliasDeclaration(code, false, expected, testContext); } - it.each([ + it.for([ ['type Test = unknown;', true], ['type Test = any;', true], ['type Test = string;', false], - ])('when code is "%s" expected is %s', runTest); + ] as const)('when code is "%s" expected is %s', runTest); }); }); @@ -63,6 +71,7 @@ describe('containsAllTypesByName', () => { code: string, matchAnyInstead: boolean, expected: boolean, + { expect }: TestContext, ): void { const type = getType(code); const result = containsAllTypesByName( @@ -75,27 +84,33 @@ describe('containsAllTypesByName', () => { } describe('is true', () => { - function runTest(code: string, expected: boolean): void { - runTestForAliasDeclaration(code, true, expected); + function runTest( + [code, expected]: readonly [code: string, expected: boolean], + testContext: TestContext, + ): void { + runTestForAliasDeclaration(code, true, expected, testContext); } - it.each([ + it.for([ [`type Test = Promise & string`, true], ['type Test = Promise | string', true], ['type Test = Promise | Object', true], - ])('when code is "%s" expected is %s', runTest); + ] as const)('when code is "%s" expected is %s', runTest); }); describe('is false', () => { - function runTest(code: string, expected: boolean): void { - runTestForAliasDeclaration(code, false, expected); + function runTest( + [code, expected]: readonly [code: string, expected: boolean], + testContext: TestContext, + ): void { + runTestForAliasDeclaration(code, false, expected, testContext); } - it.each([ + it.for([ ['type Test = Promise & string', false], ['type Test = Promise | string', false], ['type Test = Promise | Object', true], - ])('when code is "%s" expected is %s', runTest); + ] as const)('when code is "%s" expected is %s', runTest); }); }); }); diff --git a/packages/type-utils/tests/discriminateAnyType.test.ts b/packages/type-utils/tests/discriminateAnyType.test.ts index 67a84298b057..6b933322086e 100644 --- a/packages/type-utils/tests/discriminateAnyType.test.ts +++ b/packages/type-utils/tests/discriminateAnyType.test.ts @@ -1,4 +1,5 @@ import type { TSESTree } from '@typescript-eslint/typescript-estree'; +import type { TestContext } from 'vitest'; import { parseForESLint } from '@typescript-eslint/parser'; import path from 'node:path'; @@ -8,7 +9,7 @@ import { expectToHaveParserServices } from './test-utils/expectToHaveParserServi type GetNode = (ast: TSESTree.Program) => TSESTree.Node; -describe('discriminateAnyType', () => { +describe(discriminateAnyType, () => { const rootDir = path.join(__dirname, 'fixtures'); function getDeclarationId(ast: TSESTree.Program): TSESTree.Node { @@ -36,9 +37,12 @@ describe('discriminateAnyType', () => { } function runTest( - code: string, - expected: AnyType, - getNode: GetNode = getDeclarationId, + [code, expected, getNode = getDeclarationId]: readonly [ + code: string, + expected: AnyType, + getNode?: GetNode, + ], + { expect }: TestContext, ): void { const { checker, program, tsNode, type } = getTypes(code, getNode); const result = discriminateAnyType(type, checker, program, tsNode); @@ -46,13 +50,13 @@ describe('discriminateAnyType', () => { } describe('returns Safe', () => { - it.each([ + it.for([ ['const foo = "foo";', AnyType.Safe], ['const foo = 1;', AnyType.Safe], ['const foo = [1, 2];', AnyType.Safe], - ])('when code is %s, returns %s', runTest); + ] as const)('when code is %s, returns %s', runTest); - it('should returns Safe for a recursive thenable.', () => { + it('should returns Safe for a recursive thenable.', testContext => { const code = ` class Foo { foo() { @@ -63,39 +67,46 @@ class Foo { } }; `; - runTest(code, AnyType.Safe, ast => { - const classDeclration = ast.body[0] as TSESTree.ClassDeclaration; - const method = classDeclration.body - .body[0] as TSESTree.MethodDefinition; - const returnStatement = method.value.body?.body.at( - -1, - ) as TSESTree.ReturnStatement; - return returnStatement.argument!; - }); + runTest( + [ + code, + AnyType.Safe, + ast => { + const classDeclration = ast.body[0] as TSESTree.ClassDeclaration; + const method = classDeclration.body + .body[0] as TSESTree.MethodDefinition; + const returnStatement = method.value.body?.body.at( + -1, + ) as TSESTree.ReturnStatement; + return returnStatement.argument!; + }, + ], + testContext, + ); }); }); describe('returns Any', () => { - it.each([ + it.for([ ['const foo = 1 as any;', AnyType.Any], ['let foo;', AnyType.Any], - ])('when code is %s, returns %s', runTest); + ] as const)('when code is %s, returns %s', runTest); }); describe('returns PromiseAny', () => { - it.each([ + it.for([ ['const foo = Promise.resolve({} as any);', AnyType.PromiseAny], [ 'const foo = Promise.resolve(Promise.resolve({} as any));', AnyType.PromiseAny, ], - ])('when code is %s, returns %s', runTest); + ] as const)('when code is %s, returns %s', runTest); }); describe('returns AnyArray', () => { - it.each([ + it.for([ ['const foo = [{} as any];', AnyType.AnyArray], ['const foo = [{} as any, 2];', AnyType.AnyArray], - ])('when code is %s, returns %s', runTest); + ] as const)('when code is %s, returns %s', runTest); }); }); diff --git a/packages/type-utils/tests/getConstrainedTypeAtLocation.test.ts b/packages/type-utils/tests/getConstrainedTypeAtLocation.test.ts index 598e78500afe..c033dba526d7 100644 --- a/packages/type-utils/tests/getConstrainedTypeAtLocation.test.ts +++ b/packages/type-utils/tests/getConstrainedTypeAtLocation.test.ts @@ -21,9 +21,9 @@ function parseCodeForEslint(code: string): ReturnType & { }); } -describe('getConstrainedTypeAtLocation', () => { +describe(getConstrainedTypeAtLocation, () => { // See https://github.com/typescript-eslint/typescript-eslint/issues/10438 - // eslint-disable-next-line jest/no-disabled-tests -- known issue. + // eslint-disable-next-line vitest/no-disabled-tests -- known issue. it.skip('returns unknown for unconstrained generic', () => { const sourceCode = ` function foo(x: T); diff --git a/packages/type-utils/tests/getDeclaration.test.ts b/packages/type-utils/tests/getDeclaration.test.ts index a7af315b6b28..172e4b8bbd4b 100644 --- a/packages/type-utils/tests/getDeclaration.test.ts +++ b/packages/type-utils/tests/getDeclaration.test.ts @@ -24,7 +24,7 @@ const mockDeclaration = (): ts.Declaration => { return {} as ts.Declaration; }; -describe('getDeclaration', () => { +describe(getDeclaration, () => { describe('when symbol does not exist', () => { it('returns null', () => { const services = mockServices(); diff --git a/packages/type-utils/tests/getTypeName.test.ts b/packages/type-utils/tests/getTypeName.test.ts index 7ab59ae0aae7..92aa0140204b 100644 --- a/packages/type-utils/tests/getTypeName.test.ts +++ b/packages/type-utils/tests/getTypeName.test.ts @@ -1,5 +1,6 @@ import type { TSESTree } from '@typescript-eslint/typescript-estree'; import type * as ts from 'typescript'; +import type { TestContext } from 'vitest'; import { parseForESLint } from '@typescript-eslint/parser'; import path from 'node:path'; @@ -7,7 +8,7 @@ import path from 'node:path'; import { getTypeName } from '../src'; import { expectToHaveParserServices } from './test-utils/expectToHaveParserServices'; -describe('getTypeName', () => { +describe(getTypeName, () => { function getTypes(code: string): { checker: ts.TypeChecker; type: ts.Type } { const rootDir = path.join(__dirname, 'fixtures'); @@ -24,14 +25,17 @@ describe('getTypeName', () => { return { checker, type: services.getTypeAtLocation(declaration.id) }; } - function runTest(code: string, expected: string): void { + function runTest( + [code, expected]: readonly [code: string, expected: string], + { expect }: TestContext, + ): void { const { checker, type } = getTypes(code); const result = getTypeName(checker, type); expect(result).toBe(expected); } describe('returns primitive type', () => { - it.each([ + it.for([ ['type Test = string;', 'string'], ['type Test = "text";', 'string'], ['type Test = string | "text";', 'string'], @@ -45,11 +49,11 @@ describe('getTypeName', () => { ['type Test = undefined;', 'undefined'], ['type Test = null;', 'null'], ['type Test = symbol;', 'symbol'], - ])('when code is %s, returns %s', runTest); + ] as const)('when code is %s, returns %s', runTest); }); describe('returns non-primitive type', () => { - it.each([ + it.for([ ['type Test = 123;', '123'], ['type Test = true;', 'true'], ['type Test = false;', 'false'], @@ -57,6 +61,6 @@ describe('getTypeName', () => { ['type Test = T & boolean;', 'Test'], ['type Test = string | number;', 'Test'], ['type Test = string | string[];', 'Test'], - ])('when code is %s, returns %s', runTest); + ] as const)('when code is %s, returns %s', runTest); }); }); diff --git a/packages/type-utils/tests/isSymbolFromDefaultLibrary.test.ts b/packages/type-utils/tests/isSymbolFromDefaultLibrary.test.ts index 4f7050fb38d9..eb4ecbf55b83 100644 --- a/packages/type-utils/tests/isSymbolFromDefaultLibrary.test.ts +++ b/packages/type-utils/tests/isSymbolFromDefaultLibrary.test.ts @@ -1,5 +1,6 @@ import type { TSESTree } from '@typescript-eslint/typescript-estree'; import type * as ts from 'typescript'; +import type { TestContext } from 'vitest'; import { parseForESLint } from '@typescript-eslint/parser'; import path from 'node:path'; @@ -7,7 +8,7 @@ import path from 'node:path'; import { isSymbolFromDefaultLibrary } from '../src'; import { expectToHaveParserServices } from './test-utils/expectToHaveParserServices'; -describe('isSymbolFromDefaultLibrary', () => { +describe(isSymbolFromDefaultLibrary, () => { const rootDir = path.join(__dirname, 'fixtures'); function getTypes(code: string): { @@ -26,35 +27,45 @@ describe('isSymbolFromDefaultLibrary', () => { return { program: services.program, symbol: type.getSymbol() }; } - function runTestForAliasDeclaration(code: string, expected: boolean): void { + function runTestForAliasDeclaration( + code: string, + expected: boolean, + expect: TestContext['expect'], + ): void { const { program, symbol } = getTypes(code); const result = isSymbolFromDefaultLibrary(program, symbol); expect(result).toBe(expected); } describe('is symbol from default library', () => { - function runTest(code: string): void { - runTestForAliasDeclaration(code, true); + function runTest( + [code]: readonly [code: string], + { expect }: TestContext, + ): void { + runTestForAliasDeclaration(code, true, expect); } - it.each([ + it.for([ ['type Test = Array;'], ['type Test = Map;'], ['type Test = Promise'], ['type Test = Error'], ['type Test = Object'], - ])('when code is %s, returns true', runTest); + ] as const)('when code is %s, returns true', runTest); }); describe('is not symbol from default library', () => { - function runTest(code: string): void { - runTestForAliasDeclaration(code, false); + function runTest( + [code]: readonly [code: string], + { expect }: TestContext, + ): void { + runTestForAliasDeclaration(code, false, expect); } - it.each([ + it.for([ ['const test: Array = [1,2,3];'], ['type Test = number;'], ['interface Test { bar: string; };'], - ])('when code is %s, returns false', runTest); + ] as const)('when code is %s, returns false', runTest); }); }); diff --git a/packages/type-utils/tests/isTypeReadonly.test.ts b/packages/type-utils/tests/isTypeReadonly.test.ts index f7405e2e5add..8f2d04765cb8 100644 --- a/packages/type-utils/tests/isTypeReadonly.test.ts +++ b/packages/type-utils/tests/isTypeReadonly.test.ts @@ -2,6 +2,7 @@ import type { TSESTree } from '@typescript-eslint/utils'; import type * as ts from 'typescript'; import { parseForESLint } from '@typescript-eslint/parser'; +import { AST_NODE_TYPES } from '@typescript-eslint/utils'; import path from 'node:path'; import type { ReadonlynessOptions } from '../src/isTypeReadonly'; @@ -9,10 +10,10 @@ import type { ReadonlynessOptions } from '../src/isTypeReadonly'; import { isTypeReadonly } from '../src/isTypeReadonly'; import { expectToHaveParserServices } from './test-utils/expectToHaveParserServices'; -describe('isTypeReadonly', () => { +describe(isTypeReadonly, () => { const rootDir = path.join(__dirname, 'fixtures'); - describe('TSTypeAliasDeclaration ', () => { + describe(AST_NODE_TYPES.TSTypeAliasDeclaration, () => { function getType(code: string): { program: ts.Program; type: ts.Type; @@ -24,8 +25,7 @@ describe('isTypeReadonly', () => { tsconfigRootDir: rootDir, }); expectToHaveParserServices(services); - const program = services.program; - const esTreeNodeToTSNodeMap = services.esTreeNodeToTSNodeMap; + const { esTreeNodeToTSNodeMap, program } = services; const declaration = ast.body[0] as TSESTree.TSTypeAliasDeclaration; return { @@ -59,33 +59,33 @@ describe('isTypeReadonly', () => { } describe('basics', () => { - describe('is readonly', () => { + describe('is readonly', { timeout: 10_000 }, () => { const runTests = runTestIsReadonly; // Record. it.each([ ['type Test = { readonly bar: string; };'], ['type Test = Readonly<{ bar: string; }>;'], - ])('handles fully readonly records', runTests); + ] as const)('handles fully readonly records', runTests); // Array. it.each([ ['type Test = Readonly;'], ['type Test = Readonly>;'], - ])('handles fully readonly arrays', runTests); + ] as const)('handles fully readonly arrays', runTests); // Array - special case. // Note: Methods are mutable but arrays are treated special; hence no failure. it.each([ ['type Test = readonly string[];'], ['type Test = ReadonlyArray;'], - ])('treats readonly arrays as fully readonly', runTests); + ] as const)('treats readonly arrays as fully readonly', runTests); // Set and Map. it.each([ ['type Test = Readonly>;'], ['type Test = Readonly>;'], - ])('handles fully readonly sets and maps', runTests); + ] as const)('handles fully readonly sets and maps', runTests); // Private Identifier. // Note: It can't be accessed from outside of class thus exempt from the checks. @@ -93,7 +93,7 @@ describe('isTypeReadonly', () => { ['class Foo { readonly #readonlyPrivateField = "foo"; }'], ['class Foo { #privateField = "foo"; }'], ['class Foo { #privateMember() {}; }'], - ])('treat private identifier as readonly', runTests); + ] as const)('treat private identifier as readonly', runTests); }); describe('is not readonly', () => { @@ -103,13 +103,13 @@ describe('isTypeReadonly', () => { it.each([ ['type Test = { foo: string; };'], ['type Test = { foo: string; readonly bar: number; };'], - ])('handles non fully readonly records', runTests); + ] as const)('handles non fully readonly records', runTests); // Array. - it.each([['type Test = string[]'], ['type Test = Array']])( - 'handles non fully readonly arrays', - runTests, - ); + it.each([ + ['type Test = string[]'], + ['type Test = Array'], + ] as const)('handles non fully readonly arrays', runTests); // Set and Map. // Note: Methods are mutable for ReadonlySet and ReadonlyMet; hence failure. @@ -118,7 +118,7 @@ describe('isTypeReadonly', () => { ['type Test = Map;'], ['type Test = ReadonlySet;'], ['type Test = ReadonlyMap;'], - ])('handles non fully readonly sets and maps', runTests); + ] as const)('handles non fully readonly sets and maps', runTests); }); }); @@ -131,7 +131,7 @@ describe('isTypeReadonly', () => { [ 'type Test = { readonly [key: string]: { readonly foo: readonly string[]; }; };', ], - ])( + ] as const)( 'handles readonly PropertySignature inside a readonly IndexSignature', runTests, ); @@ -140,13 +140,15 @@ describe('isTypeReadonly', () => { describe('is readonly circular', () => { const runTests = runTestIsReadonly; - it('handles circular readonly PropertySignature inside a readonly IndexSignature', () => - runTests('interface Test { readonly [key: string]: Test };')); + it('handles circular readonly PropertySignature inside a readonly IndexSignature', () => { + runTests('interface Test { readonly [key: string]: Test };'); + }); - it('handles circular readonly PropertySignature inside interdependent objects', () => + it('handles circular readonly PropertySignature inside interdependent objects', () => { runTests( 'interface Test1 { readonly [key: string]: Test } interface Test { readonly [key: string]: Test1 }', - )); + ); + }); }); describe('is not readonly', () => { @@ -155,7 +157,7 @@ describe('isTypeReadonly', () => { it.each([ ['type Test = { [key: string]: string };'], ['type Test = { readonly [key: string]: { foo: string[]; }; };'], - ])( + ] as const)( 'handles mutable PropertySignature inside a readonly IndexSignature', runTests, ); @@ -164,8 +166,9 @@ describe('isTypeReadonly', () => { describe('is not readonly circular', () => { const runTests = runTestIsNotReadonly; - it('handles circular mutable PropertySignature', () => - runTests('interface Test { [key: string]: Test };')); + it('handles circular mutable PropertySignature', () => { + runTests('interface Test { [key: string]: Test };'); + }); it.each([ [ @@ -177,7 +180,7 @@ describe('isTypeReadonly', () => { [ 'interface Test1 { [key: string]: Test } interface Test { [key: string]: Test1 }', ], - ])( + ] as const)( 'handles circular mutable PropertySignature inside interdependent objects', runTests, ); @@ -193,7 +196,7 @@ describe('isTypeReadonly', () => { 'type Test = Readonly<{ foo: string; bar: number; }> & Readonly<{ bar: number; }>;', ], ['type Test = readonly string[] | readonly number[];'], - ])('handles a union of 2 fully readonly types', runTests); + ] as const)('handles a union of 2 fully readonly types', runTests); }); describe('is not readonly', () => { @@ -207,7 +210,7 @@ describe('isTypeReadonly', () => { [ 'type Test = Readonly<{ foo: string; bar: number; }> | { bar: number; };', ], - ])('handles a union of non fully readonly types', runTests); + ] as const)('handles a union of non fully readonly types', runTests); }); }); @@ -219,13 +222,16 @@ describe('isTypeReadonly', () => { [ 'type Test = Readonly<{ foo: string; bar: number; }> & Readonly<{ bar: number; }>;', ], - ])('handles an intersection of 2 fully readonly types', runTests); + ] as const)( + 'handles an intersection of 2 fully readonly types', + runTests, + ); it.each([ [ 'type Test = Readonly<{ foo: string; bar: number; }> & { foo: string; };', ], - ])( + ] as const)( 'handles an intersection of a fully readonly type with a mutable subtype', runTests, ); @@ -237,7 +243,10 @@ describe('isTypeReadonly', () => { [ 'type Test = readonly [string, number] & Readonly<{ foo: string; }>;', ], - ])('handles an intersections involving a readonly array', runTests); + ] as const)( + 'handles an intersections involving a readonly array', + runTests, + ); }); describe('is not readonly', () => { @@ -251,7 +260,10 @@ describe('isTypeReadonly', () => { [ 'type Test = Readonly<{ bar: number; }> & { foo: string; bar: number; };', ], - ])('handles an intersection of non fully readonly types', runTests); + ] as const)( + 'handles an intersection of non fully readonly types', + runTests, + ); }); }); @@ -263,13 +275,16 @@ describe('isTypeReadonly', () => { [ 'type Test = T extends readonly number[] ? readonly string[] : readonly number[];', ], - ])('handles conditional type that are fully readonly', runTests); + ] as const)( + 'handles conditional type that are fully readonly', + runTests, + ); it.each([ [ 'type Test = T extends number[] ? readonly string[] : readonly number[];', ], - ])('should ignore mutable conditions', runTests); + ] as const)('should ignore mutable conditions', runTests); }); describe('is not readonly', () => { @@ -283,7 +298,7 @@ describe('isTypeReadonly', () => { [ 'type Test = T extends number[] ? readonly string[] : number[];', ], - ])('handles non fully readonly conditional types', runTests); + ] as const)('handles non fully readonly conditional types', runTests); }); }); }); @@ -308,7 +323,7 @@ describe('isTypeReadonly', () => { it.each([ ['type Test = ReadonlySet;'], ['type Test = ReadonlyMap;'], - ])('handles non fully readonly sets and maps', runTests); + ] as const)('handles non fully readonly sets and maps', runTests); }); }); @@ -343,7 +358,10 @@ describe('isTypeReadonly', () => { 'interface Foo {prop: RegExp}; type Test = (arg: Readonly) => void;', ], ['interface Foo {prop: string}; type Test = (arg: Foo) => void;'], - ])('correctly marks allowlisted types as readonly', runTestIsReadonly); + ] as const)( + 'correctly marks allowlisted types as readonly', + runTestIsReadonly, + ); }); describe('is not readonly', () => { @@ -352,7 +370,7 @@ describe('isTypeReadonly', () => { 'interface Bar {prop: RegExp}; type Test = (arg: Readonly) => void;', ], ['interface Bar {prop: string}; type Test = (arg: Bar) => void;'], - ])( + ] as const)( 'correctly marks allowlisted types as readonly', runTestIsNotReadonly, ); diff --git a/packages/type-utils/tests/isUnsafeAssignment.test.ts b/packages/type-utils/tests/isUnsafeAssignment.test.ts index b4ea26a58438..af605b73a441 100644 --- a/packages/type-utils/tests/isUnsafeAssignment.test.ts +++ b/packages/type-utils/tests/isUnsafeAssignment.test.ts @@ -7,7 +7,7 @@ import path from 'node:path'; import { isUnsafeAssignment } from '../src/isUnsafeAssignment'; import { expectToHaveParserServices } from './test-utils/expectToHaveParserServices'; -describe('isUnsafeAssignment', () => { +describe(isUnsafeAssignment, () => { const rootDir = path.join(__dirname, 'fixtures'); function getTypes( diff --git a/packages/type-utils/tests/requiresQuoting.test.ts b/packages/type-utils/tests/requiresQuoting.test.ts index 59c7d02e60e4..565743913164 100644 --- a/packages/type-utils/tests/requiresQuoting.test.ts +++ b/packages/type-utils/tests/requiresQuoting.test.ts @@ -1,6 +1,6 @@ import { requiresQuoting } from '../src'; -describe('getDeclaration', () => { +describe(requiresQuoting, () => { describe('valid identifier', () => { it('upper and lower case alphabet', () => { const name = 'c'; diff --git a/packages/type-utils/tests/typeFlagUtils.test.ts b/packages/type-utils/tests/typeFlagUtils.test.ts index 24e66b394158..c5d6fcc4f552 100644 --- a/packages/type-utils/tests/typeFlagUtils.test.ts +++ b/packages/type-utils/tests/typeFlagUtils.test.ts @@ -1,4 +1,5 @@ import type { TSESTree } from '@typescript-eslint/typescript-estree'; +import type { TestContext } from 'vitest'; import { parseForESLint } from '@typescript-eslint/parser'; import path from 'node:path'; @@ -23,33 +24,40 @@ describe('typeFlagUtils', () => { return services.getTypeAtLocation(declaration.id); } - describe('getTypeFlags', () => { + describe(getTypeFlags, () => { function runTestForAliasDeclaration( - code: string, - expected: ts.TypeFlags, + [code, expected]: readonly [code: string, expected: ts.TypeFlags], + { expect }: TestContext, ): void { const type = getType(code); const result = getTypeFlags(type); expect(result).toBe(expected); } - it.each([ + it.for([ ['type Test = any;', 1], ['type Test = unknown;', 2], ['type Test = string;', 4], ['type Test = number;', 8], ['type Test = "text";', 128], ['type Test = 123;', 256], - ['type Test = string | number', 12], + [ + 'type Test = string | number', + ts.TypeFlags.String | ts.TypeFlags.Number, + ], ['type Test = "text" | 123', 384], - ])('when code is "%s", type flags is %d', runTestForAliasDeclaration); + ] as const)( + 'when code is "%s", type flags is %d', + runTestForAliasDeclaration, + ); }); - describe('isTypeFlagSet', () => { + describe(isTypeFlagSet, () => { function runTestForAliasDeclaration( code: string, flagsToCheck: ts.TypeFlags, expected: boolean, + { expect }: TestContext, ): void { const type = getType(code); const result = isTypeFlagSet(type, flagsToCheck); @@ -58,18 +66,21 @@ describe('typeFlagUtils', () => { describe('is type flags set', () => { function runTestIsTypeFlagSet( - code: string, - flagsToCheck: ts.TypeFlags, + [code, flagsToCheck]: readonly [ + code: string, + flagsToCheck: ts.TypeFlags, + ], + testContext: TestContext, ): void { - runTestForAliasDeclaration(code, flagsToCheck, true); + runTestForAliasDeclaration(code, flagsToCheck, true, testContext); } - it.each([ + it.for([ ['type Test = any;', ts.TypeFlags.Any], ['type Test = string;', ts.TypeFlags.String], ['type Test = string | number;', ts.TypeFlags.String], ['type Test = string & { foo: string };', ts.TypeFlags.Intersection], - ])( + ] as const)( 'when code is "%s" and flagsToCheck is %d , returns true', runTestIsTypeFlagSet, ); @@ -77,17 +88,20 @@ describe('typeFlagUtils', () => { describe('is not type flags set', () => { function runTestIsNotTypeFlagSet( - code: string, - flagsToCheck: ts.TypeFlags, + [code, flagsToCheck]: readonly [ + code: string, + flagsToCheck: ts.TypeFlags, + ], + testContext: TestContext, ): void { - runTestForAliasDeclaration(code, flagsToCheck, false); + runTestForAliasDeclaration(code, flagsToCheck, false, testContext); } - it.each([ + it.for([ ['type Test = string', ts.TypeFlags.Any], ['type Test = string | number;', ts.TypeFlags.Any], ['type Test = string & { foo: string }', ts.TypeFlags.String], - ])( + ] as const)( 'when code is "%s" and flagsToCheck is %d , returns false', runTestIsNotTypeFlagSet, ); diff --git a/packages/type-utils/tsconfig.build.json b/packages/type-utils/tsconfig.build.json index f409f6784f7c..821662562d80 100644 --- a/packages/type-utils/tsconfig.build.json +++ b/packages/type-utils/tsconfig.build.json @@ -9,7 +9,7 @@ "types": ["node"] }, "include": ["src/**/*.ts", "typings"], - "exclude": ["jest.config.js", "src/**/*.spec.ts", "src/**/*.test.ts"], + "exclude": ["vitest.config.mts", "src/**/*.spec.ts", "src/**/*.test.ts"], "references": [ { "path": "../types/tsconfig.build.json" diff --git a/packages/type-utils/tsconfig.spec.json b/packages/type-utils/tsconfig.spec.json index 9b6b8b55e093..7ec995aaf7dc 100644 --- a/packages/type-utils/tsconfig.spec.json +++ b/packages/type-utils/tsconfig.spec.json @@ -3,10 +3,12 @@ "compilerOptions": { "outDir": "../../dist/out-tsc/packages/type-utils", "module": "NodeNext", - "types": ["jest", "node"] + "resolveJsonModule": true, + "types": ["node", "vitest/globals", "vitest/importMeta"] }, "include": [ - "jest.config.js", + "vitest.config.mts", + "package.json", "src/**/*.test.ts", "src/**/*.spec.ts", "src/**/*.d.ts", @@ -16,6 +18,9 @@ "references": [ { "path": "./tsconfig.build.json" + }, + { + "path": "../../tsconfig.spec.json" } ] } diff --git a/packages/type-utils/vitest.config.mts b/packages/type-utils/vitest.config.mts new file mode 100644 index 000000000000..674ea2ded3b5 --- /dev/null +++ b/packages/type-utils/vitest.config.mts @@ -0,0 +1,22 @@ +import * as path from 'node:path'; +import { defineProject, mergeConfig } from 'vitest/config'; + +import { vitestBaseConfig } from '../../vitest.config.base.mjs'; +import packageJson from './package.json' with { type: 'json' }; + +const vitestConfig = mergeConfig( + vitestBaseConfig, + + defineProject({ + root: import.meta.dirname, + + test: { + dir: path.join(import.meta.dirname, 'tests'), + name: packageJson.name.replace('@typescript-eslint/', ''), + root: import.meta.dirname, + testTimeout: 10_000, + }, + }), +); + +export default vitestConfig; diff --git a/tools/scripts/postinstall.mts b/tools/scripts/postinstall.mts index ba5dbc9d809e..5d123b1991d5 100644 --- a/tools/scripts/postinstall.mts +++ b/tools/scripts/postinstall.mts @@ -44,5 +44,6 @@ void (async function (): Promise { // Build all the packages ready for use await $`yarn build`; + await $`yarn nx typecheck ast-spec`; } })(); diff --git a/yarn.lock b/yarn.lock index be528cc2a4f9..49b2159800e7 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6153,18 +6153,18 @@ __metadata: version: 0.0.0-use.local resolution: "@typescript-eslint/type-utils@workspace:packages/type-utils" dependencies: - "@jest/types": 29.6.3 "@typescript-eslint/parser": 8.29.1 "@typescript-eslint/typescript-estree": 8.29.1 "@typescript-eslint/utils": 8.29.1 + "@vitest/coverage-v8": ^3.1.1 ajv: ^6.12.6 debug: ^4.3.4 downlevel-dts: "*" - jest: 29.7.0 prettier: ^3.2.5 rimraf: "*" ts-api-utils: ^2.0.1 typescript: "*" + vitest: ^3.1.1 peerDependencies: eslint: ^8.57.0 || ^9.0.0 typescript: ">=4.8.4 <5.9.0"