blob: 810533ed5257109b7b857ef355dd256247be398e [file] [log] [blame]
Tim van der Lippe2c891972021-07-29 16:22:50 +01001'use strict';
2exports.__esModule = true;
Tim van der Lippefdbd42e2020-04-07 15:14:36 +01003
Tim van der Lippe2c891972021-07-29 16:22:50 +01004const moduleRequire = require('./module-require').default;
5const extname = require('path').extname;
Tim van der Lippebc3a0b72021-11-08 15:22:37 +00006const fs = require('fs');
Tim van der Lippefdbd42e2020-04-07 15:14:36 +01007
Tim van der Lippe2c891972021-07-29 16:22:50 +01008const log = require('debug')('eslint-plugin-import:parse');
Tim van der Lippefdbd42e2020-04-07 15:14:36 +01009
Tim van der Lippe0ceb4652022-01-06 14:23:36 +010010function getBabelEslintVisitorKeys(parserPath) {
Tim van der Lippebc3a0b72021-11-08 15:22:37 +000011 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 }
Tim van der Lippebc3a0b72021-11-08 15:22:37 +000017 }
18 return null;
19}
20
21function keysFromParser(parserPath, parserInstance, parsedResult) {
Tim van der Lippe0ceb4652022-01-06 14:23:36 +010022 // Exposed by @typescript-eslint/parser and @babel/eslint-parser
23 if (parsedResult && parsedResult.visitorKeys) {
24 return parsedResult.visitorKeys;
25 }
Tim van der Lippebc3a0b72021-11-08 15:22:37 +000026 if (/.*espree.*/.test(parserPath)) {
27 return parserInstance.VisitorKeys;
28 }
Tim van der Lippe0ceb4652022-01-06 14:23:36 +010029 if (/.*babel-eslint.*/.test(parserPath)) {
30 return getBabelEslintVisitorKeys(parserPath);
Tim van der Lippebc3a0b72021-11-08 15:22:37 +000031 }
32 return null;
33}
34
Tim van der Lippefdbd42e2020-04-07 15:14:36 +010035exports.default = function parse(path, content, context) {
36
Tim van der Lippe2c891972021-07-29 16:22:50 +010037 if (context == null) throw new Error('need context to parse properly');
Tim van der Lippefdbd42e2020-04-07 15:14:36 +010038
Tim van der Lippe2c891972021-07-29 16:22:50 +010039 let parserOptions = context.parserOptions;
40 const parserPath = getParserPath(path, context);
Tim van der Lippefdbd42e2020-04-07 15:14:36 +010041
Tim van der Lippe2c891972021-07-29 16:22:50 +010042 if (!parserPath) throw new Error('parserPath is required!');
Tim van der Lippefdbd42e2020-04-07 15:14:36 +010043
44 // hack: espree blows up with frozen options
Tim van der Lippe2c891972021-07-29 16:22:50 +010045 parserOptions = Object.assign({}, parserOptions);
46 parserOptions.ecmaFeatures = Object.assign({}, parserOptions.ecmaFeatures);
Tim van der Lippefdbd42e2020-04-07 15:14:36 +010047
48 // always include comments and tokens (for doc parsing)
Tim van der Lippe2c891972021-07-29 16:22:50 +010049 parserOptions.comment = true;
50 parserOptions.attachComment = true; // keeping this for backward-compat with older parsers
51 parserOptions.tokens = true;
Tim van der Lippefdbd42e2020-04-07 15:14:36 +010052
53 // attach node locations
Tim van der Lippe2c891972021-07-29 16:22:50 +010054 parserOptions.loc = true;
55 parserOptions.range = true;
Tim van der Lippefdbd42e2020-04-07 15:14:36 +010056
57 // provide the `filePath` like eslint itself does, in `parserOptions`
58 // https://github.com/eslint/eslint/blob/3ec436ee/lib/linter.js#L637
Tim van der Lippe2c891972021-07-29 16:22:50 +010059 parserOptions.filePath = path;
60
Tim van der Lippefdbd42e2020-04-07 15:14:36 +010061 // @typescript-eslint/parser will parse the entire project with typechecking if you provide
62 // "project" or "projects" in parserOptions. Removing these options means the parser will
63 // only parse one file in isolate mode, which is much, much faster.
Tim van der Lippea6619412021-09-13 14:28:55 +020064 // https://github.com/import-js/eslint-plugin-import/issues/1408#issuecomment-509298962
Tim van der Lippe2c891972021-07-29 16:22:50 +010065 delete parserOptions.project;
66 delete parserOptions.projects;
67
Tim van der Lippefdbd42e2020-04-07 15:14:36 +010068 // require the parser relative to the main module (i.e., ESLint)
Tim van der Lippe2c891972021-07-29 16:22:50 +010069 const parser = moduleRequire(parserPath);
Tim van der Lippefdbd42e2020-04-07 15:14:36 +010070
71 if (typeof parser.parseForESLint === 'function') {
Tim van der Lippe2c891972021-07-29 16:22:50 +010072 let ast;
Tim van der Lippefdbd42e2020-04-07 15:14:36 +010073 try {
Tim van der Lippebc3a0b72021-11-08 15:22:37 +000074 const parserRaw = parser.parseForESLint(content, parserOptions);
75 ast = parserRaw.ast;
76 return {
77 ast,
78 visitorKeys: keysFromParser(parserPath, parser, parserRaw),
79 };
Tim van der Lippefdbd42e2020-04-07 15:14:36 +010080 } catch (e) {
Tim van der Lippe2c891972021-07-29 16:22:50 +010081 console.warn();
82 console.warn('Error while parsing ' + parserOptions.filePath);
83 console.warn('Line ' + e.lineNumber + ', column ' + e.column + ': ' + e.message);
Tim van der Lippefdbd42e2020-04-07 15:14:36 +010084 }
85 if (!ast || typeof ast !== 'object') {
Tim van der Lippebc3a0b72021-11-08 15:22:37 +000086 console.warn(
87 '`parseForESLint` from parser `' +
88 parserPath +
89 '` is invalid and will just be ignored'
90 );
Tim van der Lippefdbd42e2020-04-07 15:14:36 +010091 } else {
Tim van der Lippebc3a0b72021-11-08 15:22:37 +000092 return {
93 ast,
94 visitorKeys: keysFromParser(parserPath, parser, undefined),
95 };
Tim van der Lippefdbd42e2020-04-07 15:14:36 +010096 }
97 }
98
Tim van der Lippebc3a0b72021-11-08 15:22:37 +000099 const keys = keysFromParser(parserPath, parser, undefined);
100 return {
101 ast: parser.parse(content, parserOptions),
102 visitorKeys: keys,
103 };
Tim van der Lippe2c891972021-07-29 16:22:50 +0100104};
Tim van der Lippefdbd42e2020-04-07 15:14:36 +0100105
106function getParserPath(path, context) {
Tim van der Lippe2c891972021-07-29 16:22:50 +0100107 const parsers = context.settings['import/parsers'];
Tim van der Lippefdbd42e2020-04-07 15:14:36 +0100108 if (parsers != null) {
Tim van der Lippe2c891972021-07-29 16:22:50 +0100109 const extension = extname(path);
110 for (const parserPath in parsers) {
Tim van der Lippefdbd42e2020-04-07 15:14:36 +0100111 if (parsers[parserPath].indexOf(extension) > -1) {
112 // use this alternate parser
Tim van der Lippe2c891972021-07-29 16:22:50 +0100113 log('using alt parser:', parserPath);
114 return parserPath;
Tim van der Lippefdbd42e2020-04-07 15:14:36 +0100115 }
116 }
117 }
118 // default to use ESLint parser
Tim van der Lippe2c891972021-07-29 16:22:50 +0100119 return context.parserPath;
Tim van der Lippefdbd42e2020-04-07 15:14:36 +0100120}