diff --git a/packages/core/src/design.mjs b/packages/core/src/design.mjs index cc5a4b7e10f..991d65af3ce 100644 --- a/packages/core/src/design.mjs +++ b/packages/core/src/design.mjs @@ -15,13 +15,32 @@ export function Design(config) { options: {}, parts: [], plugins: [], + // A place to store deprecation and other warnings before we even have a pattern instantiated + events: { + debug: [], + error: [], + info: [], + suggestion: [], + warning: [], + }, ...config } + const raiseEvent = function (data, type) { + config.events[type].push(data) + } + // Polyfill for pattern raise methods + const raise = { + debug: data => raiseEvent(`[early] `+data, 'debug'), + error: data => raiseEvent(`[early] `+data, 'error'), + info: data => raiseEvent(`[early] `+data, 'info'), + suggestion: data => raiseEvent(`[early] `+data, 'suggestion'), + warning: data => raiseEvent(`[early] `+data, 'warning'), + } const parts = {} for (const part of config.parts) { if (typeof part === 'object') { parts[part.name] = part - config = addPartConfig(parts[part.name], config) + config = addPartConfig(parts[part.name], config, raise ) } else throw("Invalid part configuration. Part is not an object") } @@ -31,8 +50,6 @@ export function Design(config) { // Ensure all options have a hide() method and menu property config.options = completeOptions(config.options) - // A place to store deprecation and other warnings before we even have a pattern instantiated - config.warnings = [] const pattern = function (settings) { Pattern.call(this, config) diff --git a/packages/core/src/pattern.mjs b/packages/core/src/pattern.mjs index db47f1bf0b0..9cf2f3742d5 100644 --- a/packages/core/src/pattern.mjs +++ b/packages/core/src/pattern.mjs @@ -178,10 +178,6 @@ Pattern.prototype.getPartList = function () { */ Pattern.prototype.init = function () { this.initialized++ - // Load plugins - if (this.config.plugins) { - for (const plugin of Object.values(this.config.plugins)) this.use(plugin) - } // Resolve all dependencies this.dependencies = this.config.dependencies this.inject = this.config.inject @@ -190,6 +186,10 @@ Pattern.prototype.init = function () { this.resolvedDependencies = this.resolveDependencies(this.dependencies) this.config.resolvedDependencies = this.resolvedDependencies this.config.draftOrder = this.draftOrder(this.resolvedDependencies) + // Load plugins + if (this.config.plugins) { + for (const plugin of Object.values(this.config.plugins)) this.use(plugin) + } // Make all parts uniform if (this.__parts) { @@ -274,7 +274,7 @@ Pattern.prototype.addPart = function (part) { if (part.name) { this.config.parts[part.name] = part // Add part-level config to config - this.config = addPartConfig(part, this.config) + this.config = addPartConfig(part, this.config, this.raise) } else this.raise.error(`Part must have a name`) } @@ -545,16 +545,33 @@ Pattern.prototype.on = function (hook, method, data) { return this } -Pattern.prototype.use = function (plugin, data) { - // Don't load plugins more than once - if (this.plugins?.[plugin.name]) return this +Pattern.prototype.loadPlugin = function (plugin, data, explicit=false) { this.plugins[plugin.name] = plugin - // Conditional plugin? - if (plugin.plugin && plugin.condition) return this.useIf(plugin, data) - // Regular plugin - this.raise.info(`Loaded plugin \`${plugin.name}:${plugin.version}\``) if (plugin.hooks) this.loadPluginHooks(plugin, data) if (plugin.macros) this.loadPluginMacros(plugin) + this.raise.info(`Loaded plugin \`${plugin.name}:${plugin.version}\``) + + return this +} + + +Pattern.prototype.use = function (plugin, data) { + // Existing plugin - But we may still need to load it + // if it was previously loaded conditionally, and is now loaded explicitly + if (this.plugins?.[plugin.name]?.condition && !plugin.condition) { + this.raise.info( + `Plugin \`${plugin.plugin.name} was loaded conditionally earlier, but is now loaded explicitly.` + ) + return this.loadPlugin(plugin, data) + } + // New plugin? + else if (!this.plugins?.[plugin.name]) return (plugin.plugin && plugin.condition) + ? this.useIf(plugin, data) // Conditional plugin + : this.loadPlugin(plugin, data) // Regular plugin + + this.raise.info( + `Plugin \`${plugin.plugin ? plugin.plugin.name : plugin.name}\` was requested, but it's already loaded. Skipping.` + ) return this } @@ -564,7 +581,7 @@ Pattern.prototype.useIf = function (plugin, settings) { this.raise.info( `Condition met: Loaded plugin \`${plugin.plugin.name}:${plugin.plugin.version}\`` ) - this.loadPluginHooks(plugin.plugin, plugin.data) + this.loadPlugin(plugin.plugin, plugin.data) } else { this.raise.info( `Condition not met: Skipped loading plugin \`${plugin.plugin.name}:${plugin.plugin.version}\`` @@ -693,14 +710,15 @@ Pattern.prototype.resolveDependency = function ( /** Adds a part as a simple dependency **/ Pattern.prototype.addDependency = function (name, part, dep) { - if (part.hideDependencies || part.hideAll) { - dep.hide = true - dep.hideAll = true - } + // FIXME: This causes issues + //if (part.hideDependencies || part.hideAll) { + // dep.hide = true + // dep.hideAll = true + //} this.dependencies[name] = mergeDependencies(dep.name, this.dependencies[name]) if (typeof this.__parts[dep.name] === 'undefined') { this.__parts[dep.name] = decoratePartDependency(dep) - addPartConfig(this.__parts[dep.name], this.config) + addPartConfig(this.__parts[dep.name], this.config, this.raise) } return this @@ -728,7 +746,7 @@ Pattern.prototype.preresolveDependencies = function (count=0) { this.__parts[part.from.name].hide = true this.__parts[part.from.name].hideAll = true } - addPartConfig(this.__parts[part.from.name], this.config) + addPartConfig(this.__parts[part.from.name], this.config, this.raise) } } // Simple dependency (after) @@ -745,7 +763,7 @@ Pattern.prototype.preresolveDependencies = function (count=0) { if (len > count) return this.preresolveDependencies(len) for (const [name, part] of Object.entries(this.__parts)) { - addPartConfig(name, this.config) + addPartConfig(part, this.config, this.raise) } // Weed out doubles diff --git a/packages/core/src/utils.mjs b/packages/core/src/utils.mjs index a43801672e0..7f18e056cb3 100644 --- a/packages/core/src/utils.mjs +++ b/packages/core/src/utils.mjs @@ -493,18 +493,18 @@ const addPartOptionGroups = (part, config) => { } // Add part-level measurements -const addPartMeasurements = (part, config, list=false) => { +const addPartMeasurements = (part, config, raise, list=false) => { if (!list) list = config.measurements ? [...config.measurements] : [] if (part.measurements) { for (const m of part.measurements) list.push(m) } - if (part.from) addPartMeasurements(part.from, config, list) + if (part.from) addPartMeasurements(part.from, config, raise, list) if (part.after) { if (Array.isArray(part.after)) { - for (const dep of part.after) addPartMeasurements(dep, config, list) - } else addPartMeasurements(part.after, config, list) + for (const dep of part.after) addPartMeasurements(dep, config, raise, list) + } else addPartMeasurements(part.after, config, raise, list) } // Weed out duplicates @@ -514,7 +514,7 @@ const addPartMeasurements = (part, config, list=false) => { } // Add part-level optional measurements -const addPartOptionalMeasurements = (part, config, list=false) => { +const addPartOptionalMeasurements = (part, config, raise, list=false) => { if (!list) list = config.optionalMeasurements ? [...config.optionalMeasurements] : [] @@ -568,24 +568,31 @@ export const addPartDependencies = (part, config) => { } // Add part-level plugins -export const addPartPlugins = (part, config) => { +export const addPartPlugins = (part, config, raise) => { if (!part.plugins) return config if (!Array.isArray(part.plugins)) part.plugins = [ part.plugins ] for (const plugin of part.plugins) { - if (plugin.plugin && plugin.condition) config.plugins[plugin.plugin.name] = plugin + // Do not overwrite an existing plugin with a conditional plugin unless it is also conditional + if (plugin.plugin && plugin.condition) { + if (config.plugins[plugin.plugin.name]?.condition) { + raise.info(`Plugin \`${plugin.plugin.name}\` was re-requested conditionally. Overwriting earlier condition.`) + config.plugins[plugin.plugin.name] = plugin + } + else raise.info(`Plugin \`${plugin.plugin.name}\` was requested conditionally, but is already loaded explicitly. Not loading bitch.`) + } else config.plugins[plugin.name] = plugin } return config } -export const addPartConfig = (part, config) => { - config = addPartOptions(part, config) - config = addPartMeasurements(part, config) - config = addPartOptionalMeasurements(part, config) - config = addPartDependencies(part, config) - config = addPartOptionGroups(part, config) - config = addPartPlugins(part, config) +export const addPartConfig = (part, config, raise) => { + config = addPartOptions(part, config, raise) + config = addPartMeasurements(part, config, raise) + config = addPartOptionalMeasurements(part, config, raise) + config = addPartDependencies(part, config, raise) + config = addPartOptionGroups(part, config, raise) + config = addPartPlugins(part, config, raise) return config }