Skip to content

Commit bfab4cc

Browse files
pmcelhaneyljharb
authored andcommittedJul 21, 2021
[Fix] Use context.getPhysicalFilename() when available (ESLint 7.28+)
1 parent 3761435 commit bfab4cc

17 files changed

+187
-23
lines changed
 

‎CHANGELOG.md

+3
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ This change log adheres to standards from [Keep a CHANGELOG](http://keepachangel
1010
- [`no-duplicates`]: ensure autofix avoids excessive newlines ([#2028], thanks [@ertrzyiks])
1111
- [`extensions`]: avoid crashing on partially typed import/export statements ([#2118], thanks [@ljharb])
1212
- [`no-extraneous-dependencies`]: add ESM intermediate package.json support] ([#2121], thanks [@paztis])
13+
- Use `context.getPhysicalFilename()` when available (ESLint 7.28+) ([#2160], thanks [@pmcelhaney])
1314

1415
### Changed
1516
- [Docs] `extensions`: removed incorrect cases ([#2138], thanks [@wenfangdu])
@@ -809,6 +810,7 @@ for info on changes for earlier releases.
809810

810811
[`memo-parser`]: ./memo-parser/README.md
811812

813+
[#2160]: https://github.com/benmosher/eslint-plugin-import/pull/2160
812814
[#2158]: https://github.com/benmosher/eslint-plugin-import/pull/2158
813815
[#2138]: https://github.com/benmosher/eslint-plugin-import/pull/2138
814816
[#2121]: https://github.com/benmosher/eslint-plugin-import/pull/2121
@@ -1374,6 +1376,7 @@ for info on changes for earlier releases.
13741376
[@paztis]: https://github.com/paztis
13751377
[@pcorpet]: https://github.com/pcorpet
13761378
[@Pessimistress]: https://github.com/Pessimistress
1379+
[@pmcelhaney]: https://github.com/pmcelhaney
13771380
[@preco21]: https://github.com/preco21
13781381
[@pzhine]: https://github.com/pzhine
13791382
[@ramasilveyra]: https://github.com/ramasilveyra

‎src/core/packagePath.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import readPkgUp from 'read-pkg-up';
44

55

66
export function getContextPackagePath(context) {
7-
return getFilePackagePath(context.getFilename());
7+
return getFilePackagePath(context.getPhysicalFilename ? context.getPhysicalFilename() : context.getFilename());
88
}
99

1010
export function getFilePackagePath(filePath) {

‎src/rules/named.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ module.exports = {
4343
if (!deepLookup.found) {
4444
if (deepLookup.path.length > 1) {
4545
const deepPath = deepLookup.path
46-
.map(i => path.relative(path.dirname(context.getFilename()), i.path))
46+
.map(i => path.relative(path.dirname(context.getPhysicalFilename ? context.getPhysicalFilename() : context.getFilename()), i.path))
4747
.join(' -> ');
4848

4949
context.report(im[key],

‎src/rules/newline-after-import.js

+3-3
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ function isExportDefaultClass(node) {
4848
}
4949

5050
function isExportNameClass(node) {
51-
51+
5252
return node.type === 'ExportNamedDeclaration' && node.declaration && node.declaration.type === 'ClassDeclaration';
5353
}
5454

@@ -124,7 +124,7 @@ after ${type} statement not followed by another ${type}.`,
124124
const { parent } = node;
125125
const nodePosition = parent.body.indexOf(node);
126126
const nextNode = parent.body[nodePosition + 1];
127-
127+
128128
// skip "export import"s
129129
if (node.type === 'TSImportEqualsDeclaration' && node.isExport) {
130130
return;
@@ -144,7 +144,7 @@ after ${type} statement not followed by another ${type}.`,
144144
}
145145
},
146146
'Program:exit': function () {
147-
log('exit processing for', context.getFilename());
147+
log('exit processing for', context.getPhysicalFilename ? context.getPhysicalFilename() : context.getFilename());
148148
const scopeBody = getScopeBody(context.getScope());
149149
log('got scope:', scopeBody);
150150

‎src/rules/no-cycle.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ module.exports = {
3737
},
3838

3939
create: function (context) {
40-
const myPath = context.getFilename();
40+
const myPath = context.getPhysicalFilename ? context.getPhysicalFilename() : context.getFilename();
4141
if (myPath === '<text>') return {}; // can't cycle-check a non-file
4242

4343
const options = context.options[0] || {};

‎src/rules/no-extraneous-dependencies.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ function getDependencies(context, packageDir) {
6969
Object.assign(
7070
packageContent,
7171
extractDepFields(
72-
readPkgUp.sync({ cwd: context.getFilename(), normalize: false }).pkg
72+
readPkgUp.sync({ cwd: context.getPhysicalFilename ? context.getPhysicalFilename() : context.getFilename(), normalize: false }).pkg
7373
)
7474
);
7575
}
@@ -254,7 +254,7 @@ module.exports = {
254254

255255
create: function (context) {
256256
const options = context.options[0] || {};
257-
const filename = context.getFilename();
257+
const filename = context.getPhysicalFilename ? context.getPhysicalFilename() : context.getFilename();
258258
const deps = getDependencies(context, options.packageDir) || extractDepFields({});
259259

260260
const depsOptions = {

‎src/rules/no-import-module-exports.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import path from 'path';
33
import pkgUp from 'pkg-up';
44

55
function getEntryPoint(context) {
6-
const pkgPath = pkgUp.sync(context.getFilename());
6+
const pkgPath = pkgUp.sync(context.getPhysicalFilename ? context.getPhysicalFilename() : context.getFilename());
77
try {
88
return require.resolve(path.dirname(pkgPath));
99
} catch (error) {
@@ -39,7 +39,7 @@ module.exports = {
3939
let alreadyReported = false;
4040

4141
function report(node) {
42-
const fileName = context.getFilename();
42+
const fileName = context.getPhysicalFilename ? context.getPhysicalFilename() : context.getFilename();
4343
const isEntryPoint = entryPoint === fileName;
4444
const isIdentifier = node.object.type === 'Identifier';
4545
const hasKeywords = (/^(module|exports)$/).test(node.object.name);

‎src/rules/no-relative-packages.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ function checkImportForRelativePackage(context, importPath, node) {
2121
}
2222

2323
const resolvedImport = resolve(importPath, context);
24-
const resolvedContext = context.getFilename();
24+
const resolvedContext = context.getPhysicalFilename ? context.getPhysicalFilename() : context.getFilename();
2525

2626
if (!resolvedImport || !resolvedContext) {
2727
return;

‎src/rules/no-relative-parent-imports.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ module.exports = {
1515
},
1616

1717
create: function noRelativePackages(context) {
18-
const myPath = context.getFilename();
18+
const myPath = context.getPhysicalFilename ? context.getPhysicalFilename() : context.getFilename();
1919
if (myPath === '<text>') return {}; // can't check a non-file
2020

2121
function checkSourceValue(sourceNode) {

‎src/rules/no-restricted-paths.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ module.exports = {
5252
const options = context.options[0] || {};
5353
const restrictedPaths = options.zones || [];
5454
const basePath = options.basePath || process.cwd();
55-
const currentFilename = context.getFilename();
55+
const currentFilename = context.getPhysicalFilename ? context.getPhysicalFilename() : context.getFilename();
5656
const matchingZones = restrictedPaths.filter((zone) => {
5757
const targetPath = path.resolve(basePath, zone.target);
5858

‎src/rules/no-self-import.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import moduleVisitor from 'eslint-module-utils/moduleVisitor';
88
import docsUrl from '../docsUrl';
99

1010
function isImportingSelf(context, node, requireName) {
11-
const filePath = context.getFilename();
11+
const filePath = context.getPhysicalFilename ? context.getPhysicalFilename() : context.getFilename();
1212

1313
// If the input is from stdin, this test can't fail
1414
if (filePath !== '<text>' && filePath === resolve(requireName, context)) {

‎src/rules/no-unassigned-import.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ function testIsAllow(globs, filename, source) {
3232

3333
function create(context) {
3434
const options = context.options[0] || {};
35-
const filename = context.getFilename();
35+
const filename = context.getPhysicalFilename ? context.getPhysicalFilename() : context.getFilename();
3636
const isAllow = source => testIsAllow(options.allow, filename, source);
3737

3838
return {

‎src/rules/no-unused-modules.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -463,7 +463,7 @@ module.exports = {
463463
doPreparation(src, ignoreExports, context);
464464
}
465465

466-
const file = context.getFilename();
466+
const file = context.getPhysicalFilename ? context.getPhysicalFilename() : context.getFilename();
467467

468468
const checkExportPresence = node => {
469469
if (!missingExports) {

‎src/rules/no-useless-path-segments.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ module.exports = {
5858
},
5959

6060
create(context) {
61-
const currentDir = path.dirname(context.getFilename());
61+
const currentDir = path.dirname(context.getPhysicalFilename ? context.getPhysicalFilename() : context.getFilename());
6262
const options = context.options[0];
6363

6464
function checkSourceValue(source) {

‎tests/src/core/getExports.js

+12-5
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,18 @@ import { getFilename } from '../utils';
1111
import * as unambiguous from 'eslint-module-utils/unambiguous';
1212

1313
describe('ExportMap', function () {
14-
const fakeContext = {
15-
getFilename: getFilename,
16-
settings: {},
17-
parserPath: 'babel-eslint',
18-
};
14+
const fakeContext = Object.assign(
15+
semver.satisfies(eslintPkg.version, '>= 7.28') ? {
16+
getFilename: function () { throw new Error('Should call getPhysicalFilename() instead of getFilename()'); },
17+
getPhysicalFilename: getFilename,
18+
} : {
19+
getFilename,
20+
},
21+
{
22+
settings: {},
23+
parserPath: 'babel-eslint',
24+
},
25+
);
1926

2027
it('handles ExportAllDeclaration', function () {
2128
let imports;

‎tests/src/core/resolve.js

+154
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
import { expect } from 'chai';
2+
import eslintPkg from 'eslint/package.json';
3+
import semver from 'semver';
24

35
import resolve, { CASE_SENSITIVE_FS, fileExistsWithCaseSync } from 'eslint-module-utils/resolve';
46
import ModuleCache from 'eslint-module-utils/ModuleCache';
@@ -162,6 +164,158 @@ describe('resolve', function () {
162164
expect(testContextReports[0].loc).to.eql({ line: 1, column: 0 });
163165
});
164166

167+
// context.getPhysicalFilename() is available in ESLint 7.28+
168+
(semver.satisfies(eslintPkg.version, '>= 7.28') ? describe : describe.skip)('getPhysicalFilename()', () => {
169+
function unexpectedCallToGetFilename() {
170+
throw new Error('Expected to call to getPhysicalFilename() instead of getFilename()');
171+
}
172+
173+
it('resolves via a custom resolver with interface version 1', function () {
174+
const testContext = utils.testContext({ 'import/resolver': './foo-bar-resolver-v1' });
175+
176+
expect(resolve( '../files/foo'
177+
, Object.assign({}, testContext, { getFilename: unexpectedCallToGetFilename, getPhysicalFilename: function () { return utils.getFilename('foo.js'); } }),
178+
)).to.equal(utils.testFilePath('./bar.jsx'));
179+
180+
expect(resolve( '../files/exception'
181+
, Object.assign({}, testContext, { getFilename: unexpectedCallToGetFilename, getPhysicalFilename: function () { return utils.getFilename('exception.js'); } }),
182+
)).to.equal(undefined);
183+
184+
expect(resolve( '../files/not-found'
185+
, Object.assign({}, testContext, { getFilename: unexpectedCallToGetFilename, getPhysicalFilename: function () { return utils.getFilename('not-found.js'); } }),
186+
)).to.equal(undefined);
187+
});
188+
189+
it('resolves via a custom resolver with interface version 1 assumed if not specified', function () {
190+
const testContext = utils.testContext({ 'import/resolver': './foo-bar-resolver-no-version' });
191+
192+
expect(resolve( '../files/foo'
193+
, Object.assign({}, testContext, { getFilename: unexpectedCallToGetFilename, getPhysicalFilename: function () { return utils.getFilename('foo.js'); } }),
194+
)).to.equal(utils.testFilePath('./bar.jsx'));
195+
196+
expect(resolve( '../files/exception'
197+
, Object.assign({}, testContext, { getFilename: unexpectedCallToGetFilename, getPhysicalFilename: function () { return utils.getFilename('exception.js'); } }),
198+
)).to.equal(undefined);
199+
200+
expect(resolve( '../files/not-found'
201+
, Object.assign({}, testContext, { getFilename: unexpectedCallToGetFilename, getPhysicalFilename: function () { return utils.getFilename('not-found.js'); } }),
202+
)).to.equal(undefined);
203+
});
204+
205+
it('resolves via a custom resolver with interface version 2', function () {
206+
const testContext = utils.testContext({ 'import/resolver': './foo-bar-resolver-v2' });
207+
const testContextReports = [];
208+
testContext.report = function (reportInfo) {
209+
testContextReports.push(reportInfo);
210+
};
211+
212+
expect(resolve( '../files/foo'
213+
, Object.assign({}, testContext, { getFilename: unexpectedCallToGetFilename, getPhysicalFilename: function () { return utils.getFilename('foo.js'); } }),
214+
)).to.equal(utils.testFilePath('./bar.jsx'));
215+
216+
testContextReports.length = 0;
217+
expect(resolve( '../files/exception'
218+
, Object.assign({}, testContext, { getFilename: unexpectedCallToGetFilename, getPhysicalFilename: function () { return utils.getFilename('exception.js'); } }),
219+
)).to.equal(undefined);
220+
expect(testContextReports[0]).to.be.an('object');
221+
expect(replaceErrorStackForTest(testContextReports[0].message)).to.equal('Resolve error: foo-bar-resolver-v2 resolve test exception\n<stack-was-here>');
222+
expect(testContextReports[0].loc).to.eql({ line: 1, column: 0 });
223+
224+
testContextReports.length = 0;
225+
expect(resolve( '../files/not-found'
226+
, Object.assign({}, testContext, { getFilename: unexpectedCallToGetFilename, getPhysicalFilename: function () { return utils.getFilename('not-found.js'); } }),
227+
)).to.equal(undefined);
228+
expect(testContextReports.length).to.equal(0);
229+
});
230+
231+
it('respects import/resolver as array of strings', function () {
232+
const testContext = utils.testContext({ 'import/resolver': [ './foo-bar-resolver-v2', './foo-bar-resolver-v1' ] });
233+
234+
expect(resolve( '../files/foo'
235+
, Object.assign({}, testContext, { getFilename: unexpectedCallToGetFilename, getPhysicalFilename: function () { return utils.getFilename('foo.js'); } }),
236+
)).to.equal(utils.testFilePath('./bar.jsx'));
237+
});
238+
239+
it('respects import/resolver as object', function () {
240+
const testContext = utils.testContext({ 'import/resolver': { './foo-bar-resolver-v2': {} } });
241+
242+
expect(resolve( '../files/foo'
243+
, Object.assign({}, testContext, { getFilename: unexpectedCallToGetFilename, getPhysicalFilename: function () { return utils.getFilename('foo.js'); } }),
244+
)).to.equal(utils.testFilePath('./bar.jsx'));
245+
});
246+
247+
it('respects import/resolver as array of objects', function () {
248+
const testContext = utils.testContext({ 'import/resolver': [ { './foo-bar-resolver-v2': {} }, { './foo-bar-resolver-v1': {} } ] });
249+
250+
expect(resolve( '../files/foo'
251+
, Object.assign({}, testContext, { getFilename: unexpectedCallToGetFilename, getPhysicalFilename: function () { return utils.getFilename('foo.js'); } }),
252+
)).to.equal(utils.testFilePath('./bar.jsx'));
253+
});
254+
255+
it('finds resolvers from the source files rather than eslint-module-utils', function () {
256+
const testContext = utils.testContext({ 'import/resolver': { 'foo': {} } });
257+
258+
expect(resolve( '../files/foo'
259+
, Object.assign({}, testContext, { getFilename: unexpectedCallToGetFilename, getPhysicalFilename: function () { return utils.getFilename('foo.js'); } }),
260+
)).to.equal(utils.testFilePath('./bar.jsx'));
261+
});
262+
263+
it('reports invalid import/resolver config', function () {
264+
const testContext = utils.testContext({ 'import/resolver': 123.456 });
265+
const testContextReports = [];
266+
testContext.report = function (reportInfo) {
267+
testContextReports.push(reportInfo);
268+
};
269+
270+
testContextReports.length = 0;
271+
expect(resolve( '../files/foo'
272+
, Object.assign({}, testContext, { getFilename: unexpectedCallToGetFilename, getPhysicalFilename: function () { return utils.getFilename('foo.js'); } }),
273+
)).to.equal(undefined);
274+
expect(testContextReports[0]).to.be.an('object');
275+
expect(testContextReports[0].message).to.equal('Resolve error: invalid resolver config');
276+
expect(testContextReports[0].loc).to.eql({ line: 1, column: 0 });
277+
});
278+
279+
it('reports loaded resolver with invalid interface', function () {
280+
const resolverName = './foo-bar-resolver-invalid';
281+
const testContext = utils.testContext({ 'import/resolver': resolverName });
282+
const testContextReports = [];
283+
testContext.report = function (reportInfo) {
284+
testContextReports.push(reportInfo);
285+
};
286+
testContextReports.length = 0;
287+
expect(resolve( '../files/foo'
288+
, Object.assign({}, testContext, { getFilename: unexpectedCallToGetFilename, getPhysicalFilename: function () { return utils.getFilename('foo.js'); } }),
289+
)).to.equal(undefined);
290+
expect(testContextReports[0]).to.be.an('object');
291+
expect(testContextReports[0].message).to.equal(`Resolve error: ${resolverName} with invalid interface loaded as resolver`);
292+
expect(testContextReports[0].loc).to.eql({ line: 1, column: 0 });
293+
});
294+
295+
it('respects import/resolve extensions', function () {
296+
const testContext = utils.testContext({ 'import/resolve': { 'extensions': ['.jsx'] } });
297+
298+
expect(resolve( './jsx/MyCoolComponent'
299+
, testContext,
300+
)).to.equal(utils.testFilePath('./jsx/MyCoolComponent.jsx'));
301+
});
302+
303+
it('reports load exception in a user resolver', function () {
304+
const testContext = utils.testContext({ 'import/resolver': './load-error-resolver' });
305+
const testContextReports = [];
306+
testContext.report = function (reportInfo) {
307+
testContextReports.push(reportInfo);
308+
};
309+
310+
expect(resolve( '../files/exception'
311+
, Object.assign({}, testContext, { getFilename: unexpectedCallToGetFilename, getPhysicalFilename: function () { return utils.getFilename('exception.js'); } }),
312+
)).to.equal(undefined);
313+
expect(testContextReports[0]).to.be.an('object');
314+
expect(replaceErrorStackForTest(testContextReports[0].message)).to.equal('Resolve error: SyntaxError: TEST SYNTAX ERROR\n<stack-was-here>');
315+
expect(testContextReports[0].loc).to.eql({ line: 1, column: 0 });
316+
});
317+
});
318+
165319
const caseDescribe = (!CASE_SENSITIVE_FS ? describe : describe.skip);
166320
caseDescribe('case sensitivity', function () {
167321
let file;

‎utils/resolve.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -217,7 +217,7 @@ const erroredContexts = new Set();
217217
*/
218218
function resolve(p, context) {
219219
try {
220-
return relative(p, context.getFilename(), context.settings);
220+
return relative(p, context.getPhysicalFilename ? context.getPhysicalFilename() : context.getFilename(), context.settings);
221221
} catch (err) {
222222
if (!erroredContexts.has(context)) {
223223
// The `err.stack` string starts with `err.name` followed by colon and `err.message`.

0 commit comments

Comments
 (0)
Please sign in to comment.