Skip to content

Commit 7579748

Browse files
maxkomarychevHypnosphialaddin-add
authored andcommitted
[utils] [new] add visit, to support dynamic imports
See #1660, #2212. Co-authored-by: Max Komarychev <[email protected]> Co-authored-by: Filipp Riabchun <[email protected]> Co-authored-by: 薛定谔的猫 <[email protected]>
1 parent 35bd977 commit 7579748

File tree

6 files changed

+88
-14
lines changed

6 files changed

+88
-14
lines changed

tests/src/core/getExports.js

+2-5
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import ExportMap from '../../../src/ExportMap';
88
import * as fs from 'fs';
99

1010
import { getFilename } from '../utils';
11-
import * as unambiguous from 'eslint-module-utils/unambiguous';
11+
import { test as testUnambiguous } from 'eslint-module-utils/unambiguous';
1212

1313
describe('ExportMap', function () {
1414
const fakeContext = Object.assign(
@@ -438,7 +438,6 @@ describe('ExportMap', function () {
438438

439439
// todo: move to utils
440440
describe('unambiguous regex', function () {
441-
442441
const testFiles = [
443442
['deep/b.js', true],
444443
['bar.js', true],
@@ -449,10 +448,8 @@ describe('ExportMap', function () {
449448
for (const [testFile, expectedRegexResult] of testFiles) {
450449
it(`works for ${testFile} (${expectedRegexResult})`, function () {
451450
const content = fs.readFileSync('./tests/files/' + testFile, 'utf8');
452-
expect(unambiguous.test(content)).to.equal(expectedRegexResult);
451+
expect(testUnambiguous(content)).to.equal(expectedRegexResult);
453452
});
454453
}
455-
456454
});
457-
458455
});

tests/src/core/parse.js

-1
Original file line numberDiff line numberDiff line change
@@ -69,5 +69,4 @@ describe('parse(content, { settings, ecmaFeatures })', function () {
6969
expect(parse.bind(null, path, content, { settings: { 'import/parsers': { [parseStubParserPath]: [ '.js' ] } }, parserPath: null, parserOptions })).not.to.throw(Error);
7070
expect(parseSpy.callCount, 'custom parser to be called once').to.equal(1);
7171
});
72-
7372
});

utils/CHANGELOG.md

+7-1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ This change log adheres to standards from [Keep a CHANGELOG](http://keepachangel
77

88
### Added
99
- `fileExistsWithCaseSync`: add `strict` argument ([#1262], thanks [@sergei-startsev])
10+
- add `visit`, to support dynamic imports ([#1660], [#2212], thanks [@maxkomarychev], [@aladdin-add], [@Hypnosphi])
1011

1112
## v2.6.2 - 2021-08-08
1213

@@ -93,10 +94,12 @@ Yanked due to critical issue with cache key resulting from #839.
9394
### Fixed
9495
- `unambiguous.test()` regex is now properly in multiline mode
9596

97+
[#2212]: https://github.com/import-js/eslint-plugin-import/pull/2212
9698
[#2160]: https://github.com/import-js/eslint-plugin-import/pull/2160
9799
[#2026]: https://github.com/import-js/eslint-plugin-import/pull/2026
98100
[#1786]: https://github.com/import-js/eslint-plugin-import/pull/1786
99101
[#1671]: https://github.com/import-js/eslint-plugin-import/pull/1671
102+
[#1660]: https://github.com/import-js/eslint-plugin-import/pull/1660
100103
[#1606]: https://github.com/import-js/eslint-plugin-import/pull/1606
101104
[#1602]: https://github.com/import-js/eslint-plugin-import/pull/1602
102105
[#1591]: https://github.com/import-js/eslint-plugin-import/pull/1591
@@ -126,4 +129,7 @@ Yanked due to critical issue with cache key resulting from #839.
126129
[@sergei-startsev]: https://github.com/sergei-startsev
127130
[@sompylasar]: https://github.com/sompylasar
128131
[@timkraut]: https://github.com/timkraut
129-
[@vikr01]: https://github.com/vikr01
132+
[@vikr01]: https://github.com/vikr01
133+
[@maxkomarychev]: https://github.com/maxkomarychev
134+
[@aladdin-add]: https://github.com/aladdin-add
135+
[@Hypnosphi]: https://github.com/Hypnosphi

utils/parse.js

+53-4
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,42 @@ exports.__esModule = true;
33

44
const moduleRequire = require('./module-require').default;
55
const extname = require('path').extname;
6+
const fs = require('fs');
67

78
const log = require('debug')('eslint-plugin-import:parse');
89

10+
function getBabelVisitorKeys(parserPath) {
11+
if (parserPath.endsWith('index.js')) {
12+
const hypotheticalLocation = parserPath.replace('index.js', 'visitor-keys.js');
13+
if (fs.existsSync(hypotheticalLocation)) {
14+
const keys = moduleRequire(hypotheticalLocation);
15+
return keys.default || keys;
16+
}
17+
} else if (parserPath.endsWith('index.cjs')) {
18+
const hypotheticalLocation = parserPath.replace('index.cjs', 'worker/ast-info.cjs');
19+
if (fs.existsSync(hypotheticalLocation)) {
20+
const astInfo = moduleRequire(hypotheticalLocation);
21+
return astInfo.getVisitorKeys();
22+
}
23+
}
24+
return null;
25+
}
26+
27+
function keysFromParser(parserPath, parserInstance, parsedResult) {
28+
if (/.*espree.*/.test(parserPath)) {
29+
return parserInstance.VisitorKeys;
30+
}
31+
if (/.*(babel-eslint|@babel\/eslint-parser).*/.test(parserPath)) {
32+
return getBabelVisitorKeys(parserPath);
33+
}
34+
if (/.*@typescript-eslint\/parser/.test(parserPath)) {
35+
if (parsedResult) {
36+
return parsedResult.visitorKeys;
37+
}
38+
}
39+
return null;
40+
}
41+
942
exports.default = function parse(path, content, context) {
1043

1144
if (context == null) throw new Error('need context to parse properly');
@@ -45,20 +78,36 @@ exports.default = function parse(path, content, context) {
4578
if (typeof parser.parseForESLint === 'function') {
4679
let ast;
4780
try {
48-
ast = parser.parseForESLint(content, parserOptions).ast;
81+
const parserRaw = parser.parseForESLint(content, parserOptions);
82+
ast = parserRaw.ast;
83+
return {
84+
ast,
85+
visitorKeys: keysFromParser(parserPath, parser, parserRaw),
86+
};
4987
} catch (e) {
5088
console.warn();
5189
console.warn('Error while parsing ' + parserOptions.filePath);
5290
console.warn('Line ' + e.lineNumber + ', column ' + e.column + ': ' + e.message);
5391
}
5492
if (!ast || typeof ast !== 'object') {
55-
console.warn('`parseForESLint` from parser `' + parserPath + '` is invalid and will just be ignored');
93+
console.warn(
94+
'`parseForESLint` from parser `' +
95+
parserPath +
96+
'` is invalid and will just be ignored',
97+
);
5698
} else {
57-
return ast;
99+
return {
100+
ast,
101+
visitorKeys: keysFromParser(parserPath, parser, undefined),
102+
};
58103
}
59104
}
60105

61-
return parser.parse(content, parserOptions);
106+
const keys = keysFromParser(parserPath, parser, undefined);
107+
return {
108+
ast: parser.parse(content, parserOptions),
109+
visitorKeys: keys,
110+
};
62111
};
63112

64113
function getParserPath(path, context) {

utils/unambiguous.js

+2-3
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
'use strict';
22
exports.__esModule = true;
33

4-
5-
const pattern = /(^|;)\s*(export|import)((\s+\w)|(\s*[{*=]))/m;
4+
const pattern = /(^|;)\s*(export|import)((\s+\w)|(\s*[{*=]))|import\(/m;
65
/**
76
* detect possible imports/exports without a full parse.
87
*
@@ -26,5 +25,5 @@ const unambiguousNodeType = /^(?:(?:Exp|Imp)ort.*Declaration|TSExportAssignment)
2625
* @return {Boolean}
2726
*/
2827
exports.isModule = function isUnambiguousModule(ast) {
29-
return ast.body.some(node => unambiguousNodeType.test(node.type));
28+
return ast.body && ast.body.some(node => unambiguousNodeType.test(node.type));
3029
};

utils/visit.js

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
'use strict';
2+
exports.__esModule = true;
3+
4+
exports.default = function visit(node, keys, visitorSpec) {
5+
if (!node || !keys) {
6+
return;
7+
}
8+
const type = node.type;
9+
if (typeof visitorSpec[type] === 'function') {
10+
visitorSpec[type](node);
11+
}
12+
const childFields = keys[type];
13+
if (!childFields) {
14+
return;
15+
}
16+
childFields.forEach((fieldName) => {
17+
[].concat(node[fieldName]).forEach((item) => {
18+
visit(item, keys, visitorSpec);
19+
});
20+
});
21+
if (typeof visitorSpec[`${type}:Exit`] === 'function') {
22+
visitorSpec[`${type}:Exit`](node);
23+
}
24+
};

0 commit comments

Comments
 (0)