Skip to content

Commit 188d44d

Browse files
authored
feat: add issue.scope option (#442)
The plugin uses TypeScript settings regarding files that are included in the compilation. It can be a different set of files comparing to the webpack compilation. To not display issues that are related to files outside webpack compilation, an `issue.scope` option has been added. BREAKING CHANGE: 🧨 Issues outside webpack compilation will not be reported by default. See `issue.scope` option.
1 parent b865f1d commit 188d44d

File tree

9 files changed

+136
-3
lines changed

9 files changed

+136
-3
lines changed

.github/workflows/main.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
name: CI/CD
2-
on: [push]
2+
on: [push, pull_request]
33
jobs:
44
build:
55
runs-on: ubuntu-latest

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,7 @@ Options for the issues filtering (`issues` option object).
195195
| --------- | --------------------------------- | ------------- | ----------- |
196196
| `include` | `object` or `function` or `array` | `undefined` | If `object`, defines issue properties that should be [matched](./src/issue/IssueMatch.ts). If `function`, acts as a predicate where `issue` is an argument. |
197197
| `exclude` | `object` or `function` or `array` | `undefined` | Same as `include` but issues that match this predicate will be excluded. |
198+
| `scope` | `'all'` or `'webpack'` | `'webpack'` | Defines issues scope to be reported. If `'webpack'`, reports errors only related to the webpack compilation. Reports all errors otherwise (like `tsc` and `eslint` command). |
198199

199200
## Vue.js
200201

src/ForkTsCheckerWebpackPluginOptions.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,11 @@
246246
},
247247
"exclude": {
248248
"$ref": "#/definitions/IssuePredicateOption"
249+
},
250+
"scope": {
251+
"type": "string",
252+
"enum": ["all", "webpack"],
253+
"description": "Defines issues scope to be reported. If 'webpack', reports errors only related to a given webpack compilation. Reports all errors otherwise."
249254
}
250255
}
251256
},

src/hooks/tapAfterCompileToGetIssues.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import webpack from 'webpack';
2+
import path from 'path';
23
import { ForkTsCheckerWebpackPluginConfiguration } from '../ForkTsCheckerWebpackPluginConfiguration';
34
import { ForkTsCheckerWebpackPluginState } from '../ForkTsCheckerWebpackPluginState';
45
import { getForkTsCheckerWebpackPluginHooks } from './pluginHooks';
@@ -32,6 +33,13 @@ function tapAfterCompileToGetIssues(
3233
return;
3334
}
3435

36+
if (configuration.issue.scope === 'webpack') {
37+
// exclude issues that are related to files outside webpack compilation
38+
issues = issues.filter(
39+
(issue) => !issue.file || compilation.fileDependencies.has(path.normalize(issue.file))
40+
);
41+
}
42+
3543
// filter list of issues by provided issue predicate
3644
issues = issues.filter(configuration.issue.predicate);
3745

src/hooks/tapDoneToAsyncGetIssues.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
import webpack from 'webpack';
2+
import chalk from 'chalk';
3+
import path from 'path';
24
import { ForkTsCheckerWebpackPluginConfiguration } from '../ForkTsCheckerWebpackPluginConfiguration';
35
import { ForkTsCheckerWebpackPluginState } from '../ForkTsCheckerWebpackPluginState';
46
import { getForkTsCheckerWebpackPluginHooks } from './pluginHooks';
@@ -7,7 +9,6 @@ import { Issue } from '../issue';
79
import { IssueWebpackError } from '../issue/IssueWebpackError';
810
import isPending from '../utils/async/isPending';
911
import wait from '../utils/async/wait';
10-
import chalk from 'chalk';
1112

1213
function tapDoneToAsyncGetIssues(
1314
compiler: webpack.Compiler,
@@ -50,6 +51,13 @@ function tapDoneToAsyncGetIssues(
5051
return;
5152
}
5253

54+
if (configuration.issue.scope === 'webpack') {
55+
// exclude issues that are related to files outside webpack compilation
56+
issues = issues.filter(
57+
(issue) => !issue.file || stats.compilation.fileDependencies.has(path.normalize(issue.file))
58+
);
59+
}
60+
5361
// filter list of issues by provided issue predicate
5462
issues = issues.filter(configuration.issue.predicate);
5563

src/issue/IssueConfiguration.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import { IssuePredicateOption, IssueOptions } from './IssueOptions';
99

1010
interface IssueConfiguration {
1111
predicate: IssuePredicate;
12+
scope: 'all' | 'webpack';
1213
}
1314

1415
function createIssuePredicateFromOption(
@@ -47,6 +48,7 @@ function createIssueConfiguration(
4748

4849
return {
4950
predicate: (issue) => include(issue) && !exclude(issue),
51+
scope: options.scope || 'webpack',
5052
};
5153
}
5254

src/issue/IssueOptions.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ type IssuePredicateOption = IssuePredicate | IssueMatch | (IssuePredicate | Issu
66
interface IssueOptions {
77
include?: IssuePredicateOption;
88
exclude?: IssuePredicateOption;
9+
scope?: 'all' | 'webpack';
910
}
1011

1112
export { IssueOptions, IssuePredicateOption };

src/typescript-reporter/reporter/ControlledTypeScriptSystem.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -215,7 +215,7 @@ function createControlledTypeScriptSystem(
215215
invokeFileChanged(path: string) {
216216
const normalizedPath = realFileSystem.normalizePath(path);
217217

218-
if (deletedFiles.get(normalizedPath) || !fileWatchersMap.has(path)) {
218+
if (deletedFiles.get(normalizedPath) || !fileWatchersMap.has(normalizedPath)) {
219219
invokeFileWatchers(path, ts.FileWatcherEventKind.Created);
220220
invokeDirectoryWatchers(normalizedPath);
221221

test/e2e/WebpackIssueScope.spec.ts

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
import { readFixture } from './sandbox/Fixture';
2+
import { join } from 'path';
3+
import { createSandbox, FORK_TS_CHECKER_WEBPACK_PLUGIN_VERSION, Sandbox } from './sandbox/Sandbox';
4+
import {
5+
createWebpackDevServerDriver,
6+
WEBPACK_CLI_VERSION,
7+
WEBPACK_DEV_SERVER_VERSION,
8+
} from './sandbox/WebpackDevServerDriver';
9+
10+
describe('Webpack Issue Scope', () => {
11+
let sandbox: Sandbox;
12+
13+
beforeAll(async () => {
14+
sandbox = await createSandbox();
15+
});
16+
17+
beforeEach(async () => {
18+
await sandbox.reset();
19+
});
20+
21+
afterAll(async () => {
22+
await sandbox.cleanup();
23+
});
24+
25+
it.each([
26+
{ webpack: '4.0.0', async: true, scope: 'webpack' },
27+
{ webpack: '4.0.0', async: false, scope: 'all' },
28+
{ webpack: '^4.0.0', async: false, scope: 'webpack' },
29+
{ webpack: '^4.0.0', async: true, scope: 'all' },
30+
{ webpack: '^5.0.0-beta.16', async: true, scope: 'webpack' },
31+
{ webpack: '^5.0.0-beta.16', async: false, scope: 'all' },
32+
])(
33+
'reports errors only related to the given scope with %p',
34+
async ({ webpack, async, scope }) => {
35+
await sandbox.load([
36+
await readFixture(join(__dirname, 'fixtures/environment/typescript-basic.fixture'), {
37+
FORK_TS_CHECKER_WEBPACK_PLUGIN_VERSION: JSON.stringify(
38+
FORK_TS_CHECKER_WEBPACK_PLUGIN_VERSION
39+
),
40+
TS_LOADER_VERSION: JSON.stringify('^5.0.0'),
41+
TYPESCRIPT_VERSION: JSON.stringify('~3.8.0'),
42+
WEBPACK_VERSION: JSON.stringify(webpack),
43+
WEBPACK_CLI_VERSION: JSON.stringify(WEBPACK_CLI_VERSION),
44+
WEBPACK_DEV_SERVER_VERSION: JSON.stringify(WEBPACK_DEV_SERVER_VERSION),
45+
ASYNC: JSON.stringify(async),
46+
}),
47+
await readFixture(join(__dirname, 'fixtures/implementation/typescript-basic.fixture')),
48+
]);
49+
50+
// add importsNotUsedAsValues which is supported from TypeScript 3.8.0+
51+
// this option is required for proper watching of type-only files in the `transpileOnly: true` mode
52+
await sandbox.patch(
53+
'./tsconfig.json',
54+
' "outDir": "./dist"',
55+
[' "outDir": "./dist",', ' "importsNotUsedAsValues": "preserve"'].join('\n')
56+
);
57+
58+
// update configuration
59+
await sandbox.write(
60+
'fork-ts-checker.config.js',
61+
`module.exports = { issue: { scope: ${JSON.stringify(scope)} } };`
62+
);
63+
await sandbox.write('src/notUsedFile.ts', 'const x: number = "1";');
64+
65+
const driver = createWebpackDevServerDriver(
66+
sandbox.spawn('npm run webpack-dev-server'),
67+
async
68+
);
69+
70+
// first compilation should be successful only if we use "webpack" scope
71+
if (scope === 'webpack') {
72+
await driver.waitForNoErrors();
73+
74+
// add reference to the file to include it to the compilation
75+
await sandbox.patch(
76+
'src/model/User.ts',
77+
"import { Role } from './Role';",
78+
"import { Role } from './Role';\nimport '../notUsedFile';"
79+
);
80+
81+
const errors = await driver.waitForErrors();
82+
expect(errors).toEqual([
83+
[
84+
'ERROR in src/notUsedFile.ts 1:7-8',
85+
"TS2322: Type '\"1\"' is not assignable to type 'number'.",
86+
' > 1 | const x: number = "1";',
87+
' | ^',
88+
].join('\n'),
89+
]);
90+
91+
// remove reference to the file to exclude it from the compilation
92+
await sandbox.patch('src/model/User.ts', "import '../notUsedFile';", '');
93+
94+
await driver.waitForNoErrors();
95+
} else {
96+
const errors = await driver.waitForErrors();
97+
expect(errors).toEqual([
98+
[
99+
'ERROR in src/notUsedFile.ts 1:7-8',
100+
"TS2322: Type '\"1\"' is not assignable to type 'number'.",
101+
' > 1 | const x: number = "1";',
102+
' | ^',
103+
].join('\n'),
104+
]);
105+
}
106+
}
107+
);
108+
});

0 commit comments

Comments
 (0)