1
0
Fork 0

feat(core): Move plugins to part-level config

This commit is contained in:
Joost De Cock 2022-08-31 17:52:39 +02:00
parent fa14ad0fa3
commit 8a74a36697
5 changed files with 124 additions and 196 deletions

View file

@ -8,12 +8,12 @@ import { addPartConfig } from './utils.mjs'
*/ */
export function Design(config) { export function Design(config) {
// Merge config with defaults // Initialize config with defaults
config = { config = {
parts: [],
options: {},
measurements: [], measurements: [],
optionalMeasurements: [], optionalMeasurements: [],
options: {},
parts: [],
plugins: [], plugins: [],
...config ...config
} }
@ -37,16 +37,7 @@ export function Design(config) {
const pattern = function (settings) { const pattern = function (settings) {
Pattern.call(this, config) Pattern.call(this, config)
// Load plugins return this.init().apply(settings)
if (!Array.isArray(config.plugins)) config.plugins = [ config.plugins ]
for (const plugin of config.plugins) {
if (plugin.plugin && plugin.condition) this.useIf(plugin, settings)
else this.use(plugin)
}
this.apply(settings)
return this
} }
// Set up inheritance // Set up inheritance

View file

@ -173,6 +173,10 @@ Pattern.prototype.getPartList = function () {
*/ */
Pattern.prototype.init = function () { Pattern.prototype.init = function () {
this.initialized++ this.initialized++
// Load plugins
if (this.config.plugins) {
for (const plugin of Object.values(this.config.plugins)) this.use(plugin)
}
// Resolve all dependencies // Resolve all dependencies
this.dependencies = this.config.dependencies this.dependencies = this.config.dependencies
this.inject = this.config.inject this.inject = this.config.inject
@ -522,12 +526,19 @@ Pattern.prototype.render = function () {
} }
Pattern.prototype.on = function (hook, method, data) { Pattern.prototype.on = function (hook, method, data) {
for (const added of this.hooks[hook]) {
// Don't add it twice
if (added.method === method) return this
}
this.hooks[hook].push({ method, data }) this.hooks[hook].push({ method, data })
return this return this
} }
Pattern.prototype.use = function (plugin, data) { Pattern.prototype.use = function (plugin, data) {
// Conditional plugin?
if (plugin.plugin && plugin.condition) return this.useIf(plugin, data)
// Regular plugin
this.raise.info(`Loaded plugin \`${plugin.name}:${plugin.version}\``) this.raise.info(`Loaded plugin \`${plugin.name}:${plugin.version}\``)
if (plugin.hooks) this.loadPluginHooks(plugin, data) if (plugin.hooks) this.loadPluginHooks(plugin, data)
if (plugin.macros) this.loadPluginMacros(plugin) if (plugin.macros) this.loadPluginMacros(plugin)

View file

@ -567,12 +567,25 @@ export const addPartDependencies = (part, config) => {
return config return config
} }
// Add part-level plugins
export const addPartPlugins = (part, config) => {
if (!part.plugins) return config
if (!Array.isArray(part.plugins)) part.plugins = [ part.plugins ]
for (const plugin of part.plugins) {
if (plugin.plugin && plugin.condition) config.plugins[plugin.plugin.name] = plugin
else config.plugins[plugin.name] = plugin
}
return config
}
export const addPartConfig = (part, config) => { export const addPartConfig = (part, config) => {
config = addPartOptions(part, config) config = addPartOptions(part, config)
config = addPartMeasurements(part, config) config = addPartMeasurements(part, config)
config = addPartOptionalMeasurements(part, config) config = addPartOptionalMeasurements(part, config)
config = addPartDependencies(part, config) config = addPartDependencies(part, config)
config = addPartOptionGroups(part, config) config = addPartOptionGroups(part, config)
config = addPartPlugins(part, config)
return config return config
} }

View file

@ -24,99 +24,6 @@ describe('Design', () => {
expect(pattern.settings.options.percentage).to.equal(0.3); expect(pattern.settings.options.percentage).to.equal(0.3);
}); });
it("Design constructor should load single plugin", () => {
let plugin = {
name: "example",
version: 1,
hooks: {
preRender: function(svg, attributes) {
svg.attributes.add("freesewing:plugin-example", version);
}
}
};
let design = new Design({plugins: plugin});
let pattern = new design();
expect(pattern.hooks.preRender.length).to.equal(1);
});
it("Design constructor should load array of plugins", () => {
let plugin1 = {
name: "example1",
version: 1,
hooks: {
preRender: function(svg, attributes) {
svg.attributes.add("freesewing:plugin-example1", version);
}
}
};
let plugin2 = {
name: "example2",
version: 2,
hooks: {
preRender: function(svg, attributes) {
svg.attributes.add("freesewing:plugin-example2", version);
}
}
};
let design = new Design( { plugins: [plugin1, plugin2] });
let pattern = new design();
expect(pattern.hooks.preRender.length).to.equal(2);
});
it("Design constructor should load conditional plugin", () => {
const plugin = {
name: "example",
version: 1,
hooks: {
preRender: function(svg, attributes) {
svg.attributes.add("freesewing:plugin-example", version);
}
}
};
const condition = () => true
const design = new Design({ plugins: { plugin, condition } });
const pattern = new design();
expect(pattern.hooks.preRender.length).to.equal(1);
});
it("Design constructor should not load conditional plugin", () => {
const plugin = {
name: "example",
version: 1,
hooks: {
preRender: function(svg, attributes) {
svg.attributes.add("freesewing:plugin-example", version);
}
}
};
const condition = () => false
const design = new Design({ plugins: { plugin, condition } });
const pattern = new design();
expect(pattern.hooks.preRender.length).to.equal(0);
});
it("Design constructor should load multiple conditional plugins", () => {
const plugin = {
name: "example",
version: 1,
hooks: {
preRender: function(svg, attributes) {
svg.attributes.add("freesewing:plugin-example", version);
}
}
};
const condition1 = () => true
const condition2 = () => false
const design = new Design({ plugins: [
{ plugin, condition: condition1 },
{ plugin, condition: condition2 },
]});
const pattern = new design();
expect(pattern.hooks.preRender.length).to.equal(1);
});
/* /*
it("Design constructor should not require depencies for injected parts", () => { it("Design constructor should not require depencies for injected parts", () => {
let design = new freesewing.Design({ let design = new freesewing.Design({

View file

@ -1059,98 +1059,104 @@ describe('Pattern', () => {
expect(pattern.parts.partD.paths.d.ops[1].to.x).to.equal(44) 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) expect(pattern.parts.partD.paths.d.ops[1].to.y).to.equal(44)
}) })
it("Pattern should merge optiongroups", () => {
const partA = { it("Pattern should load single plugin", () => {
name: "partA", const plugin = {
options: { optionA: { bool: true } }, name: "example",
measurements: [ 'measieA' ], version: 1,
optionalMeasurements: [ 'optmeasieA' ], hooks: {
optionGroups: { preRender: function(svg, attributes) {
simple: ['simplea1', 'simplea2', 'simplea3'], svg.attributes.add("freesewing:plugin-example", version);
nested: {
nested1: [ 'nested1a1', 'nested1a2', 'nested1a3' ],
},
subnested: {
subnested1: [
'subnested1a1',
'subnested1a2',
'subnested1a3',
{
subsubgroup: [
'subsuba1',
'subsuba2',
{
subsubsubgroup: [ 'subsubsub1', 'simplea1' ],
}
]
}
]
} }
}, }
draft: part => part, };
const part = {
name: 'test.part',
plugins: plugin,
draft: (part) => part
} }
const partB = { const design = new Design({ parts: [ part ] })
name: "partB", const pattern = new design();
from: partA, pattern.init()
options: { optionB: { pct: 12, min: 2, max: 20 } }, console.log(pattern)
measurements: [ 'measieB' ], expect(pattern.hooks.preRender.length).to.equal(1);
optionalMeasurements: [ 'optmeasieB', 'measieA' ], });
optionGroups: { /*
simple: ['simpleb1', 'simpleb2', 'simpleb3'], it("Design constructor should load array of plugins", () => {
bsimple: ['bsimpleb1', 'bsimpleb2', 'bsimpleb3'], let plugin1 = {
nested: { name: "example1",
nested2: [ 'nested2b1', 'nested2b2', 'nested2b3' ], version: 1,
}, hooks: {
subnested: { preRender: function(svg, attributes) {
subnested1: [ svg.attributes.add("freesewing:plugin-example1", version);
'subnested1b1',
'subnested1b2',
'subnested1b3',
{
subsubgroup: [
'subsubb1',
'subsubb2',
{
subsubsubgroup: [ 'bsubsubsub1', 'simplea1' ],
}
]
}
]
} }
}, }
draft: part => part, };
} let plugin2 = {
let design, pattern name: "example2",
try { version: 2,
design = new Design({ parts: [ partB ] }); hooks: {
pattern = new design().init() preRender: function(svg, attributes) {
} catch(err) { svg.attributes.add("freesewing:plugin-example2", version);
console.log(err) }
} }
const og = pattern.config.optionGroups };
expect(og.simple.length).to.equal(6)
expect(og.simple.indexOf('simplea1') === -1).to.equal(false) let design = new Design( { plugins: [plugin1, plugin2] });
expect(og.simple.indexOf('simplea2') === -1).to.equal(false) let pattern = new design();
expect(og.simple.indexOf('simplea3') === -1).to.equal(false) expect(pattern.hooks.preRender.length).to.equal(2);
expect(og.simple.indexOf('simpleb1') === -1).to.equal(false) });
expect(og.simple.indexOf('simpleb2') === -1).to.equal(false) it("Design constructor should load conditional plugin", () => {
expect(og.simple.indexOf('simpleb3') === -1).to.equal(false) const plugin = {
expect(og.nested.nested1.length).to.equal(3) name: "example",
expect(og.nested.nested1.indexOf('nested1a1') === -1).to.equal(false) version: 1,
expect(og.nested.nested1.indexOf('nested1a2') === -1).to.equal(false) hooks: {
expect(og.nested.nested1.indexOf('nested1a3') === -1).to.equal(false) preRender: function(svg, attributes) {
expect(og.nested.nested2.length).to.equal(3) svg.attributes.add("freesewing:plugin-example", version);
expect(og.nested.nested2.indexOf('nested2b1') === -1).to.equal(false) }
expect(og.nested.nested2.indexOf('nested2b2') === -1).to.equal(false) }
expect(og.nested.nested2.indexOf('nested2b3') === -1).to.equal(false) };
expect(og.subnested.subnested1.length).to.equal(8) const condition = () => true
expect(og.subnested.subnested1.indexOf('subnested1a1') === -1).to.equal(false) const design = new Design({ plugins: { plugin, condition } });
expect(og.subnested.subnested1.indexOf('subnested1a2') === -1).to.equal(false) const pattern = new design();
expect(og.subnested.subnested1.indexOf('subnested1a3') === -1).to.equal(false) expect(pattern.hooks.preRender.length).to.equal(1);
expect(og.subnested.subnested1.indexOf('subnested1b1') === -1).to.equal(false) });
expect(og.subnested.subnested1.indexOf('subnested1b2') === -1).to.equal(false)
expect(og.subnested.subnested1.indexOf('subnested1b3') === -1).to.equal(false) it("Design constructor should not load conditional plugin", () => {
// FIXME: Some work to be done still with deep-nesting of groups with the same name const plugin = {
}) name: "example",
version: 1,
hooks: {
preRender: function(svg, attributes) {
svg.attributes.add("freesewing:plugin-example", version);
}
}
};
const condition = () => false
const design = new Design({ plugins: { plugin, condition } });
const pattern = new design();
expect(pattern.hooks.preRender.length).to.equal(0);
});
it("Design constructor should load multiple conditional plugins", () => {
const plugin = {
name: "example",
version: 1,
hooks: {
preRender: function(svg, attributes) {
svg.attributes.add("freesewing:plugin-example", version);
}
}
};
const condition1 = () => true
const condition2 = () => false
const design = new Design({ plugins: [
{ plugin, condition: condition1 },
{ plugin, condition: condition2 },
]});
const pattern = new design();
expect(pattern.hooks.preRender.length).to.equal(1);
*/
}) })