1
0
Fork 0

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:
joostdecock 2022-08-14 16:59:51 +02:00
parent 4cf9c3bd47
commit 2b254c721d
3 changed files with 203 additions and 13 deletions

View file

@ -4,6 +4,7 @@ import {
capitalize, capitalize,
decoratePartDependency, decoratePartDependency,
addPartConfig, addPartConfig,
mergeDependencies,
} from './utils.js' } from './utils.js'
import Part from './part' import Part from './part'
import Point from './point' import Point from './point'
@ -215,7 +216,7 @@ function snappedOption(option, pattern) {
// Merges settings object with this.settings // Merges settings object with this.settings
Pattern.prototype.apply = function (settings) { Pattern.prototype.apply = function (settings) {
if (typeof settings !== 'object') { if (typeof settings !== 'object') {
this.raise.warning('Pattern initialized without any settings') this.raise.warning('Pattern instantiated without any settings')
return this return this
} }
for (let key of Object.keys(settings)) { for (let key of Object.keys(settings)) {
@ -678,23 +679,57 @@ Pattern.prototype.resolveDependency = function (
return deps 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 */ /** Pre-Resolves part dependencies that are passed in 2022 style */
Pattern.prototype.preresolveDependencies = function (count=0) { Pattern.prototype.preresolveDependencies = function (count=0) {
const len = Object.keys(this.__parts).length
if (!this.__parts) return if (!this.__parts) return
for (const [name, part] of Object.entries(this.__parts)) { for (const [name, part] of Object.entries(this.__parts)) {
// Inject (from)
if (part.from) { if (part.from) {
this.inject[name] = part.from.name this.inject[name] = part.from.name
if (typeof this.__parts[part.from.name] === 'undefined') { if (typeof this.__parts[part.from.name] === 'undefined') {
this.__parts[part.from.name] = decoratePartDependency(part.from) 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) if (len > count) return this.preresolveDependencies(len)
? this.preresolveDependencies()
: this 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 */ /** Resolves part dependencies into a flat array */

View file

@ -437,7 +437,7 @@ const addPartOptionalMeasurements = (part, config, list=false) => {
} }
const addDependencies = (dep, current) => { export const mergeDependencies = (dep=[], current=[]) => {
// Current dependencies // Current dependencies
const list = [] const list = []
if (Array.isArray(current)) list.push(...current) if (Array.isArray(current)) list.push(...current)
@ -446,13 +446,21 @@ const addDependencies = (dep, current) => {
if (Array.isArray(dep)) list.push(...dep) if (Array.isArray(dep)) list.push(...dep)
else if (typeof dep === 'string') 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 // Add part-level dependencies
export const addPartDependencies = (part, config) => { export const addPartDependencies = (part, config) => {
if (part.after) { 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 return config
@ -467,4 +475,3 @@ export const addPartConfig = (part, config) => {
return config return config
} }

View file

@ -1,6 +1,6 @@
let expect = require("chai").expect; let expect = require("chai").expect;
let freesewing = require("../dist/index.js"); let freesewing = require("../dist/index.js");
/*
it("Pattern constructor should initialize object", () => { it("Pattern constructor should initialize object", () => {
let pattern = new freesewing.Pattern({ let pattern = new freesewing.Pattern({
foo: "bar", foo: "bar",
@ -725,7 +725,7 @@ it("Should retrieve the cutList", () => {
// 2022 style part inheritance // 2022 style part inheritance
// I am aware this does too much for one unit test, but this is to simplify TDD // I am aware this does too much for one unit test, but this is to simplify TDD
// we can split it up later // we can split it up later
it("Design constructor should resolve nested dependencies (2022)", () => { it("Design constructor should resolve nested injections (2022)", () => {
const partA = { const partA = {
name: "partA", name: "partA",
options: { optionA: { bool: true } }, 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 const partR = { // R for runtime, which is when this wil be attached
name: "partR", name: "partR",
from: partA, from: partA,
after: partC,
options: { optionR: { dflt: 'red', list: ['red', 'green', 'blue'] } }, options: { optionR: { dflt: 'red', list: ['red', 'green', 'blue'] } },
measurements: [ 'measieR' ], measurements: [ 'measieR' ],
optionalMeasurements: [ 'optmeasieR', 'measieA' ], optionalMeasurements: [ 'optmeasieR', 'measieA' ],
@ -812,7 +813,8 @@ it("Design constructor should resolve nested dependencies (2022)", () => {
// Dependencies // Dependencies
expect(pattern.config.dependencies.partB[0]).to.equal('partA') expect(pattern.config.dependencies.partB[0]).to.equal('partA')
expect(pattern.config.dependencies.partC[0]).to.equal('partB') 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 // Inject
expect(pattern.config.inject.partB).to.equal('partA') expect(pattern.config.inject.partB).to.equal('partA')
expect(pattern.config.inject.partC).to.equal('partB') 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.x).to.equal(44)
expect(pattern.parts.partR.paths.r.ops[1].to.y).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)
})