diff --git a/packages/core/src/design.mjs b/packages/core/src/design.mjs index c96f811889d..6d62ed70a1a 100644 --- a/packages/core/src/design.mjs +++ b/packages/core/src/design.mjs @@ -29,8 +29,9 @@ export function Design(designConfig) { pattern.prototype = Object.create(Pattern.prototype) pattern.prototype.constructor = pattern - // Make designConfig available without need to instantiate pattern + // Make design & pattern config available without instantiating a pattern pattern.designConfig = designConfig + pattern.patternConfig = new pattern().getConfig() return pattern } diff --git a/packages/core/src/pattern.mjs b/packages/core/src/pattern.mjs index 39bc83b2318..30f731c0fd7 100644 --- a/packages/core/src/pattern.mjs +++ b/packages/core/src/pattern.mjs @@ -137,9 +137,15 @@ Pattern.prototype.draft = function () { ) } else this.parts[set][partName] = result } catch (err) { - this.setStores[set].log.error([`Unable to draft part \`${partName}\` (set ${set})`, err]) + this.setStores[set].log.error([ + `Unable to draft part \`${partName}\` (set ${set})`, + err, + ]) } - } else this.setStores[set].log.error(`Unable to draft pattern part __${partName}__. Part.draft() is not callable`) + } else + this.setStores[set].log.error( + `Unable to draft pattern part __${partName}__. Part.draft() is not callable` + ) this.parts[set][partName].hidden = this.parts[set][partName].hidden === true ? true : !this.__wants(partName, set) } else { @@ -191,7 +197,7 @@ Pattern.prototype.getRenderProps = function () { info: store.logs.info, error: store.logs.error, warning: store.logs.warning, - })) + })), } props.parts = [] for (const set of this.parts) { @@ -316,13 +322,12 @@ Pattern.prototype.render = function () { */ Pattern.prototype.use = function (plugin, data) { const name = getPluginName(plugin) - if (!this.plugins?.[name]) return (plugin.plugin && plugin.condition) + if (!this.plugins?.[name]) + return plugin.plugin && plugin.condition ? this.__useIf(plugin, data) // Conditional plugin : this.__loadPlugin(plugin, data) // Regular plugin - this.store.log.info( - `Plugin \`${name}\` was requested, but it's already loaded. Skipping.` - ) + this.store.log.info(`Plugin \`${name}\` was requested, but it's already loaded. Skipping.`) return this } @@ -359,7 +364,6 @@ Pattern.prototype.__addDependency = function (name, part, dep) { * @return {object} config - The mutated global config */ Pattern.prototype.__addPartConfig = function (part) { - if (this.__resolvedParts.includes(part.name)) return this // Add parts, using set to keep them unique in the array @@ -379,7 +383,7 @@ Pattern.prototype.__addPartConfig = function (part) { * @param {array} list - The list of resolved measurements * @return {Pattern} this - The Pattern instance */ -Pattern.prototype.__addPartMeasurements = function (part, list=false) { +Pattern.prototype.__addPartMeasurements = function (part, list = false) { if (!this.config.measurements) this.config.measurements = [] if (!list) list = this.config.measurements if (part.measurements) { @@ -411,7 +415,7 @@ Pattern.prototype.__addPartMeasurements = function (part, list=false) { * @param {array} list - The list of resolved optional measurements * @return {Pattern} this - The Pattern instance */ -Pattern.prototype.__addPartOptionalMeasurements = function (part, list=false) { +Pattern.prototype.__addPartOptionalMeasurements = function (part, list = false) { if (!this.config.optionalMeasurements) this.config.optionalMeasurements = [] if (!list) list = this.config.optionalMeasurements if (part.optionalMeasurements) { @@ -454,7 +458,9 @@ Pattern.prototype.__addPartOptions = function (part) { // Keep design parts immutable in the pattern or risk subtle bugs this.config.options[optionName] = Object.freeze(part.options[optionName]) this.store.log.debug(`🔵 __${optionName}__ option loaded from \`${part.name}\``) - } else if (this.__mutated.optionDistance[optionName] > this.__mutated.partDistance[part.name]) { + } else if ( + this.__mutated.optionDistance[optionName] > this.__mutated.partDistance[part.name] + ) { this.config.options[optionName] = part.options[optionName] this.store.log.debug(`🟣 __${optionName}__ option overwritten by \`${part.name}\``) } @@ -474,7 +480,7 @@ function getPluginName(plugin) { if (Array.isArray(plugin)) { if (plugin[0].name) return plugin[0].name if (plugin[0].plugin.name) return plugin[0].plugin.name - } else { + } else { if (plugin.name) return plugin.name if (plugin.plugin.name) return plugin.plugin.name } @@ -504,28 +510,30 @@ Pattern.prototype.__addPartPlugins = function (part) { const pluginObj = { ...plugin[0], data: plugin[1] } plugin = pluginObj } - if (plugin.plugin) this.store.log.debug(`🔌 Resolved __${name}__ conditional plugin in \`${part.name}\``) + if (plugin.plugin) + this.store.log.debug(`🔌 Resolved __${name}__ conditional plugin in \`${part.name}\``) else this.store.log.debug(`🔌 Resolved __${name}__ plugin in \`${part.name}\``) // Do not overwrite an existing plugin with a conditional plugin unless it is also conditional if (plugin.plugin && plugin.condition) { if (!plugins[name]) { plugins[name] = plugin this.store.log.info(`Plugin \`${name}\` was conditionally added.`) - } - else if (plugins[name]?.condition) { - plugins[name+'_'] = plugin - this.store.log.info(`Plugin \`${name}\` was conditionally added again. Renaming to ${name}_.`) - } - else this.store.log.info( - `Plugin \`${name}\` was requested conditionally, but is already added explicitly. Not loading.` - ) + } else if (plugins[name]?.condition) { + plugins[name + '_'] = plugin + this.store.log.info( + `Plugin \`${name}\` was conditionally added again. Renaming to ${name}_.` + ) + } else + this.store.log.info( + `Plugin \`${name}\` was requested conditionally, but is already added explicitly. Not loading.` + ) } else { plugins[name] = plugin this.store.log.info(`Plugin \`${name}\` was added.`) } } - this.config.plugins = {...plugins } + this.config.plugins = { ...plugins } return this } @@ -539,14 +547,11 @@ Pattern.prototype.__addPartPlugins = function (part) { Pattern.prototype.__createSetStore = function () { const store = new Store() store.set('data', this.store.data) - for (const method of [...this.__storeMethods]) { - store.set(method[0], (...args) => method[1](store, ...args)) - } + store.extend([...this.__storeMethods]) return store } - /** * Merges (sets of) settings with the default settings * @@ -803,7 +808,7 @@ Pattern.prototype.__loadOptionDefaults = function () { else if (typeof option.dflt !== 'undefined') this.settings[i].options[name] = option.dflt else { let err = 'Unknown option type: ' + JSON.stringify(option) - this.setStores[i].log.error(err) + this.store.log.error(err) throw new Error(err) } } else this.settings[i].options[name] = option @@ -877,10 +882,8 @@ Pattern.prototype.__loadPluginMacros = function (plugin) { */ Pattern.prototype.__loadPlugins = function () { if (!this.config.plugins) return this - for (const plugin in this.config.plugins) this.use( - this.config.plugins[plugin], - this.config.plugins[plugin]?.data, - ) + for (const plugin in this.config.plugins) + this.use(this.config.plugins[plugin], this.config.plugins[plugin]?.data) return this } @@ -895,8 +898,7 @@ Pattern.prototype.__loadPlugins = function () { Pattern.prototype.__loadPluginStoreMethods = function (plugin) { if (Array.isArray(plugin.store)) { for (const method of plugin.store) this.__storeMethods.add(method) - } - else this.store.log.warning(`Plugin store methods should be an Array`) + } else this.store.log.warning(`Plugin store methods should be an Array`) return this } @@ -1209,7 +1211,8 @@ Pattern.prototype.__resolveParts = function (count = 0, distance = 0) { } distance++ for (const part of this.designConfig.parts) { - if (typeof this.__mutated.partDistance[part.name] === 'undefined') this.__mutated.partDistance[part.name] = distance + if (typeof this.__mutated.partDistance[part.name] === 'undefined') + this.__mutated.partDistance[part.name] = distance } for (const [name, part] of Object.entries(this.__designParts)) { // Hide when hideAll is set @@ -1218,8 +1221,8 @@ Pattern.prototype.__resolveParts = function (count = 0, distance = 0) { if (part.from) { if (part.hideDependencies || part.hideAll) { // Don't mutate the part, keep this info in the pattern object - this.__mutated.partHide[from.name] = true - this.__mutated.partHideAll[from.name] = true + this.__mutated.partHide[part.from.name] = true + this.__mutated.partHideAll[part.from.name] = true this.__mutated.partDistance = distance } this.__designParts[part.from.name] = part.from @@ -1410,9 +1413,6 @@ Pattern.prototype.__wants = function (partName, set = 0) { return true } - - - ////////////////////////////////////////////// // STATIC PRIVATE FUNCTIONS // ////////////////////////////////////////////// diff --git a/packages/core/src/stack.mjs b/packages/core/src/stack.mjs index 32eb0b0efc2..8eb002de5e6 100644 --- a/packages/core/src/stack.mjs +++ b/packages/core/src/stack.mjs @@ -27,14 +27,13 @@ Stack.prototype.addPart = function (part) { } /* Returns a stack object suitbale for renderprops */ -Stack.prototype.asProps = function (part) { +Stack.prototype.asProps = function () { return { ...this, - parts: [...this.parts] + parts: [...this.parts], } } - /* Returns a list of parts in this stack */ Stack.prototype.getPartList = function () { return [...this.parts] @@ -126,7 +125,7 @@ Stack.prototype.attr = function (name, value, overwrite = false) { /** Generates the transform for a stack */ Stack.prototype.generateTransform = function (transforms) { const { move, rotate, flipX, flipY } = transforms - const generated = utils.generateStackTransform( move?.x, move?.y, rotate, flipX, flipY, this) + const generated = utils.generateStackTransform(move?.x, move?.y, rotate, flipX, flipY, this) for (var t in generated) { this.attr(t, generated[t], true) diff --git a/packages/core/tests/design.test.mjs b/packages/core/tests/design.test.mjs index 993ac0a4206..ad2f85ac199 100644 --- a/packages/core/tests/design.test.mjs +++ b/packages/core/tests/design.test.mjs @@ -35,4 +35,61 @@ describe('Design', () => { expect(o.two.min).to.equal(5) expect(o.two.max).to.equal(15) }) + + it(`Design constructor should generate configuration`, () => { + const partA = { + name: 'test.partA', + measurements: ['head', 'knee'], + optionalMeasurements: ['chest', 'waist'], + options: { + optA: { pct: 40, min: 20, max: 80 }, + }, + draft: ({ part }) => part, + } + const partB = { + name: 'test.partB', + measurements: ['hpsToWaist', 'shoulderToWrist'], + optionalMeasurements: ['neck'], + after: partA, + plugins: [ + { + name: 'testPlugin', + hooks: { + preRender: () => {}, + }, + }, + ], + options: { + optB: { deg: 40, min: 20, max: 80 }, + }, + draft: ({ part }) => part, + } + const partC = { + name: 'test.partC', + measurements: ['seat', 'ankle'], + optionalMeasurements: ['knee', 'hpsToWaist'], + from: partB, + options: { + optC: { pct: 20, min: 10, max: 30 }, + }, + draft: ({ part }) => part, + } + const design = new Design({ + data: { + name: 'test', + version: '1.2.3', + }, + parts: [partC], + }) + expect(design.designConfig.data.name).to.equal('test') + expect(design.designConfig.data.version).to.equal('1.2.3') + expect(design.patternConfig.measurements.length).to.equal(6) + for (const m of ['seat', 'ankle', 'hpsToWaist', 'shoulderToWrist', 'head', 'knee']) { + expect(design.patternConfig.measurements.includes(m)).to.equal(true) + } + for (const m of ['neck', 'chest', 'waist']) { + expect(design.patternConfig.optionalMeasurements.includes(m)).to.equal(true) + } + expect(design.patternConfig.plugins.testPlugin.name).to.equal('testPlugin') + }) })