diff --git a/.babelrc b/.babelrc index f91ebace..7a8bc5a7 100644 --- a/.babelrc +++ b/.babelrc @@ -1,8 +1,4 @@ { - "presets": [ - "env" - ], - "plugins": [ - "transform-object-rest-spread" - ] + "presets": ["env"], + "plugins": ["transform-object-rest-spread"] } diff --git a/.codeclimate.yml b/.codeclimate.yml index 556c1559..9ac19cfd 100644 --- a/.codeclimate.yml +++ b/.codeclimate.yml @@ -11,15 +11,15 @@ engines: enabled: true ratings: paths: - - "**.inc" - - "**.js" - - "**.jsx" - - "**.module" - - "**.php" - - "**.py" - - "**.rb" + - "**.inc" + - "**.js" + - "**.jsx" + - "**.module" + - "**.php" + - "**.py" + - "**.rb" exclude_paths: -- "lib/" -- "tests/" -- "spec/" -- "**/vendor/" + - "lib/" + - "tests/" + - "spec/" + - "**/vendor/" diff --git a/.eslintrc.js b/.eslintrc.js index b8590f9c..145cc3c3 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -1,7 +1,7 @@ module.exports = { - extends: 'smartprocure', - parser: 'babel-eslint', + extends: "smartprocure", + parser: "babel-eslint", parserOptions: { - sourceType: 'module' - } + sourceType: "module", + }, } diff --git a/CHANGELOG.md b/CHANGELOG.md index 654ce3e7..1574c142 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,166 +1,212 @@ # 1.71.3 + - Library issue resolution, two libraries where auto-updating minor versions and no longer compatible in those versions. - Added ignore for yarn as NPM is being used currently - Added versioning of package-lock files to resolve dependency issue. # 1.71.2 -- Tests: + +- Tests: - Replaced all `eql` with `deep.equal` - Replaced all unnecessary `deep.equal` assertions with `.equal` - Replaced `to.equal(true)` and `to.equal(false)` with `to.be.true` and `to.be.false` # 1.71.1 + - Organized and added to regexp tests # 1.71.0 + - New docs site! The new docs site is packed with awesome features. We've got dark mode, super fast search, embedded runkits, and the ability to search futil, lodash, and ramda based on input/output expectations. # 1.70.0 + - Add state to deprecated methods so they can be inspected # 1.69.9 + - Removed basic function tests from the misc.spec file. A separate PR moves them into the function.spec file. # 1.69.8 + - Organized string tests # 1.69.7 + - Organized and added to functions tests # 1.69.6 + - Organized and added to logic tests # 1.69.5 + - Organized and added lang tests # 1.69.4 + - Organized and added to conversions tests # 1.69.3 + - Moves tests from algebra file to collections file to mirror functions file system # 1.69.2 + - Adds and revised the array tests # 1.69.1 + - Fixed f and F discrepancy. Changed all f. to F. in all tests for consistency. # 1.69.0 + - Add `isPromise` utility # 1.68.0 + - Add `mapTree`, `mapTreeLeaves`, `leavesBy` - Improve `leaves` performance (by not adding branches at all instead of rejecting them later) - Passes all props to `treeToArrayBy` iteratees - previously only `node` was passed # 1.67.3 + - Fixed `import` syntax in docs # 1.67.2 + - change fixed issue, Logic functions behave unpredictably with `undefined` as predicate -- add test cases to logic.spec for when. +- add test cases to logic.spec for when. - drop IE 10 support # 1.67.1 + - Fix `isBlank` docs # 1.67.0 + - Improvements to `unwind`: use `_.castArray` to avoid unwinding strings and other array-likes - Add `unwindArray` # 1.66.3 + - Use deep comparison on F.{simple,}diff # 1.66.2 + - Allow `walkAsync` to handle non-async traversals # 1.66.1 + - Kill promises in `findIndexedAsync` to fix regeneratorRuntime shenanigans # 1.66.0 + - Add `walkAsync` - Add `findIndexedAsync` (used internally and not documented, but exported for testing) - Add `mapArgs` - Add `commonKeys` and `firstCommonKey` # 1.65.0 + - Add support for regular expression arguments to `highlight` - Clarify `highlight` description in README - Add description for `postingsForWords` to README # 1.64.4 + - Change `domLens.hover` to use `onMouseEnter`/`onMouseLeave` instead of `onMouseOver`/`onMouseOut` # 1.64.3 + - Fix typo in README # 1.64.2 + - Handle `[]`, `undefined`, and `null` arguments in `chunkBy` # 1.64.1 + - Use `_.hasIn` in `targetBinding` to account for objects with `target` as an inherited property (eg, in synthetic DOM events) # 1.64.0 + - Add new native lens formats, `arrayLens` and `functionPairLens` - Make `domLens.value` more flexible by supporting non-native onChange events (allow `targetBinding` to fall back to the provided value if `e.target[key]` is not passed in) - Update a bunch of dev dependencies # 1.63.1 + - Clarify `chunkBy` description in README # 1.63.0 + - Add partial currying support to `mergeOverAll` - Add `mergeOverAllWith` and `mergeOverAllArrays` # 1.62.1 + - Better currying for `logic` methods (`ifElse`, `when`, `whenExists`, etc) # 1.62.0 + - Add `getWith`, `expandObject`, and `expandObjectBy` # 1.61.0 + - Add `compactMap` # 1.60.0 + - Add `mergeOverAll` # 1.59.1 + - change all words regex to report full string as match rather than empty string # 1.59.0 + - export `anyWordToRegexp` and `wordsToRegexp` # 1.58.1 + - Fixed issue where `renameProperty` was not a pure function. Specifically: - 1. The original object was mutated. - 2. If the original object din't have the property to be renamed the function was + +1. The original object was mutated. +2. If the original object din't have the property to be renamed the function was adding the property with a value of `undefined`. - 3. If code was relying in this incorrect behavior this will be a braking change. +3. If code was relying in this incorrect behavior this will be a braking change. # 1.58.0 + - Add `uniqueString` and `uniqueStringWith` # 1.57.0 + - Added new `object` functions: - `omitNil` - `omitNull` - `omitBlank` - `omitEmpty` + `omitNil` + `omitNull` + `omitBlank` + `omitEmpty` - Added new `array` functions: - `replaceElementBy` - `replaceElement` + `replaceElementBy` + `replaceElement` # 1.56.0 + - New lens helper for React users: `stateLens` # 1.55.1 + - Fix issue with autoLabelOption not accepting correctly falsy values as valid options # 1.55.0 + - Added intersperse, differentLast, toSentence and toSentenceWith. # 1.54.0 -- Add `domLens` functions: + +- Add `domLens` functions: `domLens.value` `domLens.checkboxValues` `domLens.hover` @@ -169,6 +215,7 @@ `domLens.binding` # 1.53.0 + - Add `moveIndex` - Add `toggleElement` - Add `toggleElementBy` @@ -177,190 +224,243 @@ - Make `insertAtIndex` support arrays and strings # 1.52.0 + - Add a default export with all methods to support `import F` instead of `import * as F` - Also publish as `futil`! # 1.51.0 + - Added `_.iteratee` support to `findApply` # 1.50.0 + - Added `chunkBy`. # 1.49.1 + - Upgraded several dependencies. # 1.49.0 + - Fixed a webpack global variable issue. # 1.48.0 + - Added `stampKey` # 1.47.1 + - Added Runkit examples # 1.47.0 + - Added VERSION property to the library's API # 1.46.0 - - Deprecated `mapProps` in favor of lodash _.update + +- Deprecated `mapProps` in favor of lodash \_.update # 1.45.0 + - Added `updateOn` # 1.44.0 + - Added `matchesSome` # 1.43.4 + - Fixed issue with `postings` when a regex lacking the `g` flag is passed - improvements to README.md # 1.43.3 + Fixed webpack.config.js # 1.43.2 (UNPUBLISHED because it breaks in NodeJS) + Upgraded some dependencies. # 1.43.1 + Fixed the conversion reference for pickBy. # 1.43.0 + Added pickByIndexed, and improved our conversion file performance by a significant ammount. # 1.42.3 + Made tree lookup curried. # 1.42.2 + Remove Standard JS badge in favor of [Prettier](https://prettier.io). # 1.42.1 + Enable coveralls integration. # 1.42.0 + - Add `flurry`, a flow + curry preserving the arity of the initial function. See https://github.com/lodash/lodash/issues/3612. # 1.41.0 + - Add `pullOn`, `prefixes` - Add `encoder`, `dotEncoder`, `slashEncoder` - Add `flattenTree`, `treePath`, `propTreePath`, `treeKeys`, `treeValues` - Expose `traverse` on `Tree` # 1.40.3 + - Updated eslint to version 4.16.0. # 1.40.2 + - Updating babel-eslint, eslint, chokidar and mocha. # 1.40.1 + - Add docs link # 1.40.0 + - [`cascade`, `cascadeIn`] added support for an optional defaultValue (last param) and iteratee support instead of just paths # 1.39.0 + - Add `transformTree` - Add `keyTreeByWith` # 1.38.0 + - Add `allMatches`. It creates regexp and returns all matched results with indexes. # 1.37.0 + - Added implicit `lensProp` support to all current lens functions (`view`, `views`, `set`, `sets`, `flip`, `on`, `off`) # 1.36.0 + - Add `mergeAllArrays`, `invertByArray`, `zipObjectDeepWith`, and `flags` # 1.35.0 + - Add tree `treeLookup` - Add deep path support to `lensProp` - Add `unsetOn` # 1.34.1 + - Ignore browser testing errors. - Add karma JSON reporter. - Only watch files and record videos/screenshots for the local test. # 1.34.0 + - Fixed flattenObject and diffArray to properly say the paths of arrays with only one object, by making them use a new function: `dotJoinWith`, which is like `dotJoin` but allows you to provide a function to select which elements to filter by. # 1.33.2 + - Add cross browsers testing support with `karma + webpack + saucelabs` - Use babel-preset-latest instead of babel-preset-env - Fixed unstable tests for mobile Safari browsers. - Fixed unstable tests for IE9/10/11. # 1.33.1 + - Currying the postings and highlighting functions. # 1.33.0 + - Add `debounceAsync` and `defer` # 1.32.1 + - Add autofixing PRs with [Duti](https://github.com/smartprocure/duti) # 1.32.0 + - Added `diff` and `diffArray`, just like `simpleDiff` and `simpleDiffArray`, but they also take in count removed properties. # 1.31.0 + - Add new utility for objects called `pickOn`, which works as `pick` in lodash but it mutates the object # 1.30.0 + - Add tree functions `traverse`, `walk`, `reduceTree`, `treeToArray`, `treeToArrayBy`, `leaves`, and `tree` - Add `isBlank`, `isNotBlank`, and `isBlankDeep` - Add `findIndexed` - # 1.29.9 + - Added pushOn, like pushIn but it alters the original array. # 1.29.8 + - Added pushIn since `_.curry` doesn't allow us to do `F.push(_, array)`. # 1.29.7 + - Curried `push` # 1.29.6 + - Faster `matchAnyWord` # 1.29.5 + - Always run duti in CI # 1.29.4 + - Use latest duti version # 1.29.3 + - Fix IE 11 erroring when using a deprecated function # 1.29.2 + - Add missing stack reference to `deprecate`. - Fix internal usage of deprecated functions. - Lint and readme cleanup. # 1.29.1 + - 75% faster `matchallwords`. # 1.29.0 August 11th, 2017 18:53 + - Add arrayToObject to array. # 1.28.4 August 10th, 2017 21:35 + - Fix for diff functions to properly ignore things that didn't change. # 1.28.3 August 9th, 2017 15:10 + - Remove old dangerfile. # 1.28.2 August 8th, 2017 20:50 + - Use Circle 2.0 configuration. # 1.28.1 + - Add Duti to the repo. # 1.28.0 August 8th, 2017 03:29 + - Added `Indexed` conversions(`mapIndexed`, `eachIndexed`, `reduceIndexed`, `mapValuesIndexed`) - Add `aspectSync` and `deprecate` - Deprecated the uncap conversions that don't follow the naming convention @@ -368,103 +468,136 @@ Enable coveralls integration. - Add `simpleDiff` and `simpleDiffArray` # 1.27.0 August 3rd, 2017 15:58 + - Added `hasIn`, `cascadeProp` and `cascadePropKey`. # 1.26.4 - August 2nd, 2017 18:21 + - Added release dates to change log file. Downgrade danger to version 0.17.0. # 1.26.3 - August 2nd, 2017 17:54 + - Update danger to version 0.19.0 # 1.26.2 - August 2nd, 2017 17:54 + - Update webpack to version 3.0.0 # 1.26.1 - August 2nd, 2017 14:37 + - Update chai to version 4.1.0 # 1.26.0 - August 2nd, 2017 06:46 + - Add `autoLabel`, `autoLabelOption`, and `autoLabelOptions`. Also rearranged test files a bit. # 1.25.1 - August 2nd, 2017 06:26 + - Fixed issue where concurrency aspect should throw Error using the string constructor. Also fixed failing unit tests. # 1.25.0 - July 31st, 2017 19:49 + - Add support for aspect `always`, `name`, and bug fix for processing sample aspect. Also added `tapError` and new high level aspect, `command` # 1.24.0 - July 28th, 2017 16:07 + - Added `trimStrings`, and our new shiny logo on the README thanks to @giulianok # 1.23.0 - July 28th, 2017 05:40 + - Add `setOn` (mutable set) # 1.22.0 - July 28th, 2017 03:25 + - Add `error` aspect example # 1.21.0 - July 27th, 2017 21:37 + - `aspect` now supports async `before`, `after`, and `onError` # 1.20.0 - July 25th, 2017 20:04 + - Add `findApply`, `isNotNil`, `exists`, `unlessExists`, `unlessTruth`, `getOrReturn`, `alias`, `cascade`, `cascadeIn`, `cascadeKey`, `isMultiple`, `append`, `composeApply`, `comply` # 1.19.0 - July 13th, 2017 14:23 + - Add ramda style `ifElse`, `where`, and `unless` to a new `logic` section # 1.18.1 - July 13th, 2017 14:23 + - Update lensOf to use reduce instead of mapValues # 1.18.0 - June 23rd, 2017 22:01 + - Add `callOrReturn`, `each`, and `mergeOn` # 1.17.4 - June 23rd, 2017 21:58 + - Made f.map uncapped # 1.17.3 - June 9th, 2017 23:47 + - Convert aspect to Promise instead of async/await and rip out babel-polyfill # 1.17.2 - June 8th, 2017 21:27 + - Pass original params to onError and after # 1.17.1 - June 8th, 2017 19:18 + - Include babel-polyfill in webpack build now that aspects have `async` functions # 1.17.0 - June 7th, 2017 22:51 + - Added `unflattenObject` and a deprecation warning about `mapProp` in favor of lodash `_.update` # 1.16.0 - June 6th, 2017 22:30 + - Added `aspect` and the reusable examples on `aspects` (`logs`, `errors`, `status`, and `concurrency`), as well as `throws` # 1.15.1 - May 30th, 2017 15:57 + - Added `views` # 1.15.0 - May 26th, 2017 21:43 + - Added `lens` functions `functionLens`, `objectLens`, `fnToObj`, `objToFn`, `lensProp`, `lensOf`, `view`, `set`, `sets`, `flip`, `on`, `off` # 1.14.0 - May 24th, 2017 02:08 + - Added a `mapProp`. # 1.13.0 - May 16th, 2017 22:32 + - Added a noCap conversion for `mapValues`. # 1.12.0 - May 16th, 2017 22:11 + - Added `boundMethod`. # 1.11.1 - May 2nd, 2017 13:22 + - Greenkeeper udpated the babel-loader and danger-js # 1.11.0 - April 6th, 2017 15:47 + - Added `cycle` # 1.10.2 - March 30th, 2017 21:48 + - Circle CI now help us enforce CHANGELOG.md and package.json updates in any PR. # 1.10.1 - March 30th, 2017 21:48 + - Fix `testRegex` # 1.10.0 - March 30th, 2017 18:32 + - Add `matchAllWords` # 1.9.0 - March 29th, 2017 17:03 + - Added regex and postings based highlighting functions `postings`, `postingsForWords`, `highlightFromPostings`, `highlight` - Added range manipulation funcitons `push`, `mergeRanges`, `insertAtIndex` - `makeRegex` curried implementation of the RegExp construction. @@ -474,6 +607,7 @@ Enable coveralls integration. - Add regex.spec.js # 1.8.0-1.8.3 - February 27th, 2017 20:18 + - `map` added to seamlessly map array and plain objects. - `deepMap` added to seamlessly map recursive arrays and plain objects. Also optionally allows mappings to any recursive algebraic @@ -481,50 +615,64 @@ Enable coveralls integration. - Versions 1.8.0-1.8.3 were assimilated by the borg. # 1.7.3 - February 21st, 2017 19:57 + - `compareDeep` is ok with ===, and it's now tested - Eslint, coverage and CI fixes # 1.7.1 - February 17th, 2017 23:03 + - Fix npm publish # 1.7.0 - February 17th, 2017 14:23 + - Add `defaultsOn` # 1.6.0 - February 16th, 2017 21:35 + - Add `extendOn` # 1.5.1 and 1.5.2 - February 16th, 2017 21:35 + Travis related CI stuff # 1.5.0 - February 15th, 2017 22:11 + - Add `pickIn` # 1.4.1 - February 10th, 2017 23:40 + - `maybeCall` fixed, rest params added to get the `fn` arguments # 1.4.0 - February 10th, 2017 23:40 + - Added Array Function `repeated` - Added String Functions - * `quote` - * `parens` - * `processQuotes` - * `getUniqueWords` + - `quote` + - `parens` + - `processQuotes` + - `getUniqueWords` # 1.3.0 - February 10th, 2017 23:40 + - Added `flattenObject` and `singleObjectR` - Split index to multiple files # 1.2.2 - February 10th, 2017 20:14 + - Changed filename to `futil-js` to match the current npm package name # 1.2.1 - February 10th, 2017 16:51 + - Changed package.json main entry point to reflect the built output # 1.2.0 - February 9th, 2017 05:21 + - Added unwind # 1.1.0 - February 8th, 2017 20:04 + - Added flowMap # 1.0.0 - February 6th, 2017 21:16 + - Initial Release diff --git a/README.md b/README.md index 306e9441..8ef4c7ce 100644 --- a/README.md +++ b/README.md @@ -19,20 +19,23 @@ A collection of F(unctional) Util(ities). Resistance is futile. Mostly, these are generic utilities that could conceivably be part of a library like [lodash/fp](https://github.com/lodash/lodash/wiki/FP-Guide), but for one reason or another are not. # Docs + https://smartprocure.github.io/futil-js/ # Version History/Changelog + See our [changelog](https://github.com/smartprocure/futil-js/blob/master/CHANGELOG.md) # Installing + `npm i -S futil` or `npm i -S futil-js` - This package requires `lodash/fp`, so make sure that's available in your app. # Usage + `import * as F from 'futil'` or `import F from 'futil'` @@ -44,105 +47,125 @@ or ## Function ### maybeCall + `(fn, a, b) -> fn(a, b)` If `fn` is a function, call the function with the passed-in arguments. Otherwise, return `false`. ### callOrReturn + `(fn, a, b) -> fn(a, b)` If `fn` is a function, call the function with the passed-in arguments. Otherwise, return `fn`. ### boundMethod + `(a, Monoid f) -> f[a] :: f a` Binds a function of an object to it's object. ### converge + `(f, [g1, g2, ...gn]) -> a -> f([g1(a), g2(a), ...])` http://ramdajs.com/docs/#converge. Note that `f` is called on the array of the return values of `[g1, g2, ...gn]` rather than applied to it. ### comply (alias: composeApply) + `(f, g) -> x -> f(g(x))(x)` A combinator that combines compose and apply. `f` should be a 2 place curried function. Useful for applying comparisons to pairs defined by some one place function, e.g. `var isShorterThanFather = F.comply(isTallerThan, fatherOf)` ### defer + Implement `defer`, ported from bluebird docs and used by debounceAsync ### debounceAsync + A `_.debounce` for async functions that ensure the returned promise is resolved with the result of the execution of the actual call. Using `_.debounce` with `await` or `.then` would result in the earlier calls never returning because they're not executed - the unit tests demonstate it failing with `_.debounce`. ### flurry + `(f1, f2, ...fn) -> f1Arg1 -> f1Arg2 -> ...f1ArgN -> fn(f2(f1))` Flurry is combo of flow + curry, preserving the arity of the initial function. See https://github.com/lodash/lodash/issues/3612. ### mapArgs -`(mapper, fn) -> (...args) -> fn(...args.map(mapper))` -Returns a function that applies the mapping operation to all of the arguments of a function. Very similar to _.overArgs, but runs a single mapper on all of the args args. +`(mapper, fn) -> (...args) -> fn(...args.map(mapper))` +Returns a function that applies the mapping operation to all of the arguments of a function. Very similar to \_.overArgs, but runs a single mapper on all of the args args. ## Iterators ### differentLast + `handleItem -> handleLastItem -> iterator` Creates an iterator that handles the last item differently for use in any function that passes `(value, index, list)` (e.g. `mapIndexed`, `eachIndexed`, etc). Both the two handlers and the result are iterator functions that take `(value, index, list)`. - ## Logic ### overNone + `([f1, f2, ...fn]) -> !f1(x) && !f2(x) && ...!fn(x)` Creates a function that checks if none of the array of predicates passed in returns truthy for `x` ### ifElse + `(condition, onTrue, onFalse, x) -> (T(condition)(x) ? onTrue(x) : onFalse(x))` http://ramdajs.com/docs/#ifElse. The transform function T supports passing a boolean for `condition` as well as any valid argument of `_.iteratee`, e.g. `myBool = applyTest(x); F.ifElse(myBool, doSomething, doSomethingElse);` ### when + `(condition, onTrue, x) -> (T(condition)(x) ? onTrue(x) : _.identity(x))` http://ramdajs.com/docs/#when. `T` extends `_.iteratee` as above. ### unless + `(condition, onFalse, x) -> (T(condition)(x) ? _.identity(x) : onFalse(x))` http://ramdajs.com/docs/#unless. `T` extends `_.iteratee` as above. ### whenTruthy + `when` curried with `Boolean` ### whenExists -`when` curried with `exists` +`when` curried with `exists` ## Collection ### flowMap + `[f1, f2, ...fn] -> _.map(_.flow(fn))` Maps a flow of `f1, f2, ...fn` over a collection. ### findApply + `f -> x -> f(find(f, x))` A version of `find` that also applies the predicate function to the result. Useful when you have an existing function that you want to apply to a member of a collection that you can best find by applying the same function. ### map + `(a -> b) -> [a] -> [b]` Maps a function over an iterable. Works by default for Arrays and Plain Objects. ### deepMap + `(a -> b) -> [a] -> [b]` Maps a function over a recursive iterable. Works by default for nested Arrays, nested Plain Objects and mixed nested Arrays and Plain Objects. Also works for any other iterable data type as long as two other values are sent: a mapping function, and a type checker (See the unit tests for deepMap). ### insertAtIndex + `(index, val, array|string) -> array|string` Inserts value into an array or string at `index` Example: + ```jsx (1, '123', 'hi') -> 'h123i' ``` ### compactMap + `(fn, collection) -> collection` Maps `fn` over the input collection and compacts the result. +## Convert(\_In) -## Convert(_In) lodash/fp is great, but sometimes the curry order isn't exactly what you want. These methods provide alternative orderings that are sometimes more convenient. @@ -150,19 +173,23 @@ These methods provide alternative orderings that are sometimes more convenient. The idea of `In` methods is to name them by convention, so when ever you need a method that actually takes the collection first (e.g. a `get` where the data is static but the field is dynamic), you can just add `In` to the end (such as `getIn` which takes the object first) ### getIn + Just like `_.get`, but with `{rearg: false}` so the argument order is unchanged from non fp lodash. ### hasIn + Just like `_.has`, but with `{rearg: false}` so the argument order is unchanged from non fp lodash. ### pickIn + Just like `_.pick`, but with `{rearg: false}` so the argument order is unchanged from non fp lodash. ### includesIn + Just like `_.includes`, but with `{rearg: false}` so the argument order is unchanged from non fp lodash. +## Convert(\_On) -## Convert(_On) lodash/fp likes to keep things pure, but sometimes JS can get pretty dirty. These methods are alternatives for working with data that--for whatever the use case is--needs to be mutable @@ -170,28 +197,35 @@ These methods are alternatives for working with data that--for whatever the use Any methods that interact with mutable data will use the `On` convention (as it is some action occuring `On` some data) ### extendOn + Just like `_.extend`, but with `{mutable: true}` so it mutates. ### defaultsOn + Just like `_.defaults`, but with `{mutable: true}` so it mutates. ### mergeOn + Just like `_.merge`, but with `{mutable: true}` so it mutates. ### setOn + Just like `_.set`, but with `{mutable: true}` so it mutates. ### unsetOn + Just like `_.unset`, but with `{mutable: true}` so it mutates. ### pullOn + Just like `_.pull`, but with `{mutable: true}` so it mutates. ### updateOn + Just like `_.update`, but with `{mutable: true}` so it mutates. +## Convert(\_Indexed) -## Convert(_Indexed) lodash/fp caps iteratees to one argument by default, but sometimes you need the index. These methods are uncapped versions of lodash's methods. @@ -199,207 +233,266 @@ These methods are uncapped versions of lodash's methods. Any method with uncapped iteratee arguments will use the `Indexed` convention. ### mapIndexed + Just like `_.map`, but with `{cap: false}` so iteratees are not capped (e.g. indexes are passed). ### findIndexed + Just like `_.find`, but with `{cap: false}` so iteratees are not capped (e.g. indexes are passed). ### eachIndexed + Just like `_.each`, but with `{cap: false}` so iteratees are not capped (e.g. indexes are passed). ### reduceIndexed + Just like `_.reduce`, but with `{cap: false}` so iteratees are not capped (e.g. indexes are passed). ### pickByIndexed + Just like `_.pickBy`, but with `{cap: false}` so iteratees are not capped (e.g. indexes are passed). ### mapValuesIndexed -Just like `_.mapValues`, but with `{cap: false}` so iteratees are not capped (e.g. indexes are passed). +Just like `_.mapValues`, but with `{cap: false}` so iteratees are not capped (e.g. indexes are passed). ## Array ### compactJoin -`joinString -> [string1, string2, ...stringN] -> string1 + joinString + string2 + joinString ... + stringN` + +`joinString -> [string1, string2, ...stringN] -> string1 + joinString + string2 + joinString ... + stringN` Joins an array after compacting. Note that due to the underlying behavior of `_.curry` no default `join` value is supported -- you must pass in some string with which to perform the join. ### dotJoin + `[string1, string2, ...stringN] -> string1 + '.' + string2 + '.' ... + stringN` Compacts and joins an array with `.` ### dotJoinWith + `filterFunction -> [string1, string2, ...stringN] -> string1 + '.' + string2 + '.' ... + stringN` Compacts an array by the provided function, then joins it with `.` ### repeated + `[a] -> [a]` Returns an array of elements that are repeated in the array. ### push + `(val, array) -> array` Return `array` with `val` pushed. ### moveIndex + `(from, to, array) -> array` Moves a value from one index to another ### mergeRanges + `([[], [], []]) -> [[], []]` Takes any number of ranges and return the result of merging them all. Example: + ```jsx [[0,7], [3,9], [11,15]] -> [[0,9], [11,15]] ``` ### cycle + `[a, b...] -> a -> b` Creates a function that takes an element of the original array as argument and returns the next element in the array (with wrapping). Note that (1) This will return the first element of the array for any argument not in the array and (2) due to the behavior of `_.curry` the created function will return a function equivalent to itself if called with no argument. ### arrayToObject + `(k, v, [a]) -> { k(a): v(a) }` Creates an object from an array by generating a key/value pair for each element in the array using the key and value mapper functions. ### zipObjectDeepWith + A version of `_.zipObjectDeep` that supports passing a function to determine values intead of an array, which will be invoked for each key. ### flags + `[a, b] -> {a:true, b:true}` Converts an array of strings into an object mapping to true. Useful for optimizing `includes`. ### prefixes + `['a', 'b', 'c'] -> [['a'], ['a', 'b'], ['a', 'b', 'c']]` Returns a list of all prefixes. Works on strings, too. Implementations must guarantee that the orginal argument has a length property. ### encoder + `string -> {encode: array -> string, decode: string -> array}` Creates an object with encode and decode functions for encoding arrays as strings. The input string is used as input for join/split. ### dotEncoder + `{ encode: ['a', 'b'] -> 'a.b', decode: 'a.b' -> ['a', 'b'] }` An encoder using `.` as the separator ### slashEncoder + `{ encode: ['a', 'b'] -> 'a/b', decode: 'a/b' -> ['a', 'b'] }` An encoder using `/` as the separator ### chunkBy + `(([a], a) -> Boolean) -> [a] -> [[a]]` Takes a predicate function and an array, and returns an array of arrays where each element has one or more elements of the original array. Similar to Haskell's [groupBy](http://zvon.org/other/haskell/Outputlist/groupBy_f.html). The predicate is called with two arguments: the current group, and the current element. If it returns truthy, the element is appended to the current group; otherwise, it's used as the first element in a new group. ### toggleElementBy + `bool -> value -> list -> newList` Just like toggleElement, but takes an iteratee to determine if it should remove or add. This is useful for example in situations where you might have a checkbox that you want to represent membership of a value in a set instead of an implicit toggle. Used by includeLens. ### toggleElement + `(any, array) -> array` Removes an element from an array if it's included in the array, or pushes it in if it doesn't. Immutable (so it's a clone of the array). ### intersperse + `f -> array -> [array[0], f(), array[n], ....)` Puts the result of calling `f` in between each element of the array. `f` is a standard lodash iterator taking the value, index, and list. If `f` is not a function, it will treat `f` as the value to intersperse. See https://ramdajs.com/docs/#intersperse. Example: + ```jsx // Example with words (toSentence is basically this flowed into a `_.join('')`): -F.intersperse(differentLast(() => 'or', () => 'or perhaps'), ['first', 'second', 'third']) +F.intersperse( + differentLast( + () => "or", + () => "or perhaps" + ), + ["first", "second", "third"] +) // ['first', 'or', 'second', 'or perhaps', 'third'] // Example with React and JSX: let results = [1, 2, 3] -return
- Results: -
- { - _.flow( - _.map(x => {x}), - F.intersperse(F.differentLast(() => ', ', () => ' and ')) - )(results) - } -
+return ( +
+ Results: +
+ {_.flow( + _.map((x) => {x}), + F.intersperse( + F.differentLast( + () => ", ", + () => " and " + ) + ) + )(results)} +
+) // Output: // **Results:** // **1**, **2** and **3**. ``` + **Note:** This works great with the `differentLast` iterator. Also, `intersperse` can be used with JSX components! ### replaceElementBy + `(fn(array_element), value, array) -> array` Replaces an element in an array with `value` based on the boolean result of a function `fn`. ### replaceElement + `(target, value, array) -> array` Replaces all elements equal to `target` in an array with `value`. - ## Object ### singleObject + `(k, v) -> {k: v}` Creates an object with a key and value. ### singleObjectR + `(v, k) -> {k: v}` Flipped version of `singleObject`. ### chunkObject + `({a, b}) -> [{a}, {b}]` Breaks an object into an array of objects with one key each. ### compactObject + Remove properties with falsey values. Example: + ```jsx ({ a: 1, b: null, c: false }) -> {a:1} ``` ### isEmptyObject + Check if the variable is an empty object (`{}`). ### isNotEmptyObject + Check if the variable is **not** an empty object (`{}`). ### stripEmptyObjects + Omit properties whose values are empty objects. Example: + ```jsx { a:1, b:{}, c:2 } -> {a:1, c:2} ``` -**Note:** (*TODO* rename to `omitEmptyObjects`) + +**Note:** (_TODO_ rename to `omitEmptyObjects`) ### pickInto -*TODO* + +_TODO_ ### renameProperty + `sourcePropertyName -> targetPropertyName -> sourceObject -> sourceObject` Rename a property on an object. Example: + ```jsx renameProperty('a', 'b', { a: 1 }) -> { b: 1 } ``` ### unwind + `k -> { k: [a, b] } -> [{ k: a }, { k: b }]` Just like mongo's `$unwind`: produces an array of objects from an object and one of its array-valued properties. Each object is constructed from the original object with the array value replaced by its elements. Unwinding on a nonexistent property or a property whose value is not an array returns an empty array. Example: + ```jsx -F.unwind('b', [{ a: true, b: [1, 2] }]) - //=> [{ a: true, b: 1 }, { a: true, b: 2 }] +F.unwind("b", [{ a: true, b: [1, 2] }]) +//=> [{ a: true, b: 1 }, { a: true, b: 2 }] ``` ### unwindArray + `k -> [{ k: [a, b] }] -> [{ k: a }, { k: b }]` Unwinds an array of objects instead of a single object, as you might expect if you're used to mongo's `$unwind`. Alias for `(key, data) => _.flatMap(F.unwind(key), data)` Example: + ```jsx -F.unwindArray('b', [{ a: true, b: [1, 2] }, { a: false, b: [3, 4] }]) +F.unwindArray("b", [ + { a: true, b: [1, 2] }, + { a: false, b: [3, 4] }, +]) //=> [ //=> { a: true, b: 1 }, //=> { a: true, b: 2 }, @@ -409,262 +502,323 @@ F.unwindArray('b', [{ a: true, b: [1, 2] }, { a: false, b: [3, 4] }]) ``` ### flattenObject + Flatten an object with the paths for keys. Example: + ```jsx { a: { b: { c: 1 } } } => { 'a.b.c' : 1 } ``` ### unflattenObject + Unlatten an object with the paths for keys. Example: + ```jsx { 'a.b.c' : 1 } => { a: { b: { c: 1 } } } ``` ### matchesSignature + Returns true if object keys are only elements from signature list. (but does not require all signature keys to be present) ### matchesSome + Similar to `_.matches`, except it returns true if 1 or more object properties match instead of all of them. See https://github.com/lodash/lodash/issues/3713. ### compareDeep + Checks if an object's property is equal to a value. ### mapProp + _Deprecated in favor of lodash `update`_ Applies a map function at a specific path Example: + ```jsx mapProp(double, 'a', {a: 2, b: 1}) -> {a: 4, b: 1} ``` ### getOrReturn + `_.get` that returns the target object if lookup fails ### alias + `_.get` that returns the prop if lookup fails ### aliasIn + Flipped `alias` ### cascade + A `_.get` that takes an array of paths (or functions to return values) and returns the value at the first path that matches. Similar to `_.overSome`, but returns the first result that matches instead of just truthy (and supports a default value) ### cascadeIn + Flipped cascade ### cascadeKey + A `_.get` that takes an array of paths and returns the first path that matched ### cascadePropKey + A `_.get` that takes an array of paths and returns the first path that exists ### cascadeProp + A `_.get` that takes an array of paths and returns the first value that has an existing path ### unkeyBy + `newKey -> {a:x, b:y} -> [{...x, newKey: a}, {...y, newKey: b}]` Opposite of `_.keyBy`. Creates an array from an object where the key is merged into the values keyed by `newKey`. Example: + ```jsx F.unkeyBy('_key')({ a: { status: true}, b: { status: false }) -> [{ status: true, _key: 'a' }, { status: false, _key: 'b' }] ``` + **Note:** Passing a falsy value other than `undefined` for `newKay` will result in each object key being pushed into its corresponding return array member with itself as value, e.g. `F.unkeyBy('')({ a: { status: true}, b: { status: false }) -> [{ status: true, a: 'a' }, { status: false, b: 'b' }]`. Passing `undefined` will return another instance of F.unkeyBy. ### simpleDiff + `(from, to) -> simpleDiff` Produces a simple flattened (see `flattenObject`) diff between two objects. For each (flattened) key, it produced a `from` and a `to` value. Note that this will omit any values that are not present in the deltas object. ### simpleDiffArray + `(from, to) -> [simpleDiffChanges]` Same as `simpleDiff`, but produces an array of `{ field, from, to }` objects instead of `{ field: { from, to } }` ### diff + `(from, to) -> diff` Same as `simpleDiff`, but also takes in count deleted properties. **Note:** We're considering not maintaining this in the long term, so you might probably have more success with any existing library for this purpose. ### diffArray + `(from, to) -> [diffChanges]` Same as `simpleDiffArray`, but also takes in count deleted properties. **Note:** We're considering not maintaining this in the long term, so you might probably have more success with any existing library for this purpose. ### pickOn + A `_.pick` that mutates the object ### mergeAllArrays + Like `_.mergeAll`, but concats arrays instead of replacing. This is basically the example from the lodash `mergeAllWith` docs. ### invertByArray + `{ a: [x, y, z], b: [x] } -> { x: [a, b], y: [a], z: [a] }` Similar to `_.invert`, but expands arrays instead of converting them to strings before making them keys. ### stampKey + `key -> { a: { x: 1 }, b: { y: 2 } } -> { a: { x: 1, key: 'a' }, b: { y: 2, key: 'b' } }` Iterates over object properties and stamps their keys on the values in the field name provided. ### omitNil + `_.omitBy` using `_.isNil` as function argument. ### omitNull + `_.omitBy` using `_.isNull` as function argument. ### omitBlank + `_.omitBy` using `F.isBlank` as function argument. ### omitEmpty + `_.omitBy` using `_.isEmpty` as function argument. ### mergeOverAll + `([f, g], ...args) -> {...f(...args), ...g(...args)}` Composition of `_.over` and `_.mergeAll`. Takes an array of functions and an arbitrary number of arguments, calls each function with those arguments, and merges the results. Can be called with `mergeOverAll([f, g], x, y)` or `mergeOverAll([f, g])(x, y)`. **Note:** For functions that do not return objects, `_.merge`'s behavior is followed: for strings and arrays, the indices will be converted to keys and the result will be merged, and for all other primitives, nothing will be merged. ### mergeOverAllWith + `(customizer, [f, g], ...args) -> {...f(...args), ...g(...args)}` A customizable `mergeOverAll` that takes a function of the form `(objValue, srcValue) -> newValue` as its first argument; see [`_.mergeWith`](https://lodash.com/docs/latest#mergeWith). Both the customizer and array of functions can be partially applied. ### mergeOverAllArrays + `([f, g], ...args) -> {...f(...args), ...g(...args)}` A customized `mergeOverAll` that applies the array-merging behavior of `mergeAllArrays`. ### getWith + `(x -> y) -> k -> {k: x} -> y` Like `_.get`, but accepts a customizer function which is called on the value to transform it before it is returned. Argument order is `(customizer, path, object)`. ### expandObject + `(transform: obj -> newObj) -> obj -> { ...obj, ...newObj }` Accepts a transform function and an object. Returns the result of applying the transform function to the object, merged onto the original object. `expandObject(f, obj)` is equivalent to `mergeOverAll([_.identity, f], obj)`. ### expandObjectBy + `key -> (transform: x -> newObj) -> (obj: { key: x }) -> { ...obj, ...newObj }` Expands an object by transforming the value at a single key into a new object, and merging the result with the original object. Similar to `expandObject`, but the argument order is `(key, transform, object)`, and the transform function is called on the value at that key instead of on the whole object. ### commonKeys + `(x, y) -> [keys]` Takes two objects and returns the keys they have in common ### firstCommonKey + `(x, y) -> key` Takes two objects and returns the first key in `y` that x also has - ## String ### parens + `'asdf' -> '(asdf)'` Wraps a string in parenthesis. ### trimStrings + Maps `_.trim` through all the strings of a given object or array. ### autoLabel + `string -> string` Converts strings like variable names to labels (generally) suitable for GUIs, including support for acronyms and numbers. It's basically `_.startCase` with acronym and number support. ### autoLabelOption + `string -> {value:string, label:string}` Creates a `{value, label}` which applies `autoLabel` the string parameter on puts it on the label property, with the original on the value property. You can also pass in an object with value or with both value and label. ### autoLabelOptions + `[string] -> [{value:string, label:string}]` Applies `autoLabelOption` to a collection. Useful for working with option lists like generating select tag options from an array of strings. ### toSentenceWith + `(separator, lastSeparator, array) => string` Just like `toSentence`, but with the ability to override the `separator` and `lastSeparator` Example: + ```jsx (' - ', ' or ', ['a', 'b', 'c']) -> 'a - b or c' ``` ### toSentence + `array => string` Joins an array into a human readable string. See https://github.com/epeli/underscore.string#tosentencearray-delimiter-lastdelimiter--string Example: + ```jsx ['a', 'b', 'c'] -> 'a, b and c' ``` ### uniqueStringWith + `(fn, array) -> string -> string` Allows passing a "cachizer" function (`array -> object`) to override the way `uniqueString`'s initial array is converted into a cache object. Can be curried to create a custom `uniqueString` function, eg: `let myUniqueString = uniqueStringWith(myFunc)` Like `uniqueString`, the resulting deduplication function exposes `cache` and `clear()` properties. Example: + ```jsx let uniqueStringStripDigits = uniqueStringWith( - _.countBy(_.replace(/(\d+)$/, '')) + _.countBy(_.replace(/(\d+)$/, "")) ) -let dedupe = uniqueStringStripDigits(['foo', 'foo42', 'foo3000']) -dedupe('foo') //-> 'foo3' -uniqueStringWith(_.identity, dedupe.cache)('foo') //-> 'foo4' +let dedupe = uniqueStringStripDigits(["foo", "foo42", "foo3000"]) +dedupe("foo") //-> 'foo3' +uniqueStringWith(_.identity, dedupe.cache)("foo") //-> 'foo4' ``` ### uniqueString + `array -> string -> string` Returns a function that takes a string and de-duplicates it against an internal cache. Each time this function is called, the resulting deduplicated string is added to the cache. Exposes `cache` and `clear()` properties to read and clear the cache, respectively. Example: + ```jsx let dedupe = uniqueString() -_.map(dedupe, ['foo', 'foo', 'foo']) //-> ['foo', 'foo1', 'foo2'] -dedupe.cache //-> { foo: 3, foo1: 1, foo2: 1 } +_.map(dedupe, ["foo", "foo", "foo"]) //-> ['foo', 'foo1', 'foo2'] +dedupe.cache //-> { foo: 3, foo1: 1, foo2: 1 } dedupe.clear() -dedupe.cache //-> {} -dedupe('foo') //-> 'foo' +dedupe.cache //-> {} +dedupe("foo") //-> 'foo' ``` - ## Regex ### testRegex + `regex -> string -> bool` Just like ramda test, creates a function to test a regex on a string. ### makeRegex + `options:string -> string -> regex` A curried implementation of `RegExp` construction. ### makeAndTest + `options:string -> string -> (string -> bool)` Makes and tests a RegExp with makeRegex and testRegex. ### matchAllWords + `string -> string -> bool` Returns true if the second string matches all of the words in the first string. ### matchAnyWord + `string -> string -> bool` Returns true if the second string matches any of the words in the first string. ### allMatches + `regex -> string -> [{text: string, start: number, end: number}]` Returns an array of matches with start/end data Example: + ```jsx F.allMatches(/a/g, 'vuhfaof') -> [ { text: 'a', start: 4, end: 5 } ] ``` ### postings + `regex -> string -> [[number, number]]` Returns an array of postings (position ranges) for a regex and string to test, e.g. `F.postings(/a/g, 'vuhfaof') -> [[4, 5]]` ### postingsForWords + `words -> string -> [[[number, number]]]` Takes a string of words and a string to test, and returns an array of arrays of postings for each word. Example: + ```jsx -F.postingsForWords('she lls', 'she sells sea shells') +F.postingsForWords("she lls", "she sells sea shells") // [ // [[0, 3], [14, 17]] // [[6, 9], [17, 20]] @@ -672,62 +826,73 @@ F.postingsForWords('she lls', 'she sells sea shells') ``` ### highlight + `start -> end -> pattern -> input -> highlightedInput` Wraps the matches for `pattern` found in `input` with the strings `start` and `end`. The `pattern` argument can either be a string of words to match, or a regular expression. Example: + ```jsx -let braceHighlight = F.highlight('{', '}') -braceHighlight('l o', 'hello world') //-> "he{llo} w{o}r{l}d" -braceHighlight(/l+\w/, 'hello world') //-> "he{llo} wor{ld}" +let braceHighlight = F.highlight("{", "}") +braceHighlight("l o", "hello world") //-> "he{llo} w{o}r{l}d" +braceHighlight(/l+\w/, "hello world") //-> "he{llo} wor{ld}" ``` - ## Math ### greaterThanOne + `number -> bool` Returns true if number is greater than one. - ## Lang + Language level utilities ### isPromise + `x -> bool` A utility that checks if the argument passed in is of type promise ### throws + Just throws whatever it is passed. ### tapError + Tap error will run the provided function and then throw the first argument. It's like `_.tap` for rethrowing errors. ### exists (alias: isNotNil) + Negated `_.isNil` ### isMultiple + `(Array | string | {length}) -> bool` Returns true if the input has a `length` property > 1, such as arrays, strings, or custom objects with a lenth property ### append + `(a, b) => b + a` A curried, flipped `_.add`. The flipping matters for strings, e.g. `F.append('a')('b') -> 'ba'` ### isBlank + `x -> bool` Designed to determine if something has a meaningful value, like a ux version of truthiness. It's false for everything except null, undefined, '', [], and {}. Another way of describing it is that it's the same as falsiness except 0 and false are truthy and {} is falsey. Useful for implementing "required" validation rules. ### isNotBlank + `x -> bool` Opposite of `isBlank` ### isBlankDeep + `f -> x -> bool` Recurses through an object's leaf properties and passes an array of booleans to the combinator, such as `_.some`, `_.every`, and `F.none` - ## Lens + A lens is a getter and setter pair. You use them to write code that needs to read _and_ write a value (like a method to flip a boolean switch, or a React component that reads and writes some state) without worrying about the implementation. Functions that operate on lenses can handle a few different "shorthand" structures. This is similar to lodash's `_.iteratee` (which allows their methods to treat strings, objects, or functions as shorthand predicates) @@ -765,61 +930,78 @@ We've included a few example "bindings" on `F.domLens`. These take a lens and re ![lens meme](http://giphygifs.s3.amazonaws.com/media/1jnyRP4DorCh2/giphy.gif) ### functionLens + Takes a value and returns a function lens for that value. Mostly used for testing and mocking purposes. ### objectLens + Takes a value and returns a object lens for that value. Mostly used for testing and mocking purposes. ### set + `propertyValue -> Lens -> object.propertyName` Sets the value of the lens, regardless of its format ### fnToObj + Converts a function lens an object lens. Mostly used for testing and mocking purposes. ### objToFn + Converts an object lens to a function lens. Mostly used for testing and mocking purposes. ### lensProp + `propertyName -> object -> { get: () -> object.propertyName, set: propertyValue -> object.propertyName }` Creates an object lens for a given property on an object. `.get` returns the value at that path and `set` places a new value at that path. Supports deep paths like lodash get/set. You typically won't use this directly since it is supported implicitly. ### lensOf + Takes an object and returns an object with lenses at the values of each path. Basically `mapValues(lensProp)`. Typically you would use the implicit `(key, object)` format instead. ### includeLens + `value -> arrayLens -> includeLens` An include lens represents membership of a value in a set. It takes a value and lens and returns a new lens - kind of like a "writeable computed" from MobX or Knockout. The view and set functions allow you to read and write a boolean value for whether or not a value is in an array. If you change to true or false, it will set the underlying array lens with a new array either without the value or with it pushed at the end. ### view + `Lens -> object.propertyName` Gets the value of the lens, regardless of its format ### views + `Lens -> (() -> object.propertyName)` Returns a function that gets the value of the lens, regardless of its format ### sets + Creates a function that will set a lens with the provided value ### setsWith + Takes an iteratee and lens and creates a function that will set a lens with the result of calling the iteratee with the provided value ### flip + Takes a lens and negates its value ### on + Returns a function that will set a lens to `true` ### off + Returns a function that will set a lens to `false` ### domLens.value + `lens -> {value, onChange}` Takes a lens and returns a value/onChange pair that views/sets the lens appropriately. `onChange` sets with `e.target.value` (or `e` if that path isn't present). Example: + ```jsx let Component = () => { let state = React.useState('') @@ -828,31 +1010,37 @@ let Component = () => { ``` ### domLens.checkboxValues + `(value, lens) -> {checked, onChange}` Creates an includeLens and maps view to checked and set to `onChange` (set with `e.target.checked` or `e` if that path isn't present) ### domLens.hover + `lens -> { onMouseEnter, onMouseLeave }` Takes a lens and returns on onMouseEnter which calls `on` on the lens and onMouseLeave which calls `off`. Models a mapping of "hovering" to a boolean. ### domLens.focus + `lens -> { onFocus, onBlur }` Takes a lens and returns on onFocus which calls `on` on the lens and onBlur which calls `off`. Models a mapping of "focusing" to a boolean. ### domLens.targetBinding + `field -> lens -> {[field], onChange}` Utility for building lens consumers like `value` and `checkboxValues` ### domLens.binding + `(field, getValue) -> lens -> {[field], onChange}` Even more generic utility than targetBinding which uses `getEventValue` to as the function for a setsWith which is mapped to `onChange`. ### stateLens + `([value, setValue]) -> lens` Given the popularity of React, we decided to include this little helper that converts a `useState` hook call to a lens. Ex: `let lens = stateLens(useState(false))`. You generally won't use this directly since you can pass the `[value, setter]` pair directly to lens functions - ## Aspect + Aspects provide a functional oriented implementation of Aspect Oriented Programming. An aspect wraps a function and allows you run code at various points like before and after execution. Notably, aspects in this library allow you to have a shared state object between aspects and are very useful for automating things like status indicators, etc on functions. @@ -869,27 +1057,29 @@ All of the provided aspects take an `extend` function to allow customizing the s If null, they default to `defaultsOn` from `futil-js` - check the unit tests for example usage. ### aspect + `{options} -> f -> aspectWrapped(f)` The aspect api takes an options object and returns a function which takes a function to wrap. - The wrapped function will be decorated with a `state` object and is equivalent to the original function for all arguments. +The wrapped function will be decorated with a `state` object and is equivalent to the original function for all arguments. Options supports the following parameters: -| Name | Description | -| --- | --- | -| `init: (state) -> ()` | A function for setting any inital state requirements. Should mutate the shared state object. | -| `after: (result, state, params) -> ()` | Runs after the wrapped function executes and recieves the shared state and the result of the function. Can be async. | -| `before: (params, state) -> ()` | Runs before the wrapped function executes and receves the shared state and the params passed to the wrapped function. Can be async. | -| `onError: (error, state, params) -> ()` | Runs if the wrapped function throws an error. If you don't throw inside this, it will swallow any errors that happen. | -| `always: (state, params) -> ()` | Runs after the wrapped function whether it throws an error or not, similar to a `Promise.catch` | +| Name | Description | +| --------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------- | +| `init: (state) -> ()` | A function for setting any inital state requirements. Should mutate the shared state object. | +| `after: (result, state, params) -> ()` | Runs after the wrapped function executes and recieves the shared state and the result of the function. Can be async. | +| `before: (params, state) -> ()` | Runs before the wrapped function executes and receves the shared state and the params passed to the wrapped function. Can be async. | +| `onError: (error, state, params) -> ()` | Runs if the wrapped function throws an error. If you don't throw inside this, it will swallow any errors that happen. | +| `always: (state, params) -> ()` | Runs after the wrapped function whether it throws an error or not, similar to a `Promise.catch` | Example: + ```jsx let exampleAspect = aspect({ - before: () => console.log('pre run'), - after: () => console.log('post run') + before: () => console.log("pre run"), + after: () => console.log("post run"), }) -let f = () => console.log('run') +let f = () => console.log("run") let wrapped = exampleAspect(f) wrapped() // Logs to the console: @@ -899,115 +1089,144 @@ wrapped() ``` ### aspectSync + This is a synchronous version of `aspect`, for situations when it's not desirable to `await` a method you're adding aspects to. The API is the same, but things like `onError` won't work if you pass an async function to the aspect. ### aspects.logs + Logs adds a `logs` array to the function state and just pushes in results on each run ### aspects.error + Captures any exceptions thrown and set it on an `error` error it puts on state ### aspects.errors + Captures any exceptions thrown and pushes them sequentially into an `errors` array it puts on state ### aspects.status + Adds a `status` property that is set to `processing` before the wrapped function runs and `succeeded` when it's done or `failed` if it threw an exception. Also adds shortcuts on state for `processing`, `succeeded`, and `failed`, which are booleans which are based on the value of `status`. Also adds a `setStatus` method which is used internally to update these properties. ### aspects.deprecate + Utility for marking functions as deprecated - it's just a `before` with a console.warn. Takes the name of thing being deprecated, optionally deprecation version, and optionally an alternative and returns a higher order function which you can wrap deprecated methods in. This is what's used internally to mark deprecations. Includes a partial stack trace as part of the deprecation warning. ### aspects.clearStatus + Sets `status` to null after provided timeout (default is 500ms) elapses. If a null timeout is passed, it will never set status to null. ### aspects.concurrency + Prevents a function from running if it's state has `processing` set to true at the time of invocation ### aspects.command -Flows together `status`, `clearStatus`, `concurrency`, and `error`, taking `extend` and `timeout` as optional parameters to construct the aspect +Flows together `status`, `clearStatus`, `concurrency`, and `error`, taking `extend` and `timeout` as optional parameters to construct the aspect ## Tree + All tree functions take a traversal function so that you can customize how to traverse arbitrary nested structures. -*Note*: Be careful about cyclic structures that can result in infinite loops, such as objects with references to itself. There are cases where you'd intentionally want to visit the same node multiple times, such as traversing a directed acyclic graph (which would work just fine and eventually terminate, but would visit a node once for each parent it has connected to it) - but it's up to the user to be sure you don't create infinite loops. +_Note_: Be careful about cyclic structures that can result in infinite loops, such as objects with references to itself. There are cases where you'd intentionally want to visit the same node multiple times, such as traversing a directed acyclic graph (which would work just fine and eventually terminate, but would visit a node once for each parent it has connected to it) - but it's up to the user to be sure you don't create infinite loops. ### isTraversable + `node -> bool` A default check if something can be traversed - currently it is arrays and plain objects. ### traverse + `node -> [...childNodes]` The default traversal function used in other tree methods if you don't supply one. It returns false if it's not traversable or empty, and returns the object if it is. ### walk + `traverse -> (pre, post=_.noop) -> tree -> x` A depth first search which visits every node returned by `traverse` recursively. Both `pre-order` and `post-order` traversals are supported (and can be mixed freely). `walk` also supports exiting iteration early by returning a truthy value from either the `pre` or `post` functions. The returned value is also the return value of `walk`. The pre, post, and traversal functions are passed the current node as well as the parent stack (where parents[0] is the direct parent). ### walkAsync + `traverse -> (pre, post=_.noop) -> async tree -> x` A version of `walk` which supports async traversals. ### transformTree + `traverse -> _iteratee -> tree -> newTree` Structure preserving pre-order depth first traversal which clones, mutates, and then returns a tree. Basically `walk` with a `_.cloneDeep` first (similar to a tree map because it preserves structure). `_iteratee` can be any suitable argument to `_.iteratee` https://lodash.com/docs/4.17.5#iteratee ### reduceTree + `traverse -> (accumulator, initialValue, tree) -> x` Just like `_.reduce`, but traverses over the tree with the traversal function in `pre-order`. ### mapTree + `(traverse, writeNode) -> f -> tree -> newTree` Structure preserving tree map! `writeNode` informs how to write a single node, but the default will generally work for most cases. The iteratee is passed the standard `node, index, parents, parentIndexes` args and is expected to return a transformed node. ### mapTreeLeaves + `(traverse, writeNode) -> f -> tree -> newTree` Like `mapTree`, but only operates on lead nodes. It is a convenience method for `mapTree(next, writeNode)(F.unless(next, mapper), tree)` ### treeToArrayBy + `traverse -> f -> tree -> [f(treeNode), f(treeNode), ...]` Like `treeToArray`, but accepts a customizer to process the tree nodes before putting them in an array. The customizer is passed the standard `node, index, parents, parentIndexes` args and is expected to return a transformed node. It's `_.map` for trees - but it's not called treeMap because it does not preserve the structure as you might expect `map` to do. See `mapTree` for that behavior. ### treeToArray + `traverse -> tree -> [treeNode, treeNode, ...]` Flattens the tree nodes into an array, simply recording the node values in pre-order traversal. ### leavesBy + `traverse -> f -> tree -> [f(treeNode), f(treeNode), ...]` Like `leaves`, but accepts a customizer to process the leaves before putting them in an array. ### leaves + `traverse -> tree -> [treeNodes]` Returns an array of the tree nodes that can't be traversed into in `pre-order`. ### treeLookup + `(traverse, buildIteratee) -> ([_iteratee], tree) -> treeNode` Looks up a node matching a path, which defaults to lodash `iteratee` but can be customized with buildIteratee. The `_iteratee` members of the array can be any suitable arguments for `_.iteratee` https://lodash.com/docs/4.17.5#iteratee ### keyTreeByWith + `traverse -> transformer -> _iteratee -> tree -> result` Similar to a keyBy (aka groupBy) for trees, but also transforms the grouped values (instead of filtering out tree nodes). The transformer takes three args, the current node, a boolean of if the node matches the current group, and what group is being evaluated for this iteratee. The transformer is called on each node for each grouping. `_iteratee` is any suitable argument to `_.iteratee`, as above. ### treeKeys + `(x, i, xs, is) => [i, ...is]` A utility tree iteratee that returns the stack of node indexes ### treeValues + `(x, i, xs) => [x, ...xs]` A utility tree iteratee that returns the stack of node values ### treePath + `(build, encoder) -> treePathBuilderFunction` Creates a path builder for use in `flattenTree`. By default, the builder will look use child indexes and a dotEncoder. Encoder can be an encoding function or a futil `encoder` (an object with encode and decode functions) ### propTreePath + `prop -> treePathBuilderFunction` Creates a path builder for use in `flattenTree`, using a slashEncoder and using the specified prop function as an iteratee on each node to determine the keys. ### flattenTree + `traverse -> buildPath -> tree -> result` Creates a flat object with a property for each node, using `buildPath` to determine the keys. `buildPath` takes the same arguments as a tree walking iteratee. It will default to a dot tree path. ### tree + `(traverse, buildIteratee, writeNode) -> {walk, reduce, transform, toArray, toArrayBy, leaves, leavesBy, map, mapLeaves, lookup, keyByWith, traverse, flatten, flatLeaves }` Takes a traversal function and returns an object with all of the tree methods pre-applied with the traversal. This is useful if you want to use a few of the tree methods with a custom traversal and can provides a slightly nicer api. Exposes provided `traverse` function as `traverse` diff --git a/docs/beta/README.md b/docs/beta/README.md index 2c111335..801f3585 100644 --- a/docs/beta/README.md +++ b/docs/beta/README.md @@ -1,4 +1,5 @@ # Futil Doc Notes + To run this, you'll want to run `npm run docs-site` at the root of the repo, and then `npm start` (or `npm build`, etc) here. # Original CRA Readme diff --git a/docs/beta/public/index.html b/docs/beta/public/index.html index 4259f6f2..9294d38c 100644 --- a/docs/beta/public/index.html +++ b/docs/beta/public/index.html @@ -26,8 +26,11 @@ --> Futil Docs - - + + diff --git a/docs/beta/src/App.tsx b/docs/beta/src/App.tsx index 0aca7754..bb4b27eb 100644 --- a/docs/beta/src/App.tsx +++ b/docs/beta/src/App.tsx @@ -1,5 +1,5 @@ -import * as React from 'react' -import _ from 'lodash/fp' +import * as React from "react" +import _ from "lodash/fp" import { Box, ChakraProvider, @@ -7,22 +7,22 @@ import { Grid, useColorModeValue, VStack, -} from '@chakra-ui/react' -import { setupHashScroll } from './utils/scroll' -import { Doc } from './types/Doc' +} from "@chakra-ui/react" +import { setupHashScroll } from "./utils/scroll" +import { Doc } from "./types/Doc" // Components -import Home from './components/Home' -import { PageHeader } from './components/Header' -import { Changelog } from './components/Changelog' -import { TagDocs } from './components/TagDocs' -import { MethodBox } from './components/MethodBox' -import { Sidebar } from './components/Sidebar' +import Home from "./components/Home" +import { PageHeader } from "./components/Header" +import { Changelog } from "./components/Changelog" +import { TagDocs } from "./components/TagDocs" +import { MethodBox } from "./components/MethodBox" +import { Sidebar } from "./components/Sidebar" // Data -import docs from './data/docs.json' -import tagDocs from './data/tag-docs.json' -import tests from './data/tests.json' +import docs from "./data/docs.json" +import tagDocs from "./data/tag-docs.json" +import tests from "./data/tests.json" // Stamp tests on docs _.each((doc) => { @@ -31,15 +31,15 @@ _.each((doc) => { let theme = extendTheme({ fonts: { - heading: 'Lato, system-ui, sans-serif', - body: 'Lato, system-ui, sans-serif', + heading: "Lato, system-ui, sans-serif", + body: "Lato, system-ui, sans-serif", }, }) let headerHeight = 75 let MainContent = React.memo(() => ( - + {_.map( (doc) => ( @@ -54,27 +54,27 @@ let MainContent = React.memo(() => ( )) -let initialState = { input: '', output: '', search: '', page: 'docs' } +let initialState = { input: "", output: "", search: "", page: "docs" } export const App = () => { React.useEffect(setupHashScroll, []) let [state, dispatch]: any = React.useReducer(_.merge, initialState) let { page } = state return ( - {page !== 'home' && } + {page !== "home" && } {/* 400 is arbitrary */} - {page === 'docs' && ( + {page === "docs" && ( )} - {page === 'changelog' && ( + {page === "changelog" && ( )} - {page === 'home' && } + {page === "home" && } ) } diff --git a/docs/beta/src/components/Badges.tsx b/docs/beta/src/components/Badges.tsx index 93c1b3a6..95e03da1 100644 --- a/docs/beta/src/components/Badges.tsx +++ b/docs/beta/src/components/Badges.tsx @@ -1,5 +1,5 @@ -import _ from 'lodash/fp' -import { Badge, HStack } from '@chakra-ui/react' +import _ from "lodash/fp" +import { Badge, HStack } from "@chakra-ui/react" export let Badges = ({ badges }: { badges: string[] }) => ( diff --git a/docs/beta/src/components/Changelog.tsx b/docs/beta/src/components/Changelog.tsx index 0bbb0482..edfdd344 100644 --- a/docs/beta/src/components/Changelog.tsx +++ b/docs/beta/src/components/Changelog.tsx @@ -1,16 +1,16 @@ -import { useState, useEffect, memo } from 'react' -import _ from 'lodash/fp' -import { Container, Heading, Link } from '@chakra-ui/react' -import { Markdown } from './Markdown' +import { useState, useEffect, memo } from "react" +import _ from "lodash/fp" +import { Container, Heading, Link } from "@chakra-ui/react" +import { Markdown } from "./Markdown" let fetchText = _.memoize( async (url: string) => await (await fetch(url)).text() ) let changelogUrl = - 'https://raw.githubusercontent.com/smartprocure/futil-js/master/CHANGELOG.md' + "https://raw.githubusercontent.com/smartprocure/futil-js/master/CHANGELOG.md" export let Changelog = memo(() => { - let [text, setData] = useState('') + let [text, setData] = useState("") useEffect(() => { fetchText(changelogUrl).then(setData) }, []) diff --git a/docs/beta/src/components/CodeSnippet.tsx b/docs/beta/src/components/CodeSnippet.tsx index 678b3afa..d3b90f35 100644 --- a/docs/beta/src/components/CodeSnippet.tsx +++ b/docs/beta/src/components/CodeSnippet.tsx @@ -1,7 +1,7 @@ -import { useEffect, useState, useRef, useCallback } from 'react' -import SyntaxHighlighter from 'react-syntax-highlighter' -import { vs2015, vs } from 'react-syntax-highlighter/dist/esm/styles/hljs' -import { useColorMode, useColorModeValue, Flex, Button } from '@chakra-ui/react' +import { useEffect, useState, useRef, useCallback } from "react" +import SyntaxHighlighter from "react-syntax-highlighter" +import { vs2015, vs } from "react-syntax-highlighter/dist/esm/styles/hljs" +import { useColorMode, useColorModeValue, Flex, Button } from "@chakra-ui/react" let Runkit = ({ source, @@ -17,7 +17,7 @@ let Runkit = ({ // https://twitter.com/runkitdev/status/1110994781616799744 // atom-dark, atom-light, one-dark, one-light, solarized-dark, solarized-light, and the default runkit-light. // let theme = useColorModeValue(undefined, 'untilted-6dtfo0ftb4ws') - let theme = useColorModeValue('runkit-light', 'atom-dark') + let theme = useColorModeValue("runkit-light", "atom-dark") let init = useCallback(() => { if (!embed.current) { @@ -33,17 +33,14 @@ let Runkit = ({ } }, [preamble, source, theme]) useEffect(init, [preamble, source, theme, init]) - useEffect( - () => { - if (embed.current) { - // @ts-ignore:next-line - embed.current.destroy() - embed.current = null - init() - } - }, - [colorMode, init] - ) + useEffect(() => { + if (embed.current) { + // @ts-ignore:next-line + embed.current.destroy() + embed.current = null + init() + } + }, [colorMode, init]) return
} @@ -59,7 +56,12 @@ type Props = { language?: string children?: string } -export const CodeSnippet = ({ forceDark, noRepl, language = 'javascript', children }: Props) => { +export const CodeSnippet = ({ + forceDark, + noRepl, + language = "javascript", + children, +}: Props) => { let [repl, setRepl] = useState(false) let style = useColorModeValue(vs, vs2015) return repl ? ( @@ -71,10 +73,11 @@ export const CodeSnippet = ({ forceDark, noRepl, language = 'javascript', childr {!noRepl && ( - + )} ) - } diff --git a/docs/beta/src/components/Header.tsx b/docs/beta/src/components/Header.tsx index 2598bf41..b6ec42a0 100644 --- a/docs/beta/src/components/Header.tsx +++ b/docs/beta/src/components/Header.tsx @@ -1,4 +1,4 @@ -import _ from 'lodash/fp' +import _ from "lodash/fp" import { chakra, Grid, @@ -16,17 +16,17 @@ import { Tooltip, useColorModeValue, VStack, -} from '@chakra-ui/react' +} from "@chakra-ui/react" import { BsChevronCompactLeft, BsChevronCompactRight, BsJournalCode, -} from 'react-icons/bs' -import { FiGitPullRequest } from 'react-icons/fi' -import { AiFillGithub, AiOutlineFunction, AiOutlineHome } from 'react-icons/ai' -import { ColorModeSwitcher } from './ColorModeSwitcher' -import LogoLight from '../logos/logo-light.svg' -import LogoDark from '../logos/logo-dark.svg' +} from "react-icons/bs" +import { FiGitPullRequest } from "react-icons/fi" +import { AiFillGithub, AiOutlineFunction, AiOutlineHome } from "react-icons/ai" +import { ColorModeSwitcher } from "./ColorModeSwitcher" +import LogoLight from "../logos/logo-light.svg" +import LogoDark from "../logos/logo-dark.svg" let WWTMTooltip = () => ( @@ -49,7 +49,7 @@ let NavIcon = ({ name, icon, page, dispatch }) => ( dispatch({ page: name })} icon={icon} aria-label={_.startCase(name)} @@ -63,18 +63,18 @@ export let PageHeader = ({ search, input, output, page, dispatch }) => ( w="100%" borderBottom="solid 1px" // dark moder border is divider color - borderColor={useColorModeValue('gray.200', 'rgba(255, 255, 255, 0.16)')} + borderColor={useColorModeValue("gray.200", "rgba(255, 255, 255, 0.16)")} zIndex={10} > - dispatch({ page: 'home' })} cursor="pointer"> - + dispatch({ page: "home" })} cursor="pointer"> + }> diff --git a/docs/beta/src/components/Home.tsx b/docs/beta/src/components/Home.tsx index ba9defd2..490113e9 100644 --- a/docs/beta/src/components/Home.tsx +++ b/docs/beta/src/components/Home.tsx @@ -1,4 +1,4 @@ -import { memo } from 'react' +import { memo } from "react" import { Code, Container, @@ -10,10 +10,10 @@ import { Image, Button, Flex, -} from '@chakra-ui/react' -import { CodeSnippet } from './CodeSnippet' -import { ColorModeSwitcher } from './ColorModeSwitcher' -import LogoDark from '../logos/logo-dark.svg' +} from "@chakra-ui/react" +import { CodeSnippet } from "./CodeSnippet" +import { ColorModeSwitcher } from "./ColorModeSwitcher" +import LogoDark from "../logos/logo-dark.svg" type BadgeProps = { src: string @@ -21,7 +21,7 @@ type BadgeProps = { href?: string } let Badge = ({ src, alt, href }: BadgeProps) => { - let style = { marginRight: '5px', display: 'inline-block' } + let style = { marginRight: "5px", display: "inline-block" } let image = return href ? {image} : image } @@ -59,8 +59,8 @@ let Logo = () => ( // let green = 'linear(to-r, #39b54a, #8dc63f)' // let blue = 'linear(to-r, #27aae1, #1c75bc)' // let blue = 'linear(to-r, #1c75bc, #27aae1)' -let gray = 'linear(to-b, gray.900, gray.700)' -let lightGray = 'linear(225deg, gray.700, gray.900)' +let gray = "linear(to-b, gray.900, gray.700)" +let lightGray = "linear(225deg, gray.700, gray.900)" let Summary = ({ dispatch }) => ( @@ -68,7 +68,7 @@ let Summary = ({ dispatch }) => ( - A collection of Functional Utilities. Resistance is{' '} + A collection of Functional Utilities. Resistance is{" "} futile. @@ -77,21 +77,21 @@ let Summary = ({ dispatch }) => ( are not. - Designed to work with any other utility library. lodash{' '} + Designed to work with any other utility library. lodash{" "} and ramda work great. lodash/fp works best. @@ -132,7 +132,7 @@ let BrowserCoverage = () => ( {/* Browser Compatibility */} Sauce Test Status @@ -145,8 +145,8 @@ export default memo(({ dispatch }: { dispatch: (any) => {} }) => ( @@ -155,7 +155,7 @@ export default memo(({ dispatch }: { dispatch: (any) => {} }) => ( Why futil? - Designed to work with any other utility library. lodash{' '} + Designed to work with any other utility library. lodash{" "} and ramda work great. lodash/fp works best. @@ -163,8 +163,8 @@ export default memo(({ dispatch }: { dispatch: (any) => {} }) => ( Brought to you by the SmartProcure/GovSpend team diff --git a/docs/beta/src/components/Markdown.tsx b/docs/beta/src/components/Markdown.tsx index ac6149a7..417b1e04 100644 --- a/docs/beta/src/components/Markdown.tsx +++ b/docs/beta/src/components/Markdown.tsx @@ -1,13 +1,13 @@ -import remarkGfm from 'remark-gfm' -import ReactMarkdown from 'react-markdown' -import ChakraUIRenderer from 'chakra-ui-markdown-renderer' -import { Heading } from '@chakra-ui/react' +import remarkGfm from "remark-gfm" +import ReactMarkdown from "react-markdown" +import ChakraUIRenderer from "chakra-ui-markdown-renderer" +import { Heading } from "@chakra-ui/react" export let Markdown = ({ children }: { children: string }) => ( ( - + {children} ), diff --git a/docs/beta/src/components/MethodBox.tsx b/docs/beta/src/components/MethodBox.tsx index 7d035ee4..3baf9d8d 100644 --- a/docs/beta/src/components/MethodBox.tsx +++ b/docs/beta/src/components/MethodBox.tsx @@ -11,11 +11,11 @@ import { Tabs, useColorModeValue, VStack, -} from '@chakra-ui/react' -import { Doc } from '../types/Doc' -import { Badges } from './Badges' -import { Markdown } from './Markdown' -import { CodeSnippet } from './CodeSnippet' +} from "@chakra-ui/react" +import { Doc } from "../types/Doc" +import { Badges } from "./Badges" +import { Markdown } from "./Markdown" +import { CodeSnippet } from "./CodeSnippet" let headerHeight = 75 @@ -25,7 +25,7 @@ export let MethodBox = ({ doc }: { doc: Doc }) => ( scrollMarginTop={headerHeight} p={8} rounded="md" - bg={useColorModeValue('white', 'gray.800')} + bg={useColorModeValue("white", "gray.800")} > diff --git a/docs/beta/src/components/Sidebar.tsx b/docs/beta/src/components/Sidebar.tsx index 75299b4b..68295bc8 100644 --- a/docs/beta/src/components/Sidebar.tsx +++ b/docs/beta/src/components/Sidebar.tsx @@ -1,18 +1,18 @@ -import * as React from 'react' -import _ from 'lodash/fp' -import F from 'futil' +import * as React from "react" +import _ from "lodash/fp" +import F from "futil" import { Divider, Flex, Link, useColorModeValue, VStack, -} from '@chakra-ui/react' -import { Doc } from '../types/Doc' -import { filterDocs } from '../utils/filterDocs' -import { scrollToMethod } from '../utils/scroll' -import { TextHighlight } from './TextHighlight' -import { Badges } from './Badges' +} from "@chakra-ui/react" +import { Doc } from "../types/Doc" +import { filterDocs } from "../utils/filterDocs" +import { scrollToMethod } from "../utils/scroll" +import { TextHighlight } from "./TextHighlight" +import { Badges } from "./Badges" let headerHeight = 75 @@ -33,24 +33,24 @@ export let Sidebar = ({ docs, search, input, output }: SidebarProps) => ( py={4} borderRight="solid 1px" // dark moder border is divider color - borderColor={useColorModeValue('gray.200', 'rgba(255, 255, 255, 0.16)')} + borderColor={useColorModeValue("gray.200", "rgba(255, 255, 255, 0.16)")} spacing={4} _before={{ - pointerEvents: 'none', - position: 'fixed', + pointerEvents: "none", + position: "fixed", content: '""', - display: 'block', - left: '0px', - bottom: '0px', - width: '400px', // arbitrary sidebar width - height: '142px', // arbitrary height + display: "block", + left: "0px", + bottom: "0px", + width: "400px", // arbitrary sidebar width + height: "142px", // arbitrary height background: useColorModeValue( // linear gradient from 0-100 opacity of bg color - 'linear-gradient(0deg, rgba(255, 255, 255, 1) 30%, rgba(255, 255, 255, 0) 100%)', + "linear-gradient(0deg, rgba(255, 255, 255, 1) 30%, rgba(255, 255, 255, 0) 100%)", // rgb values for dark body bg - 'linear-gradient(0deg, rgba(26, 32, 44, 1) 30%, rgba(26, 32, 44, 0) 100%)' + "linear-gradient(0deg, rgba(26, 32, 44, 1) 30%, rgba(26, 32, 44, 0) 100%)" ), - transition: 'opacity 1s ease 0s', + transition: "opacity 1s ease 0s", }} _hover={{ _before: { opacity: 0 } }} > @@ -72,9 +72,9 @@ export let Sidebar = ({ docs, search, input, output }: SidebarProps) => ( ( > {/* Our TextHighlight seems more performant than Chakra's */} {/* {`${ diff --git a/docs/beta/src/components/TagDocs.tsx b/docs/beta/src/components/TagDocs.tsx index d57eebb4..272a8797 100644 --- a/docs/beta/src/components/TagDocs.tsx +++ b/docs/beta/src/components/TagDocs.tsx @@ -1,5 +1,5 @@ -import * as React from 'react' -import _ from 'lodash/fp' +import * as React from "react" +import _ from "lodash/fp" import { Box, Heading, @@ -9,20 +9,20 @@ import { AccordionButton, AccordionPanel, AccordionIcon, -} from '@chakra-ui/react' -import { Markdown } from './Markdown' +} from "@chakra-ui/react" +import { Markdown } from "./Markdown" let TagTitle = ({ tag }) => ( {tag} - {' '} + {" "} Methods ) export let TagDocs = ({ unseenTags, tagDocs }) => { - let panelBg = useColorModeValue('gray.200', 'gray.600') + let panelBg = useColorModeValue("gray.200", "gray.600") return ( <> {_.map( diff --git a/docs/beta/src/components/TextHighlight.tsx b/docs/beta/src/components/TextHighlight.tsx index b8fb69d3..a5e40608 100644 --- a/docs/beta/src/components/TextHighlight.tsx +++ b/docs/beta/src/components/TextHighlight.tsx @@ -1,11 +1,11 @@ -import F from 'futil' -import { Text } from '@chakra-ui/react' +import F from "futil" +import { Text } from "@chakra-ui/react" let TextWrap = (props: any) => // Since start and end are the same token, splitting on it means every even element was a match type Props = { pattern: string; text: string; Wrap?: any } export let TextHighlight = ({ pattern, text, Wrap = TextWrap }: Props) => pattern - ? F.highlight('<>', '<>', pattern, text) - .split('<>') + ? F.highlight("<>", "<>", pattern, text) + .split("<>") .map((x: string, i: number) => (i % 2 ? {x} : x)) : text diff --git a/docs/beta/src/index.tsx b/docs/beta/src/index.tsx index c28e918a..66f86af9 100644 --- a/docs/beta/src/index.tsx +++ b/docs/beta/src/index.tsx @@ -5,16 +5,15 @@ import { App } from "./App" import reportWebVitals from "./reportWebVitals" import * as serviceWorker from "./serviceWorker" - const container = document.getElementById("root") -if (!container) throw new Error('Failed to find the root element'); +if (!container) throw new Error("Failed to find the root element") const root = ReactDOM.createRoot(container) root.render( - , + ) // If you want your app to work offline and load faster, you can change @@ -26,4 +25,3 @@ serviceWorker.unregister() // to log results (for example: reportWebVitals(console.log)) // or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals reportWebVitals() - diff --git a/docs/beta/src/serviceWorker.ts b/docs/beta/src/serviceWorker.ts index 69f26b60..9ae62b3d 100644 --- a/docs/beta/src/serviceWorker.ts +++ b/docs/beta/src/serviceWorker.ts @@ -16,8 +16,8 @@ const isLocalhost = Boolean( window.location.hostname === "[::1]" || // 127.0.0.0/8 are considered localhost for IPv4. window.location.hostname.match( - /^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/, - ), + /^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/ + ) ) type Config = { @@ -48,7 +48,7 @@ export function register(config?: Config) { navigator.serviceWorker.ready.then(() => { console.log( "This web app is being served cache-first by a service " + - "worker. To learn more, visit https://cra.link/PWA", + "worker. To learn more, visit https://cra.link/PWA" ) }) } else { @@ -76,7 +76,7 @@ function registerValidSW(swUrl: string, config?: Config) { // content until all client tabs are closed. console.log( "New content is available and will be used when all " + - "tabs for this page are closed. See https://cra.link/PWA.", + "tabs for this page are closed. See https://cra.link/PWA." ) // Execute callback @@ -128,7 +128,7 @@ function checkValidServiceWorker(swUrl: string, config?: Config) { }) .catch(() => { console.log( - "No internet connection found. App is running in offline mode.", + "No internet connection found. App is running in offline mode." ) }) } diff --git a/docs/beta/src/utils/exploreAPI.js b/docs/beta/src/utils/exploreAPI.js index 9958c2e0..249d73d0 100644 --- a/docs/beta/src/utils/exploreAPI.js +++ b/docs/beta/src/utils/exploreAPI.js @@ -1,5 +1,5 @@ -import F from 'futil' -import _ from 'lodash/fp' +import F from "futil" +import _ from "lodash/fp" // Needed because calling methods with unexpected parameters could cause exceptions export let ignoreError = _.curryN(2, (f, ...args) => { @@ -13,24 +13,21 @@ export let ignoreError = _.curryN(2, (f, ...args) => { let suppressedEval = ignoreError(eval) // Needed because eval({ a:1 }) returns 1 -export let tolerantEval = x => suppressedEval(`(${x})`) -export let tolerantArrayEval = x => suppressedEval(`[${x}]`) +export let tolerantEval = (x) => suppressedEval(`(${x})`) +export let tolerantArrayEval = (x) => suppressedEval(`[${x}]`) // Find _all_ keys that match export let findKeys = (f, obj) => - _.flow( - _.pickBy.convert({ cap: false })(f), - _.keys - )(obj) + _.flow(_.pickBy.convert({ cap: false })(f), _.keys)(obj) // The main exploreAPI function -export let exploreAPI = (lib, inputs, output, e = x => x) => { +export let exploreAPI = (lib, inputs, output, e = (x) => x) => { let inputValues = _.map(e, inputs) let expected = e(output) return findKeys( ignoreError( - f => - !_.get('state.isDeprecated', f) && + (f) => + !_.get("state.isDeprecated", f) && _.isEqual(F.maybeCall(f, ...inputValues), expected) ), lib diff --git a/docs/beta/src/utils/filterDocs.ts b/docs/beta/src/utils/filterDocs.ts index 91457613..285c88fd 100644 --- a/docs/beta/src/utils/filterDocs.ts +++ b/docs/beta/src/utils/filterDocs.ts @@ -1,8 +1,8 @@ -import F from 'futil' -import _ from 'lodash/fp' -import * as R from 'ramda' -import { Doc } from '../types/Doc' -import { exploreAPI, tolerantEval, tolerantArrayEval } from './exploreAPI' +import F from "futil" +import _ from "lodash/fp" +import * as R from "ramda" +import { Doc } from "../types/Doc" +import { exploreAPI, tolerantEval, tolerantArrayEval } from "./exploreAPI" export let filterDocs = ( search: string, @@ -20,17 +20,11 @@ export let filterDocs = ( let exploreRamda = input ? exploreAPI(R, processedInput, processedOutput) : [] return [ - ..._.filter(doc => { + ..._.filter((doc) => { if (input) return _.includes(doc.name, exploreMatches) return regex.test(doc.name) || regex.test(doc.description) }, docs), - ..._.map( - name => ({ name, lib: '_', tags: ['lodash'] }), - exploreLodash - ), - ..._.map( - name => ({ name, lib: 'R', tags: ['ramda'] }), - exploreRamda - ), + ..._.map((name) => ({ name, lib: "_", tags: ["lodash"] }), exploreLodash), + ..._.map((name) => ({ name, lib: "R", tags: ["ramda"] }), exploreRamda), ] } diff --git a/docs/beta/src/utils/scroll.ts b/docs/beta/src/utils/scroll.ts index 8957dd34..b684852d 100644 --- a/docs/beta/src/utils/scroll.ts +++ b/docs/beta/src/utils/scroll.ts @@ -1,15 +1,15 @@ export let scrollToMethod = (name: string) => { let element = document.getElementById(`${name}-method`) - element && element.scrollIntoView({ behavior: 'smooth' }) + element && element.scrollIntoView({ behavior: "smooth" }) } let scrollToHash = () => { - scrollToMethod(window.location.hash.replace('#', '')) + scrollToMethod(window.location.hash.replace("#", "")) } export let setupHashScroll = () => { scrollToHash() - window.addEventListener('hashchange', scrollToHash) + window.addEventListener("hashchange", scrollToHash) return () => { - window.removeEventListener('hashchange', scrollToHash) + window.removeEventListener("hashchange", scrollToHash) } } diff --git a/docs/beta/tsconfig.json b/docs/beta/tsconfig.json index eb5e7286..ebac916a 100644 --- a/docs/beta/tsconfig.json +++ b/docs/beta/tsconfig.json @@ -1,11 +1,7 @@ { "compilerOptions": { "target": "es5", - "lib": [ - "dom", - "dom.iterable", - "esnext" - ], + "lib": ["dom", "dom.iterable", "esnext"], "allowJs": true, "skipLibCheck": true, "esModuleInterop": true, @@ -19,9 +15,7 @@ "isolatedModules": true, "noEmit": true, "jsx": "react-jsx", - "noImplicitAny": false, + "noImplicitAny": false }, - "include": [ - "src" -, "manual-data-backup/data" ] + "include": ["src", "manual-data-backup/data"] } diff --git a/docs/index.html b/docs/index.html index 94d408a6..0c3dbe64 100644 --- a/docs/index.html +++ b/docs/index.html @@ -1,4 +1,4 @@ - + - - - - + + + + - futil-js + futil-js - - - - + + + + - - - + + + - - - + + + - - - - - -
- -
- - + + + + +
+
+

futil-js

+ +
+
+ + +
-
-
- - - + diff --git a/karma.conf.js b/karma.conf.js index 3a534980..8123af41 100644 --- a/karma.conf.js +++ b/karma.conf.js @@ -4,63 +4,63 @@ let local = false module.exports = function (config) { - 'use strict' + "use strict" let browsers let reporters let jsonReporter = { stdout: false, - outputFile: 'browser-results.json', // defaults to none + outputFile: "browser-results.json", // defaults to none } switch (process.env.TEST_ENV) { - case 'browser': + case "browser": browsers = Object.keys(customLaunchers) - reporters = ['dots', 'json', 'saucelabs'] + reporters = ["dots", "json", "saucelabs"] break // default is local default: local = true - browsers = ['Chrome'] - reporters = ['progress', 'json'] + browsers = ["Chrome"] + reporters = ["progress", "json"] } config.set({ // base path that will be used to resolve all patterns (eg. files, exclude) - basePath: '', + basePath: "", // frameworks to use // available frameworks: https://npmjs.org/browse/keyword/karma-adapter - frameworks: ['mocha', 'chai'], + frameworks: ["mocha", "chai"], // list of files / patterns to load in the browser files: [ // Load the babel polyfill - 'node_modules/babel-polyfill/dist/polyfill.js', + "node_modules/babel-polyfill/dist/polyfill.js", // We need to use singl entry file to avoid circular import error between // `aspect.js` and `conversion.js` - 'src/index.js', - 'test/*.spec.js', + "src/index.js", + "test/*.spec.js", ], webpack: { // kind of a copy of your webpack config - devtool: 'inline-source-map', // just do inline source maps instead of the default - mode: 'production', + devtool: "inline-source-map", // just do inline source maps instead of the default + mode: "production", module: { rules: [ { test: /(\.jsx|\.js)$/, exclude: /(node_modules|bower_components)/, use: { - loader: 'babel-loader', + loader: "babel-loader", }, }, { // We need to transpile chai-as-promised to ES5 - test: require.resolve('chai-as-promised'), + test: require.resolve("chai-as-promised"), use: { - loader: 'babel-loader', + loader: "babel-loader", }, }, ], @@ -71,10 +71,10 @@ module.exports = function (config) { // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor preprocessors: { // add webpack as preprocessor - 'src/*.js': ['webpack', 'sourcemap'], - 'test/*.js': ['webpack', 'sourcemap'], + "src/*.js": ["webpack", "sourcemap"], + "test/*.js": ["webpack", "sourcemap"], // We need to transpile chai-as-promised to ES5 - [require.resolve('chai-as-promised')]: ['webpack'], + [require.resolve("chai-as-promised")]: ["webpack"], }, // test results reporter to use @@ -101,7 +101,7 @@ module.exports = function (config) { // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher // browsers: ['Chrome'], sauceLabs: { - testName: 'Futil-js browser tests', + testName: "Futil-js browser tests", recordVideo: local, recordScreenshots: local, }, @@ -127,34 +127,34 @@ module.exports = function (config) { // UPDATED to match angular's config https://github.com/angular/angular.js/blob/master/karma-shared.conf.js let customLaunchers = { SL_Chrome: { - base: 'SauceLabs', - browserName: 'chrome', - version: 'latest', + base: "SauceLabs", + browserName: "chrome", + version: "latest", }, - 'SL_Chrome-1': { - base: 'SauceLabs', - browserName: 'chrome', - version: 'latest-1', + "SL_Chrome-1": { + base: "SauceLabs", + browserName: "chrome", + version: "latest-1", }, SL_Firefox: { - base: 'SauceLabs', - browserName: 'firefox', - version: 'latest', + base: "SauceLabs", + browserName: "firefox", + version: "latest", }, - 'SL_Firefox-1': { - base: 'SauceLabs', - browserName: 'firefox', - version: 'latest-1', + "SL_Firefox-1": { + base: "SauceLabs", + browserName: "firefox", + version: "latest-1", }, - 'SL_Safari-1': { - base: 'SauceLabs', - browserName: 'safari', - version: 'latest-1', + "SL_Safari-1": { + base: "SauceLabs", + browserName: "safari", + version: "latest-1", }, SL_Safari: { - base: 'SauceLabs', - browserName: 'safari', - version: 'latest', + base: "SauceLabs", + browserName: "safari", + version: "latest", }, // 'SL_IE_9': { // base: 'SauceLabs', @@ -164,31 +164,31 @@ let customLaunchers = { // }, SL_IE_11: { - base: 'SauceLabs', - browserName: 'internet explorer', - platform: 'Windows 8.1', - version: '11', + base: "SauceLabs", + browserName: "internet explorer", + platform: "Windows 8.1", + version: "11", }, SL_EDGE: { - base: 'SauceLabs', - browserName: 'microsoftedge', - platform: 'Windows 10', - version: 'latest', + base: "SauceLabs", + browserName: "microsoftedge", + platform: "Windows 10", + version: "latest", }, - 'SL_EDGE-1': { - base: 'SauceLabs', - browserName: 'microsoftedge', - platform: 'Windows 10', - version: 'latest-1', + "SL_EDGE-1": { + base: "SauceLabs", + browserName: "microsoftedge", + platform: "Windows 10", + version: "latest-1", }, SL_iOS: { - base: 'SauceLabs', - browserName: 'iphone', - version: 'latest', + base: "SauceLabs", + browserName: "iphone", + version: "latest", }, - 'SL_iOS-1': { - base: 'SauceLabs', - browserName: 'iphone', - version: 'latest-1', + "SL_iOS-1": { + base: "SauceLabs", + browserName: "iphone", + version: "latest-1", }, } diff --git a/renamePackage.js b/renamePackage.js index 9863964a..d52bb017 100644 --- a/renamePackage.js +++ b/renamePackage.js @@ -1,11 +1,11 @@ -let _ = require('lodash/fp') -let readPkg = require('read-pkg') -let writePkg = require('write-pkg') +let _ = require("lodash/fp") +let readPkg = require("read-pkg") +let writePkg = require("write-pkg") -let rename = async (name = 'futil-js') => { +let rename = async (name = "futil-js") => { let current = await readPkg() writePkg( - _.omit(['_id'], { + _.omit(["_id"], { ...current, name, }) diff --git a/runkit.example.js b/runkit.example.js index 825176cd..1b718446 100644 --- a/runkit.example.js +++ b/runkit.example.js @@ -1,8 +1,8 @@ -var F = require('futil-js') +var F = require("futil-js") -var cities = ['London', 'Boston', 'Lisbon'] +var cities = ["London", "Boston", "Lisbon"] -F.dotJoinWith((c) => c.startsWith('L'))(cities) +F.dotJoinWith((c) => c.startsWith("L"))(cities) // "London.Lisbon" F.arrayToObject( diff --git a/scripts/copy-docs.js b/scripts/copy-docs.js index a07538bc..d512e970 100644 --- a/scripts/copy-docs.js +++ b/scripts/copy-docs.js @@ -1,13 +1,16 @@ // This script exists to workaround create-react-app's limitation around importing outside /src // Once this moves out of docs/beta, we could just drive readme generation out of docs/src/data instead of docs/data and not copy -import { copyFile, mkdir } from 'fs/promises' +import { copyFile, mkdir } from "fs/promises" let run = async () => { - await mkdir('./docs/beta/src/data', { recursive: true }) - await copyFile('./docs/data/docs.json', './docs/beta/src/data/docs.json') - await copyFile('./docs/data/tag-docs.json', './docs/beta/src/data/tag-docs.json') - await copyFile('./docs/data/tests.json', './docs/beta/src/data/tests.json') + await mkdir("./docs/beta/src/data", { recursive: true }) + await copyFile("./docs/data/docs.json", "./docs/beta/src/data/docs.json") + await copyFile( + "./docs/data/tag-docs.json", + "./docs/beta/src/data/tag-docs.json" + ) + await copyFile("./docs/data/tests.json", "./docs/beta/src/data/tests.json") } -run() \ No newline at end of file +run() diff --git a/scripts/docs-folder.js b/scripts/docs-folder.js index 611f75e1..3b6957c6 100644 --- a/scripts/docs-folder.js +++ b/scripts/docs-folder.js @@ -1,5 +1,5 @@ -import { mkdir } from 'fs/promises' +import { mkdir } from "fs/promises" -let run = async () => await mkdir('./docs/data', { recursive: true }) +let run = async () => await mkdir("./docs/data", { recursive: true }) -run() \ No newline at end of file +run() diff --git a/scripts/generate-docs.js b/scripts/generate-docs.js index 51be2710..2ab4e175 100644 --- a/scripts/generate-docs.js +++ b/scripts/generate-docs.js @@ -1,47 +1,47 @@ -import _ from 'lodash/fp' -import { writeFile, readFile } from 'fs/promises' -import docs from '../docs/data/jsdoc.json' -import { stringify, getTag } from './utils' +import _ from "lodash/fp" +import { writeFile, readFile } from "fs/promises" +import docs from "../docs/data/jsdoc.json" +import { stringify, getTag } from "./utils" -let outputDir = './docs/data/' +let outputDir = "./docs/data/" -let githubSrcUrl = 'https://github.com/smartprocure/futil-js/blob/master/src/' +let githubSrcUrl = "https://github.com/smartprocure/futil-js/blob/master/src/" let getNameFromDoc = _.flow( - _.get('longname'), + _.get("longname"), // Cases: // "longname": "module:aspect~aspects.logs", // "longname": "module:lang.throws", - _.replace(/module:\w*(~|\.)/, ''), + _.replace(/module:\w*(~|\.)/, ""), // "longname": "convert(_In).hasIn", - x => _.last(x.split(').')) + (x) => _.last(x.split(").")) ) let seenTags = [] // Memoize so we only read each file once -let readSourceFile = _.memoize(path => readFile(path, { encoding: 'utf8' })) +let readSourceFile = _.memoize((path) => readFile(path, { encoding: "utf8" })) let getDocs = async () => { let jsDocToJson = _.flow( - _.reject('undocumented'), - _.reject({ kind: 'module' }), - _.filter('name'), - _.map(async x => { - let path = x.meta.path + '/' + x.meta.filename + _.reject("undocumented"), + _.reject({ kind: "module" }), + _.filter("name"), + _.map(async (x) => { + let path = x.meta.path + "/" + x.meta.filename let file = await readSourceFile(path) let source = file.slice(...x.meta.range).slice(7) - let lineCount = _.size(_.split('\n', source)) + let lineCount = _.size(_.split("\n", source)) // TODO: change to @category or something similar - let tags = [getTag('tags', x) || x.meta.filename.slice(0, -3)] + let tags = [getTag("tags", x) || x.meta.filename.slice(0, -3)] // Track tags that are new for this method (to insert tag docs) let unseenTags = _.difference(tags, seenTags) seenTags = _.uniq(_.concat(seenTags, tags)) return { name: getNameFromDoc(x), deprecated: x.deprecated, - aliases: getTag('aliases', x), - signature: getTag('signature', x), + aliases: getTag("aliases", x), + signature: getTag("signature", x), description: x.description, - note: getTag('note', x), + note: getTag("note", x), example: _.head(x.examples), // todo: support more? tags, unseenTags, @@ -50,51 +50,51 @@ let getDocs = async () => { lineno: x.meta.lineno, // https://github.com/smartprocure/futil-js/blob/master/src/array.js#L20-L25 link: `${githubSrcUrl}${x.meta.filename}#L${x.meta.lineno}${ - lineCount === 1 ? '' : `-L${x.meta.lineno + lineCount - 1}` + lineCount === 1 ? "" : `-L${x.meta.lineno + lineCount - 1}` }`, } }), - x => Promise.all(x) + (x) => Promise.all(x) ) let jsDocToTagDocs = _.flow( - _.filter({ kind: 'module' }), + _.filter({ kind: "module" }), // Cases: // "longname": "convert(_In)~inversions", // "longname": "module:lens" - _.keyBy(x => _.last(x.longname.split(':'))), - _.mapValues('description') + _.keyBy((x) => _.last(x.longname.split(":"))), + _.mapValues("description") ) let readmeOrder = [ - 'function', - 'iterators', - 'logic', - 'collection', - 'convert', - 'convert(_In)', - 'convert(_On)', - 'convert(_Indexed)', - 'array', - 'object', - 'string', - 'regex', - 'math', - 'lang', - 'lens', - 'aspect', - 'tree', + "function", + "iterators", + "logic", + "collection", + "convert", + "convert(_In)", + "convert(_On)", + "convert(_Indexed)", + "array", + "object", + "string", + "regex", + "math", + "lang", + "lens", + "aspect", + "tree", ] let sortTagsByReadmeOrder = _.sortBy(({ tags }) => - _.findIndex(x => x == _.first(tags), readmeOrder) + _.findIndex((x) => x == _.first(tags), readmeOrder) ) let result = sortTagsByReadmeOrder(await jsDocToJson(docs)) - await writeFile(`${outputDir}docs.json`, stringify(result), { flag: 'w' }) + await writeFile(`${outputDir}docs.json`, stringify(result), { flag: "w" }) let tagDocs = jsDocToTagDocs(docs) await writeFile(`${outputDir}tag-docs.json`, stringify(tagDocs), { - flag: 'w', + flag: "w", }) } diff --git a/scripts/generate-readme.js b/scripts/generate-readme.js index eb2d0519..ea470653 100644 --- a/scripts/generate-readme.js +++ b/scripts/generate-readme.js @@ -1,28 +1,25 @@ -import _ from 'lodash/fp' -import { writeFile, readFile } from 'fs/promises' -import docs from '../docs/data/docs.json' -import tagDocs from '../docs/data/tag-docs.json' -import { maybeWrap, joinWith } from './utils' +import _ from "lodash/fp" +import { writeFile, readFile } from "fs/promises" +import docs from "../docs/data/docs.json" +import tagDocs from "../docs/data/tag-docs.json" +import { maybeWrap, joinWith } from "./utils" // Renderers for doc fields -let signature = maybeWrap('`', '`\n') -let example = maybeWrap('\n\nExample:\n```jsx\n', '\n```') -let alias = maybeWrap(' (alias: ', ')') -let note = maybeWrap('\n**Note:** ', '') +let signature = maybeWrap("`", "`\n") +let example = maybeWrap("\n\nExample:\n```jsx\n", "\n```") +let alias = maybeWrap(" (alias: ", ")") +let note = maybeWrap("\n**Note:** ", "") -let tag = _.flow( - _.upperFirst, - maybeWrap('\n\n## ', '\n') -) +let tag = _.flow(_.upperFirst, maybeWrap("\n\n## ", "\n")) let tagDoc = _.flow( // getIn is in futil, but simpler to not create nested dependency here - x => _.get(x, tagDocs), - maybeWrap('', '\n') + (x) => _.get(x, tagDocs), + maybeWrap("", "\n") ) -let tags = joinWith(x => `${tag(x)}${tagDoc(x)}`) +let tags = joinWith((x) => `${tag(x)}${tagDoc(x)}`) let apiDocs = joinWith( - doc => `${tags(doc.unseenTags)} + (doc) => `${tags(doc.unseenTags)} ### ${doc.name}${alias(doc.aliases)} ${signature(doc.signature)}${doc.description}${example(doc.example)}${note( doc.note @@ -31,9 +28,9 @@ ${signature(doc.signature)}${doc.description}${example(doc.example)}${note( ) let run = async () => { - let readmeHeader = await readFile('./scripts/readme-preamble.md') + let readmeHeader = await readFile("./scripts/readme-preamble.md") let markdown = `${readmeHeader}\n# API${apiDocs(docs)}` - return writeFile('./README.md', markdown, { flag: 'w' }) + return writeFile("./README.md", markdown, { flag: "w" }) } run() diff --git a/scripts/generate-tests-json.js b/scripts/generate-tests-json.js index 496133d7..eb4b2d8a 100644 --- a/scripts/generate-tests-json.js +++ b/scripts/generate-tests-json.js @@ -1,7 +1,7 @@ -import _ from 'lodash/fp' -import prettier from 'prettier' -import { readdir, writeFile } from 'fs/promises' -import { stringify } from './utils' +import _ from "lodash/fp" +import prettier from "prettier" +import { readdir, writeFile } from "fs/promises" +import { stringify } from "./utils" let getTests = async () => { // Collect tests into an object by overriding global test fns @@ -10,7 +10,7 @@ let getTests = async () => { global.describe = (name, fn) => fn() // Capture the tests in an object global.it = (name, fn) => { - tests[_.replace('should ', '', name)] = fn + tests[_.replace("should ", "", name)] = fn return { timeout: () => {}, } @@ -18,10 +18,10 @@ let getTests = async () => { // Dynamically import tests to fill the test object await _.flow( - _.filter(x => x.match(/spec\.js$/)), - _.map(path => import(`../test/${path}`)), - x => Promise.all(x) - )(await readdir('./test')) + _.filter((x) => x.match(/spec\.js$/)), + _.map((path) => import(`../test/${path}`)), + (x) => Promise.all(x) + )(await readdir("./test")) return tests } @@ -45,11 +45,11 @@ let removeTestWrappers = _.flow( ), _.replace( /expect\((\(\) => )?(.+?)\)(\.not)?\.to\.throw\((.*?)\)/g, - (a, b, c, d, e) => `${c}\n/* => throws ${e || 'exception'} */` + (a, b, c, d, e) => `${c}\n/* => throws ${e || "exception"} */` ), _.replace( /expect\((.+?)\)(\.not)?\.to\.be\.rejectedWith\((.*?)\)/g, - (a, b, c, d) => `${b}\n/* => throws ${d || 'exception'} */` + (a, b, c, d) => `${b}\n/* => throws ${d || "exception"} */` ), _.replace( /expect\((.+?)\)(\.not)?\.to(\.deep)?(\.equal|\.eql)\((.+?)\)/gs, @@ -59,26 +59,26 @@ let removeTestWrappers = _.flow( let cleanup = _.flow( _.toString, - _.split('\n'), + _.split("\n"), // Remove the fn wrapper - x => x.slice(1, -1), - _.join('\n'), + (x) => x.slice(1, -1), + _.join("\n"), // remove newlines after `{` to force objects as compact as possible - _.replace(/{\n|\r/g, '{') + _.replace(/{\n|\r/g, "{") ) -let format = code => +let format = (code) => prettier.format(code, { semi: false, singleQuote: true, - parser: 'babel', - arrowParens: 'avoid', + parser: "babel", + arrowParens: "avoid", }) let run = async () => { let tests = await getTests() - let content = _.mapValues(test => { + let content = _.mapValues((test) => { let code = format(cleanup(test)) try { // Attempt to remove test wrappers but fallback if prettier explodes due to invalid JS @@ -88,7 +88,7 @@ let run = async () => { } }, tests) - let outputDir = './docs/data/' + let outputDir = "./docs/data/" return writeFile(`${outputDir}tests.json`, stringify(content)) } diff --git a/scripts/readme-preamble.md b/scripts/readme-preamble.md index ccce2110..4a2a95f0 100644 --- a/scripts/readme-preamble.md +++ b/scripts/readme-preamble.md @@ -19,20 +19,23 @@ A collection of F(unctional) Util(ities). Resistance is futile. Mostly, these are generic utilities that could conceivably be part of a library like [lodash/fp](https://github.com/lodash/lodash/wiki/FP-Guide), but for one reason or another are not. # Docs + https://smartprocure.github.io/futil-js/ # Version History/Changelog + See our [changelog](https://github.com/smartprocure/futil-js/blob/master/CHANGELOG.md) # Installing + `npm i -S futil` or `npm i -S futil-js` - This package requires `lodash/fp`, so make sure that's available in your app. # Usage + `import * as F from 'futil'` or `import F from 'futil'` diff --git a/scripts/utils.js b/scripts/utils.js index 52e02b82..646278e8 100644 --- a/scripts/utils.js +++ b/scripts/utils.js @@ -1,18 +1,13 @@ -import _ from 'lodash/fp' +import _ from "lodash/fp" -export let stringify = data => JSON.stringify(data, 0, 2) +export let stringify = (data) => JSON.stringify(data, 0, 2) -export let joinWith = _.curry((f, data) => - _.flow( - _.map, - _.join('') - )(f, data) -) +export let joinWith = _.curry((f, data) => _.flow(_.map, _.join(""))(f, data)) // Gets a tag value from a jsdoc entry -export let getTag = (tag, x) => _.get('text', _.find({ title: tag }, x.tags)) +export let getTag = (tag, x) => _.get("text", _.find({ title: tag }, x.tags)) /// TODO::: replace `wrap` with this export let maybeWrap = _.curry((left, right, center) => - center ? left + center + right : '' + center ? left + center + right : "" ) diff --git a/src/array.js b/src/array.js index 70ff0c8e..b881205c 100644 --- a/src/array.js +++ b/src/array.js @@ -1,7 +1,7 @@ -import _ from 'lodash/fp' -import { callOrReturn } from './function' -import { insertAtIndex } from './collection' -import { reduceIndexed } from './conversion' +import _ from "lodash/fp" +import { callOrReturn } from "./function" +import { insertAtIndex } from "./collection" +import { reduceIndexed } from "./conversion" // TODO: Move to proper files and expose let callUnless = (check) => (failFn) => (fn) => (x, y) => @@ -24,14 +24,14 @@ export let compactJoin = _.curry((join, x) => _.compact(x).join(join)) * * @signature [string1, string2, ...stringN] -> string1 + '.' + string2 + '.' ... + stringN */ -export let dotJoin = compactJoin('.') +export let dotJoin = compactJoin(".") /** * Compacts an array by the provided function, then joins it with `.` * * @signature filterFunction -> [string1, string2, ...stringN] -> string1 + '.' + string2 + '.' ... + stringN */ -export let dotJoinWith = (fn) => (x) => _.filter(fn, x).join('.') +export let dotJoinWith = (fn) => (x) => _.filter(fn, x).join(".") /** * Returns an array of elements that are repeated in the array. @@ -142,14 +142,14 @@ export let encoder = (separator) => ({ * * @signature { encode: ['a', 'b'] -> 'a.b', decode: 'a.b' -> ['a', 'b'] } */ -export let dotEncoder = encoder('.') +export let dotEncoder = encoder(".") /** * An encoder using `/` as the separator * * @signature { encode: ['a', 'b'] -> 'a/b', decode: 'a/b' -> ['a', 'b'] } */ -export let slashEncoder = encoder('/') +export let slashEncoder = encoder("/") /** * Takes a predicate function and an array, and returns an array of arrays where each element has one or more elements of the original array. Similar to Haskell's [groupBy](http://zvon.org/other/haskell/Outputlist/groupBy_f.html). diff --git a/src/aspect.js b/src/aspect.js index 7f01d489..8f7d1538 100644 --- a/src/aspect.js +++ b/src/aspect.js @@ -16,9 +16,9 @@ * @module aspect */ -import _ from 'lodash/fp' -import { defaultsOn, setOn } from './conversion' -import { throws, tapError } from './lang' +import _ from "lodash/fp" +import { defaultsOn, setOn } from "./conversion" +import { throws, tapError } from "./lang" /** * The aspect api takes an options object and returns a function which takes a function to wrap. @@ -50,7 +50,7 @@ Options supports the following parameters: */ export let aspect = ({ - name = 'aspect', + name = "aspect", init = _.noop, after = _.noop, before = _.noop, @@ -95,7 +95,7 @@ export let aspect = */ export let aspectSync = ({ - name = 'aspect', + name = "aspect", init = _.noop, after = _.noop, before = _.noop, @@ -131,19 +131,19 @@ let logs = (extend = defaultsOn) => aspect({ init: extend({ logs: [] }), after: (result, state) => state.logs.push(result), - name: 'logs', + name: "logs", }) let error = (extend = defaultsOn) => aspect({ init: extend({ error: null }), - onError: setOn('error'), - name: 'error', + onError: setOn("error"), + name: "error", }) let errors = (extend = defaultsOn) => aspect({ init: extend({ errors: [] }), onError: (e, state) => state.errors.push(e), - name: 'errors', + name: "errors", }) let status = (extend = defaultsOn) => aspect({ @@ -155,21 +155,21 @@ let status = (extend = defaultsOn) => // Computed get/set properties don't work, probably because lodash extend methods don't support copying them setStatus(x) { this.status = x - this.failed = x === 'failed' - this.succeeded = x === 'succeeded' - this.processing = x === 'processing' + this.failed = x === "failed" + this.succeeded = x === "succeeded" + this.processing = x === "processing" }, }), before(params, state) { - state.setStatus('processing') + state.setStatus("processing") }, after(result, state) { - state.setStatus('succeeded') + state.setStatus("succeeded") }, onError: tapError((e, state) => { - state.setStatus('failed') + state.setStatus("failed") }), - name: 'status', + name: "status", }) let clearStatus = (timeout = 500) => aspect({ @@ -180,17 +180,17 @@ let clearStatus = (timeout = 500) => }, timeout) } }, - name: 'clearStatus', + name: "clearStatus", }) // This is a function just for consistency let concurrency = () => aspect({ before(params, state) { if (state.processing) { - throw Error('Concurrent Runs Not Allowed') + throw Error("Concurrent Runs Not Allowed") } }, - name: 'concurrency', + name: "concurrency", }) let command = (extend, timeout) => @@ -205,9 +205,9 @@ let deprecate = (subject, version, alternative) => aspectSync({ before: () => console.warn( - `\`${subject}\` is deprecated${version ? ` as of ${version}` : ''}${ - alternative ? ` in favor of \`${alternative}\`` : '' - } ${_.trim((Error().stack || '').split('\n')[3])}` + `\`${subject}\` is deprecated${version ? ` as of ${version}` : ""}${ + alternative ? ` in favor of \`${alternative}\`` : "" + } ${_.trim((Error().stack || "").split("\n")[3])}` ), init(state) { state.isDeprecated = true diff --git a/src/collection.js b/src/collection.js index d79f0ee3..77c951a9 100644 --- a/src/collection.js +++ b/src/collection.js @@ -1,5 +1,5 @@ -import _ from 'lodash/fp' -import { isTraversable } from './tree' +import _ from "lodash/fp" +import { isTraversable } from "./tree" /** * Maps a flow of `f1, f2, ...fn` over a collection. diff --git a/src/conversion.js b/src/conversion.js index d63c5d9f..b2deb2a0 100644 --- a/src/conversion.js +++ b/src/conversion.js @@ -1,5 +1,5 @@ -import _ from 'lodash/fp' -import { aspects } from './aspect' +import _ from "lodash/fp" +import { aspects } from "./aspect" const noRearg = _.convert({ rearg: false }) const mutable = _.convert({ immutable: false }) @@ -119,19 +119,19 @@ export const updateOn = mutable.update // Un-prefixed Deprecated export const reduce = aspects.deprecate( - 'reduce', - '1.28.0', - 'reduceIndexed' + "reduce", + "1.28.0", + "reduceIndexed" )(noCap.reduce) export const mapValues = aspects.deprecate( - 'mapValues', - '1.28.0', - 'mapValuesIndexed' + "mapValues", + "1.28.0", + "mapValuesIndexed" )(noCap.mapValues) export const each = aspects.deprecate( - 'each', - '1.28.0', - 'eachIndexed' + "each", + "1.28.0", + "eachIndexed" )(noCap.each) /** diff --git a/src/function.js b/src/function.js index fe299a6c..172fd455 100644 --- a/src/function.js +++ b/src/function.js @@ -1,4 +1,4 @@ -import _ from 'lodash/fp' +import _ from "lodash/fp" /** * If `fn` is a function, call the function with the passed-in arguments. Otherwise, return `false`. diff --git a/src/index.js b/src/index.js index cec49999..beef707f 100644 --- a/src/index.js +++ b/src/index.js @@ -1,32 +1,32 @@ -import _ from 'lodash/fp' +import _ from "lodash/fp" -export * from './conversion' -export * from './collection' -export * from './function' -export * from './string' -export * from './object' -export * from './aspect' -export * from './array' -export * from './logic' -export * from './regex' -export * from './lang' -export * from './lens' -export * from './tree' -export * from './iterators' +export * from "./conversion" +export * from "./collection" +export * from "./function" +export * from "./string" +export * from "./object" +export * from "./aspect" +export * from "./array" +export * from "./logic" +export * from "./regex" +export * from "./lang" +export * from "./lens" +export * from "./tree" +export * from "./iterators" -import * as conversion from './conversion' -import * as collection from './collection' -import * as fn from './function' -import * as string from './string' -import * as object from './object' -import * as aspect from './aspect' -import * as array from './array' -import * as logic from './logic' -import * as regex from './regex' -import * as lang from './lang' -import * as lens from './lens' -import * as tree from './tree' -import * as iterators from './iterators' +import * as conversion from "./conversion" +import * as collection from "./collection" +import * as fn from "./function" +import * as string from "./string" +import * as object from "./object" +import * as aspect from "./aspect" +import * as array from "./array" +import * as logic from "./logic" +import * as regex from "./regex" +import * as lang from "./lang" +import * as lens from "./lens" +import * as tree from "./tree" +import * as iterators from "./iterators" // Math // ---- @@ -50,8 +50,8 @@ export const greaterThanOne = _.lt(1) */ export const isPromise = (obj) => !!obj && - (typeof obj === 'object' || typeof obj === 'function') && - typeof obj.then === 'function' + (typeof obj === "object" || typeof obj === "function") && + typeof obj.then === "function" // Version // ---- diff --git a/src/iterators.js b/src/iterators.js index 4ddefdca..ea5be5da 100644 --- a/src/iterators.js +++ b/src/iterators.js @@ -1,4 +1,4 @@ -import _ from 'lodash/fp' +import _ from "lodash/fp" /** * Creates an iterator that handles the last item differently for use in any function that passes `(value, index, list)` (e.g. `mapIndexed`, `eachIndexed`, etc). Both the two handlers and the result are iterator functions that take `(value, index, list)`. diff --git a/src/lang.js b/src/lang.js index a738cc00..0d255351 100644 --- a/src/lang.js +++ b/src/lang.js @@ -3,8 +3,8 @@ * @module lang */ -import _ from 'lodash/fp' -import { tree } from './tree' +import _ from "lodash/fp" +import { tree } from "./tree" /** * Just throws whatever it is passed. @@ -54,7 +54,7 @@ export let append = _.curry((x, y) => y + x) */ export let isBlank = _.overSome([ _.isNil, - _.isEqual(''), + _.isEqual(""), _.isEqual([]), _.isEqual({}), ]) diff --git a/src/lens.js b/src/lens.js index 6c401e3e..9188e5e9 100644 --- a/src/lens.js +++ b/src/lens.js @@ -37,10 +37,10 @@ * @module lens */ -import _ from 'lodash/fp' -import { setOn } from './conversion' -import { toggleElementBy } from './array' -import { when } from './logic' +import _ from "lodash/fp" +import { setOn } from "./conversion" +import { toggleElementBy } from "./array" +import { when } from "./logic" // Stubs @@ -223,14 +223,14 @@ export let domLens = { * return * } */ - value: targetBinding('value'), + value: targetBinding("value"), /** * Creates an includeLens and maps view to checked and set to `onChange` (set with `e.target.checked` or `e` if that path isn't present) * * @signature (value, lens) -> {checked, onChange} */ - checkboxValues: _.flow(includeLens, targetBinding('checked')), + checkboxValues: _.flow(includeLens, targetBinding("checked")), /** * Takes a lens and returns on onMouseEnter which calls `on` on the lens and onMouseLeave which calls `off`. Models a mapping of "hovering" to a boolean. diff --git a/src/logic.js b/src/logic.js index 36b4a7ec..c2bb7316 100644 --- a/src/logic.js +++ b/src/logic.js @@ -1,6 +1,6 @@ -import _ from 'lodash/fp' -import { callOrReturn } from './function' -import { exists } from './lang' +import _ from "lodash/fp" +import { callOrReturn } from "./function" +import { exists } from "./lang" /** * Creates a function that checks if none of the array of predicates passed in returns truthy for `x` diff --git a/src/object.js b/src/object.js index 76a3422e..8471157b 100644 --- a/src/object.js +++ b/src/object.js @@ -1,7 +1,7 @@ -import _ from 'lodash/fp' -import { dotJoinWith, zipObjectDeepWith } from './array' -import { overNone, ifElse } from './logic' -import { isNotNil, isBlank } from './lang' +import _ from "lodash/fp" +import { dotJoinWith, zipObjectDeepWith } from "./array" +import { overNone, ifElse } from "./logic" +import { isNotNil, isBlank } from "./lang" import { reduceIndexed, pickIn, @@ -9,10 +9,10 @@ import { hasIn, mapIndexed, mapValuesIndexed, -} from './conversion' -import { findApply } from './collection' -import { aspects } from './aspect' -import { mapArgs } from './function' +} from "./conversion" +import { findApply } from "./collection" +import { aspects } from "./aspect" +import { mapArgs } from "./function" const noCap = _.convert({ cap: false }) /** @@ -168,9 +168,9 @@ export const compareDeep = _.curry( * @deprecated 1.46.0 */ export const mapProp = aspects.deprecate( - 'mapProp', - '1.46.0', - '_.update' + "mapProp", + "1.46.0", + "_.update" )(noCap.update) /** @@ -252,7 +252,7 @@ export let simpleDiff = (original, deltas) => { * * @signature (from, to) -> [simpleDiffChanges] */ -export let simpleDiffArray = _.flow(simpleDiff, unkeyBy('field')) +export let simpleDiffArray = _.flow(simpleDiff, unkeyBy("field")) /** * Same as `simpleDiff`, but also takes in count deleted properties. @@ -275,7 +275,7 @@ export let diff = (original, deltas) => { * @signature (from, to) -> [diffChanges] * @note We're considering not maintaining this in the long term, so you might probably have more success with any existing library for this purpose. */ -export let diffArray = _.flow(diff, unkeyBy('field')) +export let diffArray = _.flow(diff, unkeyBy("field")) /** * A `_.pick` that mutates the object diff --git a/src/regex.js b/src/regex.js index d273b2b9..3ebb28b4 100644 --- a/src/regex.js +++ b/src/regex.js @@ -1,6 +1,6 @@ -import _ from 'lodash/fp' -import { push, mergeRanges } from './array' -import { insertAtIndex } from './collection' +import _ from "lodash/fp" +import { push, mergeRanges } from "./array" +import { insertAtIndex } from "./collection" /** * Just like ramda test, creates a function to test a regex on a string. @@ -23,18 +23,18 @@ export const makeRegex = (options) => (text) => RegExp(text, options) */ export const makeAndTest = (options) => _.flow(makeRegex(options), testRegex) -export const anyWordToRegexp = _.flow(_.words, _.join('|')) +export const anyWordToRegexp = _.flow(_.words, _.join("|")) export const wordsToRegexp = _.flow( _.words, _.map((x) => `(?=.*${x}.*)`), - _.join(''), + _.join(""), (x) => `.*${x}.*` ) const matchWords = _.curry((buildRegex, x) => { // Not inlining so that we don't create the regexp every time - const regexp = RegExp(buildRegex(x), 'gi') + const regexp = RegExp(buildRegex(x), "gi") return (y) => !!(y && y.match(regexp)) }) @@ -60,7 +60,7 @@ export const matchAnyWord = matchWords(anyWordToRegexp) */ export const allMatches = _.curry((regexStr, str) => { let matched - const regex = new RegExp(regexStr, 'g') + const regex = new RegExp(regexStr, "g") const result = [] while ((matched = regex.exec(str)) !== null) { @@ -82,7 +82,7 @@ export const allMatches = _.curry((regexStr, str) => { export const postings = _.curry((regex, str) => { var match = regex.exec(str) let result = [] - if (regex.flags.indexOf('g') < 0 && match) { + if (regex.flags.indexOf("g") < 0 && match) { result.push([match.index, match.index + match[0].length]) } else { while (match) { @@ -105,7 +105,7 @@ export const postings = _.curry((regex, str) => { */ export const postingsForWords = _.curry((string, str) => _.reduce( - (result, word) => push(postings(RegExp(word, 'gi'), str), result), + (result, word) => push(postings(RegExp(word, "gi"), str), result), [] )(_.words(string)) ) diff --git a/src/string.js b/src/string.js index 13e92765..b4f02c05 100644 --- a/src/string.js +++ b/src/string.js @@ -1,11 +1,11 @@ -import { map } from './collection' -import _ from 'lodash/fp' -import { when } from './logic' -import { intersperse } from './array' -import { differentLast } from './iterators' +import { map } from "./collection" +import _ from "lodash/fp" +import { when } from "./logic" +import { intersperse } from "./array" +import { differentLast } from "./iterators" export const wrap = (pre, post, content) => - (pre || '') + content + (post || pre || '') + (pre || "") + content + (post || pre || "") export const quote = _.partial(wrap, ['"', '"']) /** @@ -13,8 +13,8 @@ export const quote = _.partial(wrap, ['"', '"']) * * @signature 'asdf' -> '(asdf)' */ -export const parens = _.partial(wrap, ['(', ')']) -export const concatStrings = _.flow(_.compact, _.map(_.trim), _.join(' ')) +export const parens = _.partial(wrap, ["(", ")"]) +export const concatStrings = _.flow(_.compact, _.map(_.trim), _.join(" ")) /** * Maps `_.trim` through all the strings of a given object or array. @@ -61,7 +61,7 @@ export let toSentenceWith = _.curry((separator, lastSeparator, array) => () => lastSeparator ) ), - _.join('') + _.join("") )(array) ) @@ -71,7 +71,7 @@ export let toSentenceWith = _.curry((separator, lastSeparator, array) => * @signature array => string * @example ['a', 'b', 'c'] -> 'a, b and c' */ -export let toSentence = toSentenceWith(', ', ' and ') +export let toSentence = toSentenceWith(", ", " and ") /** * Allows passing a "cachizer" function (`array -> object`) to override the way `uniqueString`'s initial array is converted into a cache object. Can be curried to create a custom `uniqueString` function, eg: `let myUniqueString = uniqueStringWith(myFunc)` diff --git a/src/tree.js b/src/tree.js index 42387833..5ed9ddf7 100644 --- a/src/tree.js +++ b/src/tree.js @@ -5,9 +5,9 @@ * @module tree */ -import _ from 'lodash/fp' -import { findIndexed } from './conversion' -import { push, dotEncoder, slashEncoder } from './array' +import _ from "lodash/fp" +import { findIndexed } from "./conversion" +import { push, dotEncoder, slashEncoder } from "./array" /** * A default check if something can be traversed - currently it is arrays and plain objects. diff --git a/test/array.spec.js b/test/array.spec.js index 122e2a9d..1f7a1d10 100644 --- a/test/array.spec.js +++ b/test/array.spec.js @@ -1,45 +1,45 @@ -import chai from 'chai' -import F from '../src/' +import chai from "chai" +import F from "../src/" chai.expect() const expect = chai.expect -describe('Array Functions', () => { - it('compactJoin', () => { - expect(F.compactJoin(',', [1, undefined, 2, null, 3])).to.equal('1,2,3') - expect(F.compactJoin(' and ', [null, 'Alice', 'Bob', false])).to.equal( - 'Alice and Bob' +describe("Array Functions", () => { + it("compactJoin", () => { + expect(F.compactJoin(",", [1, undefined, 2, null, 3])).to.equal("1,2,3") + expect(F.compactJoin(" and ", [null, "Alice", "Bob", false])).to.equal( + "Alice and Bob" ) }) - it('dotJoin', () => { - expect(F.dotJoin([1, undefined, 2, null, 3])).to.equal('1.2.3') - expect(F.dotJoin([null, 'Alice', 'Bob', false])).to.equal('Alice.Bob') + it("dotJoin", () => { + expect(F.dotJoin([1, undefined, 2, null, 3])).to.equal("1.2.3") + expect(F.dotJoin([null, "Alice", "Bob", false])).to.equal("Alice.Bob") }) - it('repeated', () => { + it("repeated", () => { expect(F.repeated([1, 1, 2, 3, 3, 4])).to.deep.equal([1, 3]) - expect(F.repeated(['a', 'b', 'b'])).to.deep.equal(['b']) + expect(F.repeated(["a", "b", "b"])).to.deep.equal(["b"]) }) - it('push', () => { + it("push", () => { let arr = [1, 2, 3] expect(F.push(4)(arr)).to.deep.equal([1, 2, 3, 4]) expect(arr).to.deep.equal([1, 2, 3]) }) - it('pushIn', () => { + it("pushIn", () => { let arr = [1, 2, 3] expect(F.pushIn(arr)(4)).to.deep.equal([1, 2, 3, 4]) expect(arr).to.deep.equal([1, 2, 3]) }) - it('pushOn', () => { + it("pushOn", () => { let arr = [1, 2, 3] expect(F.pushOn(arr)(4)).to.deep.equal([1, 2, 3, 4]) expect(arr).to.deep.equal([1, 2, 3, 4]) }) - it('moveIndex', () => { + it("moveIndex", () => { let arr = [1, 2, 3] let x = F.moveIndex(1, 0, arr) expect(x).to.deep.equal([2, 1, 3]) expect(arr).to.deep.equal([1, 2, 3]) }) - it('mergeRanges', () => { + it("mergeRanges", () => { // arrays need to be sorted in ascending order expect( F.mergeRanges([ @@ -57,7 +57,7 @@ describe('Array Functions', () => { ]) ).to.deep.equal([[0, 5]]) }) - it('cycle', () => { + it("cycle", () => { let cycle = F.cycle([1, 2, 3]) expect(cycle(1)).to.equal(2) expect(cycle(2)).to.equal(3) @@ -71,54 +71,54 @@ describe('Array Functions', () => { expect(F.cycle([true, false], true)).to.be.false }) - it('arrayToObject', () => { + it("arrayToObject", () => { expect( F.arrayToObject( (x) => `key${x}`, (x) => `val${x}`, - ['a', 'b', 'c'] + ["a", "b", "c"] ) - ).to.deep.equal({ keya: 'vala', keyb: 'valb', keyc: 'valc' }) + ).to.deep.equal({ keya: "vala", keyb: "valb", keyc: "valc" }) }) - it('zipObjectDeepWith', () => { - expect(F.zipObjectDeepWith(['a', 'b'], () => 1)).to.deep.equal({ + it("zipObjectDeepWith", () => { + expect(F.zipObjectDeepWith(["a", "b"], () => 1)).to.deep.equal({ a: 1, b: 1, }) }) - it('flags', () => { - expect(F.flags(['a', 'b', 'c'])).to.deep.equal({ + it("flags", () => { + expect(F.flags(["a", "b", "c"])).to.deep.equal({ a: true, b: true, c: true, }) }) - it('prefixes', () => { - expect(F.prefixes(['root', 'criteria', 'someNode'])).to.deep.equal([ - ['root'], - ['root', 'criteria'], - ['root', 'criteria', 'someNode'], + it("prefixes", () => { + expect(F.prefixes(["root", "criteria", "someNode"])).to.deep.equal([ + ["root"], + ["root", "criteria"], + ["root", "criteria", "someNode"], ]) - expect(F.prefixes('abc')).to.deep.equal([ - ['a'], - ['a', 'b'], - ['a', 'b', 'c'], + expect(F.prefixes("abc")).to.deep.equal([ + ["a"], + ["a", "b"], + ["a", "b", "c"], ]) }) - it('encoder', () => { - let encoder = F.encoder('->') - expect(encoder.encode(['a', 'b'])).to.equal('a->b') - expect(encoder.decode('a->b')).to.deep.equal(['a', 'b']) + it("encoder", () => { + let encoder = F.encoder("->") + expect(encoder.encode(["a", "b"])).to.equal("a->b") + expect(encoder.decode("a->b")).to.deep.equal(["a", "b"]) }) - it('dotEncoder', () => { - expect(F.dotEncoder.encode(['a', 'b'])).to.equal('a.b') - expect(F.dotEncoder.decode('a.b')).to.deep.equal(['a', 'b']) + it("dotEncoder", () => { + expect(F.dotEncoder.encode(["a", "b"])).to.equal("a.b") + expect(F.dotEncoder.decode("a.b")).to.deep.equal(["a", "b"]) }) - it('slashEncoder', () => { - expect(F.slashEncoder.encode(['a', 'b'])).to.equal('a/b') - expect(F.slashEncoder.decode('a/b')).to.deep.equal(['a', 'b']) + it("slashEncoder", () => { + expect(F.slashEncoder.encode(["a", "b"])).to.equal("a/b") + expect(F.slashEncoder.decode("a/b")).to.deep.equal(["a", "b"]) }) - it('chunkBy', () => { + it("chunkBy", () => { expect( F.chunkBy(([a], b) => b % a === 0, [2, 2, 2, 3, 2, 2]) ).to.deep.equal([[2, 2, 2], [3], [2, 2]]) @@ -133,50 +133,50 @@ describe('Array Functions', () => { expect(F.chunkBy(() => false, undefined)).to.deep.equal([]) expect(F.chunkBy(() => false, [])).to.deep.equal([]) }) - it('toggleElement', () => { - expect(F.toggleElement('b', ['a', 'b', 'c', 'd'])).to.deep.equal([ - 'a', - 'c', - 'd', + it("toggleElement", () => { + expect(F.toggleElement("b", ["a", "b", "c", "d"])).to.deep.equal([ + "a", + "c", + "d", ]) - expect(F.toggleElement('b', ['a', 'c', 'd'])).to.deep.equal([ - 'a', - 'c', - 'd', - 'b', + expect(F.toggleElement("b", ["a", "c", "d"])).to.deep.equal([ + "a", + "c", + "d", + "b", ]) }) - it('toggleElementBy', () => { - let list = ['a', 'b', 'c'] - let valueToToggle = 'b' + it("toggleElementBy", () => { + let list = ["a", "b", "c"] + let valueToToggle = "b" let toggleB = (shouldAdd) => F.toggleElementBy(!shouldAdd, valueToToggle, list) - expect(toggleB(true)).to.deep.equal(['a', 'b', 'c', 'b']) - expect(toggleB(false)).to.deep.equal(['a', 'c']) + expect(toggleB(true)).to.deep.equal(["a", "b", "c", "b"]) + expect(toggleB(false)).to.deep.equal(["a", "c"]) }) - it('intersperse', () => { + it("intersperse", () => { expect( F.intersperse( - (acc, i, xs) => (i === xs.length - 1 ? 'and finally' : 'and'), + (acc, i, xs) => (i === xs.length - 1 ? "and finally" : "and"), [1, 2, 3, 4] ) - ).to.deep.equal([1, 'and', 2, 'and', 3, 'and finally', 4]) - expect(F.intersperse('and', [1, 2, 3])).to.deep.equal([ + ).to.deep.equal([1, "and", 2, "and", 3, "and finally", 4]) + expect(F.intersperse("and", [1, 2, 3])).to.deep.equal([ 1, - 'and', + "and", 2, - 'and', + "and", 3, ]) }) - it('replaceElementBy', () => { + it("replaceElementBy", () => { expect(F.replaceElementBy((c) => c > 10, 0, [1, 11, 3, 5])).to.deep.equal([ 1, 0, 3, 5, ]) }) - it('replaceElement', () => { + it("replaceElement", () => { expect(F.replaceElement(11, 0, [1, 11, 3, 5])).to.deep.equal([1, 0, 3, 5]) }) }) diff --git a/test/aspect.spec.js b/test/aspect.spec.js index 6352a367..56918f14 100644 --- a/test/aspect.spec.js +++ b/test/aspect.spec.js @@ -1,14 +1,14 @@ -import _ from 'lodash/fp' -import chai from 'chai' -import chaiAsPromised from 'chai-as-promised' -import { aspects, aspect, aspectSync } from '../src' -import Promise from 'bluebird' +import _ from "lodash/fp" +import chai from "chai" +import chaiAsPromised from "chai-as-promised" +import { aspects, aspect, aspectSync } from "../src" +import Promise from "bluebird" chai.use(chaiAsPromised) chai.expect() const expect = chai.expect -describe('Aspect Functions', () => { +describe("Aspect Functions", () => { // Example Aspect composition let Command = _.flow( aspects.status(), @@ -17,7 +17,7 @@ describe('Aspect Functions', () => { aspects.errors() ) - it('should combine aspect states', async () => { + it("should combine aspect states", async () => { let f = Command(() => 6) expect(f.state.status).to.equal(null) expect(f.state.processing).to.be.false @@ -26,49 +26,49 @@ describe('Aspect Functions', () => { expect(f.state.logs).to.deep.equal([]) expect(f.state.errors).to.deep.equal([]) }) - it('should support .after calls (`logs` aspect)', async () => { + it("should support .after calls (`logs` aspect)", async () => { let f = Command(() => 6) await f() expect(f.state.logs).to.deep.equal([6]) await f() expect(f.state.logs).to.deep.equal([6, 6]) }) - it('should support .onError and before (`concurrency`, `errors`, and `status` aspects)', async () => { + it("should support .onError and before (`concurrency`, `errors`, and `status` aspects)", async () => { let g = Command(() => { throw Error(5) }) expect(g.state.processing).to.be.false await g() - expect(g.state.errors[0].message).to.equal('5') + expect(g.state.errors[0].message).to.equal("5") expect(g.state.processing).to.be.false // Should be blocked as a concurrent run since it's still processing g.state.processing = true await g() - expect(g.state.errors[1].message).to.equal('Concurrent Runs Not Allowed') + expect(g.state.errors[1].message).to.equal("Concurrent Runs Not Allowed") }) - it('should support throwing in onError', async () => { + it("should support throwing in onError", async () => { // Use the single error object to avoid 'Unhandled promise rejection' in // some browsers. - let theException = new Error('hi from aspect') + let theException = new Error("hi from aspect") let ThrowHi = aspect({ onError() { throw theException }, }) let throwsHi = ThrowHi(() => { - throw Error('Not hi') + throw Error("Not hi") }) expect(throwsHi()).to.be.rejectedWith(theException) }) - it('should support single error', async () => { + it("should support single error", async () => { let throwsHi = aspects.error()(() => { - throw Error('Hi') + throw Error("Hi") }) await throwsHi() - expect(throwsHi.state.error.message).to.equal('Hi') + expect(throwsHi.state.error.message).to.equal("Hi") }) - it('should support status and clearing status', async () => { + it("should support status and clearing status", async () => { // Increase the timeout/delay to hundreds ms to make testing IE9/10/11 more // stable & avoid exception: // AssertionError: expected null to equal 'processing' @@ -76,18 +76,18 @@ describe('Aspect Functions', () => { let f = clearingStatus(async () => Promise.delay(200)) let result = f() await Promise.delay(100) - expect(f.state.status).to.equal('processing') + expect(f.state.status).to.equal("processing") expect(f.state.processing).to.be.true await result - expect(f.state.status).to.equal('succeeded') + expect(f.state.status).to.equal("succeeded") expect(f.state.succeeded).to.be.true await Promise.delay(300) expect(f.state.status).to.equal(null) let g = clearingStatus(async () => { - throw Error('error') + throw Error("error") }) await g() - expect(g.state.status).to.equal('failed') + expect(g.state.status).to.equal("failed") expect(g.state.failed).to.be.true await Promise.delay(15) expect(f.state.status).to.equal(null) @@ -96,7 +96,7 @@ describe('Aspect Functions', () => { // Timeout of 2000ms exceeded. For async tests and hooks, ensure "done()" // is called; if returning a Promise, ensure it resolves. .timeout(10000) - it('should support synchronous aspects', () => { + it("should support synchronous aspects", () => { let x = 1 let y = 0 let firstIncrementX = aspectSync({ @@ -110,8 +110,8 @@ describe('Aspect Functions', () => { f() expect(y).to.equal(2) }) - it('should mark deprecated methods on state', () => { - let fn = aspects.deprecate('test', '1.2.3', 'something else')(() => {}) + it("should mark deprecated methods on state", () => { + let fn = aspects.deprecate("test", "1.2.3", "something else")(() => {}) expect(fn.state.isDeprecated).to.be.true }) diff --git a/test/collections.spec.js b/test/collections.spec.js index 74fcd49e..ed86ddc5 100644 --- a/test/collections.spec.js +++ b/test/collections.spec.js @@ -1,12 +1,12 @@ -import chai from 'chai' -import F from '../src/' -import _ from 'lodash/fp' +import chai from "chai" +import F from "../src/" +import _ from "lodash/fp" chai.expect() const expect = chai.expect -describe('Collections Functions', () => { - it('flowMap', () => { +describe("Collections Functions", () => { + it("flowMap", () => { expect( F.flowMap( (n) => n + n, @@ -16,24 +16,24 @@ describe('Collections Functions', () => { expect( F.flowMap( (s) => s.toUpperCase(), - (s) => s.split(''), + (s) => s.split(""), (s) => s.reverse(), - (s) => s.join('') - )(['Smart', 'Procure']) - ).to.deep.equal(['TRAMS', 'ERUCORP']) + (s) => s.join("") + )(["Smart", "Procure"]) + ).to.deep.equal(["TRAMS", "ERUCORP"]) }) - it('findApply', () => { + it("findApply", () => { let x = { a: 1, } - expect(F.findApply((f) => x[f], ['b', 'c', 'a'])).to.equal(1) - expect(F.findApply((f) => x[f], ['b', 'c'])).to.equal(undefined) + expect(F.findApply((f) => x[f], ["b", "c", "a"])).to.equal(1) + expect(F.findApply((f) => x[f], ["b", "c"])).to.equal(undefined) let xs = [{ b: 2 }, { c: 3 }, { a: 1 }] expect(F.findApply((f) => f.a, xs)).to.equal(1) - expect(F.findApply('a', xs)).to.equal(1) - expect(F.findApply('d', xs)).to.equal(undefined) + expect(F.findApply("a", xs)).to.equal(1) + expect(F.findApply("d", xs)).to.equal(undefined) }) - it('map', () => { + it("map", () => { // map plain arrays expect(F.map((x) => x * x, [1, 2, 3])).to.deep.equal([1, 4, 9]) // map plain objects @@ -43,8 +43,8 @@ describe('Collections Functions', () => { c: 9, }) }) - describe('deepMap', () => { - it('deepMap arrays', () => { + describe("deepMap", () => { + it("deepMap arrays", () => { // arrays const arr = [0, [1, [2, []]]] const arrBackup = _.cloneDeep(arr) @@ -53,7 +53,7 @@ describe('Collections Functions', () => { expect(arr).to.deep.equal(arrBackup) expect(arrMutated).to.deep.equal([0, [1, [2, [101], 101], 101]]) }) - it('deepMap plain objects', () => { + it("deepMap plain objects", () => { const objA = { a: { match: { @@ -72,7 +72,7 @@ describe('Collections Functions', () => { }, } const objABackup = _.cloneDeep(objA) - const pathA = 'match.matched' + const pathA = "match.matched" const setMatchedA = (e) => e.match && _.set(pathA, true, e) const objAMutated = F.deepMap((e) => setMatchedA(e) || e)(objA) // Checking immutability @@ -98,7 +98,7 @@ describe('Collections Functions', () => { }, }) }) - it('deepMap with plain objects with arrays with objects', () => { + it("deepMap with plain objects with arrays with objects", () => { const objB = { a: { array: [0, [1, [2, [{ match: { id: 0 } }]]]], @@ -118,7 +118,7 @@ describe('Collections Functions', () => { }, } const objBBackup = _.cloneDeep(objB) - const pathB = 'match.matched' + const pathB = "match.matched" const setMatchedB = (e) => e.match && _.set(pathB, true, e) const push101 = (e) => _.isArray(e) && e.concat(101) const objBMutated = F.deepMap((e) => push101(e) || setMatchedB(e) || e)( @@ -153,32 +153,32 @@ describe('Collections Functions', () => { }) }) }) - it('insertAtIndex', () => { + it("insertAtIndex", () => { let arr = [1, 2, 3] let x = F.insertAtIndex(1, 5, arr) expect(x).to.deep.equal([1, 5, 2, 3]) expect(arr).to.deep.equal([1, 2, 3]) - expect(F.insertAtIndex(1, 'z', 'abc')).to.equal('azbc') + expect(F.insertAtIndex(1, "z", "abc")).to.equal("azbc") - var result = F.insertAtIndex(0, '', 'pretty please') - expect(result).to.equal('pretty please') + var result = F.insertAtIndex(0, "", "pretty please") + expect(result).to.equal("pretty please") }) - it('compactMap', () => { - let names = ['adam', 'betty', 'carlos', 'doug', 'emily'] - let exceptDoug = (fn) => (x) => x === 'doug' ? undefined : fn(x) + it("compactMap", () => { + let names = ["adam", "betty", "carlos", "doug", "emily"] + let exceptDoug = (fn) => (x) => x === "doug" ? undefined : fn(x) expect(F.compactMap(_.capitalize, names)).to.deep.equal([ - 'Adam', - 'Betty', - 'Carlos', - 'Doug', - 'Emily', + "Adam", + "Betty", + "Carlos", + "Doug", + "Emily", ]) expect(F.compactMap(exceptDoug(_.capitalize), names)).to.deep.equal([ - 'Adam', - 'Betty', - 'Carlos', - 'Emily', + "Adam", + "Betty", + "Carlos", + "Emily", ]) expect(F.compactMap((x) => x - 2, [0, 1, 2, 3])).to.deep.equal([-2, -1, 1]) }) diff --git a/test/conversions.spec.js b/test/conversions.spec.js index b21280ac..b65e218c 100644 --- a/test/conversions.spec.js +++ b/test/conversions.spec.js @@ -1,88 +1,88 @@ -import _ from 'lodash/fp' -import chai from 'chai' -import * as F from '../src' +import _ from "lodash/fp" +import chai from "chai" +import * as F from "../src" chai.expect() const expect = chai.expect -describe('Converted Functions', () => { - describe('Flips', () => { - it('getIn', () => { +describe("Converted Functions", () => { + describe("Flips", () => { + it("getIn", () => { let hero = { - name: 'Heracles', - father: 'Zeus', - bornAt: 'Thebes', + name: "Heracles", + father: "Zeus", + bornAt: "Thebes", } - expect(F.getIn(hero, 'name')).to.equal('Heracles') - expect(F.getIn(hero, 'Zeus')).to.equal(undefined) + expect(F.getIn(hero, "name")).to.equal("Heracles") + expect(F.getIn(hero, "Zeus")).to.equal(undefined) const obj = { a: 1 } - expect(F.inversions.getIn(obj)('a')).to.equal(1) - expect(F.getIn(obj)('a')).to.equal(1) + expect(F.inversions.getIn(obj)("a")).to.equal(1) + expect(F.getIn(obj)("a")).to.equal(1) }) - it('getIn consistent with _.get', () => { + it("getIn consistent with _.get", () => { let hero = { - name: 'Heracles', - father: 'Zeus', - bornAt: 'Thebes', + name: "Heracles", + father: "Zeus", + bornAt: "Thebes", } - expect(F.getIn(hero, 'name')).to.equal(_.get('name', hero)) + expect(F.getIn(hero, "name")).to.equal(_.get("name", hero)) }) - it('hasIn', () => { + it("hasIn", () => { let hero = { - name: 'Heracles', - father: 'Zeus', - bornAt: 'Thebes', + name: "Heracles", + father: "Zeus", + bornAt: "Thebes", } - expect(F.hasIn(hero, 'father')).to.be.true - expect(F.hasIn(hero, 'Zeus')).to.be.false + expect(F.hasIn(hero, "father")).to.be.true + expect(F.hasIn(hero, "Zeus")).to.be.false }) - it('pickIn', () => { + it("pickIn", () => { let hero = { - name: 'Heracles', - father: 'Zeus', - bornAt: 'Thebes', + name: "Heracles", + father: "Zeus", + bornAt: "Thebes", } - expect(F.pickIn(hero, 'name')).to.deep.equal({ name: 'Heracles' }) - expect(F.pickIn(hero, ['name', 'father'])).to.deep.equal({ - name: 'Heracles', - father: 'Zeus', + expect(F.pickIn(hero, "name")).to.deep.equal({ name: "Heracles" }) + expect(F.pickIn(hero, ["name", "father"])).to.deep.equal({ + name: "Heracles", + father: "Zeus", }) }) - it('pickIn consistent with _.pick', () => { + it("pickIn consistent with _.pick", () => { let hero = { - name: 'Heracles', - father: 'Zeus', - bornAt: 'Thebes', + name: "Heracles", + father: "Zeus", + bornAt: "Thebes", } - expect(F.pickIn(hero, 'name')).to.deep.equal(_.pick('name', hero)) - expect(F.pickIn(hero, ['name', 'father'])).to.deep.equal( - _.pick(['name', 'father'], hero) + expect(F.pickIn(hero, "name")).to.deep.equal(_.pick("name", hero)) + expect(F.pickIn(hero, ["name", "father"])).to.deep.equal( + _.pick(["name", "father"], hero) ) }) - it('includesIn', () => { + it("includesIn", () => { let hero = { - name: 'Heracles', - father: 'Zeus', - bornAt: 'Thebes', + name: "Heracles", + father: "Zeus", + bornAt: "Thebes", } - expect(F.includesIn(hero, 'Heracles')).to.be.true - expect(F.includesIn(hero, 'name')).to.be.false + expect(F.includesIn(hero, "Heracles")).to.be.true + expect(F.includesIn(hero, "name")).to.be.false }) - it('includesIn consistent with _.includes', () => { + it("includesIn consistent with _.includes", () => { let hero = { - name: 'Heracles', - father: 'Zeus', - bornAt: 'Thebes', + name: "Heracles", + father: "Zeus", + bornAt: "Thebes", } let expectDeepEqual = (obj, name) => expect(F.includesIn(obj, name)).to.deep.equal(_.includes(name, obj)) - expectDeepEqual(hero, 'name') - expectDeepEqual(hero, 'Heracles') - expectDeepEqual(hero, 'Zeus') + expectDeepEqual(hero, "name") + expectDeepEqual(hero, "Heracles") + expectDeepEqual(hero, "Zeus") }) }) - describe('Mutables', () => { - it('extendOn', () => { + describe("Mutables", () => { + it("extendOn", () => { expect( F.extendOn( { @@ -100,18 +100,18 @@ describe('Converted Functions', () => { c: 4, }) }) - it('extendOn consistent with _.extend', () => { + it("extendOn consistent with _.extend", () => { let hero = { - name: 'Heracles', - father: 'Zeus', - bornAt: 'Thebes', + name: "Heracles", + father: "Zeus", + bornAt: "Thebes", } let expectDeepEqual = (clone, obj) => expect(F.extendOn(clone, obj)).to.deep.equal(_.extend(obj, clone)) - expectDeepEqual(_.clone(hero), { name: 'Hercules' }) - expectDeepEqual(_.clone(hero), { consort: 'Auge' }) + expectDeepEqual(_.clone(hero), { name: "Hercules" }) + expectDeepEqual(_.clone(hero), { consort: "Auge" }) }) - it('defaultsOn', () => { + it("defaultsOn", () => { expect( F.defaultsOn( { @@ -129,50 +129,50 @@ describe('Converted Functions', () => { c: 4, }) }) - it('defaultsOn consistent with _.defaults', () => { + it("defaultsOn consistent with _.defaults", () => { let hero = { - name: 'Heracles', - father: 'Zeus', - bornAt: 'Thebes', + name: "Heracles", + father: "Zeus", + bornAt: "Thebes", } let clone = _.clone(hero) - expect(F.defaultsOn(clone, { consort: 'Auge' })).to.deep.equal( - _.defaults({ consort: 'Auge' }, clone) + expect(F.defaultsOn(clone, { consort: "Auge" })).to.deep.equal( + _.defaults({ consort: "Auge" }, clone) ) }) - it('mergeOn', () => { + it("mergeOn", () => { let hero = { - name: 'Heracles', + name: "Heracles", } - expect(F.mergeOn(hero, { consort: 'Auge' })).to.deep.equal({ - name: 'Heracles', - consort: 'Auge', + expect(F.mergeOn(hero, { consort: "Auge" })).to.deep.equal({ + name: "Heracles", + consort: "Auge", }) - expect(hero).to.deep.equal({ name: 'Heracles', consort: 'Auge' }) + expect(hero).to.deep.equal({ name: "Heracles", consort: "Auge" }) }) - it('setOn', () => { + it("setOn", () => { let object = { a: [{ b: { c: 3 } }] } - expect(F.setOn('a[0].b.c', 15)(object)).to.deep.equal({ + expect(F.setOn("a[0].b.c", 15)(object)).to.deep.equal({ a: [{ b: { c: 15 } }], }) expect(object).to.deep.equal({ a: [{ b: { c: 15 } }], }) }) - it('unsetOn', () => { + it("unsetOn", () => { let object = { a: [{ b: { c: 3 } }] } - expect(F.unsetOn('a[0].b.c')(object)).to.be.true + expect(F.unsetOn("a[0].b.c")(object)).to.be.true expect(object).to.deep.equal({ a: [{ b: {} }] }) }) - it('pullOn', () => { - let array = ['a', 'b', 'c', 'a', 'b', 'c', 'd'] - expect(F.pullOn('b')(array)).to.deep.equal(['a', 'c', 'a', 'c', 'd']) - expect(array).to.deep.equal(['a', 'c', 'a', 'c', 'd']) + it("pullOn", () => { + let array = ["a", "b", "c", "a", "b", "c", "d"] + expect(F.pullOn("b")(array)).to.deep.equal(["a", "c", "a", "c", "d"]) + expect(array).to.deep.equal(["a", "c", "a", "c", "d"]) }) - it('updateOn', () => { + it("updateOn", () => { let object = { a: [{ b: { c: 3 } }] } - expect(F.updateOn('a[0].b.c', (x) => x * x)(object)).to.deep.equal({ + expect(F.updateOn("a[0].b.c", (x) => x * x)(object)).to.deep.equal({ a: [{ b: { c: 9 } }], }) expect(object).to.deep.equal({ diff --git a/test/function.spec.js b/test/function.spec.js index 3840ee3a..bf7173a9 100644 --- a/test/function.spec.js +++ b/test/function.spec.js @@ -1,13 +1,13 @@ -import * as F from '../src' -import _ from 'lodash/fp' -import chai from 'chai' -import sinon from 'sinon' -import sinonChai from 'sinon-chai' +import * as F from "../src" +import _ from "lodash/fp" +import chai from "chai" +import sinon from "sinon" +import sinonChai from "sinon-chai" const expect = chai.expect chai.use(sinonChai) -describe('Function Functions', () => { - it('maybeCall', () => { +describe("Function Functions", () => { + it("maybeCall", () => { expect(F.maybeCall(() => 5)).to.equal(5) expect(F.maybeCall(null)).to.be.false const fn = (x, y) => x + y @@ -15,7 +15,7 @@ describe('Function Functions', () => { // maybeCall should call fn with parameters expect(F.maybeCall(fn, 5, 6)).to.equal(fn(5, 6)) }) - it('callOrReturn', () => { + it("callOrReturn", () => { expect(F.callOrReturn(() => 5)).to.equal(5) expect(F.callOrReturn(5)).to.equal(5) expect(F.callOrReturn(null)).to.equal(null) @@ -24,36 +24,36 @@ describe('Function Functions', () => { // callOrReturn should call fn with parameters expect(F.callOrReturn(fn, 5, 6)).to.equal(fn(5, 6)) }) - it('boundMethod', () => { + it("boundMethod", () => { // boundMethod should bind a method of an object to it's object let obj = { - name: 'Wade Watts', + name: "Wade Watts", greet() { return `Welcome, ${this.name}` }, } - expect(obj.greet.call({ name: 'John Henry' })).to.equal( - 'Welcome, John Henry' + expect(obj.greet.call({ name: "John Henry" })).to.equal( + "Welcome, John Henry" ) - expect(F.boundMethod('greet', obj)()).to.equal('Welcome, Wade Watts') + expect(F.boundMethod("greet", obj)()).to.equal("Welcome, Wade Watts") }) - it('converge', () => { + it("converge", () => { let divide = (arr) => arr[0] / arr[1] let sum = (arr) => _.sum(arr) let length = (arr) => arr.length // average expect(F.converge(divide, [sum, length])([5, 10, 15])).to.equal(10) }) - it('composeApply', () => { + it("composeApply", () => { let fn1 = (lastResult) => (x) => lastResult / x let fn2 = (x) => x + 5 expect(F.composeApply(fn1, fn2)(5)).to.equal(2) }) - it('comply', () => { + it("comply", () => { // F.append(x => x * 2)(5) => (5 * 2) + 5 expect(F.comply(F.append, (x) => x * 2)(5)).to.equal(15) }) - it('defer', () => { + it("defer", () => { let delay = (ms) => { let resolver = F.defer() let now = Date.now() @@ -67,8 +67,8 @@ describe('Function Functions', () => { expect(ms).is.at.least(500) }) }) - describe('debounceAsync', () => { - it('debounceAsync', async () => { + describe("debounceAsync", () => { + it("debounceAsync", async () => { let inner = sinon.spy((x) => x + 10) let fn = F.debounceAsync(10, inner) let result = await Promise.all([fn(1), fn(2), fn(3)]) @@ -77,7 +77,7 @@ describe('Function Functions', () => { let secondResult = await Promise.all([fn(11), fn(12), fn(13)]) expect(secondResult).to.deep.equal([23, 23, 23]) }) - it('should demonstrate failing with regular debounce', async () => { + it("should demonstrate failing with regular debounce", async () => { let inner2 = sinon.spy((x) => x + 10) let fn2 = _.debounce(10, inner2) let result2 = await Promise.all([fn2(1), fn2(2), fn2(3)]) @@ -87,7 +87,7 @@ describe('Function Functions', () => { expect(thirdResult).to.deep.equal([undefined, undefined, undefined]) }) }) - it('flurry', () => { + it("flurry", () => { let add = (x, y) => x + y let double = (x) => x * 2 // Passing all args @@ -95,7 +95,7 @@ describe('Function Functions', () => { // Passing 1 at a time expect(F.flurry(add, double)(1)(4)).to.equal(10) }) - it('mapArgs', () => { + it("mapArgs", () => { let add = (x, y) => x + y let double = (x) => x * 2 let doubledAdd = F.mapArgs(double, add) diff --git a/test/init.js b/test/init.js index b1efa571..b5c9cc12 100644 --- a/test/init.js +++ b/test/init.js @@ -1 +1 @@ -global.__VERSION__ = '1.0.0' +global.__VERSION__ = "1.0.0" diff --git a/test/iterators.spec.js b/test/iterators.spec.js index 00f4d425..e2e248dc 100644 --- a/test/iterators.spec.js +++ b/test/iterators.spec.js @@ -1,12 +1,12 @@ -import chai from 'chai' -import F from '../src/' +import chai from "chai" +import F from "../src/" chai.expect() const expect = chai.expect -describe('Iterator Generators', () => { - it('differentLast', () => { +describe("Iterator Generators", () => { + it("differentLast", () => { expect( - F.mapIndexed(F.differentLast('a', 'b'), [ + F.mapIndexed(F.differentLast("a", "b"), [ { a: 1, b: 2 }, { a: 1, b: 2 }, { a: 1, b: 2 }, diff --git a/test/lang.spec.js b/test/lang.spec.js index 9db06ecb..086f5898 100644 --- a/test/lang.spec.js +++ b/test/lang.spec.js @@ -1,98 +1,98 @@ -import chai from 'chai' -import * as F from '../src' -import _ from 'lodash/fp' +import chai from "chai" +import * as F from "../src" +import _ from "lodash/fp" chai.expect() const expect = chai.expect -describe('Lang Functions', () => { - it('throws', () => { - expect(() => F.throws(Error('oops'))).to.throw() +describe("Lang Functions", () => { + it("throws", () => { + expect(() => F.throws(Error("oops"))).to.throw() }) - it('tapError', () => { - let total = '' + it("tapError", () => { + let total = "" let errorFn = (e, pre, post) => (total = `${e}. The total is ${pre + post}`) - let errorOfMine = new Error('myError') + let errorOfMine = new Error("myError") try { F.tapError(errorFn)(errorOfMine, 20, 45) } catch (e) { - expect(total).to.equal('Error: myError. The total is 65') + expect(total).to.equal("Error: myError. The total is 65") expect(e).to.equal(errorOfMine) } }) - it('isNotNil', () => { + it("isNotNil", () => { expect(F.isNotNil(null)).to.be.false expect(F.isNotNil(undefined)).to.be.false expect(F.isNotNil(0)).to.be.true - expect(F.isNotNil('')).to.be.true + expect(F.isNotNil("")).to.be.true expect(F.isNotNil([])).to.be.true expect(F.isNotNil).to.equal(F.exists) }) - it('exists', () => { + it("exists", () => { expect(F.exists(null)).to.be.false expect(F.exists(undefined)).to.be.false expect(F.exists(0)).to.be.true - expect(F.exists('')).to.be.true + expect(F.exists("")).to.be.true expect(F.exists([])).to.be.true }) - it('isMultiple', () => { - expect(F.isMultiple([''])).to.be.false - expect(F.isMultiple(['', ''])).to.be.true - expect(F.isMultiple('a')).to.be.false - expect(F.isMultiple('asdf')).to.be.true + it("isMultiple", () => { + expect(F.isMultiple([""])).to.be.false + expect(F.isMultiple(["", ""])).to.be.true + expect(F.isMultiple("a")).to.be.false + expect(F.isMultiple("asdf")).to.be.true expect(F.isMultiple({ x: 1, y: 2 })).to.be.false expect(F.isMultiple({ x: 1, y: 2, length: 2 })).to.be.true }) - it('append', () => { - expect(F.append('a', 'b')).to.equal('ba') + it("append", () => { + expect(F.append("a", "b")).to.equal("ba") expect(F.append(1, 4)).to.equal(5) }) - it('isBlank', () => { + it("isBlank", () => { expect(F.isBlank(1)).to.be.false - expect(F.isBlank('asdf')).to.be.false + expect(F.isBlank("asdf")).to.be.false expect(F.isBlank({ a: 1 })).to.be.false expect(F.isBlank([3, 4])).to.be.false expect(F.isBlank(new Date())).to.be.false expect( F.isBlank({ a: 1, - b: 'as', + b: "as", }) ).to.be.false expect(F.isBlank(null)).to.be.true expect(F.isBlank(undefined)).to.be.true - expect(F.isBlank('')).to.be.true + expect(F.isBlank("")).to.be.true expect(F.isBlank([])).to.be.true expect(F.isBlank({})).to.be.true }) - it('isNotBlank', () => { + it("isNotBlank", () => { expect(F.isNotBlank(1)).to.be.true - expect(F.isNotBlank('asdf')).to.be.true + expect(F.isNotBlank("asdf")).to.be.true expect(F.isNotBlank({ a: 1 })).to.be.true expect(F.isNotBlank([3, 4])).to.be.true expect(F.isNotBlank(new Date())).to.be.true expect(F.isNotBlank(null)).to.be.false expect(F.isNotBlank(undefined)).to.be.false - expect(F.isNotBlank('')).to.be.false + expect(F.isNotBlank("")).to.be.false expect(F.isNotBlank([])).to.be.false expect(F.isNotBlank({})).to.be.false }) - it('isBlankDeep', () => { + it("isBlankDeep", () => { expect(F.isBlankDeep(_.every)(1)).to.be.false expect(F.isBlankDeep(_.every)(false)).to.be.false - expect(F.isBlankDeep(_.every)('')).to.be.true + expect(F.isBlankDeep(_.every)("")).to.be.true expect( F.isBlankDeep(_.every)({ a: 1, - b: 'as', + b: "as", }) ).to.be.false expect( F.isBlankDeep(_.every)({ a: null, - b: '', + b: "", c: [], d: { - b: '', + b: "", }, }) ).to.be.true diff --git a/test/lens.spec.js b/test/lens.spec.js index 755dd1c7..ba39cc6b 100644 --- a/test/lens.spec.js +++ b/test/lens.spec.js @@ -1,50 +1,50 @@ -import chai from 'chai' -import _ from 'lodash/fp' -import * as F from '../src' +import chai from "chai" +import _ from "lodash/fp" +import * as F from "../src" chai.expect() const expect = chai.expect -describe('Lens Functions', () => { - describe('Stubs', () => { - it('functionLens', () => { +describe("Lens Functions", () => { + describe("Stubs", () => { + it("functionLens", () => { let l = F.functionLens(1) expect(l()).to.equal(1) l(5) expect(l()).to.equal(5) }) - it('objectLens', () => { + it("objectLens", () => { let l = F.objectLens(1) expect(l.get()).to.equal(1) l.set(5) expect(l.get()).to.equal(5) }) }) - describe('Conversion', () => { - it('fnToObj', () => { + describe("Conversion", () => { + it("fnToObj", () => { let l = F.fnToObj(F.functionLens(1)) expect(l.get()).to.equal(1) l.set(5) expect(l.get()).to.equal(5) }) - it('objToFn', () => { + it("objToFn", () => { let l = F.objToFn(F.objectLens(1)) expect(l()).to.equal(1) l(5) expect(l()).to.equal(5) }) }) - describe('Construction', () => { - it('lensProp', () => { - let l = F.lensProp('x', { + describe("Construction", () => { + it("lensProp", () => { + let l = F.lensProp("x", { x: 1, }) expect(l.get()).to.equal(1) l.set(5) expect(l.get()).to.equal(5) }) - it('lensProp deep', () => { - let l = F.lensProp('x.a', { + it("lensProp deep", () => { + let l = F.lensProp("x.a", { x: { a: 1, }, @@ -53,7 +53,7 @@ describe('Lens Functions', () => { l.set(5) expect(l.get()).to.equal(5) }) - it('lensOf', () => { + it("lensOf", () => { let l = F.lensOf({ a: 1, }) @@ -61,38 +61,38 @@ describe('Lens Functions', () => { l.a.set(5) expect(l.a.get()).to.equal(5) }) - it('includeLens', () => { + it("includeLens", () => { let object = { - arr: ['a', 'b', 'c', 'd'], + arr: ["a", "b", "c", "d"], } - let includesB = F.includeLens('b', 'arr', object) + let includesB = F.includeLens("b", "arr", object) expect(F.view(includesB)).to.be.true F.off(includesB)() expect(F.view(includesB)).to.be.false - expect(object.arr).to.deep.equal(['a', 'c', 'd']) + expect(object.arr).to.deep.equal(["a", "c", "d"]) F.on(includesB)() expect(F.view(includesB)).to.be.true - expect(object.arr).to.deep.equal(['a', 'c', 'd', 'b']) + expect(object.arr).to.deep.equal(["a", "c", "d", "b"]) // Subsequent calls don't result in multiple `b`s because of _.uniq F.on(includesB)() expect(F.view(includesB)).to.be.true - expect(object.arr).to.deep.equal(['a', 'c', 'd', 'b']) + expect(object.arr).to.deep.equal(["a", "c", "d", "b"]) }) }) - describe('Manipulation', () => { - it('view', () => { + describe("Manipulation", () => { + it("view", () => { let fl = F.functionLens(1) let ol = F.objectLens(1) expect(F.view(fl)).to.equal(1) expect(F.view(ol)).to.equal(1) }) - it('views', () => { + it("views", () => { let fl = F.functionLens(1) let ol = F.objectLens(1) expect(F.views(fl)()).to.equal(1) expect(F.views(ol)()).to.equal(1) }) - it('set', () => { + it("set", () => { let object = { a: 1, } @@ -100,7 +100,7 @@ describe('Lens Functions', () => { F.set(5, l.a) expect(object.a).to.equal(5) }) - it('sets', () => { + it("sets", () => { let object = { a: 1, } @@ -108,15 +108,15 @@ describe('Lens Functions', () => { F.sets(5, l.a)() expect(object.a).to.equal(5) }) - it('setsWith', () => { + it("setsWith", () => { let object = { a: 1, } - let setter = F.setsWith((x) => x * 2, 'a', object) + let setter = F.setsWith((x) => x * 2, "a", object) setter(5) expect(object.a).to.equal(10) }) - it('flip', () => { + it("flip", () => { let object = { a: 1, } @@ -124,7 +124,7 @@ describe('Lens Functions', () => { F.flip(l.a)() expect(object.a).to.be.false }) - it('on', () => { + it("on", () => { let object = { a: 1, } @@ -132,7 +132,7 @@ describe('Lens Functions', () => { F.on(l.a)() expect(object.a).to.be.true }) - it('off', () => { + it("off", () => { let object = { a: 1, } @@ -141,61 +141,61 @@ describe('Lens Functions', () => { expect(object.a).to.be.false }) }) - describe('Implicit Lens Prop', () => { - it('view', () => { + describe("Implicit Lens Prop", () => { + it("view", () => { let x = { a: 1, b: 2, } - expect(F.view('a', x)).to.equal(1) + expect(F.view("a", x)).to.equal(1) }) - it('views', () => { + it("views", () => { let x = { a: 1, b: 2, } - expect(F.views('a', x)()).to.equal(1) + expect(F.views("a", x)()).to.equal(1) }) - it('set', () => { + it("set", () => { let x = { a: 1, b: 2, } - F.set(5, 'a', x) + F.set(5, "a", x) expect(x.a).to.equal(5) }) - it('sets', () => { + it("sets", () => { let x = { a: 1, b: 2, } - F.sets(5, 'a', x)() + F.sets(5, "a", x)() expect(x.a).to.equal(5) }) - it('flip', () => { + it("flip", () => { let object = { a: 1, } - F.flip('a', object)() + F.flip("a", object)() expect(object.a).to.be.false }) - it('on', () => { + it("on", () => { let object = { a: 1, } - F.on('a', object)() + F.on("a", object)() expect(object.a).to.be.true }) - it('off', () => { + it("off", () => { let object = { a: 1, } - F.off('a', object)() + F.off("a", object)() expect(object.a).to.be.false }) }) - describe('additional implicit lens formats', () => { - it('arrayLens', () => { + describe("additional implicit lens formats", () => { + it("arrayLens", () => { let arrayLens = (val) => { let result = [val] result.push((x) => { @@ -211,7 +211,7 @@ describe('Lens Functions', () => { F.flip(lens)() expect(lens[0]).to.be.true }) - it('functionPairLens', () => { + it("functionPairLens", () => { let object = { a: false, } @@ -227,81 +227,81 @@ describe('Lens Functions', () => { expect(object.a).to.be.true }) }) - describe('domLens', () => { - it('value', () => { + describe("domLens", () => { + it("value", () => { let state = { a: 1, } - let props = F.domLens.value('a', state) + let props = F.domLens.value("a", state) expect(props.value).to.equal(1) props.onChange({ target: { value: 5 } }) expect(state.a).to.equal(5) }) - it('non-native value', () => { + it("non-native value", () => { let state = { a: 1, } - let props = F.domLens.value('a', state) + let props = F.domLens.value("a", state) expect(props.value).to.equal(1) props.onChange(5) expect(state.a).to.equal(5) }) - it('checkboxValues', () => { + it("checkboxValues", () => { let state = { - a: ['x', 'y', 'z'], + a: ["x", "y", "z"], } // Props for if `x` is in the list - let props = F.domLens.checkboxValues('x', 'a', state) + let props = F.domLens.checkboxValues("x", "a", state) expect(props.checked).to.be.true // uncheck props.onChange({ target: { value: false } }) - expect(_.includes('a', state.a)).to.be.false + expect(_.includes("a", state.a)).to.be.false }) - it('hover', () => { + it("hover", () => { let state = { hovering: false, } - let props = F.domLens.hover('hovering', state) + let props = F.domLens.hover("hovering", state) props.onMouseEnter() expect(state.hovering).to.be.true props.onMouseLeave() expect(state.hovering).to.be.false }) - it('focus', () => { + it("focus", () => { let state = { focusing: false, } - let props = F.domLens.focus('focusing', state) + let props = F.domLens.focus("focusing", state) props.onFocus() expect(state.focusing).to.be.true props.onBlur() expect(state.focusing).to.be.false }) - it('targetBinding', () => { - let state = { color: 'red' } - let props = F.domLens.targetBinding('x')('color', state) - expect(props.x).to.equal('red') - props.onChange({ target: { x: 'green' } }) - expect(state.color).to.equal('green') + it("targetBinding", () => { + let state = { color: "red" } + let props = F.domLens.targetBinding("x")("color", state) + expect(props.x).to.equal("red") + props.onChange({ target: { x: "green" } }) + expect(state.color).to.equal("green") // should handle objects with `target` as an inherited property function Event() {} Event.prototype.target = {} - Event.prototype.target.x = 'blue' + Event.prototype.target.x = "blue" props.onChange(new Event()) - expect(state.color).to.equal('blue') + expect(state.color).to.equal("blue") // should handle targetless arguments - props.onChange('purple') - expect(state.color).to.equal('purple') + props.onChange("purple") + expect(state.color).to.equal("purple") }) - it('binding', () => { + it("binding", () => { let state = { - selectedItem: 'item1', + selectedItem: "item1", } - let weirdSelect = F.domLens.binding('selected', (e) => e.newSelectedValue) - let props = weirdSelect('selectedItem', state) - expect(props.selected).to.equal('item1') - props.onChange({ newSelectedValue: 'newItem' }) - expect(state.selectedItem).to.equal('newItem') + let weirdSelect = F.domLens.binding("selected", (e) => e.newSelectedValue) + let props = weirdSelect("selectedItem", state) + expect(props.selected).to.equal("item1") + props.onChange({ newSelectedValue: "newItem" }) + expect(state.selectedItem).to.equal("newItem") }) }) }) diff --git a/test/logic.spec.js b/test/logic.spec.js index 41843af0..40d8fb86 100644 --- a/test/logic.spec.js +++ b/test/logic.spec.js @@ -1,19 +1,19 @@ -import chai from 'chai' -import * as F from '../src' -import _ from 'lodash/fp' +import chai from "chai" +import * as F from "../src" +import _ from "lodash/fp" chai.expect() const expect = chai.expect -describe('Logic Functions', () => { - it('overNone', () => { +describe("Logic Functions", () => { + it("overNone", () => { let ten = (x) => x > 10 let twenty = (x) => x > 20 let thirty = (x) => x > 30 expect(F.overNone([ten, twenty, thirty])(5)).to.be.true expect(F.overNone([ten, twenty, thirty])(15)).to.be.false }) - describe('ifElse', () => { - it('should handle functions', () => { + describe("ifElse", () => { + it("should handle functions", () => { let clamp5 = F.ifElse( (x) => x > 5, () => 5, @@ -23,20 +23,20 @@ describe('Logic Functions', () => { expect(clamp5(5)).to.equal(5) expect(clamp5(13)).to.equal(5) }) - it('should handle passing boolean conditions', () => { + it("should handle passing boolean conditions", () => { let fn = F.ifElse( true, (x) => `success ${x}`, (x) => `fail ${x}` ) - expect(fn(1)).to.equal('success 1') + expect(fn(1)).to.equal("success 1") }) - it('should handle fancy shorthand', () => { - let fancyShortHand = F.ifElse({ a: 1 }, 'Has a1', () => 'No a1') - expect(fancyShortHand({ a: 1 })).to.equal('Has a1') - expect(fancyShortHand({ a: 2 })).to.equal('No a1') + it("should handle fancy shorthand", () => { + let fancyShortHand = F.ifElse({ a: 1 }, "Has a1", () => "No a1") + expect(fancyShortHand({ a: 1 })).to.equal("Has a1") + expect(fancyShortHand({ a: 2 })).to.equal("No a1") }) - it('should be fully curried', () => { + it("should be fully curried", () => { expect( F.ifElse( (x) => x % 2, @@ -44,10 +44,10 @@ describe('Logic Functions', () => { (x) => `${x} is even!`, 6 ) - ).to.equal('6 is even!') + ).to.equal("6 is even!") }) }) - it('when', () => { + it("when", () => { let clamp5 = F.when( (x) => x > 5, () => 5 @@ -67,7 +67,7 @@ describe('Logic Functions', () => { ]) expect(_.map(nullConvertIndex, [0, 1, 2, 3])).to.deep.equal([0, 1, 2, 3]) }) - it('unless', () => { + it("unless", () => { let clamp5 = F.unless( (x) => x < 5, () => 5 @@ -76,13 +76,13 @@ describe('Logic Functions', () => { expect(clamp5(5)).to.equal(5) expect(clamp5(13)).to.equal(5) }) - it('whenExists', () => { + it("whenExists", () => { let fn = F.whenExists(5) expect(fn(3)).to.equal(5) expect(fn(null)).to.equal(null) expect(fn(false)).to.equal(5) }) - it('whenTruthy', () => { + it("whenTruthy", () => { let fn = F.whenTruthy(5) expect(fn(3)).to.equal(5) expect(fn(null)).to.equal(null) diff --git a/test/misc.spec.js b/test/misc.spec.js index 910b892e..8eb9179e 100644 --- a/test/misc.spec.js +++ b/test/misc.spec.js @@ -1,18 +1,18 @@ -import chai from 'chai' -import F from '../src' +import chai from "chai" +import F from "../src" chai.expect() const expect = chai.expect -describe('Math Functions', () => { - it('greaterThanOne', () => { +describe("Math Functions", () => { + it("greaterThanOne", () => { for (let i = -10; i < 10; i++) { expect(F.greaterThanOne(i)).to.equal(i > 1) } }) }) -describe('Promise Functions', () => { - it('isPromise', () => { +describe("Promise Functions", () => { + it("isPromise", () => { expect(F.isPromise(Promise.resolve())).to.be.true expect(F.isPromise({ then() {} })).to.be.true expect(F.isPromise(null)).to.be.false @@ -21,8 +21,8 @@ describe('Promise Functions', () => { }) }) -describe('Version Injection', () => { - it('should export the VERSION', () => { +describe("Version Injection", () => { + it("should export the VERSION", () => { expect(F.VERSION).to.equal(global.__VERSION__) }) }) diff --git a/test/objects.spec.js b/test/objects.spec.js index d0b208ec..25c0df9b 100644 --- a/test/objects.spec.js +++ b/test/objects.spec.js @@ -1,22 +1,22 @@ -import chai from 'chai' -import * as F from '../src' -import _ from 'lodash/fp' +import chai from "chai" +import * as F from "../src" +import _ from "lodash/fp" chai.expect() const expect = chai.expect -describe('Object Functions', () => { - it('singleObject', () => { - expect(F.singleObject('a', 'b')).to.deep.equal({ - a: 'b', +describe("Object Functions", () => { + it("singleObject", () => { + expect(F.singleObject("a", "b")).to.deep.equal({ + a: "b", }) }) - it('singleObjectR', () => { - expect(F.singleObjectR('a', 'b')).to.deep.equal({ - b: 'a', + it("singleObjectR", () => { + expect(F.singleObjectR("a", "b")).to.deep.equal({ + b: "a", }) }) - it('chunkObject', () => { + it("chunkObject", () => { expect(F.chunkObject([1])).to.deep.equal([1]) expect( F.chunkObject({ @@ -32,7 +32,7 @@ describe('Object Functions', () => { }, ]) }) - it('compactObject', () => { + it("compactObject", () => { expect( F.compactObject({ a: 1, @@ -43,17 +43,17 @@ describe('Object Functions', () => { a: 1, }) }) - it('isEmptyObject', () => { + it("isEmptyObject", () => { let expectEqual = (obj, v) => expect(F.isEmptyObject(obj)).to.equal(v) expectEqual({ a: 1 }, false) expectEqual({}, true) }) - it('isNotEmptyObject', () => { + it("isNotEmptyObject", () => { let expectEqual = (obj, v) => expect(F.isNotEmptyObject(obj)).to.equal(v) expectEqual({ a: 1 }, true) expectEqual({}, false) }) - it('stripEmptyObjects', () => { + it("stripEmptyObjects", () => { expect( F.stripEmptyObjects({ a: 1, @@ -65,13 +65,13 @@ describe('Object Functions', () => { c: 2, }) }) - it('pickInto', () => { + it("pickInto", () => { expect( F.pickInto( { - a: ['a'], - b: ['b'], - c: ['c'], + a: ["a"], + b: ["b"], + c: ["c"], }, { a: 1, b: 2 } ) @@ -81,57 +81,57 @@ describe('Object Functions', () => { c: {}, }) }) - it('unwind', () => { - expect(F.unwind('x', { x: ['a', 'b'], y: 1 })).to.deep.equal([ - { x: 'a', y: 1 }, - { x: 'b', y: 1 }, + it("unwind", () => { + expect(F.unwind("x", { x: ["a", "b"], y: 1 })).to.deep.equal([ + { x: "a", y: 1 }, + { x: "b", y: 1 }, ]) // should unwind undefined values - expect(F.unwind('x', { x: ['a', undefined, 'b'], y: 1 })).to.deep.equal([ - { x: 'a', y: 1 }, + expect(F.unwind("x", { x: ["a", undefined, "b"], y: 1 })).to.deep.equal([ + { x: "a", y: 1 }, { x: undefined, y: 1 }, - { x: 'b', y: 1 }, + { x: "b", y: 1 }, ]) // should return an empty array for keys that are not present on the object - expect(F.unwind('z', { x: 'foo', y: 1 })).to.deep.equal([]) + expect(F.unwind("z", { x: "foo", y: 1 })).to.deep.equal([]) // should also return an empty array for keys whose values can't be unwound - expect(F.unwind('y', { x: 'foo', y: 1 })).to.deep.equal([]) - expect(F.unwind('y', { x: 'foo', y: undefined })).to.deep.equal([]) - expect(F.unwind('y', { x: 'foo', y: [] })).to.deep.equal([]) + expect(F.unwind("y", { x: "foo", y: 1 })).to.deep.equal([]) + expect(F.unwind("y", { x: "foo", y: undefined })).to.deep.equal([]) + expect(F.unwind("y", { x: "foo", y: [] })).to.deep.equal([]) // should not unwind strings - expect(F.unwind('x', { x: 'foo', y: 1 })).to.deep.equal([]) + expect(F.unwind("x", { x: "foo", y: 1 })).to.deep.equal([]) // duplicate objects are fine (we don't run _.uniq on the array to unwind) - expect(F.unwind('x', { x: [7, 7, 7], y: 1 })).to.deep.equal([ + expect(F.unwind("x", { x: [7, 7, 7], y: 1 })).to.deep.equal([ { x: 7, y: 1 }, { x: 7, y: 1 }, { x: 7, y: 1 }, ]) }) - it('unwindArray', () => { + it("unwindArray", () => { expect( - F.unwindArray('x', [ - { x: ['a', 'b'], y: 1 }, - { x: ['a', 'c'], y: 2 }, + F.unwindArray("x", [ + { x: ["a", "b"], y: 1 }, + { x: ["a", "c"], y: 2 }, // since `unwind` returns an empty array for non-unwindable values, // this should _not_ be present on the result of `unwindArray` - { x: 'd', y: 3 }, + { x: "d", y: 3 }, ]) ).to.deep.equal([ - { x: 'a', y: 1 }, - { x: 'b', y: 1 }, - { x: 'a', y: 2 }, - { x: 'c', y: 2 }, + { x: "a", y: 1 }, + { x: "b", y: 1 }, + { x: "a", y: 2 }, + { x: "c", y: 2 }, // { x: 'd', y: 3 }, not present ]) // should not unwind strings expect( - F.unwindArray('x', [ - { x: 'foo', y: 1 }, - { x: 'bar', y: 2 }, + F.unwindArray("x", [ + { x: "foo", y: 1 }, + { x: "bar", y: 2 }, ]) ).to.deep.equal([]) expect( - F.unwindArray('x', [ + F.unwindArray("x", [ { x: [7, 7, 7], y: 1 }, { x: [1, 1], y: 2 }, ]) @@ -143,7 +143,7 @@ describe('Object Functions', () => { { x: 1, y: 2 }, ]) }) - it('flattenObject', () => { + it("flattenObject", () => { expect( F.flattenObject({ a: { @@ -153,7 +153,7 @@ describe('Object Functions', () => { }, }) ).to.deep.equal({ - 'a.b.c': 1, + "a.b.c": 1, }) expect( F.flattenObject([ @@ -168,13 +168,13 @@ describe('Object Functions', () => { }, ]) ).to.deep.equal({ - '0.a.b.0.c': 1, + "0.a.b.0.c": 1, }) }) - it('unflattenObject', () => { + it("unflattenObject", () => { expect( F.unflattenObject({ - 'a.b.c': 1, + "a.b.c": 1, }) ).to.deep.equal({ a: { @@ -184,114 +184,114 @@ describe('Object Functions', () => { }, }) }) - it('renameProperty', () => { + it("renameProperty", () => { const o = { a: 1 } - const newO = F.renameProperty('a', 'b', o) + const newO = F.renameProperty("a", "b", o) expect(newO).not.to.deep.equal(o) expect(newO).to.deep.equal({ b: 1 }) - const new1 = F.renameProperty('c', 'b', o) + const new1 = F.renameProperty("c", "b", o) expect(new1).to.deep.equal({ a: 1 }) }) - it('matchesSignature', () => { + it("matchesSignature", () => { expect(F.matchesSignature([], 0)).to.be.false - expect(F.matchesSignature([], '')).to.be.false + expect(F.matchesSignature([], "")).to.be.false expect(F.matchesSignature([], (x) => x)).to.be.true expect(F.matchesSignature([], [])).to.be.true expect(F.matchesSignature([], { a: 1 })).to.be.false - expect(F.matchesSignature(['a'], { a: 1 })).to.be.true - expect(F.matchesSignature(['b'], { a: 1 })).to.be.false - expect(F.matchesSignature(['a'], { a: 1, b: 2 })).to.be.false - expect(F.matchesSignature(['a'], { a: undefined, b: undefined })).to.be + expect(F.matchesSignature(["a"], { a: 1 })).to.be.true + expect(F.matchesSignature(["b"], { a: 1 })).to.be.false + expect(F.matchesSignature(["a"], { a: 1, b: 2 })).to.be.false + expect(F.matchesSignature(["a"], { a: undefined, b: undefined })).to.be .false - expect(F.matchesSignature(['a', 'b'], { a: undefined })).to.be.true + expect(F.matchesSignature(["a", "b"], { a: undefined })).to.be.true }) - it('matchesSome', () => { + it("matchesSome", () => { expect(F.matchesSome({ a: 1, b: 2 })({ a: 1, b: 2, c: 3 })).to.be.true expect(F.matchesSome({ a: 1, b: 20 })({ a: 1, b: 2, c: 3 })).to.be.true expect(F.matchesSome({ a: 10, b: 2 })({ a: 1, b: 2, c: 3 })).to.be.true expect(F.matchesSome({ a: 10, b: 20 })({ a: 1, b: 2, c: 3 })).to.be.false }) - it('compareDeep', () => { + it("compareDeep", () => { const o = { a: { b: { c: 1 } } } - expect(F.compareDeep('a.b.c', o, 1)).to.be.true - expect(F.compareDeep('a.b.c', o, 2)).to.be.false - expect(F.compareDeep('a.b.c')(o, '1')).to.be.false - expect(F.compareDeep('a.b.c')(o)('1')).to.be.false + expect(F.compareDeep("a.b.c", o, 1)).to.be.true + expect(F.compareDeep("a.b.c", o, 2)).to.be.false + expect(F.compareDeep("a.b.c")(o, "1")).to.be.false + expect(F.compareDeep("a.b.c")(o)("1")).to.be.false }) // it('mapProp', () => { // const a = F.mapProp('a', val => val * val, { a: 2, b: 1 }) // expect(a).to.deep.equal({ a: 4, b: 1 }) // }) - it('getOrReturn', () => { - expect(F.getOrReturn('x', { a: 1 })).to.deep.equal({ a: 1 }) + it("getOrReturn", () => { + expect(F.getOrReturn("x", { a: 1 })).to.deep.equal({ a: 1 }) }) - it('alias', () => { - expect(F.alias('x', { a: 1 })).to.equal('x') + it("alias", () => { + expect(F.alias("x", { a: 1 })).to.equal("x") }) - it('aliasIn', () => { - expect(F.aliasIn({ a: 1 }, 'x')).to.equal('x') + it("aliasIn", () => { + expect(F.aliasIn({ a: 1 }, "x")).to.equal("x") }) - it('cascade', () => { - expect(F.cascade(['x', 'y'], { a: 1, y: 2 })).to.equal(2) - expect(F.cascade(['x', 'c'], { a: 1, y: 2 }, 2)).to.equal(2) - expect(F.cascade(['x', (x) => x.y], { a: 1, y: 2 })).to.equal(2) - expect(F.cascade(['x', 'y'], { a: 1, x: null, y: 2 })).to.equal(2) + it("cascade", () => { + expect(F.cascade(["x", "y"], { a: 1, y: 2 })).to.equal(2) + expect(F.cascade(["x", "c"], { a: 1, y: 2 }, 2)).to.equal(2) + expect(F.cascade(["x", (x) => x.y], { a: 1, y: 2 })).to.equal(2) + expect(F.cascade(["x", "y"], { a: 1, x: null, y: 2 })).to.equal(2) }) - it('cascadeIn', () => { - expect(F.cascadeIn({ a: 1, y: 2 }, ['x', 'y'])).to.equal(2) + it("cascadeIn", () => { + expect(F.cascadeIn({ a: 1, y: 2 }, ["x", "y"])).to.equal(2) }) - it('cascadeKey', () => { - expect(F.cascadeKey(['x', 'y'], { a: 1, x: 2 })).to.equal('x') + it("cascadeKey", () => { + expect(F.cascadeKey(["x", "y"], { a: 1, x: 2 })).to.equal("x") }) - it('cascadePropKey', () => { - expect(F.cascadePropKey(['x', 'y'], { a: 1, x: null, y: 2 })).to.equal('x') + it("cascadePropKey", () => { + expect(F.cascadePropKey(["x", "y"], { a: 1, x: null, y: 2 })).to.equal("x") }) - it('cascadeProp', () => { - expect(F.cascadeProp(['x', 'y'], { a: 1, x: null, y: 2 })).to.equal(null) + it("cascadeProp", () => { + expect(F.cascadeProp(["x", "y"], { a: 1, x: null, y: 2 })).to.equal(null) }) - it('unkeyBy', () => { + it("unkeyBy", () => { expect( - F.unkeyBy('field', { + F.unkeyBy("field", { a: { x: 1, }, - 'd.e': { + "d.e": { x: 5, }, }) ).to.deep.equal([ { x: 1, - field: 'a', + field: "a", }, { x: 5, - field: 'd.e', + field: "d.e", }, ]) }) - it('unkeyBy', () => { + it("unkeyBy", () => { expect( - F.unkeyBy('', { + F.unkeyBy("", { a: { x: 1, }, - 'd.e': { + "d.e": { x: 5, }, }) ).to.deep.equal([ { x: 1, - a: 'a', + a: "a", }, { x: 5, - 'd.e': 'd.e', + "d.e": "d.e", }, ]) }) - it('simpleDiff', () => { + it("simpleDiff", () => { expect( F.simpleDiff( { @@ -328,7 +328,7 @@ describe('Object Functions', () => { from: undefined, to: 3, }, - 'd.e': { + "d.e": { from: undefined, to: 5, }, @@ -342,7 +342,7 @@ describe('Object Functions', () => { }, }) }) - it('simpleDiffArray', () => { + it("simpleDiffArray", () => { expect( F.simpleDiffArray( { @@ -368,38 +368,38 @@ describe('Object Functions', () => { ) ).to.deep.equal([ { - field: 'a', + field: "a", from: 3, to: 1, }, { - field: 'b', + field: "b", from: undefined, to: 2, }, { - field: 'c', + field: "c", from: undefined, to: 3, }, { - field: 'd.e', + field: "d.e", from: undefined, to: 5, }, { - field: 'price', + field: "price", from: 20, to: undefined, }, { - field: 'amount', + field: "amount", from: undefined, to: 20, }, ]) }) - it('diff', () => { + it("diff", () => { expect( F.diff( { @@ -437,11 +437,11 @@ describe('Object Functions', () => { from: undefined, to: 3, }, - 'd.e': { + "d.e": { from: undefined, to: 5, }, - 'd.f': { + "d.f": { from: 6, to: undefined, }, @@ -455,7 +455,7 @@ describe('Object Functions', () => { }, }) }) - it('diffArray', () => { + it("diffArray", () => { expect( F.diffArray( { @@ -488,63 +488,63 @@ describe('Object Functions', () => { ) ).to.deep.equal([ { - field: 'a', + field: "a", from: 3, to: 1, }, { - field: 'd.f', + field: "d.f", from: 6, to: undefined, }, { - field: 'price', + field: "price", from: 20, to: undefined, }, { - field: 'collection1.0.b', + field: "collection1.0.b", from: 2, to: undefined, }, { - field: 'collection2.0.a', + field: "collection2.0.a", from: 1, to: undefined, }, { - field: 'collection2.0.b', + field: "collection2.0.b", from: 2, to: undefined, }, { - field: 'z.zz', + field: "z.zz", from: undefined, to: 1, }, { - field: 'b', + field: "b", from: undefined, to: 2, }, { - field: 'c', + field: "c", from: undefined, to: 3, }, { - field: 'd.e', + field: "d.e", from: undefined, to: 5, }, { - field: 'amount', + field: "amount", from: undefined, to: 20, }, ]) }) - it('mergeAllArrays', () => { + it("mergeAllArrays", () => { expect( F.mergeAllArrays([ { @@ -565,21 +565,21 @@ describe('Object Functions', () => { b: 5, }) }) - it('invertByArray', () => { + it("invertByArray", () => { expect( F.invertByArray({ - a: ['x', 'y', 'z'], - b: ['x'], + a: ["x", "y", "z"], + b: ["x"], }) ).to.deep.equal({ - x: ['a', 'b'], - y: ['a'], - z: ['a'], + x: ["a", "b"], + y: ["a"], + z: ["a"], }) }) - it('stampKey', () => { + it("stampKey", () => { expect( - F.stampKey('type', { + F.stampKey("type", { foo: { a: 1, b: 2, @@ -590,51 +590,51 @@ describe('Object Functions', () => { foo: { a: 1, b: 2, - type: 'foo', + type: "foo", }, bar: { - type: 'bar', + type: "bar", }, }) }) - it('omitNil', () => { - expect(F.omitNil({ a: 1, b: 'c', d: null, e: undefined })).to.deep.equal({ + it("omitNil", () => { + expect(F.omitNil({ a: 1, b: "c", d: null, e: undefined })).to.deep.equal({ a: 1, - b: 'c', + b: "c", }) }) - it('omitNull', () => { - expect(F.omitNull({ a: 1, b: 'c', d: null, e: undefined })).to.deep.equal({ + it("omitNull", () => { + expect(F.omitNull({ a: 1, b: "c", d: null, e: undefined })).to.deep.equal({ a: 1, - b: 'c', + b: "c", e: undefined, }) }) - it('omitBlank', () => { + it("omitBlank", () => { expect( - F.omitBlank({ a: 1, b: 'c', d: null, e: undefined, f: [], g: {}, h: '' }) + F.omitBlank({ a: 1, b: "c", d: null, e: undefined, f: [], g: {}, h: "" }) ).to.deep.equal({ a: 1, - b: 'c', + b: "c", }) }) - it('omitEmpty', () => { + it("omitEmpty", () => { expect( - F.omitEmpty({ a: 1, b: 'c', d: null, e: undefined, f: [], g: {}, h: '' }) + F.omitEmpty({ a: 1, b: "c", d: null, e: undefined, f: [], g: {}, h: "" }) ).to.deep.equal({ - b: 'c', + b: "c", }) }) - it('mergeOverAll', () => { - let foo = (x) => ({ [x]: 'foo' }) - let bar = (x) => ({ bar: x, [x]: 'bar' }) - expect(F.mergeOverAll([foo, bar])('a')).to.deep.equal({ - a: 'bar', - bar: 'a', + it("mergeOverAll", () => { + let foo = (x) => ({ [x]: "foo" }) + let bar = (x) => ({ bar: x, [x]: "bar" }) + expect(F.mergeOverAll([foo, bar])("a")).to.deep.equal({ + a: "bar", + bar: "a", }) - expect(F.mergeOverAll([bar, foo])('a')).to.deep.equal({ - a: 'foo', - bar: 'a', + expect(F.mergeOverAll([bar, foo])("a")).to.deep.equal({ + a: "foo", + bar: "a", }) // should NOT merge arrays let qux = (a) => ({ x: a.map((x) => x + 3) }) @@ -645,13 +645,13 @@ describe('Object Functions', () => { expect(F.mergeOverAll(undefined, undefined)).to.deep.equal({}) expect(F.mergeOverAll(undefined)(undefined)).to.deep.equal({}) expect(F.mergeOverAll([])(undefined)).to.deep.equal(undefined) - expect(F.mergeOverAll([(x) => x, (x, y) => y])('abc', 'de')).to.deep.equal({ - 0: 'd', - 1: 'e', - 2: 'c', + expect(F.mergeOverAll([(x) => x, (x, y) => y])("abc", "de")).to.deep.equal({ + 0: "d", + 1: "e", + 2: "c", }) }) - it('mergeOverAllWith', () => { + it("mergeOverAllWith", () => { let reverseArrayCustomizer = (objValue, srcValue) => srcValue.length ? srcValue.reverse() : srcValue let qux = (a) => ({ x: a.map((x) => x + 3) }) @@ -659,7 +659,7 @@ describe('Object Functions', () => { F.mergeOverAllWith(reverseArrayCustomizer, [() => ({}), qux])([1, 2, 3]) ).to.deep.equal({ x: [6, 5, 4] }) }) - it('mergeOverAllArrays', () => { + it("mergeOverAllArrays", () => { // should merge arrays let qux = (a) => ({ x: a.map((x) => x + 3) }) expect( @@ -668,17 +668,17 @@ describe('Object Functions', () => { x: [1, 2, 3, 4, 5, 6], }) }) - it('getWith', () => { + it("getWith", () => { let square = (x) => x * x let getWithSquare = F.getWith(square) let foo = { a: 1, b: 3, c: 5 } - expect(getWithSquare('c', foo)).to.equal(25) - expect(F.getWith((x) => x + 1, 'b', foo)).to.equal(4) + expect(getWithSquare("c", foo)).to.equal(25) + expect(F.getWith((x) => x + 1, "b", foo)).to.equal(4) // edge case: throws when customizer is not a function - expect(() => F.getWith(undefined, 'b', foo)).to.throw(TypeError) + expect(() => F.getWith(undefined, "b", foo)).to.throw(TypeError) }) - it('expandObject', () => { - let foo = { a: 1, b: 2, c: 'a' } + it("expandObject", () => { + let foo = { a: 1, b: 2, c: "a" } // should expand object let toOptions = F.mapIndexed((v, k) => ({ label: k, value: v })) expect( @@ -686,43 +686,43 @@ describe('Object Functions', () => { ).to.deep.equal({ a: 1, b: 2, - c: 'a', + c: "a", options: [ - { label: 'a', value: 1 }, - { label: 'b', value: 2 }, - { label: 'c', value: 'a' }, + { label: "a", value: 1 }, + { label: "b", value: 2 }, + { label: "c", value: "a" }, ], }) // should override keys expect(F.expandObject(_.invert, foo)).to.deep.equal({ - 1: 'a', - 2: 'b', - a: 'c', + 1: "a", + 2: "b", + a: "c", b: 2, - c: 'a', + c: "a", }) }) - it('expandObjectBy', () => { - let primeFactorization = (x) => (x === 42 ? { 2: 1, 3: 1, 7: 1 } : 'dunno') + it("expandObjectBy", () => { + let primeFactorization = (x) => (x === 42 ? { 2: 1, 3: 1, 7: 1 } : "dunno") let foo = { a: 1, b: 42 } - expect(F.expandObjectBy('b', primeFactorization, foo)).to.deep.equal({ + expect(F.expandObjectBy("b", primeFactorization, foo)).to.deep.equal({ a: 1, b: 42, 2: 1, 3: 1, 7: 1, }) - expect(F.expandObjectBy('a', primeFactorization, foo)).to.deep.equal({ - 0: 'd', - 1: 'u', - 2: 'n', - 3: 'n', - 4: 'o', + expect(F.expandObjectBy("a", primeFactorization, foo)).to.deep.equal({ + 0: "d", + 1: "u", + 2: "n", + 3: "n", + 4: "o", a: 1, b: 42, }) }) - it('commonKeys', () => { + it("commonKeys", () => { let providers = { mongo: {}, elasticsearch: {}, @@ -734,15 +734,15 @@ describe('Object Functions', () => { } expect(F.commonKeys(providers, schema)).to.deep.equal([ - 'elasticsearch', - 'mongo', + "elasticsearch", + "mongo", ]) expect(F.commonKeys(providers)(schema)).to.deep.equal([ - 'elasticsearch', - 'mongo', + "elasticsearch", + "mongo", ]) }) - it('firstCommonKey', () => { + it("firstCommonKey", () => { let providers = { mongo: {}, elasticsearch: {}, @@ -753,6 +753,6 @@ describe('Object Functions', () => { mongo: {}, } - expect(F.firstCommonKey(providers, schema)).to.equal('elasticsearch') + expect(F.firstCommonKey(providers, schema)).to.equal("elasticsearch") }) }) diff --git a/test/regex.spec.js b/test/regex.spec.js index 0d660720..7e994f15 100644 --- a/test/regex.spec.js +++ b/test/regex.spec.js @@ -1,81 +1,81 @@ -import chai from 'chai' -import * as F from '../src/regex' +import chai from "chai" +import * as F from "../src/regex" chai.expect() const expect = chai.expect -describe('Regexp Functions', () => { - it('testRegex', () => { - expect(F.testRegex(/smart/i)('SmartProcure')).to.be.true - expect(F.testRegex(/smart/)('SmartProcure')).to.be.false +describe("Regexp Functions", () => { + it("testRegex", () => { + expect(F.testRegex(/smart/i)("SmartProcure")).to.be.true + expect(F.testRegex(/smart/)("SmartProcure")).to.be.false }) - it('makeRegExp', () => { - const reText = 'Some text' - const options = 'gi' + it("makeRegExp", () => { + const reText = "Some text" + const options = "gi" expect(F.makeRegex(options)(reText)).to.deep.equal(RegExp(reText, options)) }) - it('makeAndTest', () => { - const reText = 'Some text' - const options = 'gi' - const text = 'Here is some text to test' + it("makeAndTest", () => { + const reText = "Some text" + const options = "gi" + const text = "Here is some text to test" const regex = RegExp(reText, options) expect(F.makeAndTest(options)(reText)(text)).to.deep.equal(regex.test(text)) }) - it('anyWordToRegexp', () => { - expect(F.anyWordToRegexp('Any word to regexp')).to.equal( - 'Any|word|to|regexp' + it("anyWordToRegexp", () => { + expect(F.anyWordToRegexp("Any word to regexp")).to.equal( + "Any|word|to|regexp" ) }) - it('wordsToRegexp', () => { - expect(F.wordsToRegexp('my three words')).to.equal( - '.*(?=.*my.*)(?=.*three.*)(?=.*words.*).*' + it("wordsToRegexp", () => { + expect(F.wordsToRegexp("my three words")).to.equal( + ".*(?=.*my.*)(?=.*three.*)(?=.*words.*).*" ) }) - it('matchAllWords', () => { - const reText = 'Some text' - const text = 'Here is some to test' + it("matchAllWords", () => { + const reText = "Some text" + const text = "Here is some to test" const match = F.matchAllWords(reText) expect(match(text)).to.be.false }) - it('matchAnyWord', () => { - const reText = 'Some text' - const text = 'Here is some text to test' + it("matchAnyWord", () => { + const reText = "Some text" + const text = "Here is some text to test" const match = F.matchAnyWord(reText) expect(match(text)).to.be.true }) - it('allMatches', () => { - const re = '(\\d+)' + it("allMatches", () => { + const re = "(\\d+)" const text = `1 22 333 a bb ccc 4444` const matches = F.allMatches(re, text) expect(matches).to.deep.equal([ - { text: '1', start: 0, end: 1 }, - { text: '22', start: 2, end: 4 }, - { text: '333', start: 5, end: 8 }, - { text: '4444', start: 18, end: 22 }, + { text: "1", start: 0, end: 1 }, + { text: "22", start: 2, end: 4 }, + { text: "333", start: 5, end: 8 }, + { text: "4444", start: 18, end: 22 }, ]) }) }) -describe('Posting Highlight Functions', () => { - it('postings', () => { - var result = F.postings(RegExp('p', 'gi'), 'pretty please') +describe("Posting Highlight Functions", () => { + it("postings", () => { + var result = F.postings(RegExp("p", "gi"), "pretty please") expect(result).to.deep.equal([ [0, 1], [7, 8], ]) }) - it('postingsForWords', () => { - var result = F.postingsForWords('pret pr t ', 'pretty prease') + it("postingsForWords", () => { + var result = F.postingsForWords("pret pr t ", "pretty prease") expect(result).to.deep.equal([ [[0, 4]], [ @@ -89,21 +89,21 @@ describe('Posting Highlight Functions', () => { ]) }) - describe('highlightFromPostings', () => { + describe("highlightFromPostings", () => { let start = '' - let end = '' + let end = "" - it('highlightFromPostings', () => { - let input = 'pretty please' - let postings = F.postings(RegExp('p', 'gi'), input) + it("highlightFromPostings", () => { + let input = "pretty please" + let postings = F.postings(RegExp("p", "gi"), input) let expected = 'pretty please' expect(F.highlightFromPostings(start, end, postings, input)).to.equal( expected ) }) - it('should highlight backwards postings', () => { - let input = 'pretty please' + it("should highlight backwards postings", () => { + let input = "pretty please" let expected = 'pretty please' expect( @@ -119,20 +119,20 @@ describe('Posting Highlight Functions', () => { ).to.equal(expected) }) }) - describe('highlight', () => { - it('highlight', () => { + describe("highlight", () => { + it("highlight", () => { let start = '' - let end = '' - let input = 'pretty please' - let pattern = 'pr pl' + let end = "" + let input = "pretty please" + let pattern = "pr pl" let expected = 'pretty please' expect(F.highlight(start, end, pattern, input)).to.equal(expected) }) - it('should highlight from regexp', () => { + it("should highlight from regexp", () => { let start = '' - let end = '' - let input = 'pretty please nope' + let end = "" + let input = "pretty please nope" let pattern = /\bp\w/g let expected = 'pretty please nope' diff --git a/test/string.spec.js b/test/string.spec.js index fae46e18..c3cbccea 100644 --- a/test/string.spec.js +++ b/test/string.spec.js @@ -1,108 +1,108 @@ -import chai from 'chai' -import _ from 'lodash/fp' -import * as F from '../src' +import chai from "chai" +import _ from "lodash/fp" +import * as F from "../src" chai.expect() const expect = chai.expect -describe('String Functions', () => { - it('wrap', () => { - expect(F.wrap('(', ')', 'asdf')).to.equal('(asdf)') - expect(F.wrap(null, null, 'asdf')).to.equal('asdf') +describe("String Functions", () => { + it("wrap", () => { + expect(F.wrap("(", ")", "asdf")).to.equal("(asdf)") + expect(F.wrap(null, null, "asdf")).to.equal("asdf") }) - it('quote', () => { - expect(F.quote('asdf')).to.equal('"asdf"') + it("quote", () => { + expect(F.quote("asdf")).to.equal('"asdf"') }) - it('parens', () => { - expect(F.parens('asdf')).to.equal('(asdf)') + it("parens", () => { + expect(F.parens("asdf")).to.equal("(asdf)") }) - it('concatStrings', () => { + it("concatStrings", () => { expect( - F.concatStrings(['This ', ' is a ', null, '', 'sentence!']) - ).to.equal('This is a sentence!') + F.concatStrings(["This ", " is a ", null, "", "sentence!"]) + ).to.equal("This is a sentence!") }) - it('trimStrings', () => { + it("trimStrings", () => { expect( - F.trimStrings(['This ', ' is a ', null, '', 'sentence!']) - ).to.deep.equal(['This', 'is a', null, '', 'sentence!']) + F.trimStrings(["This ", " is a ", null, "", "sentence!"]) + ).to.deep.equal(["This", "is a", null, "", "sentence!"]) expect( - F.trimStrings({ a: 'a', b: ' b ', c: 'c ', d: ' d', e: 5 }) - ).to.deep.equal({ a: 'a', b: 'b', c: 'c', d: 'd', e: 5 }) + F.trimStrings({ a: "a", b: " b ", c: "c ", d: " d", e: 5 }) + ).to.deep.equal({ a: "a", b: "b", c: "c", d: "d", e: 5 }) }) - it('autoLabel', () => { + it("autoLabel", () => { let tests = [ [ - 'whatDoYouThinkOfThisHTML5Stuff? IThinkItIsREALLYCool', - 'What Do You Think Of This HTML 5 Stuff I Think It Is REALLY Cool', + "whatDoYouThinkOfThisHTML5Stuff? IThinkItIsREALLYCool", + "What Do You Think Of This HTML 5 Stuff I Think It Is REALLY Cool", ], - ['thisIsAVariable', 'This Is A Variable'], + ["thisIsAVariable", "This Is A Variable"], [ - 'thisIs_startCaseWithACRONYMSAndNumbersLike123and4', - 'This Is Start Case With ACRONYMS And Numbers Like 123 And 4', + "thisIs_startCaseWithACRONYMSAndNumbersLike123and4", + "This Is Start Case With ACRONYMS And Numbers Like 123 And 4", ], // Passive aggressive example of how to better auto generate PR titles from branch names... - ['Feature/AutoLabel#126', 'Feature Auto Label 126'], + ["Feature/AutoLabel#126", "Feature Auto Label 126"], ] F.eachIndexed( ([input, output]) => expect(F.autoLabel(input)).to.equal(output), tests ) }) - it('autoLabelOption', () => { - expect(F.autoLabelOption('someValue')).to.deep.equal({ - value: 'someValue', - label: 'Some Value', + it("autoLabelOption", () => { + expect(F.autoLabelOption("someValue")).to.deep.equal({ + value: "someValue", + label: "Some Value", }) }) - it('autoLabelOptions', () => { + it("autoLabelOptions", () => { expect( F.autoLabelOptions([ - { value: '', label: 'Empty String Value' }, - 'someValue', - { value: 'justAValue' }, - { value: 'bothValueAndLabel', label: 'Custom Label' }, + { value: "", label: "Empty String Value" }, + "someValue", + { value: "justAValue" }, + { value: "bothValueAndLabel", label: "Custom Label" }, ]) ).to.deep.equal([ - { value: '', label: 'Empty String Value' }, - { value: 'someValue', label: 'Some Value' }, - { value: 'justAValue', label: 'Just A Value' }, - { value: 'bothValueAndLabel', label: 'Custom Label' }, + { value: "", label: "Empty String Value" }, + { value: "someValue", label: "Some Value" }, + { value: "justAValue", label: "Just A Value" }, + { value: "bothValueAndLabel", label: "Custom Label" }, ]) }) - it('toSentenceWith', () => { + it("toSentenceWith", () => { expect( - F.toSentenceWith(' - ', ' or ', ['first', 'second', 'third']) - ).to.equal('first - second or third') + F.toSentenceWith(" - ", " or ", ["first", "second", "third"]) + ).to.equal("first - second or third") }) - it('toSentence', () => { - expect(F.toSentence(['first', 'second', 'third'])).to.equal( - 'first, second and third' + it("toSentence", () => { + expect(F.toSentence(["first", "second", "third"])).to.equal( + "first, second and third" ) }) - it('uniqueStringWith', () => { - let a = ['foo20', 'foo21', 'foo23', 'foo24', 'foo25'] - let stripDigits = F.arrayToObject(_.replace(/(\d+)$/, ''), () => 1) + it("uniqueStringWith", () => { + let a = ["foo20", "foo21", "foo23", "foo24", "foo25"] + let stripDigits = F.arrayToObject(_.replace(/(\d+)$/, ""), () => 1) let uniqueStringStripDigits = F.uniqueStringWith(stripDigits, a) expect(uniqueStringStripDigits.cache).to.deep.equal({ foo: 1 }) - expect(uniqueStringStripDigits('foo')).to.equal('foo1') + expect(uniqueStringStripDigits("foo")).to.equal("foo1") // Should work with appending other stuff if you really want to - let appendHiForSomeReason = F.arrayToObject(_.identity, () => 'hi') + let appendHiForSomeReason = F.arrayToObject(_.identity, () => "hi") expect( - _.map(F.uniqueStringWith(appendHiForSomeReason, ['foo']), [ - 'foo', - 'foo', - 'bar', + _.map(F.uniqueStringWith(appendHiForSomeReason, ["foo"]), [ + "foo", + "foo", + "bar", ]) - ).to.deep.equal(['foohi', 'foohi1', 'bar']) + ).to.deep.equal(["foohi", "foohi1", "bar"]) }) - it('uniqueString', () => { + it("uniqueString", () => { let dedupe = F.uniqueString([]) expect(dedupe.cache).to.deep.equal({}) expect( _.map( dedupe, - _.times(() => 'foo', 5) + _.times(() => "foo", 5) ) - ).to.deep.equal(['foo', 'foo1', 'foo2', 'foo3', 'foo4']) + ).to.deep.equal(["foo", "foo1", "foo2", "foo3", "foo4"]) expect(dedupe.cache).to.deep.equal({ foo: 5, foo1: 1, @@ -110,18 +110,18 @@ describe('String Functions', () => { foo3: 1, foo4: 1, }) - expect(F.uniqueString(_.keys(dedupe.cache))('foo')).to.equal('foo5') + expect(F.uniqueString(_.keys(dedupe.cache))("foo")).to.equal("foo5") // should cache result strings to avoid conflicts with user-specified strings that // would have matched a uniqueString result - let badFoos = ['foo', 'foo1', 'foo', 'foo2', 'foo', 'foo3', 'foo'] + let badFoos = ["foo", "foo1", "foo", "foo2", "foo", "foo3", "foo"] expect(_.map(F.uniqueString([]), badFoos)).to.deep.equal([ - 'foo', - 'foo1', - 'foo2', - 'foo21', - 'foo3', - 'foo31', - 'foo4', + "foo", + "foo1", + "foo2", + "foo21", + "foo3", + "foo31", + "foo4", ]) let text = _.words(` Creates a function that invokes func with the arguments of the created function. If @@ -136,8 +136,8 @@ describe('String Functions', () => { dedupe.clear() expect(dedupe.cache).to.deep.equal({}) // should handle calling with no arguments - expect(F.uniqueString(null)('test')).to.be.a('string') - expect(F.uniqueString(undefined)('test')).to.be.a('string') - expect(F.uniqueString()('test')).to.be.a('string') + expect(F.uniqueString(null)("test")).to.be.a("string") + expect(F.uniqueString(undefined)("test")).to.be.a("string") + expect(F.uniqueString()("test")).to.be.a("string") }) }) diff --git a/test/tree.spec.js b/test/tree.spec.js index 2f90faea..b86067f7 100644 --- a/test/tree.spec.js +++ b/test/tree.spec.js @@ -1,19 +1,19 @@ -import chai from 'chai' -import * as F from '../src' -import _ from 'lodash/fp' -import Promise from 'bluebird' +import chai from "chai" +import * as F from "../src" +import _ from "lodash/fp" +import Promise from "bluebird" chai.expect() const expect = chai.expect -describe('Tree Functions', () => { - it('isTraversable', () => { +describe("Tree Functions", () => { + it("isTraversable", () => { expect(F.isTraversable([])).to.be.true expect(F.isTraversable({})).to.be.true - expect(F.isTraversable('')).to.be.false + expect(F.isTraversable("")).to.be.false expect(F.isTraversable(5)).to.be.false }) - it('traverse', () => { + it("traverse", () => { let x = { a: 1, b: { @@ -22,7 +22,7 @@ describe('Tree Functions', () => { } expect(F.traverse(x)).to.deep.equal(x) }) - describe('walk', () => { + describe("walk", () => { let x = { a: 1, b: { @@ -30,13 +30,13 @@ describe('Tree Functions', () => { }, } let values = [] - it('pre-order traversal', () => { + it("pre-order traversal", () => { F.walk()((tree) => { values.push(tree) })(x) expect(values).to.deep.equal([x, x.a, x.b, x.b.c]) }) - it('post-order traversal', () => { + it("post-order traversal", () => { let values = [] F.walk()( () => {}, @@ -46,7 +46,7 @@ describe('Tree Functions', () => { )(x) expect(values).to.deep.equal([x.a, x.b.c, x.b, x]) }) - it('halting', () => { + it("halting", () => { let values = [] let r = F.walk()((tree) => { values.push(tree) @@ -55,7 +55,7 @@ describe('Tree Functions', () => { expect(values).to.deep.equal([x, x.a]) expect(r).to.equal(x.a) }) - it('halting with tree return', () => { + it("halting with tree return", () => { let values = [] let r = F.walk()( () => {}, @@ -67,20 +67,20 @@ describe('Tree Functions', () => { expect(values).to.deep.equal([x.a, x.b.c, x.b, x]) expect(r).to.equal(x) }) - it('should retain parent stack and indices', () => { + it("should retain parent stack and indices", () => { let values = [] F.walk()((x, i, parents) => { values.push([x, parents, i]) })(x) expect(values).to.deep.equal([ [x, [], undefined], - [x.a, [x], 'a'], - [x.b, [x], 'b'], - [x.b.c, [x.b, x], 'c'], + [x.a, [x], "a"], + [x.b, [x], "b"], + [x.b.c, [x.b, x], "c"], ]) }) }) - it('reduceTree', () => { + it("reduceTree", () => { let x = { a: 1, b: { @@ -94,7 +94,7 @@ describe('Tree Functions', () => { x.b.c, ]) }) - it('treeToArray', () => { + it("treeToArray", () => { let x = { a: 1, b: { @@ -103,7 +103,7 @@ describe('Tree Functions', () => { } expect(F.treeToArray()(x)).to.deep.equal([x, x.a, x.b, x.b.c]) }) - it('treeToArrayBy', () => { + it("treeToArrayBy", () => { let x = { a: 1, b: { @@ -114,7 +114,7 @@ describe('Tree Functions', () => { F.treeToArrayBy()((i) => (_.isNumber(i) ? i * 2 : i), x) ).to.deep.equal([x, x.a * 2, x.b, x.b.c * 2]) }) - it('leaves', () => { + it("leaves", () => { let x = { a: 1, b: { @@ -123,7 +123,7 @@ describe('Tree Functions', () => { } expect(F.leaves()(x)).to.deep.equal([1, 2]) }) - it('tree', () => { + it("tree", () => { let x = { a: 1, b: { @@ -133,7 +133,7 @@ describe('Tree Functions', () => { let tree = F.tree() expect(tree.toArray(x)).to.deep.equal([x, x.a, x.b, x.b.c]) }) - it('lookup', () => { + it("lookup", () => { let x = { a: 1, items: [ @@ -158,24 +158,24 @@ describe('Tree Functions', () => { expect(tree.lookup([{ a: 2 }, { a: 4 }], x)).to.equal(x.items[0].items[1]) }) - it('lookup with path', () => { + it("lookup with path", () => { let x = { - a: '1', + a: "1", items: [ { - a: '2', + a: "2", items: [ { - a: '3', + a: "3", }, { - a: '4', + a: "4", b: 4, }, ], }, { - a: '5', + a: "5", }, ], } @@ -183,100 +183,100 @@ describe('Tree Functions', () => { (x) => x.items, (a) => ({ a }) ) - expect(tree.lookup(['2', '4'], x)).to.equal(x.items[0].items[1]) + expect(tree.lookup(["2", "4"], x)).to.equal(x.items[0].items[1]) }) - it('transform', () => { + it("transform", () => { let x = { - a: '1', + a: "1", items: [ { - a: '2', + a: "2", items: [ { - a: '3', + a: "3", }, { - a: '4', + a: "4", b: 4, }, ], }, { - a: '5', + a: "5", }, ], } expect( F.transformTree((x) => x.items)((x) => { - x.b = 'transformed' + x.b = "transformed" }, x) ).to.deep.equal({ - a: '1', - b: 'transformed', + a: "1", + b: "transformed", items: [ { - a: '2', - b: 'transformed', + a: "2", + b: "transformed", items: [ { - a: '3', - b: 'transformed', + a: "3", + b: "transformed", }, { - a: '4', - b: 'transformed', + a: "4", + b: "transformed", }, ], }, { - a: '5', - b: 'transformed', + a: "5", + b: "transformed", }, ], }) expect(x).to.deep.equal({ - a: '1', + a: "1", items: [ { - a: '2', + a: "2", items: [ { - a: '3', + a: "3", }, { - a: '4', + a: "4", b: 4, }, ], }, { - a: '5', + a: "5", }, ], }) }) - it('keyByWith', () => { + it("keyByWith", () => { let x = { - a: 'first', + a: "first", items: [ { - a: 'second', + a: "second", items: [ { - a: 'first', + a: "first", }, { - a: 'second', + a: "second", b: 4, }, { - a: 'second', + a: "second", b: 6, }, ], }, { - a: 'second', + a: "second", }, ], } @@ -287,95 +287,95 @@ describe('Tree Functions', () => { (x, matches, group) => { if (matches) x.type = `${group} type` }, - 'a', + "a", x ) ).to.deep.equal({ first: { - a: 'first', - type: 'first type', + a: "first", + type: "first type", items: [ { - a: 'second', + a: "second", items: [ { - a: 'first', - type: 'first type', + a: "first", + type: "first type", }, { - a: 'second', + a: "second", b: 4, }, { - a: 'second', + a: "second", b: 6, }, ], }, { - a: 'second', + a: "second", }, ], }, second: { - a: 'first', + a: "first", items: [ { - a: 'second', - type: 'second type', + a: "second", + type: "second type", items: [ { - a: 'first', + a: "first", }, { - a: 'second', - type: 'second type', + a: "second", + type: "second type", b: 4, }, { - a: 'second', - type: 'second type', + a: "second", + type: "second type", b: 6, }, ], }, { - a: 'second', - type: 'second type', + a: "second", + type: "second type", }, ], }, }) }) - it('flattenTree', () => { + it("flattenTree", () => { let properties = { Field1: { - type: 'text', + type: "text", }, Field2: { properties: { Field2A: { properties: { Field2A1: { - type: 'text', + type: "text", }, Field2A2: { - type: 'text', + type: "text", }, Field2A3: { properties: { Field2A3a: { - type: 'text', + type: "text", }, }, }, }, }, Field2B: { - type: 'text', + type: "text", }, Field2C: { - type: 'text', + type: "text", }, }, }, @@ -384,43 +384,43 @@ describe('Tree Functions', () => { let result = _.flow(Tree.flatten(), _.omitBy(Tree.traverse))({ properties }) expect(result).to.deep.equal({ Field1: { - type: 'text', + type: "text", }, - 'Field2.Field2A.Field2A1': { - type: 'text', + "Field2.Field2A.Field2A1": { + type: "text", }, - 'Field2.Field2A.Field2A2': { - type: 'text', + "Field2.Field2A.Field2A2": { + type: "text", }, - 'Field2.Field2A.Field2A3.Field2A3a': { - type: 'text', + "Field2.Field2A.Field2A3.Field2A3a": { + type: "text", }, - 'Field2.Field2B': { - type: 'text', + "Field2.Field2B": { + type: "text", }, - 'Field2.Field2C': { - type: 'text', + "Field2.Field2C": { + type: "text", }, }) }) - it('flattenTree with propTreePath', () => { + it("flattenTree with propTreePath", () => { let Tree = F.tree((x) => x.children) - let result = Tree.flatten(F.propTreePath('key'))({ - key: 'root', + let result = Tree.flatten(F.propTreePath("key"))({ + key: "root", children: [ { - key: 'criteria', + key: "criteria", children: [ { - key: 'filter', + key: "filter", }, ], }, { - key: 'analysis', + key: "analysis", children: [ { - key: 'results', + key: "results", }, ], }, @@ -428,59 +428,59 @@ describe('Tree Functions', () => { }) expect(result).to.deep.equal({ root: { - key: 'root', + key: "root", children: [ { - key: 'criteria', + key: "criteria", children: [ { - key: 'filter', + key: "filter", }, ], }, { - key: 'analysis', + key: "analysis", children: [ { - key: 'results', + key: "results", }, ], }, ], }, - 'root/analysis': { - key: 'analysis', + "root/analysis": { + key: "analysis", children: [ { - key: 'results', + key: "results", }, ], }, - 'root/analysis/results': { - key: 'results', + "root/analysis/results": { + key: "results", }, - 'root/criteria': { - key: 'criteria', + "root/criteria": { + key: "criteria", children: [ { - key: 'filter', + key: "filter", }, ], }, - 'root/criteria/filter': { - key: 'filter', + "root/criteria/filter": { + key: "filter", }, }) expect(Tree.flatLeaves(result)).to.deep.equal([ { - key: 'filter', + key: "filter", }, { - key: 'results', + key: "results", }, ]) }) - it('findIndexedAsync', async () => { + it("findIndexedAsync", async () => { let findIndexedAsyncTest = await F.findIndexedAsync( async (x) => { await Promise.delay(10) @@ -490,7 +490,7 @@ describe('Tree Functions', () => { ) expect(findIndexedAsyncTest).to.equal(2) }) - it('walkAsync', async () => { + it("walkAsync", async () => { let tree = { a: { b: { @@ -506,7 +506,7 @@ describe('Tree Functions', () => { await walkAsyncTest expect(tree.a.b.c.length).to.equal(4) }) - it('walkAsync with sync', async () => { + it("walkAsync with sync", async () => { let tree = { a: { b: { @@ -521,19 +521,19 @@ describe('Tree Functions', () => { await walkAsyncTest expect(tree.a.b.c.length).to.equal(4) }) - it('mapTreeLeaves', () => { + it("mapTreeLeaves", () => { let tree = { a: { b: { c: [1, 2, 3] } } } let double = (x) => x * 2 let result = F.mapTreeLeaves()(double, tree) expect(tree).to.deep.equal({ a: { b: { c: [1, 2, 3] } } }) expect(result).to.deep.equal({ a: { b: { c: [2, 4, 6] } } }) }) - it('mapTreeLeaves contexture tree', () => { + it("mapTreeLeaves contexture tree", () => { let tree = { - key: 'root', + key: "root", children: [ - { key: 'criteria', children: [{ key: 'filter' }, { key: 'f2' }] }, - { key: 'analysis', children: [{ key: 'results' }] }, + { key: "criteria", children: [{ key: "filter" }, { key: "f2" }] }, + { key: "analysis", children: [{ key: "results" }] }, ], } let getChildren = (x) => x.children @@ -542,44 +542,44 @@ describe('Tree Functions', () => { // parent.children[index] = node // } let mapLeaves = F.mapTreeLeaves(getChildren) //, writeChild) - let result = mapLeaves((node) => ({ ...node, value: 'test' }), tree) + let result = mapLeaves((node) => ({ ...node, value: "test" }), tree) expect(result).to.deep.equal({ - key: 'root', + key: "root", children: [ { - key: 'criteria', + key: "criteria", children: [ - { key: 'filter', value: 'test' }, - { key: 'f2', value: 'test' }, + { key: "filter", value: "test" }, + { key: "f2", value: "test" }, ], }, - { key: 'analysis', children: [{ key: 'results', value: 'test' }] }, + { key: "analysis", children: [{ key: "results", value: "test" }] }, ], }) }) - it('mapTree on JSON schema', () => { + it("mapTree on JSON schema", () => { let tree = { - type: 'object', + type: "object", additionalProperties: false, - required: ['email', 'subscriptionType'], + required: ["email", "subscriptionType"], properties: { - _id: { type: 'objectId' }, - email: { type: 'string' }, - password: { type: 'string' }, - name: { type: 'string' }, - organization: { type: 'objectId' }, - permissions: { type: 'array', items: { type: 'string' } }, - subscriptionType: { type: 'string', enum: ['basic', 'premium'] }, - createdAt: { type: 'date' }, - updatedAt: { type: 'date' }, + _id: { type: "objectId" }, + email: { type: "string" }, + password: { type: "string" }, + name: { type: "string" }, + organization: { type: "objectId" }, + permissions: { type: "array", items: { type: "string" } }, + subscriptionType: { type: "string", enum: ["basic", "premium"] }, + createdAt: { type: "date" }, + updatedAt: { type: "date" }, metrics: { - type: 'object', + type: "object", additionalProperties: false, properties: { - sessionsCount: { type: 'number' }, - totalSessionLength: { type: 'number' }, - firstSession: { type: 'date' }, - lastSession: { type: 'date' }, + sessionsCount: { type: "number" }, + totalSessionLength: { type: "number" }, + firstSession: { type: "date" }, + lastSession: { type: "date" }, }, }, }, @@ -589,33 +589,33 @@ describe('Tree Functions', () => { let { map } = F.tree(getChildren) let jsonSchemaToMongoSchema = _.flow( - F.renameProperty('type', 'bsonType'), - F.renameProperty('items.type', 'items.bsonType') + F.renameProperty("type", "bsonType"), + F.renameProperty("items.type", "items.bsonType") ) let result = map(jsonSchemaToMongoSchema, tree) expect(result).to.deep.equal({ - bsonType: 'object', + bsonType: "object", additionalProperties: false, - required: ['email', 'subscriptionType'], + required: ["email", "subscriptionType"], properties: { - _id: { bsonType: 'objectId' }, - email: { bsonType: 'string' }, - password: { bsonType: 'string' }, - name: { bsonType: 'string' }, - organization: { bsonType: 'objectId' }, - permissions: { bsonType: 'array', items: { bsonType: 'string' } }, - subscriptionType: { bsonType: 'string', enum: ['basic', 'premium'] }, - createdAt: { bsonType: 'date' }, - updatedAt: { bsonType: 'date' }, + _id: { bsonType: "objectId" }, + email: { bsonType: "string" }, + password: { bsonType: "string" }, + name: { bsonType: "string" }, + organization: { bsonType: "objectId" }, + permissions: { bsonType: "array", items: { bsonType: "string" } }, + subscriptionType: { bsonType: "string", enum: ["basic", "premium"] }, + createdAt: { bsonType: "date" }, + updatedAt: { bsonType: "date" }, metrics: { - bsonType: 'object', + bsonType: "object", additionalProperties: false, properties: { - sessionsCount: { bsonType: 'number' }, - totalSessionLength: { bsonType: 'number' }, - firstSession: { bsonType: 'date' }, - lastSession: { bsonType: 'date' }, + sessionsCount: { bsonType: "number" }, + totalSessionLength: { bsonType: "number" }, + firstSession: { bsonType: "date" }, + lastSession: { bsonType: "date" }, }, }, }, diff --git a/webpack.config.js b/webpack.config.js index bca13902..befd8675 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -1,20 +1,20 @@ -var path = require('path') -var webpack = require('webpack') -var packageMetadata = require('./package.json') +var path = require("path") +var webpack = require("webpack") +var packageMetadata = require("./package.json") var libraryName = packageMetadata.name var libraryVersion = packageMetadata.version -var outputFile = libraryName + '.js' +var outputFile = libraryName + ".js" module.exports = { - devtool: 'source-map', - mode: 'production', - entry: path.join(__dirname, 'src/index.js'), + devtool: "source-map", + mode: "production", + entry: path.join(__dirname, "src/index.js"), output: { - path: path.join(__dirname, 'lib'), + path: path.join(__dirname, "lib"), filename: outputFile, library: libraryName, - libraryTarget: 'umd', - globalObject: 'this', + libraryTarget: "umd", + globalObject: "this", }, module: { rules: [ @@ -22,17 +22,17 @@ module.exports = { test: /(\.jsx|\.js)$/, exclude: /(node_modules|bower_components)/, use: { - loader: 'babel-loader', + loader: "babel-loader", }, }, ], }, externals: { - 'lodash/fp': 'lodash/fp', + "lodash/fp": "lodash/fp", }, plugins: [ new webpack.DefinePlugin({ - 'global.__VERSION__': JSON.stringify(libraryVersion), + "global.__VERSION__": JSON.stringify(libraryVersion), }), ], }