diff --git a/packages/core/src/pattern-config.mjs b/packages/core/src/pattern-config.mjs index 4dc0b91be08..2f6e0f6a94b 100644 --- a/packages/core/src/pattern-config.mjs +++ b/packages/core/src/pattern-config.mjs @@ -65,7 +65,7 @@ const DISTANCE_DEBUG = false * @param {Object} part a part configuration * @return {boolean} whether the part is valid */ -PatternConfig.prototype.validatePart = function (part) { +PatternConfig.prototype.isPartValid = function (part) { if (typeof part?.draft !== 'function') { this.store.log.error(`Part must have a draft() method`) return false @@ -84,7 +84,7 @@ PatternConfig.prototype.validatePart = function (part) { * @param {Object} part */ PatternConfig.prototype.addPart = function (part) { - if (this.validatePart(part)) this.__addPart([part]) + if (this.isPartValid(part)) this.__addPart([part]) return this } @@ -134,9 +134,9 @@ PatternConfig.prototype.__addPart = function (depChain) { const part = depChain[0] // the longer the chain, the deeper the part is down it const distance = depChain.length - if (!this.parts[part.name]) { - this.parts[part.name] = Object.freeze(part) - } + if (!this.parts[part.name]) this.parts[part.name] = Object.freeze(part) + else return + // if it hasn't been registered with a distance, do that now if (typeof this.__mutated.partDistance[part.name] === 'undefined') { this.__mutated.partDistance[part.name] = distance diff --git a/packages/core/src/pattern-draft-queue.mjs b/packages/core/src/pattern-draft-queue.mjs new file mode 100644 index 00000000000..db8355459a4 --- /dev/null +++ b/packages/core/src/pattern-draft-queue.mjs @@ -0,0 +1,42 @@ +export function PatternDraftQueue(pattern) { + this.__configResolver = pattern.__configResolver + this.queue = this.__resolveDraftOrder() + this.start() +} + +PatternDraftQueue.prototype.start = function () { + this.queueIndex = 0 +} + +PatternDraftQueue.prototype.addPart = function (partName) { + this.queue.push(partName) + return this +} + +PatternDraftQueue.prototype.hasNext = function () { + return this.queueIndex < this.queue.length +} + +PatternDraftQueue.prototype.peek = function () { + return this.queue[this.queueIndex] +} + +PatternDraftQueue.prototype.next = function () { + const next = this.peek() + this.queueIndex++ + return next +} + +/** + * Resolves the draft order based on the configuation + * + * @private + * @param {object} graph - The object of resolved dependencies, used to call itself recursively + * @return {Pattern} this - The Pattern instance + */ +PatternDraftQueue.prototype.__resolveDraftOrder = function () { + const partDistances = this.__configResolver.__mutated.partDistance + return Object.keys(this.__configResolver.parts).sort( + (p1, p2) => partDistances[p2] - partDistances[p1] + ) +} diff --git a/packages/core/src/pattern.mjs b/packages/core/src/pattern.mjs index a3ba506cf0e..33b260007c7 100644 --- a/packages/core/src/pattern.mjs +++ b/packages/core/src/pattern.mjs @@ -12,6 +12,7 @@ import { Hooks } from './hooks.mjs' import { version } from '../data.mjs' import { __loadPatternDefaults } from './config.mjs' import { PatternConfig, getPluginName } from './pattern-config.mjs' +import { PatternDraftQueue } from './pattern-draft-queue.mjs' import cloneDeep from 'lodash.clonedeep' ////////////////////////////////////////////// @@ -67,10 +68,12 @@ export function Pattern(designConfig = {}) { * @return {object} this - The Pattern instance */ Pattern.prototype.addPart = function (part, resolveImmediately = false) { - if (this.__configResolver.validatePart(part) && this.designConfig.parts.indexOf(part) === -1) { + if (this.__configResolver.isPartValid(part) && this.designConfig.parts.indexOf(part) === -1) { this.designConfig.parts.push(part) - if (resolveImmediately) this.__configResolver.addPart(part) - else this.__initialized = false + if (resolveImmediately) { + if (this.__configResolver.addPart(part) && typeof this.draftQueue !== 'undefined') + this.draftQueue.addPart(part.name) + } else this.__initialized = false } return this } @@ -82,6 +85,7 @@ Pattern.prototype.addPart = function (part, resolveImmediately = false) { */ Pattern.prototype.draft = function () { this.__init() + this.draftQueue = new PatternDraftQueue(this) this.__runHooks('preDraft') // Keep container for drafted parts fresh this.parts = [] @@ -100,8 +104,9 @@ Pattern.prototype.draft = function () { // Handle snap for pct options this.__loadAbsoluteOptionsSet(set) - for (const partName of this.config.draftOrder) { - this.createPartForSet(partName, set) + this.draftQueue.start() + while (this.draftQueue.hasNext()) { + this.createPartForSet(this.draftQueue.next(), set) } this.__runHooks('postSetDraft') } diff --git a/packages/core/tests/pattern-runtime-parts.test.mjs b/packages/core/tests/pattern-runtime-parts.test.mjs index dbe71799dbb..4d8587b1142 100644 --- a/packages/core/tests/pattern-runtime-parts.test.mjs +++ b/packages/core/tests/pattern-runtime-parts.test.mjs @@ -22,6 +22,11 @@ describe('Pattern', () => { draft: ({ part }) => part, } + describe('with runtime: true, resolveImmediately: true', () => { + it('adds the part to the current draft cycle') + it('does not add the part to subsequent draft cycles') + }) + describe('with resolveImmediately: true', () => { it('Should add the part to parts object', () => { const design = new Design({ parts: [part1] })