diff --git a/packages/core/test/util.test.mjs b/packages/core/test/util.test.mjs index 69ee2cc3..5e8c906e 100644 --- a/packages/core/test/util.test.mjs +++ b/packages/core/test/util.test.mjs @@ -1,5 +1,5 @@ import { strict as assert } from 'assert'; -import { isNote, tokenizeNote, toMidi, mod } from '../util.mjs'; +import { isNote, tokenizeNote, toMidi, mod, compose } from '../util.mjs'; describe('isNote', () => { it('should recognize notes without accidentals', () => { @@ -83,3 +83,16 @@ describe('mod', () => { assert.equal(mod(-3, 2), 1); }); }); + +describe('compose', () => { + const add1 = (a) => a + 1; + it('should compose', () => { + assert.equal(compose(add1, add1)(0), 2); + assert.equal(compose(add1)(0), 1); + }); + const addS = (s) => (a) => a + s; + it('should compose left to right', () => { + assert.equal(compose(addS('a'), addS('b'))(''), 'ab'); + assert.equal(compose(addS('a'), addS('b'))('x'), 'xab'); + }); +}); diff --git a/packages/core/util.mjs b/packages/core/util.mjs index 4cfea99b..719918e3 100644 --- a/packages/core/util.mjs +++ b/packages/core/util.mjs @@ -42,3 +42,14 @@ export const getPlayableNoteValue = (event) => { // rotate array by n steps (to the left) export const rotate = (arr, n) => arr.slice(n).concat(arr.slice(0, n)); + +export const pipe = (...funcs) => { + return funcs.reduce( + (f, g) => + (...args) => + f(g(...args)), + (x) => x, + ); +}; + +export const compose = (...funcs) => pipe(...funcs.reverse());