Skip to content

Commit f656ee3

Browse files
dflupusindresorhus
andauthoredMar 11, 2020
Add webpack option (#375)
Co-authored-by: Sindre Sorhus <sindresorhus@gmail.com>
1 parent 5a22b77 commit f656ee3

File tree

11 files changed

+158
-8
lines changed

11 files changed

+158
-8
lines changed
 

Diff for: ‎lib/options-manager.js

+41-4
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ const mergeWith = require('lodash/mergeWith');
88
const groupBy = require('lodash/groupBy');
99
const flow = require('lodash/flow');
1010
const pathExists = require('path-exists');
11+
const findUp = require('find-up');
1112
const findCacheDir = require('find-cache-dir');
1213
const resolveFrom = require('resolve-from');
1314
const prettier = require('prettier');
@@ -313,14 +314,13 @@ const buildXOConfig = options => config => {
313314
Object.assign(config.rules, options.rules);
314315
}
315316

316-
if (options.settings) {
317-
config.baseConfig.settings = options.settings;
318-
}
319-
320317
if (options.parser) {
321318
config.baseConfig.parser = options.parser;
322319
}
323320

321+
config.baseConfig.settings = options.settings || {};
322+
config.baseConfig.settings['import/resolver'] = gatherImportResolvers(options);
323+
324324
return config;
325325
};
326326

@@ -476,6 +476,43 @@ const findApplicableOverrides = (path, overrides) => {
476476

477477
const getIgnores = ({ignores}) => DEFAULT_IGNORES.concat(ignores || []);
478478

479+
const gatherImportResolvers = options => {
480+
let resolvers = {};
481+
482+
const resolverSettings = options.settings && options.settings['import/resolver'];
483+
if (resolverSettings) {
484+
if (typeof resolverSettings === 'string') {
485+
resolvers[resolverSettings] = {};
486+
} else {
487+
resolvers = {...resolverSettings};
488+
}
489+
}
490+
491+
let webpackResolverSettings;
492+
493+
if (options.webpack) {
494+
webpackResolverSettings = options.webpack === true ? {} : options.webpack;
495+
} else if (!(options.webpack === false || resolvers.webpack)) {
496+
// If a webpack config file exists, add the import resolver automatically
497+
const webpackConfigPath = findUp.sync('webpack.config.js', {cwd: options.cwd});
498+
if (webpackConfigPath) {
499+
webpackResolverSettings = {config: webpackConfigPath};
500+
}
501+
}
502+
503+
if (webpackResolverSettings) {
504+
resolvers = {
505+
...resolvers,
506+
webpack: {
507+
...resolvers.webpack,
508+
...webpackResolverSettings
509+
}
510+
};
511+
}
512+
513+
return resolvers;
514+
};
515+
479516
module.exports = {
480517
findApplicableOverrides,
481518
mergeWithPrettierConfig,

Diff for: ‎package.json

+4-1
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@
6161
"eslint-config-xo": "^0.29.0",
6262
"eslint-config-xo-typescript": "^0.26.0",
6363
"eslint-formatter-pretty": "^3.0.1",
64+
"eslint-import-resolver-webpack": "^0.12.1",
6465
"eslint-plugin-ava": "^10.0.1",
6566
"eslint-plugin-eslint-comments": "^3.1.2",
6667
"eslint-plugin-import": "^2.20.1",
@@ -70,6 +71,7 @@
7071
"eslint-plugin-promise": "^4.2.1",
7172
"eslint-plugin-unicorn": "^17.2.0",
7273
"find-cache-dir": "^3.0.0",
74+
"find-up": "^4.1.0",
7375
"fs-extra": "^8.1.0",
7476
"get-stdin": "^7.0.0",
7577
"globby": "^9.0.0",
@@ -103,7 +105,8 @@
103105
"nyc": "^15.0.0",
104106
"pify": "^4.0.0",
105107
"proxyquire": "^2.1.3",
106-
"temp-write": "^4.0.0"
108+
"temp-write": "^4.0.0",
109+
"webpack": "^4.42.0"
107110
},
108111
"eslintConfig": {
109112
"extends": "eslint-config-xo"

Diff for: ‎readme.md

+13-2
Original file line numberDiff line numberDiff line change
@@ -252,7 +252,7 @@ Allow more extensions to be linted besides `.js` and `.jsx`. Make sure they're s
252252

253253
Type: `object`
254254

255-
[Shared ESLint settings](https://eslint.org/docs/user-guide/configuring#adding-shared-settings) exposed to rules. For example, to configure the [`import`](https://github.com/benmosher/eslint-plugin-import#settings) plugin to use your webpack configuration for determining search paths, you can put `{"import/resolver": "webpack"}` here.
255+
[Shared ESLint settings](https://eslint.org/docs/user-guide/configuring#adding-shared-settings) exposed to rules.
256256

257257
### parser
258258

@@ -269,6 +269,17 @@ Enforce ES2015+ rules. Disabling this will make it not *enforce* ES2015+ syntax
269269

270270
*ES2015+ is parsed even without this option. You can already use ES2017 features like [`async`/`await`](https://github.com/lukehoban/ecmascript-asyncawait).
271271

272+
### webpack
273+
274+
Type: `boolean | object`
275+
Default: `false`
276+
277+
Use [eslint-import-resolver-webpack](https://github.com/benmosher/eslint-plugin-import/tree/master/resolvers/webpack) to resolve import search paths. This is enabled automatically if a `webpack.config.js` file is found.
278+
279+
Set this to a boolean to explicitly enable or disable the resolver.
280+
281+
Setting this to an object enables the resolver and passes the object as configuration. See the [resolver readme](https://github.com/benmosher/eslint-plugin-import/blob/master/resolvers/webpack/README.md) along with the [webpack documentation](https://webpack.js.org/configuration/resolve/) for more information.
282+
272283
## TypeScript and Flow
273284

274285
### TypeScript
@@ -368,7 +379,7 @@ For example, if your project targets Node.js 8 but you want to use the latest Ja
368379
}
369380
```
370381

371-
This way your `package.json` will contain the actual minimum Node.js version supported by your published code, but XO will lint your source code as if it targets Node.js 12.
382+
This way your `package.json` will contain the actual minimum Node.js version supported by your published code, but XO will lint your source code as if it targets Node.js 12.
372383

373384
### Including files ignored by default
374385

Diff for: ‎test/fixtures/webpack/no-config/file1.js

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
import _ from 'file2alias'; // eslint-disable-line no-unused-vars
2+
import __ from 'inexistent'; // eslint-disable-line no-unused-vars

Diff for: ‎test/fixtures/webpack/no-config/file2.js

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
const foo = 1;
2+
export default foo;

Diff for: ‎test/fixtures/webpack/no-config/file3.js

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
import _ from '!./file2'; // eslint-disable-line no-unused-vars

Diff for: ‎test/fixtures/webpack/with-config/file1.js

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
import _ from 'file2alias'; // eslint-disable-line no-unused-vars
2+
import __ from 'inexistent'; // eslint-disable-line no-unused-vars

Diff for: ‎test/fixtures/webpack/with-config/file2.js

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
const foo = 1;
2+
export default foo;

Diff for: ‎test/fixtures/webpack/with-config/webpack.config.js

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
const path = require('path');
2+
3+
module.exports = {
4+
resolve: {
5+
alias: {
6+
file2alias: path.resolve(__dirname, 'file2.js')
7+
}
8+
}
9+
};

Diff for: ‎test/lint-files.js

+52
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,58 @@ test('typescript files', async t => {
196196
);
197197
});
198198

199+
test('webpack import resolver is used if webpack.config.js is found', async t => {
200+
const cwd = 'fixtures/webpack/with-config/';
201+
const {results} = await fn.lintFiles(path.resolve(cwd, 'file1.js'), {
202+
cwd,
203+
rules: {
204+
'import/no-unresolved': 2
205+
}
206+
});
207+
208+
t.is(results[0].errorCount, 1);
209+
210+
const errorMessage = results[0].messages[0].message;
211+
t.truthy(/Unable to resolve path to module 'inexistent'/.exec(errorMessage));
212+
});
213+
214+
test('webpack import resolver config can be passed through webpack option', async t => {
215+
const cwd = 'fixtures/webpack/no-config/';
216+
217+
const {results} = await fn.lintFiles(path.resolve(cwd, 'file1.js'), {
218+
cwd,
219+
webpack: {
220+
config: {
221+
resolve: {
222+
alias: {
223+
file2alias: path.resolve(__dirname, cwd, './file2.js')
224+
}
225+
}
226+
}
227+
},
228+
rules: {
229+
'import/no-unresolved': 2
230+
}
231+
});
232+
233+
t.is(results[0].errorCount, 1);
234+
});
235+
236+
test('webpack import resolver is used if {webpack: true}', async t => {
237+
const cwd = 'fixtures/webpack/no-config/';
238+
239+
const {results} = await fn.lintFiles(path.resolve(cwd, 'file3.js'), {
240+
cwd,
241+
webpack: true,
242+
rules: {
243+
'import/no-unresolved': 2,
244+
'import/no-webpack-loader-syntax': 0
245+
}
246+
});
247+
248+
t.is(results[0].errorCount, 0);
249+
});
250+
199251
async function configType(t, {dir}) {
200252
const {results} = await fn.lintFiles('**/*', {cwd: path.resolve('fixtures', 'config-files', dir)});
201253

Diff for: ‎test/options-manager.js

+30-1
Original file line numberDiff line numberDiff line change
@@ -384,11 +384,40 @@ test('buildConfig: parser', t => {
384384
});
385385

386386
test('buildConfig: settings', t => {
387-
const settings = {'import/resolver': 'webpack'};
387+
const settings = {'import/resolver': {webpack: {}}};
388388
const config = manager.buildConfig({settings});
389389
t.deepEqual(config.baseConfig.settings, settings);
390390
});
391391

392+
test('buildConfig: finds webpack config file', t => {
393+
const cwd = path.resolve('fixtures', 'webpack', 'with-config');
394+
const config = manager.buildConfig({cwd});
395+
const expected = {webpack: {config: path.resolve(cwd, 'webpack.config.js')}};
396+
t.deepEqual(config.baseConfig.settings['import/resolver'], expected);
397+
});
398+
399+
test('buildConfig: webpack option sets resolver', t => {
400+
const config = manager.buildConfig({webpack: true, settings: {'import/resolver': 'node'}});
401+
t.deepEqual(config.baseConfig.settings['import/resolver'], {webpack: {}, node: {}});
402+
});
403+
404+
test('buildConfig: webpack option handles object values', t => {
405+
const config = manager.buildConfig({webpack: {foo: 1}, settings: {'import/resolver': 'node'}});
406+
t.deepEqual(config.baseConfig.settings['import/resolver'], {webpack: {foo: 1}, node: {}});
407+
});
408+
409+
test('buildConfig: webpack resolver is not added automatically if webpack option is set to false', t => {
410+
const cwd = path.resolve('fixtures', 'webpack', 'with-config');
411+
const config = manager.buildConfig({cwd, webpack: false, settings: {}});
412+
t.deepEqual(config.baseConfig.settings['import/resolver'], {});
413+
});
414+
415+
test('buildConfig: webpack option is merged with import/resolver', t => {
416+
const settings = {'import/resolver': {webpack: {bar: 1}}};
417+
const config = manager.buildConfig({settings, webpack: {foo: 1}});
418+
t.deepEqual(config.baseConfig.settings['import/resolver'], {webpack: {foo: 1, bar: 1}});
419+
});
420+
392421
test('buildConfig: extends', t => {
393422
const config = manager.buildConfig({extends: [
394423
'plugin:foo/bar',

0 commit comments

Comments
 (0)
Please sign in to comment.