chore: enable a bunch more lint rules (#14794)

This commit is contained in:
Simen Bekkhus 2023-12-29 08:49:03 +01:00 committed by GitHub
parent 175665ec49
commit 0469b4c698
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
39 changed files with 144 additions and 115 deletions

View File

@ -35,13 +35,19 @@ module.exports = {
'plugin:eslint-comments/recommended', 'plugin:eslint-comments/recommended',
'plugin:prettier/recommended', 'plugin:prettier/recommended',
'plugin:unicorn/recommended', 'plugin:unicorn/recommended',
'plugin:promise/recommended',
], ],
globals: { globals: {
console: 'readonly', console: 'readonly',
}, },
overrides: [ overrides: [
{ {
extends: ['plugin:@typescript-eslint/strict', 'plugin:import/typescript'], extends: [
'plugin:@typescript-eslint/eslint-recommended',
'plugin:@typescript-eslint/strict',
'plugin:@typescript-eslint/stylistic',
'plugin:import/typescript',
],
files: ['*.ts', '*.tsx'], files: ['*.ts', '*.tsx'],
plugins: ['@typescript-eslint/eslint-plugin', 'local'], plugins: ['@typescript-eslint/eslint-plugin', 'local'],
rules: { rules: {
@ -59,6 +65,7 @@ module.exports = {
], ],
'@typescript-eslint/prefer-ts-expect-error': 'error', '@typescript-eslint/prefer-ts-expect-error': 'error',
'@typescript-eslint/no-var-requires': 'off', '@typescript-eslint/no-var-requires': 'off',
'@typescript-eslint/consistent-indexed-object-style': 'off',
// TS verifies these // TS verifies these
'consistent-return': 'off', 'consistent-return': 'off',
'no-dupe-class-members': 'off', 'no-dupe-class-members': 'off',
@ -68,10 +75,7 @@ module.exports = {
'@typescript-eslint/no-explicit-any': 'off', '@typescript-eslint/no-explicit-any': 'off',
'@typescript-eslint/no-non-null-assertion': 'off', '@typescript-eslint/no-non-null-assertion': 'off',
'@typescript-eslint/no-invalid-void-type': 'off', '@typescript-eslint/no-invalid-void-type': 'off',
'@typescript-eslint/consistent-type-definitions': 'off',
// TODO: part of "stylistic" rules, remove explicit activation when that lands
'@typescript-eslint/no-empty-function': 'error',
'@typescript-eslint/no-empty-interface': 'error',
// not needed to be enforced for TS // not needed to be enforced for TS
'import/namespace': 'off', 'import/namespace': 'off',
@ -326,6 +330,7 @@ module.exports = {
rules: { rules: {
'@typescript-eslint/ban-ts-comment': 'off', '@typescript-eslint/ban-ts-comment': 'off',
'@typescript-eslint/no-empty-function': 'off', '@typescript-eslint/no-empty-function': 'off',
'@typescript-eslint/class-literal-property-style': 'off',
}, },
}, },
{ {
@ -427,6 +432,12 @@ module.exports = {
'unicorn/no-static-only-class': 'off', 'unicorn/no-static-only-class': 'off',
}, },
}, },
{
files: '**/*.mjs',
rules: {
'unicorn/prefer-top-level-await': 'error',
},
},
], ],
parser: '@typescript-eslint/parser', parser: '@typescript-eslint/parser',
parserOptions: { parserOptions: {
@ -617,6 +628,11 @@ module.exports = {
'prefer-arrow-callback': ['error', {allowNamedFunctions: true}], 'prefer-arrow-callback': ['error', {allowNamedFunctions: true}],
'prefer-const': 'error', 'prefer-const': 'error',
'prefer-template': 'error', 'prefer-template': 'error',
'promise/always-return': 'off',
'promise/catch-or-return': 'off',
'promise/no-callback-in-promise': 'off',
quotes: [ quotes: [
'error', 'error',
'single', 'single',
@ -655,10 +671,8 @@ module.exports = {
'unicorn/prefer-event-target': 'off', 'unicorn/prefer-event-target': 'off',
'unicorn/prefer-switch': 'off', 'unicorn/prefer-switch': 'off',
'unicorn/prefer-ternary': 'off', 'unicorn/prefer-ternary': 'off',
'unicorn/switch-case-braces': 'off',
// TODO: enable for `.mjs` files
'unicorn/prefer-top-level-await': 'off', 'unicorn/prefer-top-level-await': 'off',
'unicorn/switch-case-braces': 'off',
// TODO: decide whether or not we want these // TODO: decide whether or not we want these
'unicorn/filename-case': 'off', 'unicorn/filename-case': 'off',

View File

@ -8,7 +8,7 @@
'use strict'; 'use strict';
it.concurrent('Good Test', async () => { it.concurrent('Good Test', async () => {
await new Promise(r => setTimeout(r, 100)); await new Promise(resolve => setTimeout(resolve, 100));
}); });
it.concurrent('Bad Test', async () => { it.concurrent('Bad Test', async () => {

View File

@ -7,7 +7,7 @@
*/ */
'use strict'; 'use strict';
const sleep = ms => new Promise(r => setTimeout(r, ms)); const sleep = ms => new Promise(resolve => setTimeout(resolve, ms));
describe('A', () => { describe('A', () => {
it.concurrent('a', async () => { it.concurrent('a', async () => {

View File

@ -41,6 +41,7 @@
"eslint-plugin-local": "link:./.eslintplugin", "eslint-plugin-local": "link:./.eslintplugin",
"eslint-plugin-markdown": "^3.0.0", "eslint-plugin-markdown": "^3.0.0",
"eslint-plugin-prettier": "^5.0.0", "eslint-plugin-prettier": "^5.0.0",
"eslint-plugin-promise": "^6.1.1",
"eslint-plugin-unicorn": "^50.0.0", "eslint-plugin-unicorn": "^50.0.0",
"execa": "^5.0.0", "execa": "^5.0.0",
"find-process": "^1.4.1", "find-process": "^1.4.1",

View File

@ -133,7 +133,7 @@ FUNCTIONS.mock = args => {
); );
} }
const ids: Set<NodePath<Identifier>> = new Set(); const ids = new Set<NodePath<Identifier>>();
const parentScope = moduleFactory.parentPath.scope; const parentScope = moduleFactory.parentPath.scope;
// @ts-expect-error: ReferencedIdentifier and denylist are not known on visitors // @ts-expect-error: ReferencedIdentifier and denylist are not known on visitors
moduleFactory.traverse(IDVisitor, {ids}); moduleFactory.traverse(IDVisitor, {ids});

View File

@ -76,13 +76,8 @@ function eq(
} }
const testerContext: TesterContext = {equals}; const testerContext: TesterContext = {equals};
for (let i = 0; i < customTesters.length; i++) { for (const item of customTesters) {
const customTesterResult = customTesters[i].call( const customTesterResult = item.call(testerContext, a, b, customTesters);
testerContext,
a,
b,
customTesters,
);
if (customTesterResult !== undefined) { if (customTesterResult !== undefined) {
return customTesterResult; return customTesterResult;
} }

View File

@ -203,7 +203,7 @@ const makeResolveMatcher =
)}\n\n` + )}\n\n` +
'Received promise rejected instead of resolved\n' + 'Received promise rejected instead of resolved\n' +
`Rejected to value: ${matcherUtils.printReceived(reason)}`; `Rejected to value: ${matcherUtils.printReceived(reason)}`;
return Promise.reject(outerErr); throw outerErr;
}, },
); );
}; };
@ -254,7 +254,7 @@ const makeRejectMatcher =
)}\n\n` + )}\n\n` +
'Received promise resolved instead of rejected\n' + 'Received promise resolved instead of rejected\n' +
`Resolved to value: ${matcherUtils.printReceived(result)}`; `Resolved to value: ${matcherUtils.printReceived(result)}`;
return Promise.reject(outerErr); throw outerErr;
}, },
reason => reason =>
makeThrowingMatcher(matcher, isNot, 'rejects', reason, innerErr).apply( makeThrowingMatcher(matcher, isNot, 'rejects', reason, innerErr).apply(

View File

@ -98,11 +98,10 @@ export interface BaseExpect {
setState(state: Partial<MatcherState>): void; setState(state: Partial<MatcherState>): void;
} }
export type Expect = { export type Expect = (<T = unknown>(
<T = unknown>( actual: T,
actual: T, ) => Matchers<void, T> & Inverse<Matchers<void, T>> & PromiseMatchers<T>) &
): Matchers<void, T> & Inverse<Matchers<void, T>> & PromiseMatchers<T>; BaseExpect &
} & BaseExpect &
AsymmetricMatchers & AsymmetricMatchers &
Inverse<Omit<AsymmetricMatchers, 'any' | 'anything'>>; Inverse<Omit<AsymmetricMatchers, 'any' | 'anything'>>;

View File

@ -113,8 +113,8 @@ describe('collectHandles', () => {
const server = http.createServer((_, response) => response.end('ok')); const server = http.createServer((_, response) => response.end('ok'));
// Start and stop server. // Start and stop server.
await new Promise(r => server.listen(0, r)); await new Promise(resolve => server.listen(0, resolve));
await new Promise(r => server.close(r)); await new Promise(resolve => server.close(resolve));
const openHandles = await handleCollector(); const openHandles = await handleCollector();
expect(openHandles).toHaveLength(0); expect(openHandles).toHaveLength(0);
@ -130,11 +130,13 @@ describe('collectHandles', () => {
// creates a long-lived `TCPSERVERWRAP` resource. We want to make sure we // creates a long-lived `TCPSERVERWRAP` resource. We want to make sure we
// capture that long-lived resource. // capture that long-lived resource.
const server = new http.Server(); const server = new http.Server();
await new Promise(r => server.listen({host: 'localhost', port: 0}, r)); await new Promise(resolve =>
server.listen({host: 'localhost', port: 0}, resolve),
);
const openHandles = await handleCollector(); const openHandles = await handleCollector();
await new Promise(r => server.close(r)); await new Promise(resolve => server.close(resolve));
expect(openHandles).toContainEqual( expect(openHandles).toContainEqual(
expect.objectContaining({message: 'TCPSERVERWRAP'}), expect.objectContaining({message: 'TCPSERVERWRAP'}),

View File

@ -88,7 +88,7 @@ const regularUpdateGlobalConfig = require('../lib/updateGlobalConfig').default;
const updateGlobalConfig = jest.fn(regularUpdateGlobalConfig); const updateGlobalConfig = jest.fn(regularUpdateGlobalConfig);
jest.doMock('../lib/updateGlobalConfig', () => updateGlobalConfig); jest.doMock('../lib/updateGlobalConfig', () => updateGlobalConfig);
const nextTick = () => new Promise(res => process.nextTick(res)); const nextTick = () => new Promise(resolve => process.nextTick(resolve));
beforeAll(() => { beforeAll(() => {
jest.spyOn(process, 'on').mockImplementation(() => {}); jest.spyOn(process, 'on').mockImplementation(() => {});
@ -771,7 +771,9 @@ describe('Watch mode flows', () => {
it('prevents Jest from handling keys when active and returns control when end is called', async () => { it('prevents Jest from handling keys when active and returns control when end is called', async () => {
let resolveShowPrompt; let resolveShowPrompt;
const run = jest.fn(() => new Promise(res => (resolveShowPrompt = res))); const run = jest.fn(
() => new Promise(resolve => (resolveShowPrompt = resolve)),
);
const pluginPath = `${__dirname}/__fixtures__/plugin_path_1`; const pluginPath = `${__dirname}/__fixtures__/plugin_path_1`;
jest.doMock( jest.doMock(
pluginPath, pluginPath,

View File

@ -68,7 +68,7 @@ jest.doMock(
const watch = require('../watch').default; const watch = require('../watch').default;
const nextTick = () => new Promise(res => process.nextTick(res)); const nextTick = () => new Promise(resolve => process.nextTick(resolve));
const globalConfig = { const globalConfig = {
rootDir: '', rootDir: '',

View File

@ -41,7 +41,7 @@ class TestNamePatternPlugin extends BaseWatchPlugin {
globalConfig: Config.GlobalConfig, globalConfig: Config.GlobalConfig,
updateConfigAndRun: UpdateConfigCallback, updateConfigAndRun: UpdateConfigCallback,
): Promise<void> { ): Promise<void> {
return new Promise((res, rej) => { return new Promise((resolve, reject) => {
const testNamePatternPrompt = new TestNamePatternPrompt( const testNamePatternPrompt = new TestNamePatternPrompt(
this._stdout, this._stdout,
this._prompt, this._prompt,
@ -50,9 +50,9 @@ class TestNamePatternPlugin extends BaseWatchPlugin {
testNamePatternPrompt.run( testNamePatternPrompt.run(
(value: string) => { (value: string) => {
updateConfigAndRun({mode: 'watch', testNamePattern: value}); updateConfigAndRun({mode: 'watch', testNamePattern: value});
res(); resolve();
}, },
rej, reject,
{ {
header: activeFilters(globalConfig), header: activeFilters(globalConfig),
}, },

View File

@ -41,7 +41,7 @@ class TestPathPatternPlugin extends BaseWatchPlugin {
globalConfig: Config.GlobalConfig, globalConfig: Config.GlobalConfig,
updateConfigAndRun: UpdateConfigCallback, updateConfigAndRun: UpdateConfigCallback,
): Promise<void> { ): Promise<void> {
return new Promise((res, rej) => { return new Promise((resolve, reject) => {
const testPathPatternPrompt = new TestPathPatternPrompt( const testPathPatternPrompt = new TestPathPatternPrompt(
this._stdout, this._stdout,
this._prompt, this._prompt,
@ -50,9 +50,9 @@ class TestPathPatternPlugin extends BaseWatchPlugin {
testPathPatternPrompt.run( testPathPatternPrompt.run(
(value: string) => { (value: string) => {
updateConfigAndRun({mode: 'watch', testPathPatterns: [value]}); updateConfigAndRun({mode: 'watch', testPathPatterns: [value]});
res(); resolve();
}, },
rej, reject,
{ {
header: activeFilters(globalConfig), header: activeFilters(globalConfig),
}, },

View File

@ -67,7 +67,7 @@ class UpdateSnapshotInteractivePlugin extends BaseWatchPlugin {
updateConfigAndRun: Function, updateConfigAndRun: Function,
): Promise<void> { ): Promise<void> {
if (this._failedSnapshotTestAssertions.length > 0) { if (this._failedSnapshotTestAssertions.length > 0) {
return new Promise(res => { return new Promise(resolve => {
this._snapshotInteractiveMode.run( this._snapshotInteractiveMode.run(
this._failedSnapshotTestAssertions, this._failedSnapshotTestAssertions,
(assertion, shouldUpdateSnapshot) => { (assertion, shouldUpdateSnapshot) => {
@ -79,7 +79,7 @@ class UpdateSnapshotInteractivePlugin extends BaseWatchPlugin {
updateSnapshot: shouldUpdateSnapshot ? 'all' : 'none', updateSnapshot: shouldUpdateSnapshot ? 'all' : 'none',
}); });
if (!this._snapshotInteractiveMode.isActive()) { if (!this._snapshotInteractiveMode.isActive()) {
res(); resolve();
} }
}, },
); );

View File

@ -27,8 +27,9 @@ export function extract(contents: string): string {
} }
export function strip(contents: string): string { export function strip(contents: string): string {
const match = contents.match(docblockRe); const matchResult = contents.match(docblockRe);
return match && match[0] ? contents.slice(match[0].length) : contents; const match = matchResult?.[0];
return match == null ? contents : contents.slice(match.length);
} }
export function parse(docblock: string): Pragmas { export function parse(docblock: string): Pragmas {

View File

@ -15,7 +15,7 @@
// //
// Feel free to add any extensions that cannot be a Haste module. // Feel free to add any extensions that cannot be a Haste module.
const extensions: Set<string> = new Set([ const extensions = new Set<string>([
// JSONs are never haste modules, except for "package.json", which is handled. // JSONs are never haste modules, except for "package.json", which is handled.
'.json', '.json',

View File

@ -71,9 +71,9 @@ class CallTracker {
}; };
this.allArgs = function () { this.allArgs = function () {
const callArgs = []; const callArgs: Array<unknown> = [];
for (let i = 0; i < calls.length; i++) { for (const call of calls) {
callArgs.push(calls[i].args); callArgs.push(call.args);
} }
return callArgs; return callArgs;

View File

@ -56,8 +56,7 @@ export default class ReportDispatcher implements Reporter {
constructor(methods: Array<keyof Reporter>) { constructor(methods: Array<keyof Reporter>) {
const dispatchedMethods = methods || []; const dispatchedMethods = methods || [];
for (let i = 0; i < dispatchedMethods.length; i++) { for (const method of dispatchedMethods) {
const method = dispatchedMethods[i];
this[method] = (function (m) { this[method] = (function (m) {
return function () { return function () {
dispatch(m, arguments); dispatch(m, arguments);
@ -86,8 +85,7 @@ export default class ReportDispatcher implements Reporter {
if (reporters.length === 0 && fallbackReporter !== null) { if (reporters.length === 0 && fallbackReporter !== null) {
reporters.push(fallbackReporter); reporters.push(fallbackReporter);
} }
for (let i = 0; i < reporters.length; i++) { for (const reporter of reporters) {
const reporter = reporters[i];
if (reporter[method]) { if (reporter[method]) {
// @ts-expect-error: wrong context // @ts-expect-error: wrong context
reporter[method].apply(reporter, args); reporter[method].apply(reporter, args);

View File

@ -190,8 +190,7 @@ export default class Suite {
}; };
this.result.failedExpectations.push(expectationResultFactory(data)); this.result.failedExpectations.push(expectationResultFactory(data));
} else { } else {
for (let i = 0; i < this.children.length; i++) { for (const child of this.children) {
const child = this.children[i];
child.onException.apply(child, args); child.onException.apply(child, args);
} }
} }
@ -205,8 +204,7 @@ export default class Suite {
throw new ExpectationFailed(); throw new ExpectationFailed();
} }
} else { } else {
for (let i = 0; i < this.children.length; i++) { for (const child of this.children) {
const child = this.children[i];
try { try {
child.addExpectationResult.apply(child, args); child.addExpectationResult.apply(child, args);
} catch { } catch {

View File

@ -36,7 +36,7 @@ const isMap = (value: any): value is Map<unknown, unknown> =>
export default function deepCyclicCopyReplaceable<T>( export default function deepCyclicCopyReplaceable<T>(
value: T, value: T,
cycles: WeakMap<any, any> = new WeakMap(), cycles = new WeakMap<any, any>(),
): T { ): T {
if (typeof value !== 'object' || value === null) { if (typeof value !== 'object' || value === null) {
return value; return value;

View File

@ -101,9 +101,7 @@ interface SomeFunctionObject {
one: { one: {
(oneA: number, oneB?: boolean): boolean; (oneA: number, oneB?: boolean): boolean;
more: { more: {
time: { time: (time: number) => void;
(time: number): void;
};
}; };
}; };
} }

View File

@ -30,7 +30,7 @@ export type MockMetadata<T, MetadataType = MockMetadataType> = {
length?: number; length?: number;
}; };
export type ClassLike = {new (...args: any): any}; export type ClassLike = new (...args: any) => any;
export type FunctionLike = (...args: any) => any; export type FunctionLike = (...args: any) => any;
export type ConstructorLikeKeys<T> = keyof { export type ConstructorLikeKeys<T> = keyof {
@ -91,7 +91,7 @@ export type MockedShallow<T> = T extends ClassLike
: T; : T;
export type UnknownFunction = (...args: Array<unknown>) => unknown; export type UnknownFunction = (...args: Array<unknown>) => unknown;
export type UnknownClass = {new (...args: Array<unknown>): unknown}; export type UnknownClass = new (...args: Array<unknown>) => unknown;
export type SpiedClass<T extends ClassLike = UnknownClass> = MockInstance< export type SpiedClass<T extends ClassLike = UnknownClass> = MockInstance<
(...args: ConstructorParameters<T>) => InstanceType<T> (...args: ConstructorParameters<T>) => InstanceType<T>
@ -533,9 +533,7 @@ export class ModuleMocker {
) { ) {
const ownNames = Object.getOwnPropertyNames(object); const ownNames = Object.getOwnPropertyNames(object);
for (let i = 0; i < ownNames.length; i++) { for (const prop of ownNames) {
const prop = ownNames[i];
if (!isReadonlyProp(object, prop)) { if (!isReadonlyProp(object, prop)) {
const propDesc = Object.getOwnPropertyDescriptor(object, prop); const propDesc = Object.getOwnPropertyDescriptor(object, prop);
if ((propDesc !== undefined && !propDesc.get) || object.__esModule) { if ((propDesc !== undefined && !propDesc.get) || object.__esModule) {

View File

@ -75,10 +75,10 @@ const isRecoverableError = (error: unknown) => {
if (jestProjectConfig.transform) { if (jestProjectConfig.transform) {
let transformerPath = null; let transformerPath = null;
for (let i = 0; i < jestProjectConfig.transform.length; i++) { for (const transform of jestProjectConfig.transform) {
if (new RegExp(jestProjectConfig.transform[i][0]).test('foobar.js')) { if (new RegExp(transform[0]).test('foobar.js')) {
transformerPath = jestProjectConfig.transform[i][1]; transformerPath = transform[1];
transformerConfig = jestProjectConfig.transform[i][2]; transformerConfig = transform[2];
break; break;
} }
} }

View File

@ -33,10 +33,11 @@ export async function run(
if (cliArgv) { if (cliArgv) {
argv = cliArgv; argv = cliArgv;
} else { } else {
argv = <Config.Argv>( argv = yargs
yargs.usage(args.usage).help(false).version(false).options(args.options) .usage(args.usage)
.argv .help(false)
); .version(false)
.options(args.options).argv as Config.Argv;
validateCLIOptions(argv, {...args.options, deprecationEntries}); validateCLIOptions(argv, {...args.options, deprecationEntries});
} }

View File

@ -231,10 +231,8 @@ export default class GitHubActionsReporter extends BaseReporter {
}); });
} else { } else {
let alreadyInserted = false; let alreadyInserted = false;
for (let index = 0; index < branches.length; index++) { for (const branch of branches) {
if ( if (this.arrayEqual(branch, element.ancestorTitles.slice(0, 1))) {
this.arrayEqual(branches[index], element.ancestorTitles.slice(0, 1))
) {
alreadyInserted = true; alreadyInserted = true;
break; break;
} }
@ -286,10 +284,10 @@ export default class GitHubActionsReporter extends BaseReporter {
) )
) { ) {
let alreadyInserted = false; let alreadyInserted = false;
for (let index = 0; index < branches.length; index++) { for (const branch of branches) {
if ( if (
this.arrayEqual( this.arrayEqual(
branches[index], branch,
element.ancestorTitles.slice(0, ancestors.length + 1), element.ancestorTitles.slice(0, ancestors.length + 1),
) )
) { ) {

View File

@ -192,8 +192,8 @@ export default class Status {
let height = 0; let height = 0;
for (let i = 0; i < content.length; i++) { for (const char of content) {
if (content[i] === '\n') { if (char === '\n') {
height++; height++;
} }
} }

View File

@ -139,7 +139,7 @@ export class DependencyResolver {
}; };
const relatedPaths = new Set<string>(); const relatedPaths = new Set<string>();
const changed: Set<string> = new Set(); const changed = new Set<string>();
for (const path of paths) { for (const path of paths) {
if (this._hasteFS.exists(path)) { if (this._hasteFS.exists(path)) {
const modulePath = isSnapshotPath(path) const modulePath = isSnapshotPath(path)

View File

@ -102,7 +102,7 @@ export default class TestRunner extends EmittingTestRunner {
} }
async #createParallelTestRun(tests: Array<Test>, watcher: TestWatcher) { async #createParallelTestRun(tests: Array<Test>, watcher: TestWatcher) {
const resolvers: Map<string, SerializableResolver> = new Map(); const resolvers = new Map<string, SerializableResolver>();
for (const test of tests) { for (const test of tests) {
if (!resolvers.has(test.context.config.id)) { if (!resolvers.has(test.context.config.id)) {
resolvers.set(test.context.config.id, { resolvers.set(test.context.config.id, {
@ -167,7 +167,7 @@ export default class TestRunner extends EmittingTestRunner {
return promise; return promise;
}); });
const onInterrupt = new Promise((_, reject) => { const onInterrupt = new Promise((_resolve, reject) => {
watcher.on('change', state => { watcher.on('change', state => {
if (state.interrupted) { if (state.interrupted) {
reject(new CancelRun()); reject(new CancelRun());

View File

@ -254,8 +254,8 @@ class ScriptTransformer {
return undefined; return undefined;
} }
for (let i = 0; i < transformEntry.length; i++) { for (const item of transformEntry) {
const [transformRegExp, transformPath] = transformEntry[i]; const [transformRegExp, transformPath] = item;
if (transformRegExp.test(filename)) { if (transformRegExp.test(filename)) {
return [transformRegExp.source, transformPath]; return [transformRegExp.source, transformPath];
} }
@ -1017,12 +1017,8 @@ const calcTransformRegExp = (config: Config.ProjectConfig) => {
} }
const transformRegexp: Array<[RegExp, string, Record<string, unknown>]> = []; const transformRegexp: Array<[RegExp, string, Record<string, unknown>]> = [];
for (let i = 0; i < config.transform.length; i++) { for (const item of config.transform) {
transformRegexp.push([ transformRegexp.push([new RegExp(item[0]), item[1], item[2]]);
new RegExp(config.transform[i][0]),
config.transform[i][1],
config.transform[i][2],
]);
} }
return transformRegexp; return transformRegexp;

View File

@ -113,9 +113,7 @@ interface Each<EachFn extends TestFn | BlockFn> {
) => void; ) => void;
} }
export interface HookBase { export type HookBase = (fn: HookFn, timeout?: number) => void;
(fn: HookFn, timeout?: number): void;
}
export interface Failing<T extends TestFn> { export interface Failing<T extends TestFn> {
(testName: TestNameLike, fn: T, timeout?: number): void; (testName: TestNameLike, fn: T, timeout?: number): void;

View File

@ -15,7 +15,7 @@ export type DeepCyclicCopyOptions = {
export default function deepCyclicCopy<T>( export default function deepCyclicCopy<T>(
value: T, value: T,
options: DeepCyclicCopyOptions = {blacklist: EMPTY, keepPrototype: false}, options: DeepCyclicCopyOptions = {blacklist: EMPTY, keepPrototype: false},
cycles: WeakMap<any, any> = new WeakMap(), cycles = new WeakMap<any, any>(),
): T { ): T {
if (typeof value !== 'object' || value === null || Buffer.isBuffer(value)) { if (typeof value !== 'object' || value === null || Buffer.isBuffer(value)) {
return value; return value;

View File

@ -63,8 +63,8 @@ export default function globsToMatcher(globs: Array<string>): Matcher {
let kept = undefined; let kept = undefined;
let negatives = 0; let negatives = 0;
for (let i = 0; i < matchers.length; i++) { for (const matcher of matchers) {
const {isMatch, negated} = matchers[i]; const {isMatch, negated} = matcher;
if (negated) { if (negated) {
negatives++; negatives++;

View File

@ -42,7 +42,7 @@ export function validationCondition(
export function multipleValidOptions<T extends Array<unknown>>( export function multipleValidOptions<T extends Array<unknown>>(
...args: T ...args: T
): T[number] { ): T[number] {
const options = <T>[...args]; const options = [...args] as T;
// @ts-expect-error: no index signature // @ts-expect-error: no index signature
options[MULTIPLE_VALID_OPTIONS_SYMBOL] = true; options[MULTIPLE_VALID_OPTIONS_SYMBOL] = true;

View File

@ -41,7 +41,7 @@ export default abstract class PatternPrompt {
this._pipe.write(ansiEscapes.cursorHide); this._pipe.write(ansiEscapes.cursorHide);
this._pipe.write(CLEAR); this._pipe.write(CLEAR);
if (options && options.header) { if (typeof options?.header === 'string' && options.header) {
this._pipe.write(`${options.header}\n`); this._pipe.write(`${options.header}\n`);
this._currentUsageRows = usageRows + options.header.split('\n').length; this._currentUsageRows = usageRows + options.header.split('\n').length;
} else { } else {

View File

@ -81,13 +81,11 @@ export interface WatchPlugin {
updateConfigAndRun: UpdateConfigCallback, updateConfigAndRun: UpdateConfigCallback,
) => Promise<void | boolean>; ) => Promise<void | boolean>;
} }
export interface WatchPluginClass { export type WatchPluginClass = new (options: {
new (options: { config: Record<string, unknown>;
config: Record<string, unknown>; stdin: ReadStream;
stdin: ReadStream; stdout: WriteStream;
stdout: WriteStream; }) => WatchPlugin;
}): WatchPlugin;
}
export type ScrollOptions = { export type ScrollOptions = {
offset: number; offset: number;

View File

@ -342,10 +342,10 @@ function printPlugin(
} }
function findPlugin(plugins: Plugins, val: unknown) { function findPlugin(plugins: Plugins, val: unknown) {
for (let p = 0; p < plugins.length; p++) { for (const plugin of plugins) {
try { try {
if (plugins[p].test(val)) { if (plugin.test(val)) {
return plugins[p]; return plugin;
} }
} catch (error: any) { } catch (error: any) {
throw new PrettyFormatPluginError(error.message, error.stack); throw new PrettyFormatPluginError(error.message, error.stack);

View File

@ -93,7 +93,10 @@ async function buildNodePackages() {
process.stdout.write(`${OK}\n`); process.stdout.write(`${OK}\n`);
} }
buildNodePackages().catch(error => { try {
await buildNodePackages();
} catch (error) {
process.stderr.write(`${ERROR}\n`);
console.error(error); console.error(error);
process.exitCode = 1; process.exitCode = 1;
}); }

View File

@ -85,7 +85,10 @@ try {
fix, fix,
fixTypes: ['problem', 'suggestion', 'layout'], fixTypes: ['problem', 'suggestion', 'layout'],
overrideConfig: { overrideConfig: {
extends: ['plugin:@typescript-eslint/recommended-type-checked'], extends: [
'plugin:@typescript-eslint/recommended-type-checked',
'plugin:@typescript-eslint/stylistic-type-checked',
],
overrides: [ overrides: [
{ {
files: ['**/__tests__/**'], files: ['**/__tests__/**'],
@ -97,6 +100,15 @@ try {
'jest/unbound-method': 'error', 'jest/unbound-method': 'error',
}, },
}, },
{
files: 'packages/jest-types/src/Circus.ts',
rules: {
// We're faking nominal types
'@typescript-eslint/no-duplicate-type-constituents': 'off',
// this file has `Exception`, which is `unknown`
'@typescript-eslint/no-redundant-type-constituents': 'off',
},
},
], ],
parser: '@typescript-eslint/parser', parser: '@typescript-eslint/parser',
parserOptions: { parserOptions: {
@ -109,6 +121,14 @@ try {
rules: { rules: {
'@typescript-eslint/consistent-type-exports': 'error', '@typescript-eslint/consistent-type-exports': 'error',
'@typescript-eslint/dot-notation': 'error', '@typescript-eslint/dot-notation': 'error',
'@typescript-eslint/no-base-to-string': [
'error',
// https://github.com/typescript-eslint/typescript-eslint/issues/1655#issuecomment-593639305
{ignoredTypeNames: ['AssertionError', 'Error']},
],
'@typescript-eslint/no-duplicate-type-constituents': 'error',
'@typescript-eslint/no-redundant-type-constituents': 'error',
'@typescript-eslint/no-useless-template-literals': 'error',
'@typescript-eslint/non-nullable-type-assertion-style': 'error', '@typescript-eslint/non-nullable-type-assertion-style': 'error',
'@typescript-eslint/prefer-nullish-coalescing': 'error', '@typescript-eslint/prefer-nullish-coalescing': 'error',
'@typescript-eslint/prefer-readonly': 'error', '@typescript-eslint/prefer-readonly': 'error',
@ -119,18 +139,17 @@ try {
'@typescript-eslint/strict-boolean-expressions': 'error', '@typescript-eslint/strict-boolean-expressions': 'error',
'@typescript-eslint/switch-exhaustiveness-check': 'error', '@typescript-eslint/switch-exhaustiveness-check': 'error',
// TODO: enable these // TODO: enable this
'@typescript-eslint/no-explicit-any': 'off', '@typescript-eslint/no-explicit-any': 'off',
'@typescript-eslint/no-redundant-type-constituents': 'off',
'@typescript-eslint/no-duplicate-type-constituents': 'off',
'@typescript-eslint/no-base-to-string': 'off',
// disable the ones we disable in main config // disable the ones we disable in main config
'@typescript-eslint/no-invalid-void-type': 'off', '@typescript-eslint/no-invalid-void-type': 'off',
'@typescript-eslint/no-dynamic-delete': 'off', '@typescript-eslint/no-dynamic-delete': 'off',
'@typescript-eslint/no-var-requires': 'off', '@typescript-eslint/no-var-requires': 'off',
'@typescript-eslint/consistent-type-definitions': 'off',
// nah // nah
'@typescript-eslint/consistent-indexed-object-style': 'off',
'@typescript-eslint/require-await': 'off', '@typescript-eslint/require-await': 'off',
}, },
}, },

View File

@ -3040,6 +3040,7 @@ __metadata:
eslint-plugin-local: "link:./.eslintplugin" eslint-plugin-local: "link:./.eslintplugin"
eslint-plugin-markdown: ^3.0.0 eslint-plugin-markdown: ^3.0.0
eslint-plugin-prettier: ^5.0.0 eslint-plugin-prettier: ^5.0.0
eslint-plugin-promise: ^6.1.1
eslint-plugin-unicorn: ^50.0.0 eslint-plugin-unicorn: ^50.0.0
execa: ^5.0.0 execa: ^5.0.0
find-process: ^1.4.1 find-process: ^1.4.1
@ -9647,6 +9648,15 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"eslint-plugin-promise@npm:^6.1.1":
version: 6.1.1
resolution: "eslint-plugin-promise@npm:6.1.1"
peerDependencies:
eslint: ^7.0.0 || ^8.0.0
checksum: 46b9a4f79dae5539987922afc27cc17cbccdecf4f0ba19c0ccbf911b0e31853e9f39d9959eefb9637461b52772afa1a482f1f87ff16c1ba38bdb6fcf21897e9a
languageName: node
linkType: hard
"eslint-plugin-unicorn@npm:^50.0.0": "eslint-plugin-unicorn@npm:^50.0.0":
version: 50.0.1 version: 50.0.1
resolution: "eslint-plugin-unicorn@npm:50.0.1" resolution: "eslint-plugin-unicorn@npm:50.0.1"