2021-08-13 17:58:13 +08:00

136 lines
3.7 KiB
JavaScript

import {
dirname, join, basename, relative, extname
} from 'path';
import {
compatESModuleRequire,
resolve,
winPath,
pkgUp,
lodash
} from '@fesjs/utils';
import { PluginType } from '../enums';
const RE = {
[PluginType.plugin]: /^(@fesjs\/|@webank\/fes-|fes-)plugin-/,
[PluginType.preset]: /^(@fesjs\/|@webank\/fes-|fes-)preset-/
};
export function isPluginOrPreset(type, name) {
const hasScope = name.charAt(0) === '@';
const re = RE[type];
if (hasScope) {
return re.test(name.split('/')[1]) || re.test(name);
}
return re.test(name);
}
export function getPluginsOrPresets(type, opts) {
const upperCaseType = type.toUpperCase();
return [
// dependencies
// opts
...((opts[type === PluginType.preset ? 'presets' : 'plugins']) || []),
// env
...(process.env[`FES_${upperCaseType}S`] || '').split(',').filter(Boolean),
...Object.keys(opts.pkg.devDependencies || {})
.concat(Object.keys(opts.pkg.dependencies || {}))
.filter(isPluginOrPreset.bind(null, type)),
// user config
...((opts[
type === PluginType.preset ? 'userConfigPresets' : 'userConfigPlugins'
]) || [])
].map(path => resolve.sync(path, {
basedir: opts.cwd,
extensions: ['.js', '.ts']
}));
}
// e.g.
// initial-state -> initialState
// webpack.css-loader -> webpack.cssLoader
function nameToKey(name) {
return name
.split('.')
.map(part => lodash.camelCase(part))
.join('.');
}
function pkgNameToKey(pkgName, type) {
if (pkgName.charAt(0) === '@' && !pkgName.startsWith('@fesjs/')) {
pkgName = pkgName.split('/')[1];
}
return nameToKey(pkgName.replace(RE[type], ''));
}
export function pathToObj({ path, type, cwd }) {
let pkg = null;
let isPkgPlugin = false;
const pkgJSONPath = pkgUp.sync({ cwd: path });
if (pkgJSONPath) {
// eslint-disable-next-line
pkg = require(pkgJSONPath);
isPkgPlugin = winPath(join(dirname(pkgJSONPath), pkg.main || 'index.js'))
=== winPath(path);
}
let id;
if (isPkgPlugin) {
id = pkg.name;
} else if (winPath(path).startsWith(winPath(cwd))) {
id = `./${winPath(relative(cwd, path))}`;
} else if (pkgJSONPath) {
id = winPath(join(pkg.name, relative(dirname(pkgJSONPath), path)));
} else {
id = winPath(path);
}
id = id.replace('@fesjs/preset-built-in/lib/plugins', '@@');
id = id.replace(/\.js$/, '');
const key = isPkgPlugin
? pkgNameToKey(pkg.name, type)
: nameToKey(basename(path, extname(path)));
return {
id,
key,
path: winPath(path),
apply() {
// use function to delay require
try {
// eslint-disable-next-line
const ret = require(path);
// use the default member for es modules
return compatESModuleRequire(ret);
} catch (e) {
throw new Error(`Register ${path} failed, since ${e.message}`);
}
},
defaultConfig: null
};
}
export function resolvePresets(opts) {
const type = PluginType.preset;
const presets = [...getPluginsOrPresets(type, opts)];
return presets.map(path => pathToObj({
type,
path,
cwd: opts.cwd
}));
}
export function resolvePlugins(opts) {
const type = PluginType.plugin;
const plugins = getPluginsOrPresets(type, opts);
return plugins.map(path => pathToObj({
path,
type,
cwd: opts.cwd
}));
}
export function isValidPlugin(plugin) {
return plugin.id && plugin.key && plugin.apply;
}