wip: Added part-level dependencies
Restructured code a bit to handle all part-level config in one call. Removed check in shorthand for debug as it's no longer used. Updated tests to not fall over on different error message format in newer NodeJS versions
This commit is contained in:
parent
689f908f68
commit
4cf9c3bd47
5 changed files with 187 additions and 175 deletions
|
@ -1,5 +1,5 @@
|
|||
import Pattern from './pattern'
|
||||
import { addOptions, addMeasurements, addOptionalMeasurements } from './utils.js'
|
||||
import { addPartConfig } from './utils.js'
|
||||
|
||||
/*
|
||||
* The Design constructor. Returns a Pattern constructor
|
||||
|
@ -11,11 +11,7 @@ export default function Design(config, plugins = false, conditionalPlugins = fal
|
|||
if (!config.measurements) config.measurements = []
|
||||
if (!config.optionalMeasurements) config.optionalMeasurements = []
|
||||
if (config.parts) {
|
||||
for (const partName in config.parts) {
|
||||
config = addOptions(config.parts[partName], config)
|
||||
config = addMeasurements(config.parts[partName], config)
|
||||
config = addOptionalMeasurements(config.parts[partName], config)
|
||||
}
|
||||
for (const partName in config.parts) config = addPartConfig(config.parts[partName], config)
|
||||
}
|
||||
|
||||
// Ensure all options have a hide() method
|
||||
|
|
|
@ -180,9 +180,9 @@ Part.prototype.units = function (input) {
|
|||
|
||||
/** Returns an object with shorthand access for pattern design */
|
||||
Part.prototype.shorthand = function () {
|
||||
let complete = this.context.settings.complete ? true : false
|
||||
let paperless = this.context.settings.paperless === true ? true : false
|
||||
let sa = this.context.settings.complete ? this.context.settings.sa || 0 : 0
|
||||
const complete = this.context.settings.complete ? true : false
|
||||
const paperless = this.context.settings.paperless === true ? true : false
|
||||
const sa = this.context.settings.complete ? this.context.settings.sa || 0 : 0
|
||||
const shorthand = {
|
||||
sa,
|
||||
scale: this.context.settings.scale,
|
||||
|
@ -198,154 +198,142 @@ Part.prototype.shorthand = function () {
|
|||
removeCut: this.removeCut,
|
||||
}
|
||||
|
||||
if (this.context.settings.debug) {
|
||||
// We'll need this
|
||||
let self = this
|
||||
// We'll need this
|
||||
let self = this
|
||||
|
||||
// Wrap the Point constructor so objects can raise events
|
||||
shorthand.Point = function (x, y) {
|
||||
Point.apply(this, [x, y, true])
|
||||
Object.defineProperty(this, 'raise', { value: self.context.raise })
|
||||
}
|
||||
shorthand.Point.prototype = Object.create(Point.prototype)
|
||||
// Wrap the Path constructor so objects can raise events
|
||||
shorthand.Path = function () {
|
||||
Path.apply(this, [true])
|
||||
Object.defineProperty(this, 'raise', { value: self.context.raise })
|
||||
}
|
||||
shorthand.Path.prototype = Object.create(Path.prototype)
|
||||
// Wrap the Snippet constructor so objects can raise events
|
||||
shorthand.Snippet = function (def, anchor) {
|
||||
Snippet.apply(this, [def, anchor, true])
|
||||
Snippet.apply(this, arguments)
|
||||
Object.defineProperty(this, 'raise', { value: self.context.raise })
|
||||
}
|
||||
shorthand.Snippet.prototype = Object.create(Snippet.prototype)
|
||||
|
||||
// Proxy the points object
|
||||
const pointsProxy = {
|
||||
get: function () {
|
||||
return Reflect.get(...arguments)
|
||||
},
|
||||
set: (points, name, value) => {
|
||||
// Constructor checks
|
||||
if (value instanceof Point !== true)
|
||||
self.context.raise.warning(
|
||||
`\`points.${name}\` was set with a value that is not a \`Point\` object`
|
||||
)
|
||||
if (value.x == null || !utils.isCoord(value.x))
|
||||
self.context.raise.warning(
|
||||
`\`points.${name}\` was set with a \`x\` parameter that is not a \`number\``
|
||||
)
|
||||
if (value.y == null || !utils.isCoord(value.y))
|
||||
self.context.raise.warning(
|
||||
`\`points.${name}\` was set with a \`y\` parameter that is not a \`number\``
|
||||
)
|
||||
try {
|
||||
value.name = name
|
||||
} catch (err) {
|
||||
self.context.raise.warning(`Could not set \`name\` property on \`points.${name}\``)
|
||||
}
|
||||
return (self.points[name] = value)
|
||||
},
|
||||
}
|
||||
shorthand.points = new Proxy(this.points || {}, pointsProxy)
|
||||
// Proxy the paths object
|
||||
const pathsProxy = {
|
||||
get: function () {
|
||||
return Reflect.get(...arguments)
|
||||
},
|
||||
set: (paths, name, value) => {
|
||||
// Constructor checks
|
||||
if (value instanceof Path !== true)
|
||||
self.context.raise.warning(
|
||||
`\`paths.${name}\` was set with a value that is not a \`Path\` object`
|
||||
)
|
||||
try {
|
||||
value.name = name
|
||||
} catch (err) {
|
||||
self.context.raise.warning(`Could not set \`name\` property on \`paths.${name}\``)
|
||||
}
|
||||
return (self.paths[name] = value)
|
||||
},
|
||||
}
|
||||
shorthand.paths = new Proxy(this.paths || {}, pathsProxy)
|
||||
// Proxy the snippets object
|
||||
const snippetsProxy = {
|
||||
get: function (target, prop, receiver) {
|
||||
return Reflect.get(...arguments)
|
||||
},
|
||||
set: (snippets, name, value) => {
|
||||
// Constructor checks
|
||||
if (value instanceof Snippet !== true)
|
||||
self.context.raise.warning(
|
||||
`\`snippets.${name}\` was set with a value that is not a \`Snippet\` object`
|
||||
)
|
||||
if (typeof value.def !== 'string')
|
||||
self.context.raise.warning(
|
||||
`\`snippets.${name}\` was set with a \`def\` parameter that is not a \`string\``
|
||||
)
|
||||
if (value.anchor instanceof Point !== true)
|
||||
self.context.raise.warning(
|
||||
`\`snippets.${name}\` was set with an \`anchor\` parameter that is not a \`Point\``
|
||||
)
|
||||
try {
|
||||
value.name = name
|
||||
} catch (err) {
|
||||
self.context.raise.warning(`Could not set \`name\` property on \`snippets.${name}\``)
|
||||
}
|
||||
return (self.snippets[name] = value)
|
||||
},
|
||||
}
|
||||
shorthand.snippets = new Proxy(this.snippets || {}, snippetsProxy)
|
||||
// Proxy the measurements object
|
||||
const measurementsProxy = {
|
||||
get: function (measurements, name) {
|
||||
if (typeof measurements[name] === 'undefined')
|
||||
self.context.raise.warning(
|
||||
`Tried to access \`measurements.${name}\` but it is \`undefined\``
|
||||
)
|
||||
return Reflect.get(...arguments)
|
||||
},
|
||||
set: (measurements, name, value) => (self.context.settings.measurements[name] = value),
|
||||
}
|
||||
shorthand.measurements = new Proxy(this.context.settings.measurements || {}, measurementsProxy)
|
||||
// Proxy the options object
|
||||
const optionsProxy = {
|
||||
get: function (options, name) {
|
||||
if (typeof options[name] === 'undefined')
|
||||
self.context.raise.warning(`Tried to access \`options.${name}\` but it is \`undefined\``)
|
||||
return Reflect.get(...arguments)
|
||||
},
|
||||
set: (options, name, value) => (self.context.settings.options[name] = value),
|
||||
}
|
||||
shorthand.options = new Proxy(this.context.settings.options || {}, optionsProxy)
|
||||
// Proxy the absoluteOptions object
|
||||
const absoluteOptionsProxy = {
|
||||
get: function (absoluteOptions, name) {
|
||||
if (typeof absoluteOptions[name] === 'undefined')
|
||||
self.context.raise.warning(
|
||||
`Tried to access \`absoluteOptions.${name}\` but it is \`undefined\``
|
||||
)
|
||||
return Reflect.get(...arguments)
|
||||
},
|
||||
set: (absoluteOptions, name, value) => (self.context.settings.absoluteOptions[name] = value),
|
||||
}
|
||||
shorthand.absoluteOptions = new Proxy(
|
||||
this.context.settings.absoluteOptions || {},
|
||||
absoluteOptionsProxy
|
||||
)
|
||||
} else {
|
||||
shorthand.Point = Point
|
||||
shorthand.Path = Path
|
||||
shorthand.Snippet = Snippet
|
||||
shorthand.points = this.points || {}
|
||||
shorthand.paths = this.paths || {}
|
||||
shorthand.snippets = this.snippets || {}
|
||||
shorthand.measurements = this.context.settings.measurements || {}
|
||||
shorthand.options = this.context.settings.options || {}
|
||||
shorthand.absoluteOptions = this.context.settings.absoluteOptions || {}
|
||||
// Wrap the Point constructor so objects can raise events
|
||||
shorthand.Point = function (x, y) {
|
||||
Point.apply(this, [x, y, true])
|
||||
Object.defineProperty(this, 'raise', { value: self.context.raise })
|
||||
}
|
||||
shorthand.Point.prototype = Object.create(Point.prototype)
|
||||
// Wrap the Path constructor so objects can raise events
|
||||
shorthand.Path = function () {
|
||||
Path.apply(this, [true])
|
||||
Object.defineProperty(this, 'raise', { value: self.context.raise })
|
||||
}
|
||||
shorthand.Path.prototype = Object.create(Path.prototype)
|
||||
// Wrap the Snippet constructor so objects can raise events
|
||||
shorthand.Snippet = function (def, anchor) {
|
||||
Snippet.apply(this, [def, anchor, true])
|
||||
Snippet.apply(this, arguments)
|
||||
Object.defineProperty(this, 'raise', { value: self.context.raise })
|
||||
}
|
||||
shorthand.Snippet.prototype = Object.create(Snippet.prototype)
|
||||
|
||||
// Proxy the points object
|
||||
const pointsProxy = {
|
||||
get: function () {
|
||||
return Reflect.get(...arguments)
|
||||
},
|
||||
set: (points, name, value) => {
|
||||
// Constructor checks
|
||||
if (value instanceof Point !== true)
|
||||
self.context.raise.warning(
|
||||
`\`points.${name}\` was set with a value that is not a \`Point\` object`
|
||||
)
|
||||
if (value.x == null || !utils.isCoord(value.x))
|
||||
self.context.raise.warning(
|
||||
`\`points.${name}\` was set with a \`x\` parameter that is not a \`number\``
|
||||
)
|
||||
if (value.y == null || !utils.isCoord(value.y))
|
||||
self.context.raise.warning(
|
||||
`\`points.${name}\` was set with a \`y\` parameter that is not a \`number\``
|
||||
)
|
||||
try {
|
||||
value.name = name
|
||||
} catch (err) {
|
||||
self.context.raise.warning(`Could not set \`name\` property on \`points.${name}\``)
|
||||
}
|
||||
return (self.points[name] = value)
|
||||
},
|
||||
}
|
||||
shorthand.points = new Proxy(this.points || {}, pointsProxy)
|
||||
// Proxy the paths object
|
||||
const pathsProxy = {
|
||||
get: function () {
|
||||
return Reflect.get(...arguments)
|
||||
},
|
||||
set: (paths, name, value) => {
|
||||
// Constructor checks
|
||||
if (value instanceof Path !== true)
|
||||
self.context.raise.warning(
|
||||
`\`paths.${name}\` was set with a value that is not a \`Path\` object`
|
||||
)
|
||||
try {
|
||||
value.name = name
|
||||
} catch (err) {
|
||||
self.context.raise.warning(`Could not set \`name\` property on \`paths.${name}\``)
|
||||
}
|
||||
return (self.paths[name] = value)
|
||||
},
|
||||
}
|
||||
shorthand.paths = new Proxy(this.paths || {}, pathsProxy)
|
||||
// Proxy the snippets object
|
||||
const snippetsProxy = {
|
||||
get: function (target, prop, receiver) {
|
||||
return Reflect.get(...arguments)
|
||||
},
|
||||
set: (snippets, name, value) => {
|
||||
// Constructor checks
|
||||
if (value instanceof Snippet !== true)
|
||||
self.context.raise.warning(
|
||||
`\`snippets.${name}\` was set with a value that is not a \`Snippet\` object`
|
||||
)
|
||||
if (typeof value.def !== 'string')
|
||||
self.context.raise.warning(
|
||||
`\`snippets.${name}\` was set with a \`def\` parameter that is not a \`string\``
|
||||
)
|
||||
if (value.anchor instanceof Point !== true)
|
||||
self.context.raise.warning(
|
||||
`\`snippets.${name}\` was set with an \`anchor\` parameter that is not a \`Point\``
|
||||
)
|
||||
try {
|
||||
value.name = name
|
||||
} catch (err) {
|
||||
self.context.raise.warning(`Could not set \`name\` property on \`snippets.${name}\``)
|
||||
}
|
||||
return (self.snippets[name] = value)
|
||||
},
|
||||
}
|
||||
shorthand.snippets = new Proxy(this.snippets || {}, snippetsProxy)
|
||||
// Proxy the measurements object
|
||||
const measurementsProxy = {
|
||||
get: function (measurements, name) {
|
||||
if (typeof measurements[name] === 'undefined')
|
||||
self.context.raise.warning(
|
||||
`Tried to access \`measurements.${name}\` but it is \`undefined\``
|
||||
)
|
||||
return Reflect.get(...arguments)
|
||||
},
|
||||
set: (measurements, name, value) => (self.context.settings.measurements[name] = value),
|
||||
}
|
||||
shorthand.measurements = new Proxy(this.context.settings.measurements || {}, measurementsProxy)
|
||||
// Proxy the options object
|
||||
const optionsProxy = {
|
||||
get: function (options, name) {
|
||||
if (typeof options[name] === 'undefined')
|
||||
self.context.raise.warning(`Tried to access \`options.${name}\` but it is \`undefined\``)
|
||||
return Reflect.get(...arguments)
|
||||
},
|
||||
set: (options, name, value) => (self.context.settings.options[name] = value),
|
||||
}
|
||||
shorthand.options = new Proxy(this.context.settings.options || {}, optionsProxy)
|
||||
// Proxy the absoluteOptions object
|
||||
const absoluteOptionsProxy = {
|
||||
get: function (absoluteOptions, name) {
|
||||
if (typeof absoluteOptions[name] === 'undefined')
|
||||
self.context.raise.warning(
|
||||
`Tried to access \`absoluteOptions.${name}\` but it is \`undefined\``
|
||||
)
|
||||
return Reflect.get(...arguments)
|
||||
},
|
||||
set: (absoluteOptions, name, value) => (self.context.settings.absoluteOptions[name] = value),
|
||||
}
|
||||
shorthand.absoluteOptions = new Proxy(
|
||||
this.context.settings.absoluteOptions || {},
|
||||
absoluteOptionsProxy
|
||||
)
|
||||
|
||||
return shorthand
|
||||
}
|
||||
|
|
|
@ -3,9 +3,7 @@ import {
|
|||
sampleStyle,
|
||||
capitalize,
|
||||
decoratePartDependency,
|
||||
addOptions,
|
||||
addMeasurements,
|
||||
addOptionalMeasurements
|
||||
addPartConfig,
|
||||
} from './utils.js'
|
||||
import Part from './part'
|
||||
import Point from './point'
|
||||
|
@ -256,10 +254,8 @@ Pattern.prototype.addPart = function (part, name=false) {
|
|||
if (typeof part?.draft === 'function') {
|
||||
if (part.name) {
|
||||
this.config.parts[part.name] = part
|
||||
// Add part options/measurements/optionalMeasurements to config
|
||||
this.config = addOptions(part, this.config)
|
||||
this.config = addMeasurements(part, this.config)
|
||||
this.config = addOptionalMeasurements(part, this.config)
|
||||
// Add part-level config to config
|
||||
this.config = addPartConfig(part, this.config)
|
||||
}
|
||||
else this.raise.error(`Part must have a name`)
|
||||
}
|
||||
|
|
|
@ -390,26 +390,26 @@ export const generatePartTransform = (x, y, rotate, flipX, flipY, part) => {
|
|||
export const decoratePartDependency = (obj, name) => (typeof obj === 'function') ? { draft: obj, name } : obj
|
||||
|
||||
// Add part-level options
|
||||
export const addOptions = (part, config) => {
|
||||
const addPartOptions = (part, config) => {
|
||||
if (part.options) {
|
||||
for (const optionName in part.options) {
|
||||
config.options[optionName] = part.options[optionName]
|
||||
}
|
||||
}
|
||||
if (part.from) addOptions(part.from, config)
|
||||
if (part.from) addPartOptions(part.from, config)
|
||||
|
||||
return config
|
||||
}
|
||||
|
||||
// Add part-level measurements
|
||||
export const addMeasurements = (part, config, list=false) => {
|
||||
const addPartMeasurements = (part, config, list=false) => {
|
||||
if (!list) list = config.measurements
|
||||
? [...config.measurements]
|
||||
: []
|
||||
if (part.measurements) {
|
||||
for (const m of part.measurements) list.push(m)
|
||||
}
|
||||
if (part.from) addMeasurements(part.from, config, list)
|
||||
if (part.from) addPartMeasurements(part.from, config, list)
|
||||
|
||||
// Weed out duplicates
|
||||
config.measurements = [...new Set(list)]
|
||||
|
@ -418,7 +418,7 @@ export const addMeasurements = (part, config, list=false) => {
|
|||
}
|
||||
|
||||
// Add part-level optional measurements
|
||||
export const addOptionalMeasurements = (part, config, list=false) => {
|
||||
const addPartOptionalMeasurements = (part, config, list=false) => {
|
||||
if (!list) list = config.optionalMeasurements
|
||||
? [...config.optionalMeasurements]
|
||||
: []
|
||||
|
@ -428,7 +428,7 @@ export const addOptionalMeasurements = (part, config, list=false) => {
|
|||
if (config.measurements.indexOf(m) === -1) list.push(m)
|
||||
}
|
||||
}
|
||||
if (part.from) addOptionalMeasurements(part.from, config, list)
|
||||
if (part.from) addPartOptionalMeasurements(part.from, config, list)
|
||||
|
||||
// Weed out duplicates
|
||||
config.optionalMeasurements = [...new Set(list)]
|
||||
|
@ -437,3 +437,34 @@ export const addOptionalMeasurements = (part, config, list=false) => {
|
|||
}
|
||||
|
||||
|
||||
const addDependencies = (dep, current) => {
|
||||
// Current dependencies
|
||||
const list = []
|
||||
if (Array.isArray(current)) list.push(...current)
|
||||
else if (typeof current === 'string') list.push(current)
|
||||
|
||||
if (Array.isArray(dep)) list.push(...dep)
|
||||
else if (typeof dep === 'string') list.push(dep)
|
||||
|
||||
return [...new Set(list)]
|
||||
}
|
||||
|
||||
// Add part-level dependencies
|
||||
export const addPartDependencies = (part, config) => {
|
||||
if (part.after) {
|
||||
config.dependencies[part.name] = addDependencies(config.dependencies[part.name], part.after)
|
||||
}
|
||||
|
||||
return config
|
||||
}
|
||||
|
||||
export const addPartConfig = (part, config) => {
|
||||
config = addPartOptions(part, config)
|
||||
config = addPartMeasurements(part, config)
|
||||
config = addPartOptionalMeasurements(part, config)
|
||||
config = addPartDependencies(part, config)
|
||||
|
||||
return config
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -1017,7 +1017,7 @@ it("Should raise a warning when an insop operation used an falsy ID", () => {
|
|||
new freesewing.Path().withRaise(raise).noop('test').insop('test')
|
||||
}
|
||||
catch (err) {
|
||||
expect(''+err).to.contain("Cannot read property 'ops")
|
||||
expect(''+err).to.contain("Cannot read prop")
|
||||
}
|
||||
expect(invalid).to.equal(true);
|
||||
});
|
||||
|
@ -1057,10 +1057,11 @@ it("Should raise a warning when calling join without a path", () => {
|
|||
points.a = new Point(0,0)
|
||||
points.b = new Point(10,10)
|
||||
try {
|
||||
paths.a = new Path().move(points.a).line(points.b).join()
|
||||
//paths.a = new Path().move(points.a).line(points.b).join()
|
||||
pattern.parts.a.paths.a = new Path().move(points.a).line(points.b).join()
|
||||
}
|
||||
catch (err) {
|
||||
expect(''+err).to.contain("Cannot read property 'ops")
|
||||
expect(''+err).to.contain("Cannot read prop")
|
||||
}
|
||||
expect(pattern.events.error.length).to.equal(1)
|
||||
expect(pattern.events.error[0]).to.equal("Called `Path.join(that)` but `that` is not a `Path` object")
|
||||
|
@ -1074,7 +1075,7 @@ it("Should raise a warning when calling start on a path without drawing operatio
|
|||
new freesewing.Path().withRaise(raise).start()
|
||||
}
|
||||
catch (err) {
|
||||
expect(''+err).to.contain("TypeError: Cannot read property")
|
||||
expect(''+err).to.contain("TypeError: Cannot read prop")
|
||||
}
|
||||
expect(invalid).to.equal(true);
|
||||
});
|
||||
|
@ -1087,7 +1088,7 @@ it("Should raise a warning when calling end on a path without drawing operations
|
|||
new freesewing.Path().withRaise(raise).end()
|
||||
}
|
||||
catch (err) {
|
||||
expect(''+err).to.contain("TypeError: Cannot read property")
|
||||
expect(''+err).to.contain("TypeError: Cannot read prop")
|
||||
}
|
||||
expect(invalid).to.equal(true);
|
||||
});
|
||||
|
@ -1140,7 +1141,7 @@ it("Should raise a warning when splitting a path on a non-point", () => {
|
|||
path.split()
|
||||
}
|
||||
catch (err) {
|
||||
expect(''+err).to.contain("TypeError: Cannot read property")
|
||||
expect(''+err).to.contain("TypeError: Cannot read prop")
|
||||
}
|
||||
expect(invalid).to.equal(true);
|
||||
});
|
||||
|
@ -1164,7 +1165,7 @@ it("Should raise a warning when splitting a path on a non-point", () => {
|
|||
path.split()
|
||||
}
|
||||
catch (err) {
|
||||
expect(''+err).to.contain("TypeError: Cannot read property")
|
||||
expect(''+err).to.contain("TypeError: Cannot read prop")
|
||||
}
|
||||
expect(invalid).to.equal(true);
|
||||
});
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue