Tim van der Lippe | fdbd42e | 2020-04-07 15:14:36 +0100 | [diff] [blame] | 1 | 'use strict' |
| 2 | exports.__esModule = true |
| 3 | |
| 4 | const moduleRequire = require('./module-require').default |
| 5 | const extname = require('path').extname |
| 6 | |
| 7 | const log = require('debug')('eslint-plugin-import:parse') |
| 8 | |
| 9 | exports.default = function parse(path, content, context) { |
| 10 | |
| 11 | if (context == null) throw new Error('need context to parse properly') |
| 12 | |
| 13 | let parserOptions = context.parserOptions |
| 14 | const parserPath = getParserPath(path, context) |
| 15 | |
| 16 | if (!parserPath) throw new Error('parserPath is required!') |
| 17 | |
| 18 | // hack: espree blows up with frozen options |
| 19 | parserOptions = Object.assign({}, parserOptions) |
| 20 | parserOptions.ecmaFeatures = Object.assign({}, parserOptions.ecmaFeatures) |
| 21 | |
| 22 | // always include comments and tokens (for doc parsing) |
| 23 | parserOptions.comment = true |
| 24 | parserOptions.attachComment = true // keeping this for backward-compat with older parsers |
| 25 | parserOptions.tokens = true |
| 26 | |
| 27 | // attach node locations |
| 28 | parserOptions.loc = true |
| 29 | parserOptions.range = true |
| 30 | |
| 31 | // provide the `filePath` like eslint itself does, in `parserOptions` |
| 32 | // https://github.com/eslint/eslint/blob/3ec436ee/lib/linter.js#L637 |
| 33 | parserOptions.filePath = path |
| 34 | |
| 35 | // @typescript-eslint/parser will parse the entire project with typechecking if you provide |
| 36 | // "project" or "projects" in parserOptions. Removing these options means the parser will |
| 37 | // only parse one file in isolate mode, which is much, much faster. |
| 38 | // https://github.com/benmosher/eslint-plugin-import/issues/1408#issuecomment-509298962 |
| 39 | delete parserOptions.project |
| 40 | delete parserOptions.projects |
| 41 | |
| 42 | // require the parser relative to the main module (i.e., ESLint) |
| 43 | const parser = moduleRequire(parserPath) |
| 44 | |
| 45 | if (typeof parser.parseForESLint === 'function') { |
| 46 | let ast |
| 47 | try { |
| 48 | ast = parser.parseForESLint(content, parserOptions).ast |
| 49 | } catch (e) { |
| 50 | console.warn() |
| 51 | console.warn('Error while parsing ' + parserOptions.filePath) |
| 52 | console.warn('Line ' + e.lineNumber + ', column ' + e.column + ': ' + e.message) |
| 53 | } |
| 54 | if (!ast || typeof ast !== 'object') { |
| 55 | console.warn( |
| 56 | '`parseForESLint` from parser `' + |
| 57 | parserPath + |
| 58 | '` is invalid and will just be ignored' |
| 59 | ) |
| 60 | } else { |
| 61 | return ast |
| 62 | } |
| 63 | } |
| 64 | |
| 65 | return parser.parse(content, parserOptions) |
| 66 | } |
| 67 | |
| 68 | function getParserPath(path, context) { |
| 69 | const parsers = context.settings['import/parsers'] |
| 70 | if (parsers != null) { |
| 71 | const extension = extname(path) |
| 72 | for (let parserPath in parsers) { |
| 73 | if (parsers[parserPath].indexOf(extension) > -1) { |
| 74 | // use this alternate parser |
| 75 | log('using alt parser:', parserPath) |
| 76 | return parserPath |
| 77 | } |
| 78 | } |
| 79 | } |
| 80 | // default to use ESLint parser |
| 81 | return context.parserPath |
| 82 | } |