diff --git a/lib/engine/worker-task.ts b/lib/engine/worker-task.ts index 1ce722fc..61f11455 100644 --- a/lib/engine/worker-task.ts +++ b/lib/engine/worker-task.ts @@ -39,7 +39,6 @@ const UNKNOWN_RULE_ID = 'unable-to-parse-rule-id'; // https://github.com/eslint/eslint/blob/ed1da5d96af2587b7211854e45cf8657ef808710/lib/linter/linter.js#L1194 const LINE_REGEX = /Occurred while linting \S*:([0-9]+)?/; -const MAX_LINT_TIME_SECONDS = 5; const MAX_ROW_LENGTH = 1000; /** @@ -238,18 +237,21 @@ export default async function workerTask(): Promise { let result: ESLint.LintResult[]; try { - result = await executionTimeWarningWrapper( - () => linter.lintFiles(path), - - // Warn about files taking more than 5s to lint - // Useful to identify minified files committed to remote - lintTime => - postMessage({ - type: 'FILE_LINT_SLOW', - payload: { path, lintTime }, - }), - MAX_LINT_TIME_SECONDS - ); + const lintFile = () => linter.lintFiles(path); + + if (config.slowLintTimeLimit) { + result = await executionTimeWarningWrapper( + lintFile, + lintTime => + postMessage({ + type: 'FILE_LINT_SLOW', + payload: { path, lintTime }, + }), + config.slowLintTimeLimit + ); + } else { + result = await lintFile(); + } } catch (error) { // Catch crashing linter const crashMessage = parseErrorStack(error, file); diff --git a/test/unit/__mocks__/eslint.ts b/test/unit/__mocks__/eslint.ts index 0e1dc1ad..bc2d98cd 100644 --- a/test/unit/__mocks__/eslint.ts +++ b/test/unit/__mocks__/eslint.ts @@ -4,12 +4,19 @@ type LintResult = actual.ESLint.LintResult; export class ESLint { static mockConstructor = jest.fn(); + static delay: number | null = null; constructor(config: unknown) { ESLint.mockConstructor(config); } async lintFiles(filePath: string): Promise { + if (ESLint.delay) { + const delay = ESLint.delay * 1000; + + await new Promise(resolve => setTimeout(resolve, delay)); + } + return [ { filePath, diff --git a/test/unit/worker-task.test.ts b/test/unit/worker-task.test.ts index 05502cae..b6a5005e 100644 --- a/test/unit/worker-task.test.ts +++ b/test/unit/worker-task.test.ts @@ -2,6 +2,7 @@ import { ESLint } from 'eslint'; import workerTask, { WorkerMessage } from '@engine/worker-task'; import { parentPort } from '__mocks__/worker_threads'; +import { mockConfigValue } from '__mocks__/@config'; jest.mock('worker_threads', () => require('./__mocks__/worker_threads')); @@ -23,6 +24,11 @@ beforeEach(() => { parentPort.postMessage.mockClear(); }); +afterEach(() => { + // @ts-expect-error -- Mock's API + ESLint.delay = null; +}); + test('should limit length of results to 1000 characters', async () => { await workerTask(); @@ -45,3 +51,38 @@ test('should limit length of results to 1000 characters', async () => { // Last three characters should be '...' expect(source!.slice(-3)).toBe('...'); }); + +test('should warn if lint takes longer than config.slowLintTime', async () => { + // @ts-expect-error -- Mock's API + ESLint.delay = 3; + mockConfigValue({ slowLintTimeLimit: 1 }); + + await workerTask(); + + const resultMessages = getPostMessageCalls('FILE_LINT_SLOW'); + + expect(resultMessages).toHaveLength(1); + expect(resultMessages[0].payload.path).toBe('./mock/path/file.ts'); +}); + +test('should not warn if lint takes less than config.slowLintTime', async () => { + // @ts-expect-error -- Mock's API + ESLint.delay = 1; + mockConfigValue({ slowLintTimeLimit: 3 }); + + await workerTask(); + + const resultMessages = getPostMessageCalls('FILE_LINT_SLOW'); + expect(resultMessages).toHaveLength(0); +}); + +test('should not warn if config.slowLintTime is not set', async () => { + // @ts-expect-error -- Mock's API + ESLint.delay = 3; + mockConfigValue({ slowLintTimeLimit: undefined }); + + await workerTask(); + + const resultMessages = getPostMessageCalls('FILE_LINT_SLOW'); + expect(resultMessages).toHaveLength(0); +});