From c409d6b6345888decdfde8592c68d3b927905397 Mon Sep 17 00:00:00 2001 From: Vladimir Gorej Date: Sat, 15 Apr 2017 10:02:16 +0200 Subject: [PATCH] feat: add paths Ref #27 Closes #54 --- src/index.d.ts | 6 ++++++ src/index.js | 3 +++ src/paths.js | 26 ++++++++++++++++++++++++++ test/paths.js | 29 +++++++++++++++++++++++++++++ 4 files changed, 64 insertions(+) create mode 100644 src/paths.js create mode 100644 test/paths.js diff --git a/src/index.d.ts b/src/index.d.ts index cf5d85d68e..6427a46c30 100644 --- a/src/index.d.ts +++ b/src/index.d.ts @@ -217,6 +217,12 @@ declare namespace RamdaAdjunct { */ resetToDefault(defaultOptions: Object, options: Object): Object resetToDefault(defaultOptions: Object): (options: Object) => Object + + /** + * Acts as multiple path: arrays of keys in, array of values out. Preserves order. + */ + paths(ps: Array>, obj: Object): Array + paths(ps: Array>): (obj: Object) => Array } } diff --git a/src/index.js b/src/index.js index e12bafd364..9b3e04698d 100644 --- a/src/index.js +++ b/src/index.js @@ -44,6 +44,7 @@ import list from './list'; // Object import defaults from './defaults'; import resetToDefault from './resetToDefault'; +import paths from './paths'; // Type export { default as isNotUndefined } from './isNotUndefined'; @@ -91,6 +92,7 @@ export { default as list } from './list'; // Object export { default as defaults } from './defaults'; export { default as resetToDefault } from './resetToDefault'; +export { default as paths } from './paths'; /** * @namespace RA @@ -142,6 +144,7 @@ const RA = { // Object defaults, resetToDefault, + paths, }; export default RA; diff --git a/src/paths.js b/src/paths.js new file mode 100644 index 0000000000..b33c7d4866 --- /dev/null +++ b/src/paths.js @@ -0,0 +1,26 @@ +import { curry, ap, path, __ } from 'ramda'; + +/** + * Acts as multiple path: arrays of keys in, array of values out. Preserves order. + * + * @func paths + * @memberOf RA + * @since {@link https://char0n.github.io/ramda-adjunct/1.2.0|v1.2.0} + * @category List + * @sig [[k]] -> {k: v} - [v] + * @param {Array} ps The property paths to fetch + * @param {Object} obj The object to query + * @return {Array} The corresponding values or partially applied function + * @see {@link https://github.com/ramda/ramda/wiki/Cookbook#derivative-of-rprops-for-deep-fields|Ramda Cookbook}, {@link http://ramdajs.com/docs/#props|props} + * @example + * + * const obj = { + * a: { b: { c: 1 } }, + * x: 2, + * }; + * + * RA.paths([['a', 'b', 'c'], ['x']], obj); //=> [1, 2] + */ +const paths = curry((ps, obj) => ap([path(__, obj)], ps)); + +export default paths; diff --git a/test/paths.js b/test/paths.js new file mode 100644 index 0000000000..9d06c8becf --- /dev/null +++ b/test/paths.js @@ -0,0 +1,29 @@ +import RA from '../src/index'; +import eq from './shared/eq'; + +describe('paths', function() { + const obj = { a: { b: { c: 1 } }, d: 4, e: 5, f: 6 }; + + it('returns empty array if no paths requested', function() { + eq(RA.paths([], obj), []); + }); + + it('returns values for requested paths', function() { + eq(RA.paths([['a', 'b', 'c'], ['e']], obj), [1, 5]); + }); + + it('preserves order', function() { + eq(RA.paths([['f'], ['a', 'b', 'c'], ['e']], obj), [6, 1, 5]); + }); + + it('returns undefined for nonexistent paths', function() { + const ps = RA.paths([['d'], ['nonexistent']], obj); + eq(ps.length, 2); + eq(ps[0], 4); + eq(ps[1], undefined); + }); + + it('is curried', function() { + eq(RA.paths([['a', 'b', 'c'], ['d']])(obj), [1, 4]); + }); +});