diff --git a/src/index.js b/src/index.js index cf6a03e..f4174d4 100644 --- a/src/index.js +++ b/src/index.js @@ -3,36 +3,13 @@ * @copyright (c) 2021 Julien Gonzalez */ -const tag_function = require('./utils/tag-function'); -const use_tag = require('./utils/use-tag'); -const intersperse = require('./utils/intersperse'); -const defaults = require('./defaults'); -const hide = require('./hide'); -const list = require('./list'); -const lower = require('./lower'); -const pluralize = require('./pluralize'); -const time = require('./time'); -const trim = require('./trim'); -const upper = require('./upper'); - -const - { compose - , join - } = require('./utils/fp'); - -const tag = (...fns) => - (strs, ...vals) => - compose(join(''), ...fns.map(use_tag.unwrap)) - (intersperse(strs, vals)); - -tag.defaults = use_tag(defaults); -tag.list = use_tag(list); -tag.hide = use_tag(hide); -tag.lower = use_tag(lower); -tag.pluralize = use_tag(pluralize); -tag.time = use_tag(time); -tag.trim = use_tag(trim); -tag.upper = use_tag(upper); -tag.of = compose(use_tag, tag_function); - -module.exports = tag; \ No newline at end of file +module.exports = { + defaults: require('./defaults'), + hide: require('./hide'), + list: require('./list'), + lower: require('./lower'), + pluralize: require('./pluralize'), + time: require('./time'), + trim: require('./trim'), + upper: require('./upper') +}; diff --git a/src/utils/intersperse.js b/src/utils/intersperse.js deleted file mode 100644 index d04fa24..0000000 --- a/src/utils/intersperse.js +++ /dev/null @@ -1,19 +0,0 @@ -/** - * @license MIT - * @copyright (c) 2021 Julien Gonzalez - */ - -const {init} = require('./fp'); - -/** - * Put `ys` inside `xs` at regular intervals. - * - * @example - * intersperse([1, 3, 5], [2, 4]) - * //=> [1, 2, 3, 4, 5] - * - * @param {Array} xs - * @param {Array} ys - * @return {Array} - */ -module.exports = (xs, ys) => init(xs.flatMap((x, i) => [x, ys[i]])); diff --git a/src/utils/tag-function.js b/src/utils/tag-function.js index ff32bd1..187d65a 100644 --- a/src/utils/tag-function.js +++ b/src/utils/tag-function.js @@ -3,15 +3,79 @@ * @copyright (c) 2021 Julien Gonzalez */ +const {cont, init} = require('./fp'); + +/** + * Put `ys` inside `xs` at regular intervals. + * + * @example + * intersperse([1, 3, 5], [2, 4]) + * //=> [1, 2, 3, 4, 5] + * + * @param {Array} xs + * @param {Array} ys + * @return {Array} + */ +const intersperse = + (xs, ys) => + init(xs.flatMap((x, i) => [x, ys[i]])); + +/** + * Given `fn` a function that takes three parameters and returns + * a tuple 'x' of three elements, apply `fn` to tuples 'y' of three elements. + * The first tuple 'y' is made of the first three elements of `xs`. + * The next tuple 'y' (and all others) takes its first element from the + * last element of tuple 'x' returned by `fn` when applied to the previous tuple 'y'. + * The last two elements of tuple 'y' are taken from the next two consecutive elements of `xs`. + * + * Example: + * + * ```javascript + * const fn = (a, b, c) => [a+1, b+2, c+3]; + * const xs = [10, 20, 30, 40, 50, 60]; + * transformer(fn, xs); + * // [10, 20, 30, 40, 50, 60, 70] + * // ^^ ^^ ^^ + * // [11, 22, 33, 40, 50, 60, 70] + * // ^^ ^^ ^^ + * // [11, 22, 34, 42, 53, 60, 70] + * // ^^ ^^ ^^ + * //=> [11, 22, 34, 43, 54, 62, 73] + * ``` + * + * @param {function()} fn + * @param {Array} xs + * @param {number} [i=1] + * @return {Array} + */ +const transformer = + (fn, xs, i=1) => + i >= xs.length + ? xs + : cont(fn(...xs.slice(i-1, i+2))) + ( ret => + transformer + ( fn + , xs.slice(0, i-1).concat(ret, xs.slice(i+2)) + , i+2 + )); + +const read_user_config = + fn => (strings_or_config, ...values) => + Array.isArray(strings_or_config) + ? fn({}, strings_or_config, values) + : (strings, ...values) => fn(strings_or_config, strings, values); + /** * @param {TagFunction} fn * @param {!TagOptions=} opts * @return {TagFunction|TagConfigFunction} */ module.exports = - (fn, opts = {}) => (...args) => - { const is_config_call = typeof args[0] === 'object'; // foo`…` vs foo({…})`…` - return (is_config_call - ? (l, x, r) => fn(l, x, r, {...opts, ...args[0]}) - : fn(...args, opts)); - }; + (fn, default_config = {}, postprocess = xs => xs.join('')) => + read_user_config((user_config, strings, values) => + { const final_config = {...default_config, ...user_config}; + const parts = intersperse(strings, values); + const preprocess = (l, x, r) => fn(l, x, r, final_config); + return postprocess(transformer(preprocess, parts)); + }); \ No newline at end of file diff --git a/src/utils/transform.js b/src/utils/transform.js deleted file mode 100644 index 296aa44..0000000 --- a/src/utils/transform.js +++ /dev/null @@ -1,20 +0,0 @@ -/** - * @license MIT - * @copyright (c) 2021 Julien Gonzalez - */ - -const {cont} = require('./fp'); - -const transformer = (fn, xs, i=1) => - i >= xs.length - ? xs - : cont(fn(...xs.slice(i-1, i+2))) - ( ret => - transformer - ( fn - , xs.slice(0, i-1).concat(ret, xs.slice(i+2)) - , i+2 - ) - ); - -module.exports = fn => xs => transformer(fn, xs); diff --git a/src/utils/use-tag.js b/src/utils/use-tag.js deleted file mode 100644 index 33b7ce1..0000000 --- a/src/utils/use-tag.js +++ /dev/null @@ -1,32 +0,0 @@ -/** - * @license MIT - * @copyright (c) 2021 Julien Gonzalez - */ - -const {compose, join} = require('./fp'); -const intersperse = require('./intersperse'); -const transform = require('./transform'); - -const KEY = Symbol(); - -const is_opts = - x => - x !== null - && !Array.isArray(x) - && typeof x === 'object'; - -const tag_function = fn => { - const tag_fn = - (strs, ...vals) => - is_opts(strs) - ? tag_function(fn(strs)) - : compose(join(''), transform(fn), intersperse) - (strs, vals); - - tag_fn[KEY] = transform(fn); - return tag_fn; -}; - -tag_function.unwrap = fn => fn[KEY] || fn; - -module.exports = tag_function; diff --git a/test.js b/test.js index 86e8fe0..52e8c74 100644 --- a/test.js +++ b/test.js @@ -1,5 +1,4 @@ const test = require('tape'); -const tag = require('./dist'); const { defaults , hide @@ -11,15 +10,6 @@ const , upper } = require('./dist'); -test('tag: can compose other tags', t => { - t.plan(1); - - t.is - ( tag(upper, trim)`foo=${' foo '}, bar=${' bar '}` - , "foo=FOO, bar=BAR" - ); -}); - test('defaults: replace empty values', t => { t.plan(2); @@ -36,43 +26,6 @@ test('defaults: replace empty values', t => { ); }); -test('tag: can compose user-defined tags', t => { - t.plan(1); - - const myTag = - tag.of( - (l, x, r) => - [ '|' - , x - , '|' - ]); - - t.is - ( tag(upper, myTag, trim)`foo=${' foo '}, bar=${' bar '}` - , "|FOO|BAR|" - ); -}); - -test('user-defined tags can receive options', t => { - t.plan(1); - - const myTag = - tag.of - ( (l, x, r, {foo}) => - [ l - , foo - , r - ] - , { foo: 'fooooooo' - } - ); - - t.is - ( myTag({foo: 'baaar'})`Hello ${'world'}!` - , 'Hello baaar!' - ); -}); - test('hide: hides all values', t => { t.plan(5);