Repository: mostjs/core
Pull request #153 (2017-10-13 00:12:48)

docs(concepts): Fix grammar in application errors section


Patch:
diff --git a/docs/concepts.rst b/docs/concepts.rst
index bbe66b7..cf5d017 100644
--- a/docs/concepts.rst
+++ b/docs/concepts.rst
@@ -43,11 +43,15 @@ The :ref:`recoverWith` operation allows you to handle an event stream failure.
 Stream Failure vs. Application Errors
 `````````````````````````````````````
 
-Stream failures are different from *application errors*.  A stream failure indicates that an event stream *cannot* produce more events.  Application errors may or may not indicate an event stream failure.  For example, an event stream representing messages arriving on a WebSocket *fails* if the WebSocket is disconnected unexpectedly due to a wifi drop.  In contrast, an application error may occur in application logic that receives a WebSocket message and can't process because the message application state has changed.
+Stream failures are different from *application errors*.  A stream failure indicates that an event stream *cannot* produce more events.  An application error may or may not indicate an event stream failure.
+
+For example, an event stream of messages from a WebSocket *fails* if the WebSocket is disconnected unexpectedly because of a dropped network connection.
+
+In contrast, an application error may occur in the application logic when it receives a WebSocket message that it can't process because the application state has changed.  The application must deal with this particular state conflict in an application-specific way, but the WebSocket event stream has *not* failed.
 
 Application error handling is outside the scope of these docs, as it is application-specific.  However, there are some general strategies for dealing with application errors with event streams:
 
-* Use try/catch, `Promise catch() <https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/catch>`_ to handle the application error and transform it into:
+* Use try/catch or `Promise catch() <https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/catch>`_ to handle the application error and transform it into:
 
   * a useful event value
   * a sentinel event value that can be :ref:`filtered <filter>`
diff --git a/packages/core/src/combinator/zipItems.js b/packages/core/src/combinator/zipItems.js
index 7241765..a236729 100644
--- a/packages/core/src/combinator/zipItems.js
+++ b/packages/core/src/combinator/zipItems.js
@@ -1,15 +1,16 @@
 /** @license MIT License (c) copyright 2017 original author or authors */
 
-import { empty } from '../source/empty'
 import Pipe from '../sink/Pipe'
+import { empty, isCanonicalEmpty } from '../source/empty'
+import { take } from './slice'
 
 export const withItems = (items, stream) =>
   zipItems(keepLeft, items, stream)
 
 export const zipItems = (f, items, stream) =>
-  items.length === 0 || stream === empty()
+  isCanonicalEmpty(stream) || items.length === 0
     ? empty()
-    : new ZipItems(f, items, stream)
+    : new ZipItems(f, items, take(items.length, stream))
 
 const keepLeft = (a, _) => a
 
@@ -36,10 +37,6 @@ class ZipItemsSink extends Pipe {
   event (t, b) {
     const f = this.f
     this.sink.event(t, f(this.items[this.index], b))
-
     this.index += 1
-    if (this.index >= this.items.length) {
-      this.sink.end(t)
-    }
   }
 }


Test patch:
diff --git a/packages/core/test/combinator/zipItems-test.js b/packages/core/test/combinator/zipItems-test.js
index 8ead31f..5059556 100644
--- a/packages/core/test/combinator/zipItems-test.js
+++ b/packages/core/test/combinator/zipItems-test.js
@@ -3,7 +3,11 @@ import { describe, it } from 'mocha'
 import { eq, fail } from '@briancavalier/assert'
 
 import { zipItems, withItems } from '../../src/combinator/zipItems'
+import { map } from '../../src/combinator/transform'
+import { scan } from '../../src/combinator/scan'
+import { switchLatest } from '../../src/combinator/switch'
 import { empty } from '../../src/source/empty'
+import { periodic } from '../../src/source/periodic'
 
 import { collectEventsFor, makeEvents } from '../helper/testEnv'
 
@@ -80,5 +84,28 @@ describe('zipItems', () => {
           { time: 1, value: 'b' }
         ]))
     })
+
+    describe('given https://www.webpackbin.com/bins/-KvrqudMj6C-0H494Itg', () => {
+      it('should contain expected number of items', () => {
+        // Regression test based on
+        // https://www.webpackbin.com/bins/-KvrqudMj6C-0H494Itg
+        const a1 = [1, 2]
+        const a2 = [10, 20, 30]
+        const expectedCount = (a1.length * a2.length) + 1
+
+        const t1 = 2
+        const t2 = t1 / 2
+
+        const s1 = withItems(a1, periodic(t1))
+        const s2 = withItems(a2, periodic(t2))
+
+        const add = (x, y) => x + y
+
+        const scanned = switchLatest(map(a => scan(add, a, s2), s1))
+
+        return collectEventsFor(t1 * a1.length, scanned)
+          .then(events => eq(expectedCount, events.length))
+      })
+    })
   })
 })