Skip to content

Commit 21e7c91

Browse files
Merge remote-tracking branch 'origin/master' into fix-ts
2 parents 42ba913 + cef4f74 commit 21e7c91

17 files changed

+272
-72
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,7 @@ Accepts a function that will have one argument: an array of eslint messages (obj
159159

160160
Lint only changed files, skip lint on start.
161161

162-
#### `threads`
162+
### `threads`
163163

164164
- Type: `Boolean | Number`
165165
- Default: `false`

declarations/getESLint.d.ts

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,16 +11,25 @@
1111
*/
1212
export function loadESLint(options: Options): Linter;
1313
/**
14+
* @param {string|undefined} key
1415
* @param {number} poolSize
1516
* @param {Options} options
1617
* @returns {Linter}
1718
*/
18-
export function loadESLintThreaded(poolSize: number, options: Options): Linter;
19+
export function loadESLintThreaded(
20+
key: string | undefined,
21+
poolSize: number,
22+
options: Options
23+
): Linter;
1924
/**
25+
* @param {string|undefined} key
2026
* @param {Options} options
2127
* @returns {Linter}
2228
*/
23-
export default function getESLint({ threads, ...options }: Options): Linter;
29+
export default function getESLint(
30+
key: string | undefined,
31+
{ threads, ...options }: Options
32+
): Linter;
2433
export type ESLint = import('eslint').ESLint;
2534
export type LintResult = import('eslint').ESLint.LintResult;
2635
export type Options = import('./options').PluginOptions &

declarations/index.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ declare class ESLintWebpackPlugin {
1717
* @returns {void}
1818
*/
1919
apply(compiler: Compiler): void;
20+
key: string | undefined;
2021
/**
2122
*
2223
* @param {Compiler} compiler

declarations/linter.d.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
/**
2+
* @param {string|undefined} key
23
* @param {Options} options
34
* @param {Compilation} compilation
45
* @returns {{lint: Linter, report: Reporter}}
56
*/
67
export default function linter(
8+
key: string | undefined,
79
options: Options,
810
compilation: Compilation
911
): {

src/getESLint.js

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -47,12 +47,13 @@ export function loadESLint(options) {
4747
}
4848

4949
/**
50+
* @param {string|undefined} key
5051
* @param {number} poolSize
5152
* @param {Options} options
5253
* @returns {Linter}
5354
*/
54-
export function loadESLintThreaded(poolSize, options) {
55-
const key = getCacheKey(options);
55+
export function loadESLintThreaded(key, poolSize, options) {
56+
const cacheKey = getCacheKey(key, options);
5657
const { eslintPath = 'eslint' } = options;
5758
const source = require.resolve('./worker');
5859
const workerOptions = {
@@ -75,7 +76,7 @@ export function loadESLintThreaded(poolSize, options) {
7576
(worker && (await worker.lintFiles(files))) ||
7677
/* istanbul ignore next */ [],
7778
cleanup: async () => {
78-
cache[key] = local;
79+
cache[cacheKey] = local;
7980
context.lintFiles = (files) => local.lintFiles(files);
8081
if (worker) {
8182
worker.end();
@@ -88,10 +89,11 @@ export function loadESLintThreaded(poolSize, options) {
8889
}
8990

9091
/**
92+
* @param {string|undefined} key
9193
* @param {Options} options
9294
* @returns {Linter}
9395
*/
94-
export default function getESLint({ threads, ...options }) {
96+
export default function getESLint(key, { threads, ...options }) {
9597
const max =
9698
typeof threads !== 'number'
9799
? threads
@@ -100,18 +102,19 @@ export default function getESLint({ threads, ...options }) {
100102
: /* istanbul ignore next */
101103
threads;
102104

103-
const key = getCacheKey({ threads, ...options });
104-
if (!cache[key]) {
105-
cache[key] =
106-
max > 1 ? loadESLintThreaded(max, options) : loadESLint(options);
105+
const cacheKey = getCacheKey(key, { threads, ...options });
106+
if (!cache[cacheKey]) {
107+
cache[cacheKey] =
108+
max > 1 ? loadESLintThreaded(key, max, options) : loadESLint(options);
107109
}
108-
return cache[key];
110+
return cache[cacheKey];
109111
}
110112

111113
/**
114+
* @param {string|undefined} key
112115
* @param {Options} options
113116
* @returns {string}
114117
*/
115-
function getCacheKey(options) {
116-
return JSON.stringify(options, jsonStringifyReplacerSortKeys);
118+
function getCacheKey(key, options) {
119+
return JSON.stringify({ key, options }, jsonStringifyReplacerSortKeys);
117120
}

src/index.js

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import { parseFiles, parseFoldersToGlobs } from './utils';
1313
/** @typedef {import('./options').Options} Options */
1414

1515
const ESLINT_PLUGIN = 'ESLintWebpackPlugin';
16+
let counter = 0;
1617

1718
class ESLintWebpackPlugin {
1819
/**
@@ -28,6 +29,12 @@ class ESLintWebpackPlugin {
2829
* @returns {void}
2930
*/
3031
apply(compiler) {
32+
// Generate key for each compilation,
33+
// this differentiates one from the other when being cached.
34+
this.key = compiler.name || `${ESLINT_PLUGIN}_${(counter += 1)}`;
35+
36+
// If `lintDirtyModulesOnly` is disabled,
37+
// execute the linter on the build
3138
if (!this.options.lintDirtyModulesOnly) {
3239
compiler.hooks.run.tapPromise(ESLINT_PLUGIN, this.run);
3340
}
@@ -36,7 +43,16 @@ class ESLintWebpackPlugin {
3643
// From my testing of compiler.watch() ... compiler.watching is always
3744
// undefined (webpack 4 doesn't define it either) I'm leaving it out
3845
// for now.
39-
compiler.hooks.watchRun.tapPromise(ESLINT_PLUGIN, this.run);
46+
let isFirstRun = this.options.lintDirtyModulesOnly;
47+
compiler.hooks.watchRun.tapPromise(ESLINT_PLUGIN, (c) => {
48+
if (isFirstRun) {
49+
isFirstRun = false;
50+
51+
return Promise.resolve();
52+
}
53+
54+
return this.run(c);
55+
});
4056
}
4157

4258
/**
@@ -74,7 +90,7 @@ class ESLintWebpackPlugin {
7490
let report;
7591

7692
try {
77-
({ lint, report } = linter(options, compilation));
93+
({ lint, report } = linter(this.key, options, compilation));
7894
} catch (e) {
7995
compilation.errors.push(e);
8096
return;
@@ -83,7 +99,7 @@ class ESLintWebpackPlugin {
8399
// @ts-ignore
84100
const processModule = (module) => {
85101
if (module.resource) {
86-
const file = module.resource.split('?')[0];
102+
const [file] = module.resource.split('?');
87103

88104
if (
89105
file &&

src/linter.js

Lines changed: 42 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,12 @@ import getESLint from './getESLint';
2121
const resultStorage = new WeakMap();
2222

2323
/**
24+
* @param {string|undefined} key
2425
* @param {Options} options
2526
* @param {Compilation} compilation
2627
* @returns {{lint: Linter, report: Reporter}}
2728
*/
28-
export default function linter(options, compilation) {
29+
export default function linter(key, options, compilation) {
2930
/** @type {ESLint} */
3031
let eslint;
3132

@@ -41,7 +42,7 @@ export default function linter(options, compilation) {
4142
const crossRunResultStorage = getResultStorage(compilation);
4243

4344
try {
44-
({ eslint, lintFiles, cleanup } = getESLint(options));
45+
({ eslint, lintFiles, cleanup } = getESLint(key, options));
4546
} catch (e) {
4647
throw new ESLintError(e.message);
4748
}
@@ -177,29 +178,48 @@ function formatResults(formatter, results) {
177178
*/
178179
function parseResults(options, results) {
179180
/** @type {LintResult[]} */
180-
let errors = [];
181+
const errors = [];
181182

182183
/** @type {LintResult[]} */
183-
let warnings = [];
184-
185-
if (options.emitError) {
186-
errors = results.filter(
187-
(file) => fileHasErrors(file) || fileHasWarnings(file)
188-
);
189-
} else if (options.emitWarning) {
190-
warnings = results.filter(
191-
(file) => fileHasErrors(file) || fileHasWarnings(file)
192-
);
193-
} else {
194-
warnings = results.filter(
195-
(file) => !fileHasErrors(file) && fileHasWarnings(file)
196-
);
197-
errors = results.filter(fileHasErrors);
198-
}
184+
const warnings = [];
185+
186+
results.forEach((file) => {
187+
if (fileHasErrors(file)) {
188+
const messages = file.messages.filter((message) => {
189+
if (options.emitError === undefined) {
190+
return true;
191+
} else if (options.emitError) {
192+
return message.severity === 2;
193+
}
194+
return false;
195+
});
196+
197+
if (messages.length > 0) {
198+
errors.push({
199+
...file,
200+
messages,
201+
});
202+
}
203+
}
199204

200-
if (options.quiet && warnings.length > 0) {
201-
warnings = [];
202-
}
205+
if (fileHasWarnings(file)) {
206+
const messages = file.messages.filter((message) => {
207+
if (options.emitWarning === undefined) {
208+
return true;
209+
} else if (options.emitWarning) {
210+
return message.severity === 1;
211+
}
212+
return false;
213+
});
214+
215+
if (messages.length > 0) {
216+
warnings.push({
217+
...file,
218+
messages,
219+
});
220+
}
221+
}
222+
});
203223

204224
return {
205225
errors,

src/options.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ export function getOptions(pluginOptions) {
4949
const options = {
5050
extensions: 'js',
5151
...pluginOptions,
52+
...(pluginOptions.quiet ? { emitError: true, emitWarning: false } : {}),
5253
};
5354

5455
// @ts-ignore

test/emit-error.test.js

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
import pack from './utils/pack';
2+
3+
describe('emit error', () => {
4+
it('should not emit errors if emitError is false', (done) => {
5+
const compiler = pack('error', { emitError: false });
6+
7+
compiler.run((err, stats) => {
8+
expect(err).toBeNull();
9+
expect(stats.hasErrors()).toBe(false);
10+
done();
11+
});
12+
});
13+
14+
it('should emit errors if emitError is undefined', (done) => {
15+
const compiler = pack('error', {});
16+
17+
compiler.run((err, stats) => {
18+
expect(err).toBeNull();
19+
expect(stats.hasErrors()).toBe(true);
20+
done();
21+
});
22+
});
23+
24+
it('should emit errors if emitError is true', (done) => {
25+
const compiler = pack('error', { emitError: true });
26+
27+
compiler.run((err, stats) => {
28+
expect(err).toBeNull();
29+
expect(stats.hasErrors()).toBe(true);
30+
done();
31+
});
32+
});
33+
34+
it('should emit errors, but not warnings if emitError is true and emitWarning is false', (done) => {
35+
const compiler = pack('full-of-problems', {
36+
emitError: true,
37+
emitWarning: false,
38+
});
39+
40+
compiler.run((err, stats) => {
41+
expect(err).toBeNull();
42+
expect(stats.hasWarnings()).toBe(false);
43+
expect(stats.hasErrors()).toBe(true);
44+
done();
45+
});
46+
});
47+
48+
it('should emit errors and warnings if emitError is true and emitWarning is undefined', (done) => {
49+
const compiler = pack('full-of-problems', { emitError: true });
50+
51+
compiler.run((err, stats) => {
52+
expect(err).toBeNull();
53+
expect(stats.hasWarnings()).toBe(true);
54+
expect(stats.hasErrors()).toBe(true);
55+
done();
56+
});
57+
});
58+
});

test/emit-warning.test.js

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
import pack from './utils/pack';
2+
3+
describe('emit warning', () => {
4+
it('should not emit warnings if emitWarning is false', (done) => {
5+
const compiler = pack('warn', { emitWarning: false });
6+
7+
compiler.run((err, stats) => {
8+
expect(err).toBeNull();
9+
expect(stats.hasWarnings()).toBe(false);
10+
done();
11+
});
12+
});
13+
14+
it('should emit warnings if emitWarning is undefined', (done) => {
15+
const compiler = pack('warn', {});
16+
17+
compiler.run((err, stats) => {
18+
expect(err).toBeNull();
19+
expect(stats.hasWarnings()).toBe(true);
20+
done();
21+
});
22+
});
23+
24+
it('should emit warnings if emitWarning is true', (done) => {
25+
const compiler = pack('warn', { emitWarning: true });
26+
27+
compiler.run((err, stats) => {
28+
expect(err).toBeNull();
29+
expect(stats.hasWarnings()).toBe(true);
30+
done();
31+
});
32+
});
33+
34+
it('should emit warnings, but not warnings if emitWarning is true and emitError is false', (done) => {
35+
const compiler = pack('full-of-problems', {
36+
emitWarning: true,
37+
emitError: false,
38+
});
39+
40+
compiler.run((err, stats) => {
41+
expect(err).toBeNull();
42+
expect(stats.hasWarnings()).toBe(true);
43+
expect(stats.hasErrors()).toBe(false);
44+
done();
45+
});
46+
});
47+
48+
it('should emit warnings and errors if emitWarning is true and emitError is undefined', (done) => {
49+
const compiler = pack('full-of-problems', { emitWarning: true });
50+
51+
compiler.run((err, stats) => {
52+
expect(err).toBeNull();
53+
expect(stats.hasWarnings()).toBe(true);
54+
expect(stats.hasErrors()).toBe(true);
55+
done();
56+
});
57+
});
58+
});

0 commit comments

Comments
 (0)