wip: Recursive resolving of (non-injected) dependencies
We started out with following dependencies that are injected (from) and now added dependencies that are merely required to be drafted first (after). This also adds further support for part-level configuration.
This commit is contained in:
parent
4cf9c3bd47
commit
2b254c721d
3 changed files with 203 additions and 13 deletions
|
@ -4,6 +4,7 @@ import {
|
|||
capitalize,
|
||||
decoratePartDependency,
|
||||
addPartConfig,
|
||||
mergeDependencies,
|
||||
} from './utils.js'
|
||||
import Part from './part'
|
||||
import Point from './point'
|
||||
|
@ -215,7 +216,7 @@ function snappedOption(option, pattern) {
|
|||
// Merges settings object with this.settings
|
||||
Pattern.prototype.apply = function (settings) {
|
||||
if (typeof settings !== 'object') {
|
||||
this.raise.warning('Pattern initialized without any settings')
|
||||
this.raise.warning('Pattern instantiated without any settings')
|
||||
return this
|
||||
}
|
||||
for (let key of Object.keys(settings)) {
|
||||
|
@ -678,23 +679,57 @@ Pattern.prototype.resolveDependency = function (
|
|||
return deps
|
||||
}
|
||||
|
||||
/** Adds a part as a simple dependency **/
|
||||
Pattern.prototype.addDependency = function (name, part, dep) {
|
||||
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)
|
||||
}
|
||||
|
||||
return this
|
||||
}
|
||||
|
||||
/** Filter optional measurements out of they are also required measurements */
|
||||
Pattern.prototype.filterOptionalMeasurements = function () {
|
||||
this.config.optionalMeasurements = this.config.optionalMeasurements.filter(
|
||||
m => this.config.measurements.indexOf(m) === -1
|
||||
)
|
||||
|
||||
return this
|
||||
}
|
||||
|
||||
/** Pre-Resolves part dependencies that are passed in 2022 style */
|
||||
Pattern.prototype.preresolveDependencies = function (count=0) {
|
||||
const len = Object.keys(this.__parts).length
|
||||
if (!this.__parts) return
|
||||
for (const [name, part] of Object.entries(this.__parts)) {
|
||||
// Inject (from)
|
||||
if (part.from) {
|
||||
this.inject[name] = part.from.name
|
||||
if (typeof this.__parts[part.from.name] === 'undefined') {
|
||||
this.__parts[part.from.name] = decoratePartDependency(part.from)
|
||||
addPartConfig(this.__parts[part.from.name], this.config)
|
||||
}
|
||||
}
|
||||
// Simple dependency (after)
|
||||
if (part.after) {
|
||||
if (Array.isArray(part.after)) {
|
||||
for (const dep of part.after) this.addDependency(name, part, dep)
|
||||
}
|
||||
const newlen = Object.keys(this.__parts).length
|
||||
else this.addDependency(name, part, part.after)
|
||||
}
|
||||
}
|
||||
// Did we discover any new dependencies?
|
||||
const len = Object.keys(this.__parts).length
|
||||
|
||||
return (Object.keys(this.__parts).length > len)
|
||||
? this.preresolveDependencies()
|
||||
: this
|
||||
if (len > count) return this.preresolveDependencies(len)
|
||||
|
||||
for (const [name, part] of Object.entries(this.__parts)) {
|
||||
addPartConfig(name, this.config)
|
||||
}
|
||||
|
||||
// Weed out doubles
|
||||
return this.filterOptionalMeasurements()
|
||||
}
|
||||
|
||||
/** Resolves part dependencies into a flat array */
|
||||
|
|
|
@ -437,7 +437,7 @@ const addPartOptionalMeasurements = (part, config, list=false) => {
|
|||
}
|
||||
|
||||
|
||||
const addDependencies = (dep, current) => {
|
||||
export const mergeDependencies = (dep=[], current=[]) => {
|
||||
// Current dependencies
|
||||
const list = []
|
||||
if (Array.isArray(current)) list.push(...current)
|
||||
|
@ -446,13 +446,21 @@ const addDependencies = (dep, current) => {
|
|||
if (Array.isArray(dep)) list.push(...dep)
|
||||
else if (typeof dep === 'string') list.push(dep)
|
||||
|
||||
return [...new Set(list)]
|
||||
// Dependencies should be parts names (string) not the object
|
||||
const deps = []
|
||||
for (const part of [...new Set(list)]) {
|
||||
if (typeof part === 'object') deps.push(part.name)
|
||||
else deps.push(part)
|
||||
}
|
||||
|
||||
return deps
|
||||
}
|
||||
|
||||
// Add part-level dependencies
|
||||
export const addPartDependencies = (part, config) => {
|
||||
if (part.after) {
|
||||
config.dependencies[part.name] = addDependencies(config.dependencies[part.name], part.after)
|
||||
if (typeof config.dependencies === 'undefined') config.dependencies = {}
|
||||
config.dependencies[part.name] = mergeDependencies(config.dependencies[part.name], part.after)
|
||||
}
|
||||
|
||||
return config
|
||||
|
@ -467,4 +475,3 @@ export const addPartConfig = (part, config) => {
|
|||
return config
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
let expect = require("chai").expect;
|
||||
let freesewing = require("../dist/index.js");
|
||||
|
||||
/*
|
||||
it("Pattern constructor should initialize object", () => {
|
||||
let pattern = new freesewing.Pattern({
|
||||
foo: "bar",
|
||||
|
@ -725,7 +725,7 @@ it("Should retrieve the cutList", () => {
|
|||
// 2022 style part inheritance
|
||||
// I am aware this does too much for one unit test, but this is to simplify TDD
|
||||
// we can split it up later
|
||||
it("Design constructor should resolve nested dependencies (2022)", () => {
|
||||
it("Design constructor should resolve nested injections (2022)", () => {
|
||||
const partA = {
|
||||
name: "partA",
|
||||
options: { optionA: { bool: true } },
|
||||
|
@ -770,6 +770,7 @@ it("Design constructor should resolve nested dependencies (2022)", () => {
|
|||
const partR = { // R for runtime, which is when this wil be attached
|
||||
name: "partR",
|
||||
from: partA,
|
||||
after: partC,
|
||||
options: { optionR: { dflt: 'red', list: ['red', 'green', 'blue'] } },
|
||||
measurements: [ 'measieR' ],
|
||||
optionalMeasurements: [ 'optmeasieR', 'measieA' ],
|
||||
|
@ -812,7 +813,8 @@ it("Design constructor should resolve nested dependencies (2022)", () => {
|
|||
// Dependencies
|
||||
expect(pattern.config.dependencies.partB[0]).to.equal('partA')
|
||||
expect(pattern.config.dependencies.partC[0]).to.equal('partB')
|
||||
expect(pattern.config.dependencies.partR[0]).to.equal('partA')
|
||||
expect(pattern.config.dependencies.partR[0]).to.equal('partC')
|
||||
expect(pattern.config.dependencies.partR[1]).to.equal('partA')
|
||||
// Inject
|
||||
expect(pattern.config.inject.partB).to.equal('partA')
|
||||
expect(pattern.config.inject.partC).to.equal('partB')
|
||||
|
@ -876,3 +878,149 @@ it("Design constructor should resolve nested dependencies (2022)", () => {
|
|||
expect(pattern.parts.partR.paths.r.ops[1].to.x).to.equal(44)
|
||||
expect(pattern.parts.partR.paths.r.ops[1].to.y).to.equal(44)
|
||||
})
|
||||
*/
|
||||
it("Design constructor should resolve nested dependencies (2022)", () => {
|
||||
const partA = {
|
||||
name: "partA",
|
||||
options: { optionA: { bool: true } },
|
||||
measurements: [ 'measieA' ],
|
||||
optionalMeasurements: [ 'optmeasieA' ],
|
||||
draft: part => {
|
||||
const { points, Point, paths, Path } = part.shorthand()
|
||||
points.a1 = new Point(1,1)
|
||||
points.a2 = new Point(11,11)
|
||||
paths.a = new Path().move(points.a1).line(points.a2)
|
||||
return part
|
||||
}
|
||||
}
|
||||
const partB = {
|
||||
name: "partB",
|
||||
from: partA,
|
||||
options: { optionB: { pct: 12, min: 2, max: 20 } },
|
||||
measurements: [ 'measieB' ],
|
||||
optionalMeasurements: [ 'optmeasieB', 'measieA' ],
|
||||
draft: part => {
|
||||
const { points, Point, paths, Path } = part.shorthand()
|
||||
points.b1 = new Point(2,2)
|
||||
points.b2 = new Point(22,22)
|
||||
paths.b = new Path().move(points.b1).line(points.b2)
|
||||
return part
|
||||
}
|
||||
}
|
||||
const partC = {
|
||||
name: "partC",
|
||||
from: partB,
|
||||
options: { optionC: { deg: 5, min: 0, max: 15 } },
|
||||
measurements: [ 'measieC' ],
|
||||
optionalMeasurements: [ 'optmeasieC', 'measieA' ],
|
||||
draft: part => {
|
||||
const { points, Point, paths, Path } = part.shorthand()
|
||||
points.c1 = new Point(3,3)
|
||||
points.c2 = new Point(33,33)
|
||||
paths.c = new Path().move(points.c1).line(points.c2)
|
||||
return part
|
||||
}
|
||||
}
|
||||
const partD = {
|
||||
name: "partD",
|
||||
after: partC,
|
||||
options: { optionD: { dflt: 'red', list: ['red', 'green', 'blue'] } },
|
||||
measurements: [ 'measieD' ],
|
||||
optionalMeasurements: [ 'optmeasieD', 'measieA' ],
|
||||
draft: part => {
|
||||
const { points, Point, paths, Path } = part.shorthand()
|
||||
points.d1 = new Point(4,4)
|
||||
points.d2 = new Point(44,44)
|
||||
paths.d = new Path().move(points.d1).line(points.d2)
|
||||
return part
|
||||
}
|
||||
}
|
||||
const Design = new freesewing.Design({ parts: { partD } });
|
||||
const pattern = new Design().draft()
|
||||
// Measurements
|
||||
expect(pattern.config.measurements.length).to.equal(4)
|
||||
expect(pattern.config.measurements.indexOf('measieA') === -1).to.equal(false)
|
||||
expect(pattern.config.measurements.indexOf('measieB') === -1).to.equal(false)
|
||||
expect(pattern.config.measurements.indexOf('measieC') === -1).to.equal(false)
|
||||
expect(pattern.config.measurements.indexOf('measieD') === -1).to.equal(false)
|
||||
// Optional measurements
|
||||
expect(pattern.config.optionalMeasurements.length).to.equal(4)
|
||||
expect(pattern.config.optionalMeasurements.indexOf('optmeasieA') === -1).to.equal(false)
|
||||
expect(pattern.config.optionalMeasurements.indexOf('optmeasieB') === -1).to.equal(false)
|
||||
expect(pattern.config.optionalMeasurements.indexOf('optmeasieC') === -1).to.equal(false)
|
||||
expect(pattern.config.optionalMeasurements.indexOf('optmeasieD') === -1).to.equal(false)
|
||||
expect(pattern.config.optionalMeasurements.indexOf('measieA') === -1).to.equal(true)
|
||||
// Options
|
||||
expect(pattern.config.options.optionA.bool).to.equal(true)
|
||||
expect(pattern.config.options.optionB.pct).to.equal(12)
|
||||
expect(pattern.config.options.optionB.min).to.equal(2)
|
||||
expect(pattern.config.options.optionB.max).to.equal(20)
|
||||
expect(pattern.config.options.optionC.deg).to.equal(5)
|
||||
expect(pattern.config.options.optionC.min).to.equal(0)
|
||||
expect(pattern.config.options.optionC.max).to.equal(15)
|
||||
expect(pattern.config.options.optionD.dflt).to.equal('red')
|
||||
expect(pattern.config.options.optionD.list[0]).to.equal('red')
|
||||
expect(pattern.config.options.optionD.list[1]).to.equal('green')
|
||||
expect(pattern.config.options.optionD.list[2]).to.equal('blue')
|
||||
// Dependencies
|
||||
expect(pattern.config.dependencies.partB[0]).to.equal('partA')
|
||||
expect(pattern.config.dependencies.partC[0]).to.equal('partB')
|
||||
expect(pattern.config.dependencies.partD[0]).to.equal('partC')
|
||||
// Inject
|
||||
expect(pattern.config.inject.partB).to.equal('partA')
|
||||
expect(pattern.config.inject.partC).to.equal('partB')
|
||||
// Draft order
|
||||
expect(pattern.config.draftOrder[0]).to.equal('partA')
|
||||
expect(pattern.config.draftOrder[1]).to.equal('partB')
|
||||
expect(pattern.config.draftOrder[2]).to.equal('partC')
|
||||
expect(pattern.config.draftOrder[3]).to.equal('partD')
|
||||
// Points
|
||||
expect(pattern.parts.partA.points.a1.x).to.equal(1)
|
||||
expect(pattern.parts.partA.points.a1.y).to.equal(1)
|
||||
expect(pattern.parts.partA.points.a2.x).to.equal(11)
|
||||
expect(pattern.parts.partA.points.a2.y).to.equal(11)
|
||||
expect(pattern.parts.partB.points.b1.x).to.equal(2)
|
||||
expect(pattern.parts.partB.points.b1.y).to.equal(2)
|
||||
expect(pattern.parts.partB.points.b2.x).to.equal(22)
|
||||
expect(pattern.parts.partB.points.b2.y).to.equal(22)
|
||||
expect(pattern.parts.partC.points.c1.x).to.equal(3)
|
||||
expect(pattern.parts.partC.points.c1.y).to.equal(3)
|
||||
expect(pattern.parts.partC.points.c2.x).to.equal(33)
|
||||
expect(pattern.parts.partC.points.c2.y).to.equal(33)
|
||||
expect(pattern.parts.partD.points.d1.x).to.equal(4)
|
||||
expect(pattern.parts.partD.points.d1.y).to.equal(4)
|
||||
expect(pattern.parts.partD.points.d2.x).to.equal(44)
|
||||
expect(pattern.parts.partD.points.d2.y).to.equal(44)
|
||||
// Paths in partA
|
||||
expect(pattern.parts.partA.paths.a.ops[0].to.x).to.equal(1)
|
||||
expect(pattern.parts.partA.paths.a.ops[0].to.y).to.equal(1)
|
||||
expect(pattern.parts.partA.paths.a.ops[1].to.x).to.equal(11)
|
||||
expect(pattern.parts.partA.paths.a.ops[1].to.y).to.equal(11)
|
||||
// Paths in partB
|
||||
expect(pattern.parts.partB.paths.a.ops[0].to.x).to.equal(1)
|
||||
expect(pattern.parts.partB.paths.a.ops[0].to.y).to.equal(1)
|
||||
expect(pattern.parts.partB.paths.a.ops[1].to.x).to.equal(11)
|
||||
expect(pattern.parts.partB.paths.a.ops[1].to.y).to.equal(11)
|
||||
expect(pattern.parts.partB.paths.b.ops[0].to.x).to.equal(2)
|
||||
expect(pattern.parts.partB.paths.b.ops[0].to.y).to.equal(2)
|
||||
expect(pattern.parts.partB.paths.b.ops[1].to.x).to.equal(22)
|
||||
expect(pattern.parts.partB.paths.b.ops[1].to.y).to.equal(22)
|
||||
// Paths in partC
|
||||
expect(pattern.parts.partC.paths.a.ops[0].to.x).to.equal(1)
|
||||
expect(pattern.parts.partC.paths.a.ops[0].to.y).to.equal(1)
|
||||
expect(pattern.parts.partC.paths.a.ops[1].to.x).to.equal(11)
|
||||
expect(pattern.parts.partC.paths.a.ops[1].to.y).to.equal(11)
|
||||
expect(pattern.parts.partC.paths.b.ops[0].to.x).to.equal(2)
|
||||
expect(pattern.parts.partC.paths.b.ops[0].to.y).to.equal(2)
|
||||
expect(pattern.parts.partC.paths.b.ops[1].to.x).to.equal(22)
|
||||
expect(pattern.parts.partC.paths.b.ops[1].to.y).to.equal(22)
|
||||
expect(pattern.parts.partC.paths.c.ops[0].to.x).to.equal(3)
|
||||
expect(pattern.parts.partC.paths.c.ops[0].to.y).to.equal(3)
|
||||
expect(pattern.parts.partC.paths.c.ops[1].to.x).to.equal(33)
|
||||
expect(pattern.parts.partC.paths.c.ops[1].to.y).to.equal(33)
|
||||
// Paths in partR
|
||||
expect(pattern.parts.partD.paths.d.ops[0].to.x).to.equal(4)
|
||||
expect(pattern.parts.partD.paths.d.ops[0].to.y).to.equal(4)
|
||||
expect(pattern.parts.partD.paths.d.ops[1].to.x).to.equal(44)
|
||||
expect(pattern.parts.partD.paths.d.ops[1].to.y).to.equal(44)
|
||||
})
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue