Skip to content

Commit f6630cd

Browse files
committed
fix(core): export map cache is tainted by unreliable parse results
This change addresses and issue observed with the v9 upgrade, where the ExportMap Cache is being tainted with a bad export map, if the parse doesn't yield a `visitorKeys` (which can happen if an incompatible parser is used (e.g. og babel eslint)) for one run of the no-cycle rule. If a subsequent test is run with a compatible parser, then the bad export map will be found in the cache and used instead of attempting to proceed with the parse. I also updated the `getExports` test to use a valid parserPath, rather than a mocked one, so that the tests are acting on a valid parserPath. Otherwise the export map won't be cached following this change.
1 parent 5c9757c commit f6630cd

File tree

2 files changed

+23
-7
lines changed

2 files changed

+23
-7
lines changed

src/exportMap/builder.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,11 @@ export default class ExportMapBuilder {
9292

9393
exportMap.mtime = stats.mtime;
9494

95-
exportCache.set(cacheKey, exportMap);
95+
// If the visitor keys were not populated, then we shouldn't save anything to the cache,
96+
// since the parse results may not be reliable.
97+
if (exportMap.visitorKeys) {
98+
exportCache.set(cacheKey, exportMap);
99+
}
96100
return exportMap;
97101
}
98102

tests/src/core/getExports.js

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,18 @@
11
import { expect } from 'chai';
2+
import * as fs from 'fs';
23
import semver from 'semver';
34
import sinon from 'sinon';
45
import eslintPkg from 'eslint/package.json';
6+
import { test as testUnambiguous } from 'eslint-module-utils/unambiguous';
57
import typescriptPkg from 'typescript/package.json';
68
import * as tsConfigLoader from 'tsconfig-paths/lib/tsconfig-loader';
7-
import ExportMapBuilder from '../../../src/exportMap/builder';
8-
9-
import * as fs from 'fs';
109

10+
import ExportMapBuilder from '../../../src/exportMap/builder';
1111
import { getFilename } from '../utils';
12-
import { test as testUnambiguous } from 'eslint-module-utils/unambiguous';
12+
13+
const babelPath = require.resolve('babel-eslint');
14+
const hypotheticalLocation = babelPath.replace('index.js', 'visitor-keys.js');
15+
const isVisitorKeysSupported = fs.existsSync(hypotheticalLocation);
1316

1417
describe('ExportMap', function () {
1518
const fakeContext = Object.assign(
@@ -21,7 +24,7 @@ describe('ExportMap', function () {
2124
},
2225
{
2326
settings: {},
24-
parserPath: 'babel-eslint',
27+
parserPath: require.resolve('babel-eslint'),
2528
},
2629
);
2730

@@ -36,11 +39,20 @@ describe('ExportMap', function () {
3639

3740
});
3841

39-
it('returns a cached copy on subsequent requests', function () {
42+
(isVisitorKeysSupported ? it : it.skip)('returns a cached copy on subsequent requests', function () {
4043
expect(ExportMapBuilder.get('./named-exports', fakeContext))
4144
.to.exist.and.equal(ExportMapBuilder.get('./named-exports', fakeContext));
4245
});
4346

47+
it('does not return a cached copy if the parse does not yield a visitor keys', function () {
48+
const mockContext = {
49+
...fakeContext,
50+
parserPath: 'not-real',
51+
};
52+
expect(ExportMapBuilder.get('./named-exports', mockContext))
53+
.to.exist.and.not.equal(ExportMapBuilder.get('./named-exports', mockContext));
54+
});
55+
4456
it('does not return a cached copy after modification', (done) => {
4557
const firstAccess = ExportMapBuilder.get('./mutator', fakeContext);
4658
expect(firstAccess).to.exist;

0 commit comments

Comments
 (0)