fix (core) resolve after depenndencies before from dependencies
This commit is contained in:
parent
b30e99f294
commit
cc143153b2
3 changed files with 224 additions and 32 deletions
|
@ -44,6 +44,8 @@ export function PatternConfig(pattern) {
|
||||||
this.parts = {}
|
this.parts = {}
|
||||||
/** @type {Object} which parts are hidden */
|
/** @type {Object} which parts are hidden */
|
||||||
this.partHide = {}
|
this.partHide = {}
|
||||||
|
/** @type {String[]} The order in which parts should be drafted */
|
||||||
|
this.draftOrder = []
|
||||||
|
|
||||||
/** @type {Object} to track when to overwrite options */
|
/** @type {Object} to track when to overwrite options */
|
||||||
__addNonEnumProp(this, '__mutated', {
|
__addNonEnumProp(this, '__mutated', {
|
||||||
|
@ -94,7 +96,6 @@ PatternConfig.prototype.isPartValid = function (part) {
|
||||||
*/
|
*/
|
||||||
PatternConfig.prototype.addPart = function (part) {
|
PatternConfig.prototype.addPart = function (part) {
|
||||||
if (this.isPartValid(part)) this.__addPart([part])
|
if (this.isPartValid(part)) this.__addPart([part])
|
||||||
|
|
||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -122,7 +123,7 @@ PatternConfig.prototype.asConfig = function () {
|
||||||
resolvedDependencies: this.resolvedDependencies,
|
resolvedDependencies: this.resolvedDependencies,
|
||||||
directDependencies: this.directDependencies,
|
directDependencies: this.directDependencies,
|
||||||
inject: this.inject,
|
inject: this.inject,
|
||||||
draftOrder: this.__resolveDraftOrder(),
|
draftOrder: this.draftOrder,
|
||||||
partHide: this.partHide,
|
partHide: this.partHide,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -142,9 +143,9 @@ PatternConfig.prototype.__addPart = function (depChain) {
|
||||||
const part = depChain[0]
|
const part = depChain[0]
|
||||||
|
|
||||||
// only process a part that hasn't already been processed
|
// only process a part that hasn't already been processed
|
||||||
if (!this.parts[part.name]) this.parts[part.name] = Object.freeze(part)
|
if (this.parts[part.name]) return
|
||||||
else return
|
|
||||||
|
|
||||||
|
this.parts[part.name] = Object.freeze(part)
|
||||||
// if it hasn't been registered with a distance, do that now
|
// if it hasn't been registered with a distance, do that now
|
||||||
if (typeof this.__mutated.partDistance[part.name] === 'undefined') {
|
if (typeof this.__mutated.partDistance[part.name] === 'undefined') {
|
||||||
// the longer the chain, the deeper the part is down it
|
// the longer the chain, the deeper the part is down it
|
||||||
|
@ -164,6 +165,19 @@ PatternConfig.prototype.__addPart = function (depChain) {
|
||||||
|
|
||||||
// add the part's config
|
// add the part's config
|
||||||
this.__addPartConfig(part)
|
this.__addPartConfig(part)
|
||||||
|
|
||||||
|
// if it's a top level part
|
||||||
|
if (depChain.length === 1) {
|
||||||
|
// its resolved dependency list is a backwards representation of the draft order of its dependencies
|
||||||
|
for (var i = this.resolvedDependencies[part.name].length - 1; i >= 0; i--) {
|
||||||
|
let dep = this.resolvedDependencies[part.name][i]
|
||||||
|
// only add it if it's not already on the list from another part
|
||||||
|
if (this.draftOrder.indexOf(dep) === -1) this.draftOrder.push(dep)
|
||||||
|
}
|
||||||
|
|
||||||
|
// add it last of all
|
||||||
|
this.draftOrder.push(part.name)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -403,10 +417,15 @@ PatternConfig.prototype.__resolvePartDependencies = function (depChain) {
|
||||||
if (DISTANCE_DEBUG) this.store.log.debug(`Processing \`${part.name}\` "${d}:"`)
|
if (DISTANCE_DEBUG) this.store.log.debug(`Processing \`${part.name}\` "${d}:"`)
|
||||||
|
|
||||||
// enforce an array
|
// enforce an array
|
||||||
const depsOfType = Array.isArray(part[d]) ? part[d] : [part[d]]
|
const depsOfType = [].concat(part[d])
|
||||||
|
|
||||||
|
// loop through backwards so that we're resolving last to first
|
||||||
|
// this order is necessary so that when we add the reversed chain to the draft order
|
||||||
|
// afters are included in the order they were listed in the config, but recursive
|
||||||
|
// resolution order is also correct
|
||||||
|
for (var i = depsOfType.length - 1; i >= 0; i--) {
|
||||||
|
const dot = depsOfType[i]
|
||||||
|
|
||||||
// each dependency
|
|
||||||
depsOfType.forEach((dot) => {
|
|
||||||
// add it as a direct dependency of the current part
|
// add it as a direct dependency of the current part
|
||||||
this.__addDependency('directDependencies', part.name, dot.name)
|
this.__addDependency('directDependencies', part.name, dot.name)
|
||||||
// add it as a resolved dependency of all parts in the chain
|
// add it as a resolved dependency of all parts in the chain
|
||||||
|
@ -421,13 +440,9 @@ PatternConfig.prototype.__resolvePartDependencies = function (depChain) {
|
||||||
this.__addPart([dot, ...depChain])
|
this.__addPart([dot, ...depChain])
|
||||||
} else {
|
} else {
|
||||||
// if it's already registered, recursion won't happen, but we still need to add its resolved dependencies to all parts in the chain
|
// if it's already registered, recursion won't happen, but we still need to add its resolved dependencies to all parts in the chain
|
||||||
// this.resolvedDependencies[dot.name].forEach((r) => {
|
|
||||||
// depChain.forEach((c) => this.__resolvePartDependencies('resolvedDependencies', c.name, r))
|
|
||||||
// })
|
|
||||||
this.__resolvePartDependencies([dot, ...depChain])
|
this.__resolvePartDependencies([dot, ...depChain])
|
||||||
// and check for stricter hiding policies
|
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -446,7 +461,12 @@ PatternConfig.prototype.__addDependency = function (dependencyList, partName, de
|
||||||
this[dependencyList][partName] = this[dependencyList][partName] || []
|
this[dependencyList][partName] = this[dependencyList][partName] || []
|
||||||
if (dependencyList == 'resolvedDependencies' && DISTANCE_DEBUG)
|
if (dependencyList == 'resolvedDependencies' && DISTANCE_DEBUG)
|
||||||
this.store.log.debug(`add ${depName} to ${partName} dependencyResolution`)
|
this.store.log.debug(`add ${depName} to ${partName} dependencyResolution`)
|
||||||
if (this[dependencyList][partName].indexOf(depName) === -1)
|
|
||||||
|
// if it's already in the dependency list, take it out because it needs to be put on the end
|
||||||
|
const depIndex = this[dependencyList][partName].indexOf(depName)
|
||||||
|
if (depIndex !== -1) this[dependencyList][partName].splice(depIndex, 1)
|
||||||
|
|
||||||
|
// put it at the end of the list
|
||||||
this[dependencyList][partName].push(depName)
|
this[dependencyList][partName].push(depName)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -489,16 +509,16 @@ PatternConfig.prototype.__resolveMutatedPartDistance = function (partName) {
|
||||||
if (!this.directDependencies[partName]) return
|
if (!this.directDependencies[partName]) return
|
||||||
|
|
||||||
// propose that each of the part's direct dependencies should be at a distance 1 further than the part's distance
|
// propose that each of the part's direct dependencies should be at a distance 1 further than the part's distance
|
||||||
const proposed_dependency_distance = this.__mutated.partDistance[partName] + 1
|
let proposedDependencyDistance = this.__mutated.partDistance[partName] + 1
|
||||||
// check each direct dependency
|
// check each direct dependency
|
||||||
this.directDependencies[partName].forEach((dependency) => {
|
this.directDependencies[partName].forEach((dependency) => {
|
||||||
// if the dependency doesn't have a distance, or that distance is less than the proposal
|
// if the dependency doesn't have a distance, or that distance is less than the proposal
|
||||||
if (
|
if (
|
||||||
typeof this.__mutated.partDistance[dependency] === 'undefined' ||
|
typeof this.__mutated.partDistance[dependency] === 'undefined' ||
|
||||||
this.__mutated.partDistance[dependency] < proposed_dependency_distance
|
this.__mutated.partDistance[dependency] < proposedDependencyDistance
|
||||||
) {
|
) {
|
||||||
// set the new distance
|
// set the new distance
|
||||||
this.__mutated.partDistance[dependency] = proposed_dependency_distance
|
this.__mutated.partDistance[dependency] = proposedDependencyDistance
|
||||||
// bump the dependency's dependencies as well
|
// bump the dependency's dependencies as well
|
||||||
this.__resolveMutatedPartDistance(dependency)
|
this.__resolveMutatedPartDistance(dependency)
|
||||||
}
|
}
|
||||||
|
@ -509,18 +529,3 @@ PatternConfig.prototype.__resolveMutatedPartDistance = function (partName) {
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 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
|
|
||||||
*/
|
|
||||||
PatternConfig.prototype.__resolveDraftOrder = function () {
|
|
||||||
this.__draftOrder = Object.keys(this.parts).sort(
|
|
||||||
(p1, p2) => this.__mutated.partDistance[p2] - this.__mutated.partDistance[p1]
|
|
||||||
)
|
|
||||||
|
|
||||||
return this.__draftOrder
|
|
||||||
}
|
|
||||||
|
|
6
packages/core/tests/fixtures/part.mjs
vendored
Normal file
6
packages/core/tests/fixtures/part.mjs
vendored
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
export const fixtureDraft = ({ part }) => part
|
||||||
|
export const fixturePart = (name, config = {}) => ({
|
||||||
|
name,
|
||||||
|
draft: fixtureDraft,
|
||||||
|
...config,
|
||||||
|
})
|
|
@ -1,5 +1,6 @@
|
||||||
import chai from 'chai'
|
import chai from 'chai'
|
||||||
import { Design } from '../src/index.mjs'
|
import { Design } from '../src/index.mjs'
|
||||||
|
import { fixturePart } from './fixtures/part.mjs'
|
||||||
|
|
||||||
const expect = chai.expect
|
const expect = chai.expect
|
||||||
|
|
||||||
|
@ -945,4 +946,184 @@ describe('Pattern', () => {
|
||||||
expect('' + error).to.contain('Unknown option type')
|
expect('' + error).to.contain('Unknown option type')
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
describe('Draft Order', () => {
|
||||||
|
describe('With no dependencies', () => {
|
||||||
|
it('Draft order should be the same the parts order in the config', () => {
|
||||||
|
const expectedMembers = []
|
||||||
|
const parts = []
|
||||||
|
for (var i = 0; i < 4; i++) {
|
||||||
|
let name = `part${i + 1}`
|
||||||
|
expectedMembers.push(name)
|
||||||
|
parts.push({ name, draft: (part) => part })
|
||||||
|
}
|
||||||
|
|
||||||
|
const Pattern = new Design({ parts })
|
||||||
|
const pattern = new Pattern().__init()
|
||||||
|
expect(pattern.config.draftOrder).to.have.ordered.members(expectedMembers)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('With simple dependencies', () => {
|
||||||
|
const afterPart = fixturePart('afterPart')
|
||||||
|
const fromPart = fixturePart('fromPart')
|
||||||
|
|
||||||
|
it('After dependencies should come before the parts that depend on them', () => {
|
||||||
|
const mainPart = fixturePart('mainPart', {
|
||||||
|
after: afterPart,
|
||||||
|
})
|
||||||
|
|
||||||
|
const Pattern = new Design({ parts: [mainPart] })
|
||||||
|
const pattern = new Pattern().__init()
|
||||||
|
expect(pattern.config.draftOrder).to.have.ordered.members(['afterPart', 'mainPart'])
|
||||||
|
})
|
||||||
|
it('After dependencies should be resolved in the order they are added to the part config', () => {
|
||||||
|
const secondAfter = fixturePart('secondAfter')
|
||||||
|
const mainPart = fixturePart('mainPart', {
|
||||||
|
after: [afterPart, secondAfter],
|
||||||
|
})
|
||||||
|
|
||||||
|
const Pattern = new Design({ parts: [mainPart] })
|
||||||
|
const pattern = new Pattern().__init()
|
||||||
|
expect(pattern.config.draftOrder).to.have.ordered.members([
|
||||||
|
'afterPart',
|
||||||
|
'secondAfter',
|
||||||
|
'mainPart',
|
||||||
|
])
|
||||||
|
})
|
||||||
|
it('From dependencies should come before the parts that depend on them', () => {
|
||||||
|
const mainPart = fixturePart('mainPart', {
|
||||||
|
from: fromPart,
|
||||||
|
})
|
||||||
|
|
||||||
|
const Pattern = new Design({ parts: [mainPart] })
|
||||||
|
const pattern = new Pattern().__init()
|
||||||
|
expect(pattern.config.draftOrder).to.have.ordered.members(['fromPart', 'mainPart'])
|
||||||
|
})
|
||||||
|
it('After dependencies should come before from dependencies', () => {
|
||||||
|
const mainPart = fixturePart('mainPart', {
|
||||||
|
after: afterPart,
|
||||||
|
from: fromPart,
|
||||||
|
})
|
||||||
|
|
||||||
|
const Pattern = new Design({ parts: [mainPart] })
|
||||||
|
const pattern = new Pattern().__init()
|
||||||
|
expect(pattern.config.draftOrder).to.have.ordered.members([
|
||||||
|
'afterPart',
|
||||||
|
'fromPart',
|
||||||
|
'mainPart',
|
||||||
|
])
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('With Complex dependencies', () => {
|
||||||
|
it('After dependencies should come before the entire from dependency chain', () => {
|
||||||
|
const inheritedFrontBase = fixturePart('inheritedFrontBase')
|
||||||
|
const blockWaistband = fixturePart('blockWaistband')
|
||||||
|
const inheritedWaistbandBase = fixturePart('inheritedWaistbandBase', {
|
||||||
|
from: blockWaistband,
|
||||||
|
after: inheritedFrontBase,
|
||||||
|
})
|
||||||
|
const inheritedBase = fixturePart('inheritedBase')
|
||||||
|
const inheritedWaistband = fixturePart('inheritedWaistband', {
|
||||||
|
from: inheritedWaistbandBase,
|
||||||
|
after: inheritedBase,
|
||||||
|
})
|
||||||
|
|
||||||
|
const mainBack = fixturePart('mainBack')
|
||||||
|
const inheritedFront = fixturePart('inheritedFront')
|
||||||
|
const mainFront = fixturePart('mainFront', {
|
||||||
|
after: mainBack,
|
||||||
|
from: inheritedFront,
|
||||||
|
})
|
||||||
|
|
||||||
|
const mainWaistband = fixturePart('mainWaistband', {
|
||||||
|
from: inheritedWaistband,
|
||||||
|
after: mainFront,
|
||||||
|
})
|
||||||
|
|
||||||
|
const Pattern = new Design({ parts: [mainWaistband] })
|
||||||
|
const pattern = new Pattern().__init()
|
||||||
|
/**
|
||||||
|
* chain:
|
||||||
|
* mainWaistBand
|
||||||
|
* after: mainFront
|
||||||
|
* after: mainBack
|
||||||
|
* from: inheritedFront
|
||||||
|
* from: inheritedWaistband
|
||||||
|
* after: inheritedBase
|
||||||
|
* from: inheritedWaistbandBase
|
||||||
|
* after: inheritedFrontBase
|
||||||
|
* from: blockWaistband
|
||||||
|
*/
|
||||||
|
expect(pattern.config.draftOrder).to.have.ordered.members([
|
||||||
|
'mainBack',
|
||||||
|
'inheritedFront',
|
||||||
|
'mainFront',
|
||||||
|
'inheritedBase',
|
||||||
|
'inheritedFrontBase',
|
||||||
|
'blockWaistband',
|
||||||
|
'inheritedWaistbandBase',
|
||||||
|
'inheritedWaistband',
|
||||||
|
'mainWaistband',
|
||||||
|
])
|
||||||
|
})
|
||||||
|
|
||||||
|
it('Parts with multiple dependents should come before all dependency chains', () => {
|
||||||
|
const inheritedFrontBase = fixturePart('inheritedFrontBase')
|
||||||
|
const blockWaistband = fixturePart('blockWaistband')
|
||||||
|
const inheritedWaistbandBase = fixturePart('inheritedWaistbandBase', {
|
||||||
|
from: blockWaistband,
|
||||||
|
after: inheritedFrontBase,
|
||||||
|
})
|
||||||
|
const inheritedBase = fixturePart('inheritedBase')
|
||||||
|
const inheritedWaistband = fixturePart('inheritedWaistband', {
|
||||||
|
from: inheritedWaistbandBase,
|
||||||
|
after: inheritedBase,
|
||||||
|
})
|
||||||
|
|
||||||
|
const inheritedFront = fixturePart('inheritedFront')
|
||||||
|
const mainBack = fixturePart('mainBack', {
|
||||||
|
from: inheritedFront,
|
||||||
|
after: inheritedBase,
|
||||||
|
})
|
||||||
|
const mainFront = fixturePart('mainFront', {
|
||||||
|
after: mainBack,
|
||||||
|
from: inheritedFront,
|
||||||
|
})
|
||||||
|
|
||||||
|
const mainWaistband = fixturePart('mainWaistband', {
|
||||||
|
from: inheritedWaistband,
|
||||||
|
after: mainFront,
|
||||||
|
})
|
||||||
|
|
||||||
|
const Pattern = new Design({ parts: [mainWaistband] })
|
||||||
|
const pattern = new Pattern().__init()
|
||||||
|
/**
|
||||||
|
* chain:
|
||||||
|
* mainWaistBand
|
||||||
|
* after: mainFront
|
||||||
|
* after: mainBack
|
||||||
|
* after: inheritedBase
|
||||||
|
* from: inheritedFront
|
||||||
|
* from: inheritedFront
|
||||||
|
* from: inheritedWaistband
|
||||||
|
* after: inheritedBase
|
||||||
|
* from: inheritedWaistbandBase
|
||||||
|
* after: inheritedFrontBase
|
||||||
|
* from: blockWaistband
|
||||||
|
*/
|
||||||
|
expect(pattern.config.draftOrder).to.have.ordered.members([
|
||||||
|
'inheritedBase',
|
||||||
|
'inheritedFront',
|
||||||
|
'mainBack',
|
||||||
|
'mainFront',
|
||||||
|
'inheritedFrontBase',
|
||||||
|
'blockWaistband',
|
||||||
|
'inheritedWaistbandBase',
|
||||||
|
'inheritedWaistband',
|
||||||
|
'mainWaistband',
|
||||||
|
])
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue