From c742237d3acfbeb60d0214db5a2778271a78a6be Mon Sep 17 00:00:00 2001 From: bac-joker Date: Sat, 19 Dec 2020 16:27:58 +0800 Subject: [PATCH] feat: rename Service to service --- packages/fes-core/src/Service/enums.js | 32 -- packages/fes-core/src/Service/getPaths.js | 37 -- packages/fes-core/src/Service/index.js | 522 ------------------ packages/fes-core/src/Service/pluginAPI.js | 154 ------ .../fes-core/src/Service/utils/isPromise.js | 7 - .../fes-core/src/Service/utils/loadDotEnv.js | 18 - .../fes-core/src/Service/utils/pluginUtils.js | 135 ----- .../src/{Service => service}/PluginAPI.js | 0 8 files changed, 905 deletions(-) delete mode 100644 packages/fes-core/src/Service/enums.js delete mode 100644 packages/fes-core/src/Service/getPaths.js delete mode 100644 packages/fes-core/src/Service/index.js delete mode 100644 packages/fes-core/src/Service/pluginAPI.js delete mode 100644 packages/fes-core/src/Service/utils/isPromise.js delete mode 100644 packages/fes-core/src/Service/utils/loadDotEnv.js delete mode 100644 packages/fes-core/src/Service/utils/pluginUtils.js rename packages/fes-core/src/{Service => service}/PluginAPI.js (100%) diff --git a/packages/fes-core/src/Service/enums.js b/packages/fes-core/src/Service/enums.js deleted file mode 100644 index ee29aa4e..00000000 --- a/packages/fes-core/src/Service/enums.js +++ /dev/null @@ -1,32 +0,0 @@ -export const PluginType = { - preset: 'preset', - plugin: 'plugin' -}; - -export const ServiceStage = { - uninitialized: 0, - constructor: 1, - init: 2, - initPlugins: 3, - initHooks: 4, - pluginReady: 5, - getConfig: 6, - getPaths: 7, - run: 8 -}; - -export const ConfigChangeType = { - reload: 'reload', - regenerateTmpFiles: 'regenerateTmpFiles' -}; - -export const ApplyPluginsType = { - add: 'add', - modify: 'modify', - event: 'event' -}; - -export const EnableBy = { - register: 'register', - config: 'config' -}; diff --git a/packages/fes-core/src/Service/getPaths.js b/packages/fes-core/src/Service/getPaths.js deleted file mode 100644 index 5e725ecd..00000000 --- a/packages/fes-core/src/Service/getPaths.js +++ /dev/null @@ -1,37 +0,0 @@ -import { join } from 'path'; -import { existsSync, statSync } from 'fs'; -import { lodash, winPath } from '@umijs/utils'; - -function isDirectoryAndExist(path) { - return existsSync(path) && statSync(path).isDirectory(); -} - -function normalizeWithWinPath(obj) { - return lodash.mapValues(obj, value => winPath(value)); -} - -export default function getServicePaths({ - cwd, - config, - env -}) { - let absSrcPath = cwd; - if (isDirectoryAndExist(join(cwd, 'src'))) { - absSrcPath = join(cwd, 'src'); - } - const absPagesPath = config.singular - ? join(absSrcPath, 'page') - : join(absSrcPath, 'pages'); - - const tmpDir = ['.fes', env !== 'development' && env] - .filter(Boolean) - .join('-'); - return normalizeWithWinPath({ - cwd, - absNodeModulesPath: join(cwd, 'node_modules'), - absOutputPath: join(cwd, config.outputPath || './dist'), - absSrcPath, - absPagesPath, - absTmpPath: join(absSrcPath, tmpDir) - }); -} diff --git a/packages/fes-core/src/Service/index.js b/packages/fes-core/src/Service/index.js deleted file mode 100644 index 49f7fd89..00000000 --- a/packages/fes-core/src/Service/index.js +++ /dev/null @@ -1,522 +0,0 @@ -import { join } from 'path'; -import { EventEmitter } from 'events'; -import assert from 'assert'; -import { AsyncSeriesWaterfallHook } from 'tapable'; -import { existsSync } from 'fs'; -import { BabelRegister, lodash } from '@umijs/utils'; -import { resolvePresets, pathToObj, resolvePlugins } from './utils/pluginUtils'; -import loadDotEnv from './utils/loadDotEnv'; -import isPromise from './utils/isPromise'; -import PluginAPI from './pluginAPI'; -import { - ApplyPluginsType, - ConfigChangeType, - EnableBy, - PluginType, - ServiceStage -} from './enums'; -import Config from '../config'; -import { getUserConfigWithKey } from '../config/utils/configUtils'; -import getPaths from './getPaths'; - -// TODO -// 1. duplicated key -// 2. Logger -export default class Service extends EventEmitter { - cwd; - - pkg; - - skipPluginIds = new Set(); - - // lifecycle stage - stage = ServiceStage.uninitialized; - - // registered commands - commands = {}; - - // including plugins - plugins = {}; - - // plugin methods - pluginMethods = {}; - - // initial presets and plugins from arguments, config, process.env, and package.json - initialPresets = []; - - // initial plugins from arguments, config, process.env, and package.json - initialPlugins = []; - - _extraPresets = []; - - _extraPlugins = []; - - // user config - userConfig; - - configInstance; - - config = null; - - // babel register - babelRegister; - - // hooks - hooksByPluginId = {}; - - hooks = {}; - - // paths - paths = {}; - - env; - - ApplyPluginsType = ApplyPluginsType; - - EnableBy = EnableBy; - - ConfigChangeType = ConfigChangeType; - - ServiceStage = ServiceStage; - - args; - - constructor(opts) { - super(); - this.cwd = opts.cwd || process.cwd(); - // repoDir should be the root dir of repo - this.pkg = opts.pkg || this.resolvePackage(); - this.env = opts.env || process.env.NODE_ENV; - - assert(existsSync(this.cwd), `cwd ${this.cwd} does not exist.`); - - // register babel before config parsing - this.babelRegister = new BabelRegister(); - - // load .env or .local.env - this.loadEnv(); - - // get user config without validation - this.configInstance = new Config({ - cwd: this.cwd, - service: this, - localConfig: this.env === 'development' - }); - this.userConfig = this.configInstance.getUserConfig(); - - // get paths - this.paths = getPaths({ - cwd: this.cwd, - config: this.userConfig, - env: this.env - }); - - // setup initial plugins - const baseOpts = { - pkg: this.pkg, - cwd: this.cwd - }; - this.initialPresets = resolvePresets({ - ...baseOpts, - presets: opts.presets || [], - userConfigPresets: this.userConfig.presets || [] - }); - this.initialPlugins = resolvePlugins({ - ...baseOpts, - plugins: opts.plugins || [], - userConfigPlugins: this.userConfig.plugins || [] - }); - } - - setStage(stage) { - this.stage = stage; - } - - resolvePackage() { - try { - // eslint-disable-next-line - return require(join(this.cwd, "package.json")); - } catch (e) { - return {}; - } - } - - loadEnv() { - const basePath = join(this.cwd, '.env'); - const localPath = `${basePath}.local`; - loadDotEnv(basePath); - loadDotEnv(localPath); - } - - async init() { - this.setStage(ServiceStage.init); - await this.initPresetsAndPlugins(); - - // hooksByPluginId -> hooks - // hooks is mapped with hook key, prepared for applyPlugins() - this.setStage(ServiceStage.initHooks); - Object.keys(this.hooksByPluginId).forEach((id) => { - const hooks = this.hooksByPluginId[id]; - hooks.forEach((hook) => { - const { key } = hook; - hook.pluginId = id; - this.hooks[key] = (this.hooks[key] || []).concat(hook); - }); - }); - - // plugin is totally ready - this.setStage(ServiceStage.pluginReady); - await this.applyPlugins({ - key: 'onPluginReady', - type: ApplyPluginsType.event - }); - - // get config, including: - // 1. merge default config - // 2. validate - this.setStage(ServiceStage.getConfig); - await this.setConfig(); - - // merge paths to keep the this.paths ref - this.setStage(ServiceStage.getPaths); - // config.outputPath may be modified by plugins - if (this.config.outputPath) { - this.paths.absOutputPath = join(this.cwd, this.config.outputPath); - } - const paths = await this.applyPlugins({ - key: 'modifyPaths', - type: ApplyPluginsType.modify, - initialValue: this.paths - }); - Object.keys(paths).forEach((key) => { - this.paths[key] = paths[key]; - }); - } - - async setConfig() { - const defaultConfig = await this.applyPlugins({ - key: 'modifyDefaultConfig', - type: this.ApplyPluginsType.modify, - initialValue: await this.configInstance.getDefaultConfig() - }); - this.config = await this.applyPlugins({ - key: 'modifyConfig', - type: this.ApplyPluginsType.modify, - initialValue: this.configInstance.getConfig({ - defaultConfig - }) - }); - } - - async initPresetsAndPlugins() { - this.setStage(ServiceStage.initPresets); - this._extraPlugins = []; - while (this.initialPresets.length) { - // eslint-disable-next-line - await this.initPreset(this.initialPresets.shift()); - } - - this.setStage(ServiceStage.initPlugins); - this._extraPlugins.push(...this.initialPlugins); - while (this._extraPlugins.length) { - // eslint-disable-next-line - await this.initPlugin(this._extraPlugins.shift()); - } - } - - getPluginAPI(opts) { - const pluginAPI = new PluginAPI(opts); - - // register built-in methods - [ - 'onPluginReady', - 'modifyPaths', - 'onStart', - 'modifyDefaultConfig', - 'modifyConfig' - ].forEach((name) => { - pluginAPI.registerMethod({ - name, - exitsError: false - }); - }); - - return new Proxy(pluginAPI, { - get: (target, prop) => { - // 由于 pluginMethods 需要在 register 阶段可用 - // 必须通过 proxy 的方式动态获取最新,以实现边注册边使用的效果 - if (this.pluginMethods[prop]) return this.pluginMethods[prop]; - if ( - [ - 'applyPlugins', - 'ApplyPluginsType', - 'EnableBy', - 'ConfigChangeType', - 'babelRegister', - 'stage', - 'ServiceStage', - 'paths', - 'cwd', - 'pkg', - 'userConfig', - 'config', - 'env', - 'args', - 'hasPlugins', - 'hasPresets', - 'setConfig' - ].includes(prop) - ) { - return typeof this[prop] === 'function' - ? this[prop].bind(this) - : this[prop]; - } - return target[prop]; - } - }); - } - - async applyAPI(opts) { - let ret = opts.apply()(opts.api); - if (isPromise(ret)) { - ret = await ret; - } - return ret || {}; - } - - async initPreset(preset) { - const { id, key, apply } = preset; - preset.isPreset = true; - - const api = this.getPluginAPI({ id, key, service: this }); - - // register before apply - this.registerPlugin(preset); - const { presets, plugins } = await this.applyAPI({ - api, - apply - }); - - // register extra presets and plugins - if (presets) { - assert( - Array.isArray(presets), - `presets returned from preset ${id} must be Array.`, - ); - // 插到最前面,下个 while 循环优先执行 - this._extraPresets.splice( - 0, - 0, - ...presets.map(path => pathToObj({ - type: PluginType.preset, - path, - cwd: this.cwd - })), - ); - } - - // 深度优先 - const extraPresets = lodash.clone(this._extraPresets); - this._extraPresets = []; - while (extraPresets.length) { - // eslint-disable-next-line - await this.initPreset(extraPresets.shift()); - } - - if (plugins) { - assert( - Array.isArray(plugins), - `plugins returned from preset ${id} must be Array.`, - ); - this._extraPlugins.push( - ...plugins.map(path => pathToObj({ - type: PluginType.plugin, - path, - cwd: this.cwd - })), - ); - } - } - - - async initPlugin(plugin) { - const { id, key, apply } = plugin; - - const api = this.getPluginAPI({ - id, - key, - service: this - }); - - // register before apply - this.registerPlugin(plugin); - await this.applyAPI({ - api, - apply - }); - } - - getPluginOptsWithKey(key) { - return getUserConfigWithKey({ - key, - userConfig: this.userConfig - }); - } - - registerPlugin(plugin) { - this.plugins[plugin.id] = plugin; - } - - isPluginEnable(pluginId) { - // api.skipPlugins() 的插件 - if (this.skipPluginIds.has(pluginId)) return false; - - const { key, enableBy } = this.plugins[pluginId]; - - // 手动设置为 false - if (this.userConfig[key] === false) return false; - - // 配置开启 - if (enableBy === this.EnableBy.config && !(key in this.userConfig)) { - return false; - } - - // 函数自定义开启 - if (typeof enableBy === 'function') { - return enableBy(); - } - - // 注册开启 - return true; - } - - hasPresets(presetIds) { - return presetIds.every((presetId) => { - const preset = this.plugins[presetId]; - return preset && preset.isPreset && this.isPluginEnable(presetId); - }); - } - - hasPlugins(pluginIds) { - return pluginIds.every((pluginId) => { - const plugin = this.plugins[pluginId]; - return plugin && !plugin.isPreset && this.isPluginEnable(pluginId); - }); - } - - async applyPlugins(opts) { - const hooks = this.hooks[opts.key] || []; - switch (opts.type) { - case ApplyPluginsType.add: - if ('initialValue' in opts) { - assert( - Array.isArray(opts.initialValue), - 'applyPlugins failed, opts.initialValue must be Array if opts.type is add.' - ); - } - // eslint-disable-next-line - const tAdd = new AsyncSeriesWaterfallHook(["memo"]); - for (const hook of hooks) { - if (!this.isPluginEnable(hook.pluginId)) { - continue; - } - tAdd.tapPromise( - { - name: hook.pluginId, - stage: hook.stage || 0, - // @ts-ignore - before: hook.before - }, - async (memo) => { - const items = await hook.fn(opts.args); - return memo.concat(items); - } - ); - } - return tAdd.promise(opts.initialValue || []); - case ApplyPluginsType.modify: - // eslint-disable-next-line - const tModify = new AsyncSeriesWaterfallHook(["memo"]); - for (const hook of hooks) { - if (!this.isPluginEnable(hook.pluginId)) { - continue; - } - tModify.tapPromise( - { - name: hook.pluginId, - stage: hook.stage || 0, - // @ts-ignore - before: hook.before - }, - async memo => hook.fn(memo, opts.args) - ); - } - return tModify.promise(opts.initialValue); - case ApplyPluginsType.event: - // eslint-disable-next-line - const tEvent = new AsyncSeriesWaterfallHook(["_"]); - for (const hook of hooks) { - if (!this.isPluginEnable(hook.pluginId)) { - continue; - } - tEvent.tapPromise( - { - name: hook.pluginId, - stage: hook.stage || 0, - // @ts-ignore - before: hook.before - }, - async () => { - await hook.fn(opts.args); - } - ); - } - return tEvent.promise(); - default: - throw new Error( - `applyPlugin failed, type is not defined or is not matched, got ${opts.type}.` - ); - } - } - - async run({ name, args = {} }) { - args._ = args._ || []; - // shift the command itself - if (args._[0] === name) args._.shift(); - - this.args = args; - await this.init(); - - this.setStage(ServiceStage.run); - await this.applyPlugins({ - key: 'onStart', - type: ApplyPluginsType.event, - args: { - args - } - }); - - return this.runCommand({ - name, - args - }); - } - - async runCommand({ name, args = {} }) { - assert(this.stage >= ServiceStage.init, 'service is not initialized.'); - - args._ = args._ || []; - // shift the command itself - if (args._[0] === name) args._.shift(); - - const command = typeof this.commands[name] === 'string' - ? this.commands[this.commands[name]] - : this.commands[name]; - assert(command, `run command failed, command ${name} does not exists.`); - - const { fn } = command; - return fn({ - args - }); - } -} diff --git a/packages/fes-core/src/Service/pluginAPI.js b/packages/fes-core/src/Service/pluginAPI.js deleted file mode 100644 index 64e2efd4..00000000 --- a/packages/fes-core/src/Service/pluginAPI.js +++ /dev/null @@ -1,154 +0,0 @@ -import assert from 'assert'; -import * as utils from '@umijs/utils'; -import { isValidPlugin, pathToObj } from './utils/pluginUtils'; -import { EnableBy, PluginType, ServiceStage } from './enums'; -import Logger from '../logger'; -// TODO -// 标准化 logger -export default class PluginAPI { - constructor(opts) { - this.id = opts.id; - this.key = opts.key; - this.service = opts.service; - this.utils = utils; - this.logger = new Logger(`fes:plugin:${this.id || this.key}`); - } - - // TODO: reversed keys - describe({ - id, - key, - config, - enableBy - } = {}) { - const { plugins } = this.service; - // this.id and this.key is generated automatically - // so we need to diff first - if (id && this.id !== id) { - if (plugins[id]) { - const name = plugins[id].isPreset ? 'preset' : 'plugin'; - throw new Error( - `api.describe() failed, ${name} ${id} is already registered by ${plugins[id].path}.`, - ); - } - plugins[id] = plugins[this.id]; - plugins[id].id = id; - delete plugins[this.id]; - this.id = id; - } - if (key && this.key !== key) { - this.key = key; - plugins[this.id].key = key; - } - - if (config) { - plugins[this.id].config = config; - } - - plugins[this.id].enableBy = enableBy || EnableBy.register; - } - - register(hook) { - assert( - hook.key && typeof hook.key === 'string', - `api.register() failed, hook.key must supplied and should be string, but got ${hook.key}.`, - ); - assert( - hook.fn && typeof hook.fn === 'function', - `api.register() failed, hook.fn must supplied and should be function, but got ${hook.fn}.`, - ); - this.service.hooksByPluginId[this.id] = ( - this.service.hooksByPluginId[this.id] || [] - ).concat(hook); - } - - registerCommand(command) { - const { name, alias } = command; - assert( - !this.service.commands[name], - `api.registerCommand() failed, the command ${name} is exists.`, - ); - this.service.commands[name] = command; - if (alias) { - this.service.commands[alias] = name; - } - } - - // 在 preset 初始化阶段放后面,在插件注册阶段放前面 - registerPlugins(plugins) { - assert( - this.service.stage === ServiceStage.initPresets - || this.service.stage === ServiceStage.initPlugins, - 'api.registerPlugins() failed, it should only be used in registering stage.', - ); - assert( - Array.isArray(plugins), - 'api.registerPlugins() failed, plugins must be Array.', - ); - const extraPlugins = plugins.map(plugin => (isValidPlugin(plugin) - ? (plugin) - : pathToObj({ - type: PluginType.plugin, - path: plugin, - cwd: this.service.cwd - }))); - if (this.service.stage === ServiceStage.initPresets) { - this.service._extraPlugins.push(...extraPlugins); - } else { - this.service._extraPlugins.splice(0, 0, ...extraPlugins); - } - } - - registerPresets(presets) { - assert( - this.service.stage === ServiceStage.initPresets, - 'api.registerPresets() failed, it should only used in presets.', - ); - assert( - Array.isArray(presets), - 'api.registerPresets() failed, presets must be Array.', - ); - const extraPresets = presets.map(preset => (isValidPlugin(preset) - ? (preset) - : pathToObj({ - type: PluginType.preset, - path: preset, - cwd: this.service.cwd - }))); - // 插到最前面,下个 while 循环优先执行 - this.service._extraPresets.splice(0, 0, ...extraPresets); - } - - registerMethod({ - name, - fn, - exitsError = true - }) { - if (this.service.pluginMethods[name]) { - if (exitsError) { - throw new Error( - `api.registerMethod() failed, method ${name} is already exist.`, - ); - } else { - return; - } - } - this.service.pluginMethods[name] = fn - // 这里不能用 arrow function,this 需指向执行此方法的 PluginAPI - // 否则 pluginId 会不会,导致不能正确 skip plugin - || function (hookFn) { - const hook = { - key: name, - ...(utils.lodash.isPlainObject(hookFn) ? hookFn : { fn: hookFn }) - }; - // @ts-ignore - this.register(hook); - }; - } - - skipPlugins(pluginIds) { - pluginIds.forEach((pluginId) => { - this.service.skipPluginIds.add(pluginId); - }); - } -} diff --git a/packages/fes-core/src/Service/utils/isPromise.js b/packages/fes-core/src/Service/utils/isPromise.js deleted file mode 100644 index f3ca143a..00000000 --- a/packages/fes-core/src/Service/utils/isPromise.js +++ /dev/null @@ -1,7 +0,0 @@ -export default function isPromise(obj) { - return ( - !!obj - && (typeof obj === 'object' || typeof obj === 'function') - && typeof obj.then === 'function' - ); -} diff --git a/packages/fes-core/src/Service/utils/loadDotEnv.js b/packages/fes-core/src/Service/utils/loadDotEnv.js deleted file mode 100644 index 166ed955..00000000 --- a/packages/fes-core/src/Service/utils/loadDotEnv.js +++ /dev/null @@ -1,18 +0,0 @@ -import { readFileSync, existsSync } from 'fs'; -import { parse } from 'dotenv'; - -/** - * dotenv wrapper - * @param envPath string - */ -export default function loadDotEnv(envPath) { - if (existsSync(envPath)) { - const parsed = parse(readFileSync(envPath, 'utf-8')) || {}; - Object.keys(parsed).forEach((key) => { - // eslint-disable-next-line no-prototype-builtins - if (!process.env.hasOwnProperty(key)) { - process.env[key] = parsed[key]; - } - }); - } -} diff --git a/packages/fes-core/src/Service/utils/pluginUtils.js b/packages/fes-core/src/Service/utils/pluginUtils.js deleted file mode 100644 index d394cff7..00000000 --- a/packages/fes-core/src/Service/utils/pluginUtils.js +++ /dev/null @@ -1,135 +0,0 @@ -import { - dirname, join, basename, relative, extname -} from 'path'; -import { - compatESModuleRequire, - resolve, - winPath, - pkgUp, - lodash -} from '@umijs/utils'; - -import { PluginType } from '../enums'; - -const RE = { - [PluginType.plugin]: /^(@webank\/)?fes-plugin-/, - [PluginType.preset]: /^(@webank\/)?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('@webank/')) { - 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('@webank/fes-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; -} diff --git a/packages/fes-core/src/Service/PluginAPI.js b/packages/fes-core/src/service/PluginAPI.js similarity index 100% rename from packages/fes-core/src/Service/PluginAPI.js rename to packages/fes-core/src/service/PluginAPI.js