/
parse.js
128 lines (110 loc) · 4.05 KB
/
parse.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
'use strict';
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');
let parserOptions = context.parserOptions;
const parserPath = getParserPath(path, context);
if (!parserPath) throw new Error('parserPath is required!');
// hack: espree blows up with frozen options
parserOptions = Object.assign({}, parserOptions);
parserOptions.ecmaFeatures = Object.assign({}, parserOptions.ecmaFeatures);
// always include comments and tokens (for doc parsing)
parserOptions.comment = true;
parserOptions.attachComment = true; // keeping this for backward-compat with older parsers
parserOptions.tokens = true;
// attach node locations
parserOptions.loc = true;
parserOptions.range = true;
// provide the `filePath` like eslint itself does, in `parserOptions`
// https://github.com/eslint/eslint/blob/3ec436ee/lib/linter.js#L637
parserOptions.filePath = path;
// @typescript-eslint/parser will parse the entire project with typechecking if you provide
// "project" or "projects" in parserOptions. Removing these options means the parser will
// only parse one file in isolate mode, which is much, much faster.
// https://github.com/import-js/eslint-plugin-import/issues/1408#issuecomment-509298962
delete parserOptions.project;
delete parserOptions.projects;
// require the parser relative to the main module (i.e., ESLint)
const parser = moduleRequire(parserPath);
if (typeof parser.parseForESLint === 'function') {
let ast;
try {
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',
);
} else {
return {
ast,
visitorKeys: keysFromParser(parserPath, parser, undefined),
};
}
}
const keys = keysFromParser(parserPath, parser, undefined);
return {
ast: parser.parse(content, parserOptions),
visitorKeys: keys,
};
};
function getParserPath(path, context) {
const parsers = context.settings['import/parsers'];
if (parsers != null) {
const extension = extname(path);
for (const parserPath in parsers) {
if (parsers[parserPath].indexOf(extension) > -1) {
// use this alternate parser
log('using alt parser:', parserPath);
return parserPath;
}
}
}
// default to use ESLint parser
return context.parserPath;
}