Skip to content

Commit

Permalink
[Fix] import/no-cycle: fix perf regression
Browse files Browse the repository at this point in the history
Fixes #1943.
  • Loading branch information
mblaszczyk-atlassian authored and ljharb committed Nov 12, 2020
1 parent 462b016 commit 2ae68c1
Show file tree
Hide file tree
Showing 4 changed files with 68 additions and 9 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ This change log adheres to standards from [Keep a CHANGELOG](http://keepachangel
- [`no-extraneous-dependencies`]: Add package.json cache ([#1948], thanks @fa93hws)
- [`prefer-default-export`]: handle empty array destructuring ([#1965], thanks @ljharb)
- [`no-unused-modules`]: make type imports mark a module as used (fixes #1924) ([#1974], thanks [@cherryblossom000])
- [`import/no-cycle`]: fix perf regression ([#1944], thanks [@Blasz])

## [2.22.1] - 2020-09-27
### Fixed
Expand Down Expand Up @@ -741,6 +742,7 @@ for info on changes for earlier releases.
[`memo-parser`]: ./memo-parser/README.md

[#1974]: https://github.com/benmosher/eslint-plugin-import/pull/1974
[#1944]: https://github.com/benmosher/eslint-plugin-import/pull/1944
[#1924]: https://github.com/benmosher/eslint-plugin-import/issues/1924
[#1965]: https://github.com/benmosher/eslint-plugin-import/issues/1965
[#1948]: https://github.com/benmosher/eslint-plugin-import/pull/1948
Expand Down Expand Up @@ -1293,3 +1295,4 @@ for info on changes for earlier releases.
[@straub]: https://github.com/straub
[@andreubotella]: https://github.com/andreubotella
[@cherryblossom000]: https://github.com/cherryblossom000
[@Blasz]: https://github.com/Blasz
27 changes: 22 additions & 5 deletions src/ExportMap.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ let parseConfigFileTextToJson;
const log = debug('eslint-plugin-import:ExportMap');

const exportCache = new Map();
const tsConfigCache = new Map();

export default class ExportMap {
constructor(path) {
Expand Down Expand Up @@ -438,9 +439,11 @@ ExportMap.parse = function (path, content, context) {

const source = makeSourceCode(content, ast);

function isEsModuleInterop() {
function readTsConfig() {
const tsConfigInfo = tsConfigLoader({
cwd: context.parserOptions && context.parserOptions.tsconfigRootDir || process.cwd(),
cwd:
(context.parserOptions && context.parserOptions.tsconfigRootDir) ||
process.cwd(),
getEnv: (key) => process.env[key],
});
try {
Expand All @@ -450,12 +453,26 @@ ExportMap.parse = function (path, content, context) {
// this is because projects not using TypeScript won't have typescript installed
({ parseConfigFileTextToJson } = require('typescript'));
}
const tsConfig = parseConfigFileTextToJson(tsConfigInfo.tsConfigPath, jsonText).config;
return tsConfig.compilerOptions.esModuleInterop;
return parseConfigFileTextToJson(tsConfigInfo.tsConfigPath, jsonText).config;
}
} catch (e) {
return false;
// Catch any errors
}

return null;
}

function isEsModuleInterop() {
const cacheKey = hashObject({
tsconfigRootDir: context.parserOptions && context.parserOptions.tsconfigRootDir,
}).digest('hex');
let tsConfig = tsConfigCache.get(cacheKey);
if (typeof tsConfig === 'undefined') {
tsConfig = readTsConfig();
tsConfigCache.set(cacheKey, tsConfig);
}

return tsConfig !== null ? tsConfig.compilerOptions.esModuleInterop : false;
}

ast.body.forEach(function (n) {
Expand Down
3 changes: 3 additions & 0 deletions tests/files/typescript-export-assign-property.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
const AnalyticsNode = { Analytics: {} };

export = AnalyticsNode.Analytics;
44 changes: 40 additions & 4 deletions tests/src/core/getExports.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { expect } from 'chai';
import semver from 'semver';
import sinon from 'sinon';
import eslintPkg from 'eslint/package.json';
import * as tsConfigLoader from 'tsconfig-paths/lib/tsconfig-loader';
import ExportMap from '../../../src/ExportMap';

import * as fs from 'fs';
Expand Down Expand Up @@ -51,7 +53,8 @@ describe('ExportMap', function () {
const differentSettings = Object.assign(
{},
fakeContext,
{ parserPath: 'espree' });
{ parserPath: 'espree' },
);

expect(ExportMap.get('./named-exports', differentSettings))
.to.exist.and
Expand Down Expand Up @@ -338,11 +341,11 @@ describe('ExportMap', function () {
// ['string form', { 'typescript-eslint-parser': '.ts' }],
];

if (semver.satisfies(eslintPkg.version, '>5.0.0')) {
if (semver.satisfies(eslintPkg.version, '>5')) {
configs.push(['array form', { '@typescript-eslint/parser': ['.ts', '.tsx'] }]);
}

if (semver.satisfies(eslintPkg.version, '<6.0.0')) {
if (semver.satisfies(eslintPkg.version, '<6')) {
configs.push(['array form', { 'typescript-eslint-parser': ['.ts', '.tsx'] }]);
}

Expand All @@ -358,8 +361,12 @@ describe('ExportMap', function () {
let imports;
before('load imports', function () {
this.timeout(20000); // takes a long time :shrug:
sinon.spy(tsConfigLoader, 'tsConfigLoader');
imports = ExportMap.get('./typescript.ts', context);
});
after('clear spies', function () {
tsConfigLoader.tsConfigLoader.restore();
});

it('returns something for a TypeScript file', function () {
expect(imports).to.exist;
Expand Down Expand Up @@ -388,9 +395,38 @@ describe('ExportMap', function () {
it('has exported abstract class', function () {
expect(imports.has('Bar')).to.be.true;
});

it('should cache tsconfig until tsconfigRootDir parser option changes', function () {
const customContext = Object.assign(
{},
context,
{
parserOptions: {
tsconfigRootDir: null,
},
},
);
expect(tsConfigLoader.tsConfigLoader.callCount).to.equal(0);
ExportMap.parse('./baz.ts', 'export const baz = 5', customContext);
expect(tsConfigLoader.tsConfigLoader.callCount).to.equal(1);
ExportMap.parse('./baz.ts', 'export const baz = 5', customContext);
expect(tsConfigLoader.tsConfigLoader.callCount).to.equal(1);

const differentContext = Object.assign(
{},
context,
{
parserOptions: {
tsconfigRootDir: process.cwd(),
},
},
);

ExportMap.parse('./baz.ts', 'export const baz = 5', differentContext);
expect(tsConfigLoader.tsConfigLoader.callCount).to.equal(2);
});
});
});

});

// todo: move to utils
Expand Down

0 comments on commit 2ae68c1

Please sign in to comment.