UNPKG

18.4 kBSource Map (JSON)View Raw
1{"version":3,"file":"index.js","sources":["../src/memoizeHelpers.js","../src/diffHelpers.js","../src/testHelpers.js"],"sourcesContent":["/**\n * Created by Andy Likuski on 2018.12.28\n * Copyright (c) 2018 Andy Likuski\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\nimport * as R from 'ramda';\nimport NamedTupleMap from 'namedtuplemap';\nimport {flattenObj} from './functions';\n\n/**\n *\n * Code modified from memoize-immutable. Memoizes a function using a flatArg version of the args\n * @param {Function} fn Function expecting any number of arguments\n * @returns {function([*], Object)} A function expecting\n * an array of the normal args for the second argument\n * an object of flattened args for the first argument\n */\nconst memoize = fn => {\n const cache = new NamedTupleMap();\n\n const memoized = R.curry((normalArgs, flatArg) => {\n if (!cache.has(flatArg)) {\n const result = R.apply(fn, normalArgs);\n cache.set(flatArg, result);\n return result;\n }\n return cache.get(flatArg);\n });\n\n\n // Give a meaningful displayName to the memoized function\n if (fn.name) {\n memoized.displayName = fn.name + 'Memoized';\n }\n\n return memoized;\n};\n\n/** *\n * Memomizes a function to a single argument function so that we can always NamedTupleMap for the cache.\n * In order for this to work all objects have to be flattened into one big object. This Cache won't\n * accept inner objects that have changed. So the function coverts three args like\n * {a: {wombat: 1, emu: 2}}, {b: {caracal: 1, serval: 2}}, 'hamster' to\n * {arg1.a: {wombat: 1, emu: 2}, arg2.b: {caracal: 1, serval: 2}, arg3: 'hamster}.\n * You can provide any depth of objects as arguments, but it will have performance penalties\n * Consider memoizedWith to filter out unimportant data from arguments\n * @param {Function} func A function with any number and type of args\n * @returns {Function} A function that expects the same args as func\n */\nexport const memoized = func => {\n return memoizedWith((...args) => args, func);\n};\n\n/** *\n * Memomizes a function to a single argument function so that we can always NamedTupleMap for the cache.\n * In order for this to work all objects have to be flattened into one big object. This Cache won't\n * accept inner objects that have changed. So the function coverts three args like\n * {a: {wombat: 1, emu: 2}}, {b: {caracal: 1, serval: 2}}, 'hamster' to\n * {arg1.a: {wombat: 1, emu: 2}, arg2.b: {caracal: 1, serval: 2}, arg3: 'hamster}.\n * You can provide any depth of objects as arguments, but it will have performance penalties.\n * To simplify the arguments and remove incomparable things like functions, use argumentFilter.\n * @param {Function} argumentFilter Expects the same number of arguments as func and returns an equal\n * number in an array. Each argument can be filtered to remove expensive objects or functions. Make\n * sure not to filter out anything that is used by func, since it will not figure into the argument uniqueness\n * @param {Function} func A function with any number and type of args. argumentFilter must match it\n * @returns {Function} A function that expects the same args as func. This function is curried, expecting\n * whatever number of arguments func is declared with, so you can call it partially\n */\nexport const memoizedWith = (argumentFilter, func) => {\n // memoize(func) returns the memoized function expecting args and the flattened obj\n const memo = memoize(func);\n // Returns a function expecting the args for fun\n return R.curryN(func.length, (...args) => {\n // Function that flattens the original args and called memoizedFunc with the single flattened arg\n return R.compose(\n memo(args),\n flattenObj,\n // Filter out unneeded parts of the arguments, or does nothing if argumentFilter is ...args => args\n R.apply(argumentFilter)\n )(args);\n });\n};\n","// Original source\n// https://gist.github.com/plukevdh/dec4b41d5b7d67f83be630afecee499e\nimport * as R from 'ramda';\n\nconst isObject = R.compose(R.equals('Object'), R.type);\nconst allAreObjectsOrLists = R.compose(R.either(R.all(isObject), R.all(Array.isArray)), R.values);\nconst hasVersion = versionLabel => obj => R.has(versionLabel, obj);\nconst hasBoth = versionLabels => obj => R.all(versionLabel => hasVersion(versionLabel)(obj), versionLabels);\nconst isEqual = versionLabels => obj => R.both(\n hasBoth(versionLabels),\n R.compose(\n R.apply(R.equals),\n R.values\n )\n)(obj);\n\nconst markAdded = obj => R.compose(R.append(undefined), R.values)(obj); // eslint-disable-line no-undefined\nconst markRemoved = obj => R.compose(R.prepend(undefined), R.values)(obj); // eslint-disable-line no-undefined\nconst isAddition = versionLabels => obj => R.both(\n hasVersion(R.head(versionLabels)),\n R.complement(hasVersion(R.last(versionLabels)))\n)(obj);\nconst isRemoval = versionLabels => obj => R.both(\n R.complement(\n hasVersion(R.head(versionLabels))\n ),\n hasVersion(R.last(versionLabels))\n)(obj);\n\n/**\n * Diffs objects and replaces differences with an object {__left: left value, __right: right value}\n * @param {[String]} Two values indicating the names of the versions. If left null then __left and __right\n * are used for the diff\n * @param {Object} l The left object to diff\n * @param {Object} r The right object to diff\n * @returns {Object} A deep diff of l and r. Equal values are removed, different values are replaced by an\n * object keyed by the two version strings with the corresponding values\n */\nexport const objectDiff = R.curry((versionLabels, l, r) => {\n const labels = R.defaultTo(['__left', '__right'], versionLabels);\n const [left, right] = labels;\n return R.compose(\n result => R.map(\n R.cond([\n [obj => isAddition(labels)(obj),\n obj => markAdded(obj)\n ],\n [obj => isRemoval(labels)(obj),\n obj => markRemoved(obj)\n ],\n [obj => hasBoth(labels)(obj),\n obj => R.when(\n allAreObjectsOrLists,\n // If all are objects or list recurse\n // Lists necessary become objects keyed by index since some indices are removed\n o => R.compose(\n // Remove the left, right labels and recurse\n values => R.apply(objectDiff(versionLabels), values),\n R.values\n )(o)\n // Otherwise we keep the left and right labels and we are done\n )(obj)\n ]\n ]\n ), result),\n result => R.reject(obj => isEqual(labels)(obj), result),\n R.useWith(\n R.mergeWith(R.merge),\n [\n R.map(R.objOf(left)),\n R.map(R.objOf(right))\n ]\n )\n )(l, r);\n});\n\n/**\n * Pretty-prints objectDiff\n * @param {[String]} versionLabels The two labels or null\n * @param {Object} l The left-side value\n * @param {Object} r The right-side value\n * @returns {String} The diff string\n */\nexport const prettyPrintObjectDiff = (versionLabels, l, r) => {\n return R.compose(\n result => JSON.stringify(result, null, 2),\n objectDiff\n )(versionLabels, l, r);\n};\n","/**\n * Created by Andy Likuski on 2017.06.06\n * Copyright (c) 2017 Andy Likuski\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the 'Software'), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\nimport * as R from 'ramda';\nimport {keyStringToLensPath} from './functions';\nimport {reqStrPathThrowing} from './throwingFunctions';\nimport {taskToPromise} from './monadHelpers';\n\n/**\n * Given a task, wraps it in promise and passes it to Jest's expect.\n * With this you can call resolves or rejects depending on whether success or failure is expected:\n * expectTask(task).resolves|rejects\n * @param {Task} task Task wrapped in a Promise and forked\n * @returns {undefined}\n */\nexport const expectTask = task => expect(taskToPromise(task));\n\n/**\n * Converts an Result to a Promise. Result.Ok calls resolve and Result.Error calls reject\n * @param {Object} result A Result\n * @returns {Promise} the promise\n */\nexport const resultToPromise = result => {\n return new Promise((resolve, reject) => result.map(resolve).mapError(reject));\n};\n\n\n/**\n * Convenient way to check if an object has a few expected keys at the given path\n * @param {[String]} keyPaths keys or dot-separated key paths of the object to check\n * @param {Object} obj The object to check\n * @return {*} Expects the object has the given keys. Throws if expect fails* @return {*}\n */\nexport const expectKeys = R.curry((keyPaths, obj) => {\n expect(\n R.compose(\n // Put the keyPaths that survive in a set for comparison\n a => new Set(a),\n // Filter out keyPaths that don't resolve to a non-nil value\n o => R.filter(\n keyPath => R.complement(R.isNil)(\n R.view(R.lensPath(keyStringToLensPath(keyPath)), o)\n ),\n keyPaths\n )\n )(obj)\n ).toEqual(\n new Set(keyPaths)\n );\n // Required for validated functions\n return true;\n});\n\n/**\n * Convenient way to check if an object has a few expected keys at the given path\n * @param {[String]} keyPaths keys or dot-separated key paths of the object to check\n * @param {String} strPath path in the obj to check keyPaths for\n * @param {Object} obj The object to check\n * @return {*} Expects the object has the given keys. Throws if expect fails* @return {*}\n */\nexport const expectKeysAtPath = R.curry((keyPaths, strPath, obj) => {\n expect(\n R.compose(\n // Put the keyPaths that survive in a set for comparison\n a => new Set(a),\n // Filter out keyPaths that don't resolve to a non-nil value\n o => R.filter(\n keyPath => R.complement(R.isNil)(\n R.view(\n R.lensPath(keyStringToLensPath(keyPath)),\n reqStrPathThrowing(strPath, o)\n )\n ),\n keyPaths\n )\n )(obj)\n ).toEqual(\n new Set(keyPaths)\n );\n // Required for validated functions\n return true;\n});\n"],"names":["memoize","fn","cache","NamedTupleMap","memoized","R","normalArgs","flatArg","has","result","set","get","name","displayName","func","memoizedWith","args","argumentFilter","memo","length","flattenObj","isObject","allAreObjectsOrLists","Array","isArray","hasVersion","versionLabel","obj","hasBoth","versionLabels","isEqual","markAdded","undefined","markRemoved","isAddition","isRemoval","objectDiff","l","r","labels","left","right","o","values","prettyPrintObjectDiff","JSON","stringify","expectTask","task","expect","taskToPromise","resultToPromise","Promise","resolve","reject","map","mapError","expectKeys","keyPaths","a","Set","keyPath","keyStringToLensPath","toEqual","expectKeysAtPath","strPath","reqStrPathThrowing"],"mappings":"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"}
\No newline at end of file