UNPKG

hins

Version:

[![codecov](https://codecov.io/gh/l-zoy/hins/branch/main/graph/badge.svg)](https://codecov.io/gh/l-zoy/hins) [![GitHub license](https://img.shields.io/github/license/l-zoy/hins)](https://github.com/l-zoy/hins/blob/master/LICENSE) ![node-current](https://i

182 lines (144 loc) 4.66 kB
import chokidar from 'chokidar' import assert from 'assert' import slash from 'slash' import path from 'path' import joi from 'joi' import fs from 'fs' import { compatESModuleRequire, isEqual, mergeDefault } from './tools' import { ICoreStage } from './enum' import type { IConfig, IReadConfig, IWorkDir } from './types' export default class Config { /** * @desc possible Config name */ possibleConfigName: IWorkDir[] /** * @desc Service instance */ core: IReadConfig['core'] constructor(options: IReadConfig) { this.core = options.core this.possibleConfigName = options.possibleConfigName } getPluginConfig(userConfig: IConfig) { const defaultConfig = this.getPluginDefaultConfig() const { stage, plugins } = this.core assert( stage >= ICoreStage.pluginReady, `Config.getPluginConfig() failed, it should not be executed before plugin is ready.` ) const userConfigKeys = Object.keys(userConfig) const keepKeys = {} // get config Object.keys(plugins).forEach((plugin) => { const { key, config } = plugins[plugin] if (!key || !config) { return } const value = userConfig[key] if (!keepKeys[key]) { keepKeys[key] = key } else { throw new Error(`have multiple same ${key}`) } const schema = config.schema(joi) assert( joi.isSchema(schema), `schema return from plugin ${plugin} is not valid schema.` ) const { error } = schema.validate(value) if (error) { throw new Error(error.message) } // All the configurable key values are obtained above // and the verification process is performed here. // If all the key values are filled in // the length of `userConfigKeys` should be `0` const index = userConfigKeys.indexOf(key.split('.')[0]) if (index !== -1) { userConfigKeys.splice(index, 1) } // update userConfig with defaultConfig if (key in defaultConfig) { const newValue = mergeDefault({ defaultConfig: defaultConfig[key], config: value }) userConfig[key] = newValue } }) // Same as above, if the value of `userConfigKeys` is not 0, // an error is thrown here and prompts which keys are illegal if (userConfigKeys.length) { const keys = userConfigKeys.length > 1 ? 'keys' : 'key' throw new Error(`Invalid config ${keys}: ${userConfigKeys.join(', ')}`) } return userConfig } getPluginDefaultConfig() { const { plugins } = this.core // collect default config return Object.keys(plugins).reduce((memo, pluginId) => { const { key, config } = plugins[pluginId] if (!key || !config) return memo if ('default' in config) memo[key] = config.default return memo }, {}) } getConfigFile() { const { cwd } = this.core const env = process.env.HINS_CONFIG_ENV // Get a valid file name // I.e. check if the file exists let configFile = this.possibleConfigName.find((file) => fs.existsSync(path.join(cwd, file)) ) if (configFile) { if (env) { const ext = path.extname(configFile) configFile = configFile.replace(ext, `.${env}${ext}`) } return slash(path.join(cwd, configFile)) } return false } getUserConfig(): IConfig { const { babelRegister } = this.core const configFile = this.getConfigFile() if (configFile) { // clear the require cache // load babelRegister if there is // babelRegister is initialized with default value processing delete require.cache[configFile] babelRegister(configFile) return compatESModuleRequire(require(configFile)) } return {} } watchConfig() { const { cwd, config, args, watchConfig } = this.core const configFile = this.getConfigFile() if (configFile) { const watcher = chokidar.watch(configFile, { cwd, ignoreInitial: true, awaitWriteFinish: { stabilityThreshold: 500 } }) watcher.on('all', async (event, paths) => { const initConfig = this.getUserConfig() const newConfig = this.getPluginConfig(initConfig) const isReload = !isEqual(newConfig, config) watchConfig.changeLog(event, paths, isReload) if (isReload) { watchConfig.reloadLog(event, paths) this.core.initConfig = initConfig this.core.reset() await watcher.close() this.core.start({ ...args!, reloadCommand: false }) } }) } } }