init source
This commit is contained in:
+67
@@ -0,0 +1,67 @@
|
||||
# Change Log
|
||||
All notable changes to this module will be documented in this file.
|
||||
This project adheres to [Semantic Versioning](http://semver.org/).
|
||||
This change log adheres to standards from [Keep a CHANGELOG](http://keepachangelog.com).
|
||||
|
||||
## Unreleased
|
||||
|
||||
## v2.4.1 - 2019-07-19
|
||||
|
||||
### Fixed
|
||||
- Improve parse perf when using `@typescript-eslint/parser` ([#1409], thanks [@bradzacher])
|
||||
- Improve support for Typescript declare structures ([#1356], thanks [@christophercurrie])
|
||||
|
||||
## v2.4.0 - 2019-04-13
|
||||
|
||||
### Added
|
||||
- no-useless-path-segments: Add noUselessIndex option ([#1290], thanks [@timkraut])
|
||||
|
||||
### Fixed
|
||||
- Fix overwriting of dynamic import() CallExpression ([`no-cycle`], [`no-relative-parent-import`], [`no-unresolved`], [`no-useless-path-segments`]) ([#1218], [#1166], [#1035], thanks [@vikr01])
|
||||
|
||||
|
||||
## v2.3.0 - 2019-01-22
|
||||
### Fixed
|
||||
- use `process.hrtime()` for cache dates ([#1160], thanks [@hulkish])
|
||||
|
||||
## v2.2.0 - 2018-03-29
|
||||
### Changed
|
||||
- `parse`: attach node locations by default.
|
||||
- `moduleVisitor`: visitor now gets the full `import` statement node as a second
|
||||
argument, so rules may report against the full statement / `require` call instead
|
||||
of only the string literal node.
|
||||
|
||||
## v2.1.1 - 2017-06-22
|
||||
|
||||
Re-releasing v2.1.0 after vetting (again) and unable to reproduce issue.
|
||||
|
||||
|
||||
## v2.1.0 - 2017-06-02 [YANKED]
|
||||
|
||||
Yanked due to critical issue with cache key resulting from #839.
|
||||
|
||||
### Added
|
||||
- `parse` now additionally passes `filePath` to `parser` in `parserOptions` like `eslint` core does
|
||||
|
||||
## v2.0.0 - 2016-11-07
|
||||
### Changed
|
||||
- `unambiguous` no longer exposes fast test regex
|
||||
|
||||
### Fixed
|
||||
- `unambiguous.test()` regex is now properly in multiline mode
|
||||
|
||||
|
||||
|
||||
[#1409]: https://github.com/benmosher/eslint-plugin-import/pull/1409
|
||||
[#1356]: https://github.com/benmosher/eslint-plugin-import/pull/1356
|
||||
[#1290]: https://github.com/benmosher/eslint-plugin-import/pull/1290
|
||||
[#1218]: https://github.com/benmosher/eslint-plugin-import/pull/1218
|
||||
[#1166]: https://github.com/benmosher/eslint-plugin-import/issues/1166
|
||||
[#1160]: https://github.com/benmosher/eslint-plugin-import/pull/1160
|
||||
[#1035]: https://github.com/benmosher/eslint-plugin-import/issues/1035
|
||||
|
||||
[@hulkish]: https://github.com/hulkish
|
||||
[@timkraut]: https://github.com/timkraut
|
||||
[@vikr01]: https://github.com/vikr01
|
||||
[@bradzacher]: https://github.com/bradzacher
|
||||
[@christophercurrie]: https://github.com/christophercurrie
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
"use strict"
|
||||
exports.__esModule = true
|
||||
|
||||
const log = require('debug')('eslint-module-utils:ModuleCache')
|
||||
|
||||
class ModuleCache {
|
||||
constructor(map) {
|
||||
this.map = map || new Map()
|
||||
}
|
||||
|
||||
/**
|
||||
* returns value for returning inline
|
||||
* @param {[type]} cacheKey [description]
|
||||
* @param {[type]} result [description]
|
||||
*/
|
||||
set(cacheKey, result) {
|
||||
this.map.set(cacheKey, { result, lastSeen: process.hrtime() })
|
||||
log('setting entry for', cacheKey)
|
||||
return result
|
||||
}
|
||||
|
||||
get(cacheKey, settings) {
|
||||
if (this.map.has(cacheKey)) {
|
||||
const f = this.map.get(cacheKey)
|
||||
// check fresness
|
||||
if (process.hrtime(f.lastSeen)[0] < settings.lifetime) return f.result
|
||||
} else log('cache miss for', cacheKey)
|
||||
// cache miss
|
||||
return undefined
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
ModuleCache.getSettings = function (settings) {
|
||||
const cacheSettings = Object.assign({
|
||||
lifetime: 30, // seconds
|
||||
}, settings['import/cache'])
|
||||
|
||||
// parse infinity
|
||||
if (cacheSettings.lifetime === '∞' || cacheSettings.lifetime === 'Infinity') {
|
||||
cacheSettings.lifetime = Infinity
|
||||
}
|
||||
|
||||
return cacheSettings
|
||||
}
|
||||
|
||||
exports.default = ModuleCache
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
"use strict"
|
||||
exports.__esModule = true
|
||||
|
||||
exports.default = function declaredScope(context, name) {
|
||||
let references = context.getScope().references
|
||||
, i
|
||||
for (i = 0; i < references.length; i++) {
|
||||
if (references[i].identifier.name === name) {
|
||||
break
|
||||
}
|
||||
}
|
||||
if (!references[i]) return undefined
|
||||
return references[i].resolved.scope.type
|
||||
}
|
||||
+59
@@ -0,0 +1,59 @@
|
||||
/**
|
||||
* utilities for hashing config objects.
|
||||
* basically iteratively updates hash with a JSON-like format
|
||||
*/
|
||||
"use strict"
|
||||
exports.__esModule = true
|
||||
|
||||
const createHash = require('crypto').createHash
|
||||
|
||||
const stringify = JSON.stringify
|
||||
|
||||
function hashify(value, hash) {
|
||||
if (!hash) hash = createHash('sha256')
|
||||
|
||||
if (value instanceof Array) {
|
||||
hashArray(value, hash)
|
||||
} else if (value instanceof Object) {
|
||||
hashObject(value, hash)
|
||||
} else {
|
||||
hash.update(stringify(value) || 'undefined')
|
||||
}
|
||||
|
||||
return hash
|
||||
}
|
||||
exports.default = hashify
|
||||
|
||||
function hashArray(array, hash) {
|
||||
if (!hash) hash = createHash('sha256')
|
||||
|
||||
hash.update('[')
|
||||
for (let i = 0; i < array.length; i++) {
|
||||
hashify(array[i], hash)
|
||||
hash.update(',')
|
||||
}
|
||||
hash.update(']')
|
||||
|
||||
return hash
|
||||
}
|
||||
hashify.array = hashArray
|
||||
exports.hashArray = hashArray
|
||||
|
||||
function hashObject(object, hash) {
|
||||
if (!hash) hash = createHash('sha256')
|
||||
|
||||
hash.update("{")
|
||||
Object.keys(object).sort().forEach(key => {
|
||||
hash.update(stringify(key))
|
||||
hash.update(':')
|
||||
hashify(object[key], hash)
|
||||
hash.update(",")
|
||||
})
|
||||
hash.update('}')
|
||||
|
||||
return hash
|
||||
}
|
||||
hashify.object = hashObject
|
||||
exports.hashObject = hashObject
|
||||
|
||||
|
||||
+60
@@ -0,0 +1,60 @@
|
||||
'use strict'
|
||||
exports.__esModule = true
|
||||
|
||||
const extname = require('path').extname
|
||||
|
||||
const log = require('debug')('eslint-plugin-import:utils:ignore')
|
||||
|
||||
// one-shot memoized
|
||||
let cachedSet, lastSettings
|
||||
function validExtensions(context) {
|
||||
if (cachedSet && context.settings === lastSettings) {
|
||||
return cachedSet
|
||||
}
|
||||
|
||||
lastSettings = context.settings
|
||||
cachedSet = makeValidExtensionSet(context.settings)
|
||||
return cachedSet
|
||||
}
|
||||
|
||||
function makeValidExtensionSet(settings) {
|
||||
// start with explicit JS-parsed extensions
|
||||
const exts = new Set(settings['import/extensions'] || [ '.js' ])
|
||||
|
||||
// all alternate parser extensions are also valid
|
||||
if ('import/parsers' in settings) {
|
||||
for (let parser in settings['import/parsers']) {
|
||||
const parserSettings = settings['import/parsers'][parser]
|
||||
if (!Array.isArray(parserSettings)) {
|
||||
throw new TypeError('"settings" for ' + parser + ' must be an array')
|
||||
}
|
||||
parserSettings.forEach(ext => exts.add(ext))
|
||||
}
|
||||
}
|
||||
|
||||
return exts
|
||||
}
|
||||
exports.getFileExtensions = makeValidExtensionSet
|
||||
|
||||
exports.default = function ignore(path, context) {
|
||||
// check extension whitelist first (cheap)
|
||||
if (!hasValidExtension(path, context)) return true
|
||||
|
||||
if (!('import/ignore' in context.settings)) return false
|
||||
const ignoreStrings = context.settings['import/ignore']
|
||||
|
||||
for (let i = 0; i < ignoreStrings.length; i++) {
|
||||
const regex = new RegExp(ignoreStrings[i])
|
||||
if (regex.test(path)) {
|
||||
log(`ignoring ${path}, matched pattern /${ignoreStrings[i]}/`)
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
function hasValidExtension(path, context) {
|
||||
return validExtensions(context).has(extname(path))
|
||||
}
|
||||
exports.hasValidExtension = hasValidExtension
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
"use strict"
|
||||
exports.__esModule = true
|
||||
|
||||
const Module = require('module')
|
||||
const path = require('path')
|
||||
|
||||
// borrowed from babel-eslint
|
||||
function createModule(filename) {
|
||||
const mod = new Module(filename)
|
||||
mod.filename = filename
|
||||
mod.paths = Module._nodeModulePaths(path.dirname(filename))
|
||||
return mod
|
||||
}
|
||||
|
||||
exports.default = function moduleRequire(p) {
|
||||
try {
|
||||
// attempt to get espree relative to eslint
|
||||
const eslintPath = require.resolve('eslint')
|
||||
const eslintModule = createModule(eslintPath)
|
||||
return require(Module._resolveFilename(p, eslintModule))
|
||||
} catch(err) { /* ignore */ }
|
||||
|
||||
try {
|
||||
// try relative to entry point
|
||||
return require.main.require(p)
|
||||
} catch(err) { /* ignore */ }
|
||||
|
||||
// finally, try from here
|
||||
return require(p)
|
||||
}
|
||||
+141
@@ -0,0 +1,141 @@
|
||||
'use strict'
|
||||
exports.__esModule = true
|
||||
|
||||
/**
|
||||
* Returns an object of node visitors that will call
|
||||
* 'visitor' with every discovered module path.
|
||||
*
|
||||
* todo: correct function prototype for visitor
|
||||
* @param {Function(String)} visitor [description]
|
||||
* @param {[type]} options [description]
|
||||
* @return {object}
|
||||
*/
|
||||
exports.default = function visitModules(visitor, options) {
|
||||
// if esmodule is not explicitly disabled, it is assumed to be enabled
|
||||
options = Object.assign({ esmodule: true }, options)
|
||||
|
||||
let ignoreRegExps = []
|
||||
if (options.ignore != null) {
|
||||
ignoreRegExps = options.ignore.map(p => new RegExp(p))
|
||||
}
|
||||
|
||||
function checkSourceValue(source, importer) {
|
||||
if (source == null) return //?
|
||||
|
||||
// handle ignore
|
||||
if (ignoreRegExps.some(re => re.test(source.value))) return
|
||||
|
||||
// fire visitor
|
||||
visitor(source, importer)
|
||||
}
|
||||
|
||||
// for import-y declarations
|
||||
function checkSource(node) {
|
||||
checkSourceValue(node.source, node)
|
||||
}
|
||||
|
||||
// for esmodule dynamic `import()` calls
|
||||
function checkImportCall(node) {
|
||||
if (node.callee.type !== 'Import') return
|
||||
if (node.arguments.length !== 1) return
|
||||
|
||||
const modulePath = node.arguments[0]
|
||||
if (modulePath.type !== 'Literal') return
|
||||
if (typeof modulePath.value !== 'string') return
|
||||
|
||||
checkSourceValue(modulePath, node)
|
||||
}
|
||||
|
||||
// for CommonJS `require` calls
|
||||
// adapted from @mctep: http://git.io/v4rAu
|
||||
function checkCommon(call) {
|
||||
if (call.callee.type !== 'Identifier') return
|
||||
if (call.callee.name !== 'require') return
|
||||
if (call.arguments.length !== 1) return
|
||||
|
||||
const modulePath = call.arguments[0]
|
||||
if (modulePath.type !== 'Literal') return
|
||||
if (typeof modulePath.value !== 'string') return
|
||||
|
||||
checkSourceValue(modulePath, call)
|
||||
}
|
||||
|
||||
function checkAMD(call) {
|
||||
if (call.callee.type !== 'Identifier') return
|
||||
if (call.callee.name !== 'require' &&
|
||||
call.callee.name !== 'define') return
|
||||
if (call.arguments.length !== 2) return
|
||||
|
||||
const modules = call.arguments[0]
|
||||
if (modules.type !== 'ArrayExpression') return
|
||||
|
||||
for (let element of modules.elements) {
|
||||
if (element.type !== 'Literal') continue
|
||||
if (typeof element.value !== 'string') continue
|
||||
|
||||
if (element.value === 'require' ||
|
||||
element.value === 'exports') continue // magic modules: http://git.io/vByan
|
||||
|
||||
checkSourceValue(element, element)
|
||||
}
|
||||
}
|
||||
|
||||
const visitors = {}
|
||||
if (options.esmodule) {
|
||||
Object.assign(visitors, {
|
||||
'ImportDeclaration': checkSource,
|
||||
'ExportNamedDeclaration': checkSource,
|
||||
'ExportAllDeclaration': checkSource,
|
||||
'CallExpression': checkImportCall,
|
||||
})
|
||||
}
|
||||
|
||||
if (options.commonjs || options.amd) {
|
||||
const currentCallExpression = visitors['CallExpression']
|
||||
visitors['CallExpression'] = function (call) {
|
||||
if (currentCallExpression) currentCallExpression(call)
|
||||
if (options.commonjs) checkCommon(call)
|
||||
if (options.amd) checkAMD(call)
|
||||
}
|
||||
}
|
||||
|
||||
return visitors
|
||||
}
|
||||
|
||||
/**
|
||||
* make an options schema for the module visitor, optionally
|
||||
* adding extra fields.
|
||||
*/
|
||||
function makeOptionsSchema(additionalProperties) {
|
||||
const base = {
|
||||
'type': 'object',
|
||||
'properties': {
|
||||
'commonjs': { 'type': 'boolean' },
|
||||
'amd': { 'type': 'boolean' },
|
||||
'esmodule': { 'type': 'boolean' },
|
||||
'ignore': {
|
||||
'type': 'array',
|
||||
'minItems': 1,
|
||||
'items': { 'type': 'string' },
|
||||
'uniqueItems': true,
|
||||
},
|
||||
},
|
||||
'additionalProperties': false,
|
||||
}
|
||||
|
||||
if (additionalProperties){
|
||||
for (let key in additionalProperties) {
|
||||
base.properties[key] = additionalProperties[key]
|
||||
}
|
||||
}
|
||||
|
||||
return base
|
||||
}
|
||||
exports.makeOptionsSchema = makeOptionsSchema
|
||||
|
||||
/**
|
||||
* json schema object for options parameter. can be used to build
|
||||
* rule options schema object.
|
||||
* @type {Object}
|
||||
*/
|
||||
exports.optionsSchema = makeOptionsSchema()
|
||||
+63
@@ -0,0 +1,63 @@
|
||||
{
|
||||
"_args": [
|
||||
[
|
||||
"eslint-module-utils@2.4.1",
|
||||
"/home/app"
|
||||
]
|
||||
],
|
||||
"_development": true,
|
||||
"_from": "eslint-module-utils@2.4.1",
|
||||
"_id": "eslint-module-utils@2.4.1",
|
||||
"_inBundle": false,
|
||||
"_integrity": "sha512-H6DOj+ejw7Tesdgbfs4jeS4YMFrT8uI8xwd1gtQqXssaR0EQ26L+2O/w6wkYFy2MymON0fTwHmXBvvfLNZVZEw==",
|
||||
"_location": "/eslint-module-utils",
|
||||
"_phantomChildren": {},
|
||||
"_requested": {
|
||||
"type": "version",
|
||||
"registry": true,
|
||||
"raw": "eslint-module-utils@2.4.1",
|
||||
"name": "eslint-module-utils",
|
||||
"escapedName": "eslint-module-utils",
|
||||
"rawSpec": "2.4.1",
|
||||
"saveSpec": null,
|
||||
"fetchSpec": "2.4.1"
|
||||
},
|
||||
"_requiredBy": [
|
||||
"/eslint-plugin-import"
|
||||
],
|
||||
"_resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.4.1.tgz",
|
||||
"_spec": "2.4.1",
|
||||
"_where": "/home/app",
|
||||
"author": {
|
||||
"name": "Ben Mosher",
|
||||
"email": "me@benmosher.com"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/benmosher/eslint-plugin-import/issues"
|
||||
},
|
||||
"dependencies": {
|
||||
"debug": "^2.6.8",
|
||||
"pkg-dir": "^2.0.0"
|
||||
},
|
||||
"description": "Core utilities to support eslint-plugin-import and other module-related plugins.",
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
},
|
||||
"homepage": "https://github.com/benmosher/eslint-plugin-import#readme",
|
||||
"keywords": [
|
||||
"eslint-plugin-import",
|
||||
"eslint",
|
||||
"modules",
|
||||
"esmodules"
|
||||
],
|
||||
"license": "MIT",
|
||||
"name": "eslint-module-utils",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/benmosher/eslint-plugin-import.git"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"version": "2.4.1"
|
||||
}
|
||||
+62
@@ -0,0 +1,62 @@
|
||||
"use strict"
|
||||
exports.__esModule = true
|
||||
|
||||
const moduleRequire = require('./module-require').default
|
||||
const extname = require('path').extname
|
||||
|
||||
const log = require('debug')('eslint-plugin-import:parse')
|
||||
|
||||
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/benmosher/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)
|
||||
|
||||
return parser.parse(content, parserOptions)
|
||||
}
|
||||
|
||||
function getParserPath(path, context) {
|
||||
const parsers = context.settings['import/parsers']
|
||||
if (parsers != null) {
|
||||
const extension = extname(path)
|
||||
for (let 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
|
||||
}
|
||||
+206
@@ -0,0 +1,206 @@
|
||||
"use strict"
|
||||
exports.__esModule = true
|
||||
|
||||
const pkgDir = require('pkg-dir')
|
||||
|
||||
const fs = require('fs')
|
||||
const path = require('path')
|
||||
|
||||
const hashObject = require('./hash').hashObject
|
||||
, ModuleCache = require('./ModuleCache').default
|
||||
|
||||
const CASE_SENSITIVE_FS = !fs.existsSync(path.join(__dirname, 'reSOLVE.js'))
|
||||
exports.CASE_SENSITIVE_FS = CASE_SENSITIVE_FS
|
||||
|
||||
const fileExistsCache = new ModuleCache()
|
||||
|
||||
function tryRequire(target) {
|
||||
let resolved;
|
||||
try {
|
||||
// Check if the target exists
|
||||
resolved = require.resolve(target);
|
||||
} catch(e) {
|
||||
// If the target does not exist then just return undefined
|
||||
return undefined;
|
||||
}
|
||||
|
||||
// If the target exists then return the loaded module
|
||||
return require(resolved);
|
||||
}
|
||||
|
||||
// http://stackoverflow.com/a/27382838
|
||||
exports.fileExistsWithCaseSync = function fileExistsWithCaseSync(filepath, cacheSettings) {
|
||||
// don't care if the FS is case-sensitive
|
||||
if (CASE_SENSITIVE_FS) return true
|
||||
|
||||
// null means it resolved to a builtin
|
||||
if (filepath === null) return true
|
||||
if (filepath.toLowerCase() === process.cwd().toLowerCase()) return true
|
||||
const parsedPath = path.parse(filepath)
|
||||
, dir = parsedPath.dir
|
||||
|
||||
let result = fileExistsCache.get(filepath, cacheSettings)
|
||||
if (result != null) return result
|
||||
|
||||
// base case
|
||||
if (dir === '' || parsedPath.root === filepath) {
|
||||
result = true
|
||||
} else {
|
||||
const filenames = fs.readdirSync(dir)
|
||||
if (filenames.indexOf(parsedPath.base) === -1) {
|
||||
result = false
|
||||
} else {
|
||||
result = fileExistsWithCaseSync(dir, cacheSettings)
|
||||
}
|
||||
}
|
||||
fileExistsCache.set(filepath, result)
|
||||
return result
|
||||
}
|
||||
|
||||
function relative(modulePath, sourceFile, settings) {
|
||||
return fullResolve(modulePath, sourceFile, settings).path
|
||||
}
|
||||
|
||||
function fullResolve(modulePath, sourceFile, settings) {
|
||||
// check if this is a bonus core module
|
||||
const coreSet = new Set(settings['import/core-modules'])
|
||||
if (coreSet != null && coreSet.has(modulePath)) return { found: true, path: null }
|
||||
|
||||
const sourceDir = path.dirname(sourceFile)
|
||||
, cacheKey = sourceDir + hashObject(settings).digest('hex') + modulePath
|
||||
|
||||
const cacheSettings = ModuleCache.getSettings(settings)
|
||||
|
||||
const cachedPath = fileExistsCache.get(cacheKey, cacheSettings)
|
||||
if (cachedPath !== undefined) return { found: true, path: cachedPath }
|
||||
|
||||
function cache(resolvedPath) {
|
||||
fileExistsCache.set(cacheKey, resolvedPath)
|
||||
}
|
||||
|
||||
function withResolver(resolver, config) {
|
||||
|
||||
function v1() {
|
||||
try {
|
||||
const resolved = resolver.resolveImport(modulePath, sourceFile, config)
|
||||
if (resolved === undefined) return { found: false }
|
||||
return { found: true, path: resolved }
|
||||
} catch (err) {
|
||||
return { found: false }
|
||||
}
|
||||
}
|
||||
|
||||
function v2() {
|
||||
return resolver.resolve(modulePath, sourceFile, config)
|
||||
}
|
||||
|
||||
switch (resolver.interfaceVersion) {
|
||||
case 2:
|
||||
return v2()
|
||||
|
||||
default:
|
||||
case 1:
|
||||
return v1()
|
||||
}
|
||||
}
|
||||
|
||||
const configResolvers = (settings['import/resolver']
|
||||
|| { 'node': settings['import/resolve'] }) // backward compatibility
|
||||
|
||||
const resolvers = resolverReducer(configResolvers, new Map())
|
||||
|
||||
for (let pair of resolvers) {
|
||||
let name = pair[0]
|
||||
, config = pair[1]
|
||||
const resolver = requireResolver(name, sourceFile)
|
||||
, resolved = withResolver(resolver, config)
|
||||
|
||||
if (!resolved.found) continue
|
||||
|
||||
// else, counts
|
||||
cache(resolved.path)
|
||||
return resolved
|
||||
}
|
||||
|
||||
// failed
|
||||
// cache(undefined)
|
||||
return { found: false }
|
||||
}
|
||||
exports.relative = relative
|
||||
|
||||
function resolverReducer(resolvers, map) {
|
||||
if (resolvers instanceof Array) {
|
||||
resolvers.forEach(r => resolverReducer(r, map))
|
||||
return map
|
||||
}
|
||||
|
||||
if (typeof resolvers === 'string') {
|
||||
map.set(resolvers, null)
|
||||
return map
|
||||
}
|
||||
|
||||
if (typeof resolvers === 'object') {
|
||||
for (let key in resolvers) {
|
||||
map.set(key, resolvers[key])
|
||||
}
|
||||
return map
|
||||
}
|
||||
|
||||
throw new Error('invalid resolver config')
|
||||
}
|
||||
|
||||
function getBaseDir(sourceFile) {
|
||||
return pkgDir.sync(sourceFile) || process.cwd()
|
||||
}
|
||||
function requireResolver(name, sourceFile) {
|
||||
// Try to resolve package with conventional name
|
||||
let resolver = tryRequire(`eslint-import-resolver-${name}`) ||
|
||||
tryRequire(name) ||
|
||||
tryRequire(path.resolve(getBaseDir(sourceFile), name))
|
||||
|
||||
if (!resolver) {
|
||||
throw new Error(`unable to load resolver "${name}".`)
|
||||
}
|
||||
if (!isResolverValid(resolver)) {
|
||||
throw new Error(`${name} with invalid interface loaded as resolver`)
|
||||
}
|
||||
|
||||
return resolver
|
||||
}
|
||||
|
||||
function isResolverValid(resolver) {
|
||||
if (resolver.interfaceVersion === 2) {
|
||||
return resolver.resolve && typeof resolver.resolve === 'function'
|
||||
} else {
|
||||
return resolver.resolveImport && typeof resolver.resolveImport === 'function'
|
||||
}
|
||||
}
|
||||
|
||||
const erroredContexts = new Set()
|
||||
|
||||
/**
|
||||
* Given
|
||||
* @param {string} p - module path
|
||||
* @param {object} context - ESLint context
|
||||
* @return {string} - the full module filesystem path;
|
||||
* null if package is core;
|
||||
* undefined if not found
|
||||
*/
|
||||
function resolve(p, context) {
|
||||
try {
|
||||
return relative( p
|
||||
, context.getFilename()
|
||||
, context.settings
|
||||
)
|
||||
} catch (err) {
|
||||
if (!erroredContexts.has(context)) {
|
||||
context.report({
|
||||
message: `Resolve error: ${err.message}`,
|
||||
loc: { line: 1, column: 0 },
|
||||
})
|
||||
erroredContexts.add(context)
|
||||
}
|
||||
}
|
||||
}
|
||||
resolve.relative = relative
|
||||
exports.default = resolve
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
'use strict'
|
||||
exports.__esModule = true
|
||||
|
||||
|
||||
const pattern = /(^|;)\s*(export|import)((\s+\w)|(\s*[{*=]))/m
|
||||
/**
|
||||
* detect possible imports/exports without a full parse.
|
||||
*
|
||||
* A negative test means that a file is definitely _not_ a module.
|
||||
* A positive test means it _could_ be.
|
||||
*
|
||||
* Not perfect, just a fast way to disqualify large non-ES6 modules and
|
||||
* avoid a parse.
|
||||
* @type {RegExp}
|
||||
*/
|
||||
exports.test = function isMaybeUnambiguousModule(content) {
|
||||
return pattern.test(content)
|
||||
}
|
||||
|
||||
// future-/Babel-proof at the expense of being a little loose
|
||||
const unambiguousNodeType = /^(?:(?:Exp|Imp)ort.*Declaration|TSExportAssignment)$/
|
||||
|
||||
/**
|
||||
* Given an AST, return true if the AST unambiguously represents a module.
|
||||
* @param {Program node} ast
|
||||
* @return {Boolean}
|
||||
*/
|
||||
exports.isModule = function isUnambiguousModule(ast) {
|
||||
return ast.body.some(node => unambiguousNodeType.test(node.type))
|
||||
}
|
||||
Reference in New Issue
Block a user