2017-09-27 10:59:56 +02:00
|
|
|
/* eslint-disable */
|
2017-08-15 13:54:22 +02:00
|
|
|
;(function() {
|
2019-08-16 16:25:01 +02:00
|
|
|
"use strict"
|
|
|
|
/* eslint-enable */
|
|
|
|
Stream.SKIP = {}
|
|
|
|
Stream.lift = lift
|
|
|
|
Stream.scan = scan
|
|
|
|
Stream.merge = merge
|
|
|
|
Stream.combine = combine
|
|
|
|
Stream.scanMerge = scanMerge
|
|
|
|
Stream["fantasy-land/of"] = Stream
|
|
|
|
|
|
|
|
var warnedHalt = false
|
|
|
|
Object.defineProperty(Stream, "HALT", {
|
|
|
|
get: function() {
|
|
|
|
warnedHalt || console.log("HALT is deprecated and has been renamed to SKIP");
|
|
|
|
warnedHalt = true
|
|
|
|
return Stream.SKIP
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
|
|
|
function Stream(value) {
|
|
|
|
var dependentStreams = []
|
|
|
|
var dependentFns = []
|
|
|
|
|
|
|
|
function stream(v) {
|
|
|
|
if (arguments.length && v !== Stream.SKIP) {
|
|
|
|
value = v
|
|
|
|
if (open(stream)) {
|
|
|
|
stream._changing()
|
|
|
|
stream._state = "active"
|
2022-06-27 15:33:32 +02:00
|
|
|
// Cloning the list to ensure it's still iterated in intended
|
|
|
|
// order
|
|
|
|
dependentStreams.slice().forEach(function(s, i) {
|
|
|
|
if (open(s)) s(this[i](value))
|
|
|
|
}, dependentFns.slice())
|
2019-04-24 12:41:34 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-08-16 16:25:01 +02:00
|
|
|
return value
|
|
|
|
}
|
2019-04-24 12:41:34 +02:00
|
|
|
|
2019-08-16 16:25:01 +02:00
|
|
|
stream.constructor = Stream
|
|
|
|
stream._state = arguments.length && value !== Stream.SKIP ? "active" : "pending"
|
|
|
|
stream._parents = []
|
2019-04-24 12:41:34 +02:00
|
|
|
|
2019-08-16 16:25:01 +02:00
|
|
|
stream._changing = function() {
|
|
|
|
if (open(stream)) stream._state = "changing"
|
|
|
|
dependentStreams.forEach(function(s) {
|
|
|
|
s._changing()
|
2019-01-17 09:50:05 +01:00
|
|
|
})
|
2019-08-16 16:25:01 +02:00
|
|
|
}
|
2019-04-24 12:41:34 +02:00
|
|
|
|
2019-08-16 16:25:01 +02:00
|
|
|
stream._map = function(fn, ignoreInitial) {
|
|
|
|
var target = ignoreInitial ? Stream() : Stream(fn(value))
|
|
|
|
target._parents.push(stream)
|
|
|
|
dependentStreams.push(target)
|
|
|
|
dependentFns.push(fn)
|
|
|
|
return target
|
2017-08-15 13:54:22 +02:00
|
|
|
}
|
2019-01-17 09:50:05 +01:00
|
|
|
|
2019-08-16 16:25:01 +02:00
|
|
|
stream.map = function(fn) {
|
|
|
|
return stream._map(fn, stream._state !== "active")
|
|
|
|
}
|
2019-03-05 12:14:13 +01:00
|
|
|
|
2019-08-16 16:25:01 +02:00
|
|
|
var end
|
|
|
|
function createEnd() {
|
|
|
|
end = Stream()
|
|
|
|
end.map(function(value) {
|
2019-03-05 12:14:13 +01:00
|
|
|
if (value === true) {
|
2019-08-16 16:25:01 +02:00
|
|
|
stream._parents.forEach(function (p) {p._unregisterChild(stream)})
|
|
|
|
stream._state = "ended"
|
|
|
|
stream._parents.length = dependentStreams.length = dependentFns.length = 0
|
2019-03-05 12:14:13 +01:00
|
|
|
}
|
2019-08-16 16:25:01 +02:00
|
|
|
return value
|
2019-01-17 09:50:05 +01:00
|
|
|
})
|
2019-08-16 16:25:01 +02:00
|
|
|
return end
|
2017-08-15 13:54:22 +02:00
|
|
|
}
|
2019-01-17 09:50:05 +01:00
|
|
|
|
2019-08-16 16:25:01 +02:00
|
|
|
stream.toJSON = function() { return value != null && typeof value.toJSON === "function" ? value.toJSON() : value }
|
2019-01-17 09:50:05 +01:00
|
|
|
|
2019-08-16 16:25:01 +02:00
|
|
|
stream["fantasy-land/map"] = stream.map
|
|
|
|
stream["fantasy-land/ap"] = function(x) { return combine(function(s1, s2) { return s1()(s2()) }, [x, stream]) }
|
|
|
|
|
|
|
|
stream._unregisterChild = function(child) {
|
|
|
|
var childIndex = dependentStreams.indexOf(child)
|
|
|
|
if (childIndex !== -1) {
|
|
|
|
dependentStreams.splice(childIndex, 1)
|
|
|
|
dependentFns.splice(childIndex, 1)
|
|
|
|
}
|
2019-04-24 12:41:34 +02:00
|
|
|
}
|
2017-08-15 13:54:22 +02:00
|
|
|
|
2019-08-16 16:25:01 +02:00
|
|
|
Object.defineProperty(stream, "end", {
|
|
|
|
get: function() { return end || createEnd() }
|
|
|
|
})
|
2017-08-15 13:54:22 +02:00
|
|
|
|
2019-08-16 16:25:01 +02:00
|
|
|
return stream
|
|
|
|
}
|
|
|
|
|
|
|
|
function combine(fn, streams) {
|
|
|
|
var ready = streams.every(function(s) {
|
|
|
|
if (s.constructor !== Stream)
|
2022-06-27 15:33:32 +02:00
|
|
|
throw new Error("Ensure that each item passed to stream.combine/stream.merge/lift is a stream.")
|
2019-08-16 16:25:01 +02:00
|
|
|
return s._state === "active"
|
|
|
|
})
|
|
|
|
var stream = ready
|
|
|
|
? Stream(fn.apply(null, streams.concat([streams])))
|
|
|
|
: Stream()
|
|
|
|
|
|
|
|
var changed = []
|
|
|
|
|
|
|
|
var mappers = streams.map(function(s) {
|
|
|
|
return s._map(function(value) {
|
|
|
|
changed.push(s)
|
|
|
|
if (ready || streams.every(function(s) { return s._state !== "pending" })) {
|
|
|
|
ready = true
|
|
|
|
stream(fn.apply(null, streams.concat([changed])))
|
|
|
|
changed = []
|
|
|
|
}
|
|
|
|
return value
|
|
|
|
}, true)
|
|
|
|
})
|
2017-08-15 13:54:22 +02:00
|
|
|
|
2019-08-16 16:25:01 +02:00
|
|
|
var endStream = stream.end.map(function(value) {
|
|
|
|
if (value === true) {
|
|
|
|
mappers.forEach(function(mapper) { mapper.end(true) })
|
|
|
|
endStream.end(true)
|
|
|
|
}
|
|
|
|
return undefined
|
|
|
|
})
|
2017-08-15 13:54:22 +02:00
|
|
|
|
2019-08-16 16:25:01 +02:00
|
|
|
return stream
|
|
|
|
}
|
2017-08-15 13:54:22 +02:00
|
|
|
|
2019-08-16 16:25:01 +02:00
|
|
|
function merge(streams) {
|
|
|
|
return combine(function() { return streams.map(function(s) { return s() }) }, streams)
|
|
|
|
}
|
2019-01-17 09:50:05 +01:00
|
|
|
|
2019-08-16 16:25:01 +02:00
|
|
|
function scan(fn, acc, origin) {
|
|
|
|
var stream = origin.map(function(v) {
|
|
|
|
var next = fn(acc, v)
|
|
|
|
if (next !== Stream.SKIP) acc = next
|
|
|
|
return next
|
|
|
|
})
|
|
|
|
stream(acc)
|
|
|
|
return stream
|
|
|
|
}
|
|
|
|
|
|
|
|
function scanMerge(tuples, seed) {
|
|
|
|
var streams = tuples.map(function(tuple) { return tuple[0] })
|
|
|
|
|
|
|
|
var stream = combine(function() {
|
|
|
|
var changed = arguments[arguments.length - 1]
|
|
|
|
streams.forEach(function(stream, i) {
|
|
|
|
if (changed.indexOf(stream) > -1)
|
|
|
|
seed = tuples[i][1](seed, stream())
|
2019-01-17 09:50:05 +01:00
|
|
|
})
|
|
|
|
|
2019-08-16 16:25:01 +02:00
|
|
|
return seed
|
|
|
|
}, streams)
|
|
|
|
|
|
|
|
stream(seed)
|
|
|
|
|
|
|
|
return stream
|
|
|
|
}
|
|
|
|
|
|
|
|
function lift() {
|
|
|
|
var fn = arguments[0]
|
|
|
|
var streams = Array.prototype.slice.call(arguments, 1)
|
|
|
|
return merge(streams).map(function(streams) {
|
|
|
|
return fn.apply(undefined, streams)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
function open(s) {
|
|
|
|
return s._state === "pending" || s._state === "active" || s._state === "changing"
|
|
|
|
}
|
2017-08-15 13:54:22 +02:00
|
|
|
|
2019-08-16 16:25:01 +02:00
|
|
|
if (typeof module !== "undefined") module["exports"] = Stream
|
|
|
|
else if (typeof window.m === "function" && !("stream" in window.m)) window.m.stream = Stream
|
|
|
|
else window.m = {stream : Stream}
|
2017-08-15 13:54:22 +02:00
|
|
|
|
2019-03-05 12:14:13 +01:00
|
|
|
}());
|