UNPKG

@freesewing/core

Version:

A library for creating made-to-measure sewing patterns

192 lines (171 loc) 5.42 kB
import { Hooks } from '../hooks.mjs' import { corePlugins } from '@freesewing/core-plugins' /** * Get the name of the given plugin config * * @param {(Object|Object[])} plugin the plugin to get the name of * @return {(string|false)} the name, or false if there isn't one */ export function getPluginName(plugin) { const toCheck = Array.isArray(plugin) ? plugin[0] : plugin return toCheck.name || toCheck.plugin?.name || false } /** * A class for managing the plugins and lifecycle hooks of a pattern * @param {Pattern} pattern the pattern to manage */ export function PatternPlugins(pattern) { this.store = pattern.store this.plugins = {} this.hooks = new Hooks() this.macros = {} this.__storeMethods = new Set() // Load core plugins unless the design explicitly asked not to if (!pattern.designConfig.noCorePlugins) this.use(corePlugins) } /** * Loads the plugins that are part of the config * * @private * @return {Pattern} this - The Pattern instance */ PatternPlugins.prototype.loadConfigPlugins = function (config, settings) { if (!config.plugins) return this for (const plugin in config.plugins) this.use(config.plugins[plugin], config.plugins[plugin]?.data, settings) return this } /** * Adds a lifecycle hook method to the pattern * * @param {string} hook - Name of the lifecycle hook * @param {function} method - The method to run * @param {object} data - Any data to pass to the hook method * @return {object} this - The Pattern instance */ PatternPlugins.prototype.on = function (hook, method, data) { for (const added of this.hooks[hook]) { // Don't add it twice if (added.method === method) return this } this.hooks[hook].push({ method, data }) return this } /** * Loads a plugin * * @param {object} plugin - The plugin to load * @param {object} data - Any data to pass to the plugin * @return {object} this - The Pattern instance */ PatternPlugins.prototype.use = function (plugin, data, settings = [{}]) { const name = getPluginName(plugin) if (!this.plugins?.[name]) return plugin.plugin && plugin.condition ? this.__useIf(plugin, data, settings) // Conditional plugin : this.__loadPlugin(plugin, data) // Regular plugin this.store.log.info(`Plugin \`${name}\` was requested, but it's already loaded. Skipping.`) return this } /** * Loads a plugin * * @private * @param {object} plugin - The plugin object, or an object with `plugin` and `condition` keys * @param {object} data - Any plugin data to load * @return {Pattern} this - The Pattern instance */ PatternPlugins.prototype.__loadPlugin = function (plugin, data) { const name = getPluginName(plugin) this.plugins[name] = plugin if (plugin.hooks) this.__loadPluginHooks(plugin, data) if (plugin.macros) this.__loadPluginMacros(plugin) if (plugin.store) this.__loadPluginStoreMethods(plugin) this.store.log.info(`Loaded plugin \`${plugin.name}:${plugin.version}\``) return this } /** * Loads a plugin's hooks * * @private * @param {object} plugin - The plugin object * @param {object} data - Any plugin data to load * @return {Pattern} this - The Pattern instance */ PatternPlugins.prototype.__loadPluginHooks = function (plugin, data) { // console.log('hooks', plugin) for (let hook of Object.keys(this.hooks)) { if (typeof plugin.hooks[hook] === 'function') { this.on(hook, plugin.hooks[hook], data) } else if (Array.isArray(plugin.hooks[hook])) { for (let method of plugin.hooks[hook]) { this.on(hook, method, data) } } } return this } /** * Loads a plugin's macros * * @private * @param {object} plugin - The plugin object * @return {Pattern} this - The Pattern instance */ PatternPlugins.prototype.__loadPluginMacros = function (plugin) { // console.log('macros', plugin) for (let macro in plugin.macros) { if (typeof plugin.macros[macro] === 'function') { this.__macro(macro, plugin.macros[macro]) } } } /** * Loads a plugin's store methods * * @private * @param {object} plugin - The plugin object * @return {Pattern} this - The Pattern instance */ PatternPlugins.prototype.__loadPluginStoreMethods = function (plugin) { if (Array.isArray(plugin.store)) { for (const method of plugin.store) this.__storeMethods.add(method) } else this.store.log.warn(`Plugin store methods should be an Array`) return this } /** * Sets a method for a macro * * @private * @param {string} macro - Name of the macro to run * @param {function} method - The macro method * @return {object} this - The Pattern instance */ PatternPlugins.prototype.__macro = function (key, method) { this.macros[key.toLowerCase()] = method return this } /** * Loads a conditional plugin * * @private * @param {object} plugin - An object with `plugin` and `condition` keys * @return {Pattern} this - The Pattern instance */ PatternPlugins.prototype.__useIf = function (plugin, data, settings = [{}]) { let load = 0 for (const set of settings) { if (plugin.condition(set)) load++ } if (load > 0) { this.store.log.info( `Condition met: Loaded plugin \`${plugin.plugin.name}:${plugin.plugin.version}\`` ) this.__loadPlugin(plugin.plugin, data) } else { this.store.log.info( `Condition not met: Skipped loading plugin \`${plugin.plugin.name}:${plugin.plugin.version}\`` ) } return this }