Repository: ViacomInc/data-point (js)

Issue:
helpers.createReducer is not exposed
<!--
Thanks for your interest in the project. We appreciate bugs filed and PRs submitted!
Please make sure that you are familiar with and follow the Code of Conduct for
this project (found in the CODE_OF_CONDUCT.md file).

Please fill/un-comment out this template with all the relevant information so we can
understand what's going on and fix the issue.
-->

**Problem description**:

`helpers.createReducer` is not exposed to API

https://github.com/ViacomInc/data-point/blob/cd7701998000a7cff0bca64e494f814293a6d5c3/packages/data-point/lib/index.js#L6-L14

**Suggested solution**:

Expose `createReducer` in the helpers module.

**Environment**:

- `data-point` version:  2.x


Pull request description:
feat(data-point): Expose createReducer on DataPoint object
also allow existing reducers to be passed to resolve and transform functions

<!-- What changes are being made? (What feature/bug is being fixed here?) -->
**What**: closes #233

<!-- How were these changes implemented? -->
**How**: Exports `createReducer` function and refactors `reducerResolve` 

<!-- Have you done all of these things?  -->
**Checklist**:
<!-- add "N/A" to the end of each line that's irrelevant to your changes -->
<!-- to check an item, place an "x" in the box like so: "- [x] Documentation" -->
- [ ] Has Breaking changes
- [ ] Documentation
- [x] Tests
- [x] Ready to be merged <!-- In your opinion, is this ready to be merged as soon as it's reviewed? -->

Patch:
diff --git a/packages/data-point/lib/core/transform.js b/packages/data-point/lib/core/transform.js
index c10edc2..efd8d95 100644
--- a/packages/data-point/lib/core/transform.js
+++ b/packages/data-point/lib/core/transform.js
@@ -20,7 +20,6 @@ function reducerResolve (manager, reducerSource, value, options) {
   })
 
   const reducer = Reducer.create(reducerSource)
-
   return Reducer.resolve(manager, context, reducer)
 }
 
diff --git a/packages/data-point/lib/index.js b/packages/data-point/lib/index.js
index c467ba9..1e69385 100644
--- a/packages/data-point/lib/index.js
+++ b/packages/data-point/lib/index.js
@@ -10,5 +10,6 @@ module.exports = {
   resolveEntity: helpers.resolveEntity,
   reducify: helpers.reducify,
   reducifyAll: helpers.reducifyAll,
+  createReducer: helpers.createReducer,
   createReducerResolver: helpers.reducifyAll
 }
diff --git a/packages/data-point/lib/reducer-types/factory.js b/packages/data-point/lib/reducer-types/factory.js
index 097c673..9fd2a65 100644
--- a/packages/data-point/lib/reducer-types/factory.js
+++ b/packages/data-point/lib/reducer-types/factory.js
@@ -52,6 +52,10 @@ function normalizeInput (source) {
  * @return {reducer}
  */
 function createReducer (source, options = {}) {
+  if (isReducer(source)) {
+    return source
+  }
+
   source = normalizeInput(source)
   const reducerType = reducerTypes.find(r => r.isType(source))
 


Test patch:
diff --git a/packages/data-point/lib/__snapshots__/index.test.js.snap b/packages/data-point/lib/__snapshots__/index.test.js.snap
index 755a2a1..ca27b25 100644
--- a/packages/data-point/lib/__snapshots__/index.test.js.snap
+++ b/packages/data-point/lib/__snapshots__/index.test.js.snap
@@ -4,6 +4,7 @@ exports[`lib It should explicity expose set of methods 1`] = `
 Object {
   "create": [Function],
   "createEntity": [Function],
+  "createReducer": [Function],
   "createReducerResolver": [Function],
   "helpers": Object {
     "assign": [Function],
diff --git a/packages/data-point/lib/core/transform.test.js b/packages/data-point/lib/core/transform.test.js
index d2dc161..f8e4c07 100644
--- a/packages/data-point/lib/core/transform.test.js
+++ b/packages/data-point/lib/core/transform.test.js
@@ -1,6 +1,6 @@
 /* eslint-env jest */
 
-const core = require('./core')
+const DataPoint = require('../index')
 
 const reducers = require('../../test/utils/reducers')
 const entities = require('../../test/definitions/entities')
@@ -11,7 +11,7 @@ const TestData = require('../../test/data.json')
 let dataPoint
 
 beforeAll(() => {
-  dataPoint = core.create({
+  dataPoint = DataPoint.create({
     values: {
       v1: 'v1'
     },
@@ -200,3 +200,15 @@ describe('resolve', () => {
       })
   })
 })
+
+describe('dataPoint.createReducer', () => {
+  test('it should evaluate an existing reducer', () => {
+    const reducer = DataPoint.createReducer(['$a', input => input + 1])
+    return dataPoint
+      .resolve(reducer, { a: 5 })
+      .catch(err => err)
+      .then(output => {
+        expect(output).toBe(6)
+      })
+  })
+})
diff --git a/packages/data-point/lib/reducer-types/factory.test.js b/packages/data-point/lib/reducer-types/factory.test.js
index bf4f496..078895f 100644
--- a/packages/data-point/lib/reducer-types/factory.test.js
+++ b/packages/data-point/lib/reducer-types/factory.test.js
@@ -35,6 +35,20 @@ describe('reducer#create', () => {
     expect(reducer.entityType).toBe('fooEntity')
   })
 
+  test('return the input when the input is already a reducer', () => {
+    const reducer1 = Factory.create('$test')
+    const reducer2 = Factory.create(reducer1)
+    expect(reducer1 === reducer2).toBe(true)
+    expect(reducer1).toEqual(reducer2)
+  })
+
+  test('do not modify an existing reducer in the source for a ReducerList', () => {
+    const reducer1 = Factory.create('$bar')
+    const reducer2 = Factory.create(['$foo', reducer1])
+    expect(reducer1 === reducer2.reducers[1]).toBe(true)
+    expect(reducer1).toEqual(reducer2.reducers[1])
+  })
+
   test('detect invalid', () => {
     expect(() => {
       Factory.create('a')