134 lines
4.0 KiB
JavaScript
134 lines
4.0 KiB
JavaScript
'use strict'
|
|
|
|
const path = require('path')
|
|
|
|
const ExtendableError = require('es6-error')
|
|
const pkgDir = require('pkg-dir')
|
|
const resolveFrom = require('resolve-from')
|
|
|
|
class ResolveError extends ExtendableError {
|
|
constructor (source, kind, ref) {
|
|
super(`${source}: Couldn't find ${kind} ${JSON.stringify(ref)} relative to directory`)
|
|
this.source = source
|
|
this.ref = ref
|
|
this.isPlugin = kind === 'plugin'
|
|
this.isPreset = kind === 'preset'
|
|
}
|
|
}
|
|
|
|
function normalize (arr) {
|
|
if (!Array.isArray(arr)) return []
|
|
|
|
return arr.map(item => Array.isArray(item) ? item[0] : item)
|
|
}
|
|
|
|
function isFilePath (ref) {
|
|
return path.isAbsolute(ref) || ref.startsWith('./') || ref.startsWith('../')
|
|
}
|
|
|
|
function resolveName (name, fromDir, cache) {
|
|
if (cache.has(name)) return cache.get(name)
|
|
|
|
const filename = resolveFrom.silent(fromDir, name)
|
|
cache.set(name, filename)
|
|
return filename
|
|
}
|
|
|
|
function resolvePackage (filename, fromFile) {
|
|
if (fromFile) return null
|
|
|
|
return pkgDir.sync(filename)
|
|
}
|
|
|
|
function resolvePluginsAndPresets (chains, sharedCache) {
|
|
const dirCaches = (sharedCache && sharedCache.pluginsAndPresets) || new Map()
|
|
const getCache = dir => {
|
|
if (dirCaches.has(dir)) return dirCaches.get(dir)
|
|
|
|
const cache = new Map()
|
|
dirCaches.set(dir, cache)
|
|
return cache
|
|
}
|
|
|
|
const byConfig = new Map()
|
|
for (const chain of chains) {
|
|
for (const config of chain) {
|
|
if (byConfig.has(config)) continue
|
|
|
|
const plugins = new Map()
|
|
const presets = new Map()
|
|
byConfig.set(config, { plugins, presets })
|
|
|
|
const fromDir = config.dir
|
|
const cache = getCache(fromDir)
|
|
const resolve = (kind, ref) => {
|
|
const possibleNames = []
|
|
if (isFilePath(ref)) {
|
|
possibleNames.push({ fromFile: true, name: ref })
|
|
} else {
|
|
if (kind === 'plugin') {
|
|
// Expand possible plugin names, see
|
|
// https://github.com/babel/babel/blob/510e93b2bd434f05c816fe6639137b35bac267ed/packages/babel-core/src/helpers/get-possible-plugin-names.js
|
|
|
|
// Babel doesn't expand scoped plugin references. @ is only valid at
|
|
// the start of a package name, so disregard refs that would result
|
|
// in `babel-plugin-@scope/name`.
|
|
if (!ref.startsWith('@')) {
|
|
const name = `babel-plugin-${ref}`
|
|
possibleNames.push({ fromFile: false, name })
|
|
}
|
|
} else {
|
|
// Expand possible preset names, see
|
|
// https://github.com/babel/babel/blob/510e93b2bd434f05c816fe6639137b35bac267ed/packages/babel-core/src/helpers/get-possible-preset-names.js
|
|
|
|
if (ref.startsWith('@')) {
|
|
const matches = /^(@.+?)\/([^/]+)(.*)/.exec(ref)
|
|
const scope = matches[1]
|
|
const partialName = matches[2]
|
|
const remainder = matches[3]
|
|
|
|
const name = `${scope}/babel-preset-${partialName}${remainder}`
|
|
possibleNames.push({ fromFile: false, name })
|
|
} else {
|
|
const name = `babel-preset-${ref}`
|
|
possibleNames.push({ fromFile: false, name })
|
|
}
|
|
}
|
|
|
|
possibleNames.push({ fromFile: false, name: ref })
|
|
}
|
|
|
|
let entry = null
|
|
for (const possibility of possibleNames) {
|
|
const filename = resolveName(possibility.name, fromDir, cache)
|
|
if (filename) {
|
|
const fromPackage = resolvePackage(filename, possibility.fromFile)
|
|
entry = { filename, fromPackage }
|
|
break
|
|
}
|
|
}
|
|
if (!entry) {
|
|
throw new ResolveError(config.source, kind, ref)
|
|
}
|
|
|
|
if (kind === 'plugin') {
|
|
plugins.set(ref, entry)
|
|
} else {
|
|
presets.set(ref, entry)
|
|
}
|
|
}
|
|
|
|
for (const ref of normalize(config.options.plugins)) {
|
|
resolve('plugin', ref)
|
|
}
|
|
for (const ref of normalize(config.options.presets)) {
|
|
resolve('preset', ref)
|
|
}
|
|
}
|
|
}
|
|
|
|
return byConfig
|
|
}
|
|
|
|
module.exports = resolvePluginsAndPresets
|