Skip to content

Commit

Permalink
[utils] [new] add visit, to support dynamic imports
Browse files Browse the repository at this point in the history
See #1660, #2212.

Co-authored-by: Max Komarychev <[email protected]>
Co-authored-by: Filipp Riabchun <[email protected]>
Co-authored-by: 薛定谔的猫 <[email protected]>
  • Loading branch information
3 people authored and ljharb committed Jun 20, 2020
1 parent 35bd977 commit 7579748
Show file tree
Hide file tree
Showing 6 changed files with 88 additions and 14 deletions.
7 changes: 2 additions & 5 deletions tests/src/core/getExports.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import ExportMap from '../../../src/ExportMap';
import * as fs from 'fs';

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

describe('ExportMap', function () {
const fakeContext = Object.assign(
Expand Down Expand Up @@ -438,7 +438,6 @@ describe('ExportMap', function () {

// todo: move to utils
describe('unambiguous regex', function () {

const testFiles = [
['deep/b.js', true],
['bar.js', true],
Expand All @@ -449,10 +448,8 @@ describe('ExportMap', function () {
for (const [testFile, expectedRegexResult] of testFiles) {
it(`works for ${testFile} (${expectedRegexResult})`, function () {
const content = fs.readFileSync('./tests/files/' + testFile, 'utf8');
expect(unambiguous.test(content)).to.equal(expectedRegexResult);
expect(testUnambiguous(content)).to.equal(expectedRegexResult);
});
}

});

});
1 change: 0 additions & 1 deletion tests/src/core/parse.js
Original file line number Diff line number Diff line change
Expand Up @@ -69,5 +69,4 @@ describe('parse(content, { settings, ecmaFeatures })', function () {
expect(parse.bind(null, path, content, { settings: { 'import/parsers': { [parseStubParserPath]: [ '.js' ] } }, parserPath: null, parserOptions })).not.to.throw(Error);
expect(parseSpy.callCount, 'custom parser to be called once').to.equal(1);
});

});
8 changes: 7 additions & 1 deletion utils/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ This change log adheres to standards from [Keep a CHANGELOG](http://keepachangel

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

## v2.6.2 - 2021-08-08

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

[#2212]: https://github.com/import-js/eslint-plugin-import/pull/2212
[#2160]: https://github.com/import-js/eslint-plugin-import/pull/2160
[#2026]: https://github.com/import-js/eslint-plugin-import/pull/2026
[#1786]: https://github.com/import-js/eslint-plugin-import/pull/1786
[#1671]: https://github.com/import-js/eslint-plugin-import/pull/1671
[#1660]: https://github.com/import-js/eslint-plugin-import/pull/1660
[#1606]: https://github.com/import-js/eslint-plugin-import/pull/1606
[#1602]: https://github.com/import-js/eslint-plugin-import/pull/1602
[#1591]: https://github.com/import-js/eslint-plugin-import/pull/1591
Expand Down Expand Up @@ -126,4 +129,7 @@ Yanked due to critical issue with cache key resulting from #839.
[@sergei-startsev]: https://github.com/sergei-startsev
[@sompylasar]: https://github.com/sompylasar
[@timkraut]: https://github.com/timkraut
[@vikr01]: https://github.com/vikr01
[@vikr01]: https://github.com/vikr01
[@maxkomarychev]: https://github.com/maxkomarychev
[@aladdin-add]: https://github.com/aladdin-add
[@Hypnosphi]: https://github.com/Hypnosphi
57 changes: 53 additions & 4 deletions utils/parse.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,42 @@ exports.__esModule = true;

const moduleRequire = require('./module-require').default;
const extname = require('path').extname;
const fs = require('fs');

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

function getBabelVisitorKeys(parserPath) {
if (parserPath.endsWith('index.js')) {
const hypotheticalLocation = parserPath.replace('index.js', 'visitor-keys.js');
if (fs.existsSync(hypotheticalLocation)) {
const keys = moduleRequire(hypotheticalLocation);
return keys.default || keys;
}
} else if (parserPath.endsWith('index.cjs')) {
const hypotheticalLocation = parserPath.replace('index.cjs', 'worker/ast-info.cjs');
if (fs.existsSync(hypotheticalLocation)) {
const astInfo = moduleRequire(hypotheticalLocation);
return astInfo.getVisitorKeys();
}
}
return null;
}

function keysFromParser(parserPath, parserInstance, parsedResult) {
if (/.*espree.*/.test(parserPath)) {
return parserInstance.VisitorKeys;
}
if (/.*(babel-eslint|@babel\/eslint-parser).*/.test(parserPath)) {
return getBabelVisitorKeys(parserPath);
}
if (/.*@typescript-eslint\/parser/.test(parserPath)) {
if (parsedResult) {
return parsedResult.visitorKeys;
}
}
return null;
}

exports.default = function parse(path, content, context) {

if (context == null) throw new Error('need context to parse properly');
Expand Down Expand Up @@ -45,20 +78,36 @@ exports.default = function parse(path, content, context) {
if (typeof parser.parseForESLint === 'function') {
let ast;
try {
ast = parser.parseForESLint(content, parserOptions).ast;
const parserRaw = parser.parseForESLint(content, parserOptions);
ast = parserRaw.ast;
return {
ast,
visitorKeys: keysFromParser(parserPath, parser, parserRaw),
};
} catch (e) {
console.warn();
console.warn('Error while parsing ' + parserOptions.filePath);
console.warn('Line ' + e.lineNumber + ', column ' + e.column + ': ' + e.message);
}
if (!ast || typeof ast !== 'object') {
console.warn('`parseForESLint` from parser `' + parserPath + '` is invalid and will just be ignored');
console.warn(
'`parseForESLint` from parser `' +
parserPath +
'` is invalid and will just be ignored',
);
} else {
return ast;
return {
ast,
visitorKeys: keysFromParser(parserPath, parser, undefined),
};
}
}

return parser.parse(content, parserOptions);
const keys = keysFromParser(parserPath, parser, undefined);
return {
ast: parser.parse(content, parserOptions),
visitorKeys: keys,
};
};

function getParserPath(path, context) {
Expand Down
5 changes: 2 additions & 3 deletions utils/unambiguous.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
'use strict';
exports.__esModule = true;


const pattern = /(^|;)\s*(export|import)((\s+\w)|(\s*[{*=]))/m;
const pattern = /(^|;)\s*(export|import)((\s+\w)|(\s*[{*=]))|import\(/m;
/**
* detect possible imports/exports without a full parse.
*
Expand All @@ -26,5 +25,5 @@ const unambiguousNodeType = /^(?:(?:Exp|Imp)ort.*Declaration|TSExportAssignment)
* @return {Boolean}
*/
exports.isModule = function isUnambiguousModule(ast) {
return ast.body.some(node => unambiguousNodeType.test(node.type));
return ast.body && ast.body.some(node => unambiguousNodeType.test(node.type));
};
24 changes: 24 additions & 0 deletions utils/visit.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
'use strict';
exports.__esModule = true;

exports.default = function visit(node, keys, visitorSpec) {
if (!node || !keys) {
return;
}
const type = node.type;
if (typeof visitorSpec[type] === 'function') {
visitorSpec[type](node);
}
const childFields = keys[type];
if (!childFields) {
return;
}
childFields.forEach((fieldName) => {
[].concat(node[fieldName]).forEach((item) => {
visit(item, keys, visitorSpec);
});
});
if (typeof visitorSpec[`${type}:Exit`] === 'function') {
visitorSpec[`${type}:Exit`](node);
}
};

0 comments on commit 7579748

Please sign in to comment.