New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

flyd

Package Overview
Dependencies
Maintainers
1
Versions
34
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

flyd - npm Package Compare versions

Comparing version 0.1.2 to 0.1.3

9

examples/ramda-transducer/script.js

@@ -5,3 +5,3 @@ var R = require('ramda');

// Let's create a stream of numbers
var numbers = flyd.stream(0);
var numbers = flyd.stream();

@@ -11,3 +11,4 @@ var isEven = R.compose(R.eq(0), R.modulo(R.__, 2));

// All even numbers multiplied by 3
var evenTimes3 = flyd.transduce(R.pipe(
var drop3evenTimes3 = flyd.transduce(R.compose(
R.drop(3),
R.filter(isEven),

@@ -17,4 +18,4 @@ R.map(R.multiply(3))

flyd.map(function(n) { console.log('evenTimes3: ' + n); }, evenTimes3);
flyd.map(function(n) { console.log(n); }, drop3evenTimes3);
numbers(9)(4)(3)(7)(6)(5);
numbers(9)(4)(2)(8)(6)(5)(2);

@@ -17,15 +17,13 @@ (function (root, factory) {

function isUndefined(v) {
return v === undefined;
function notUndef(v) {
return v !== undefined;
}
function each(fn, list) {
for (var i = 0; i < list.length; ++i) fn(list[i]);
}
var toUpdate = [];
var inStream;
function removeListener(listeners, s) {
var idx = listeners.indexOf(s);
listeners[idx] = listeners[listeners.length - 1];
listeners.length--;
}
function map(s, f) {

@@ -44,7 +42,7 @@ return stream([s], function() { return f(s()); });

var merge = curryN(2, function(s1, s2) {
var s = stream([s1, s2], function(n, changed) {
var s = immediate(stream([s1, s2], function(n, changed) {
return changed[0] ? changed[0]()
: s1.hasVal ? s1()
: s2();
}, true);
}));
endsOn(stream([s1.end, s2.end], function(self, changed) {

@@ -61,6 +59,2 @@ return true;

function of(v) {
return stream(v);
}
function initialDepsNotMet(stream) {

@@ -76,6 +70,6 @@ if (!stream.depsMet) {

function updateStream(s) {
if (initialDepsNotMet(s) || s.ended) return;
if (initialDepsNotMet(s) || (s.end && s.end())) return;
inStream = s;
var returnVal = s.fn(s, s.depsChanged);
if (returnVal !== undefined) {
if (notUndef(returnVal)) {
s(returnVal);

@@ -90,5 +84,3 @@ }

s.queued = true;
for (var i = 0; i < s.listeners.length; ++i) {
findDeps(order, s.listeners[i]);
}
each(findDeps.bind(null, order), s.listeners);
order.push(s);

@@ -100,10 +92,6 @@ }

var i, order = [];
for (i = 0; i < s.listeners.length; ++i) {
if (s.listeners[i].end === s) {
end(s.listeners[i]);
} else {
s.listeners[i].depsChanged.push(s);
findDeps(order, s.listeners[i]);
}
}
each(function(list) {
list.end === s ? endStream(list)
: (list.depsChanged.push(s), findDeps(order, list));
}, s.listeners);
for (i = order.length - 1; i >= 0; --i) {

@@ -118,22 +106,5 @@ if (order[i].depsChanged.length > 0) {

function flushUpdate() {
for (var s; s = toUpdate.shift();) {
updateDeps(s);
}
while (toUpdate.length > 0) updateDeps(toUpdate.shift());
}
function end(s) {
s.ended = true;
if (s.deps) s.deps.forEach(function(dep) { removeListener(dep.listeners, s); });
}
function endsOn(endS, s) {
if (s.end) {
removeListener(s.end.listeners, s);
if (isUndefined(s.end.end)) end(s.end);
}
s.end = endS;
endS.listeners.push(s);
return s;
}
function isStream(stream) {

@@ -160,9 +131,5 @@ return isFunction(stream) && 'hasVal' in stream;

} else {
for (var j = 0; j < s.listeners.length; ++j) {
if (s.listeners[j].end === s) {
end(s.listeners[j]);
} else {
s.listeners[j].depsChanged.push(s);
}
}
each(function(list) {
list.end === s ? endStream(list) : list.depsChanged.push(s);
}, s.listeners);
}

@@ -179,7 +146,6 @@ return s;

s.end = undefined;
s.ended = false;
s.map = map.bind(null, s);
s.ap = ap;
s.of = of;
s.of = stream;
s.toString = streamToString;

@@ -190,21 +156,53 @@

function createDependentStream(deps, fn, dontWaitForDeps) {
function createDependentStream(deps, fn) {
var s = createStream();
s.fn = fn;
s.deps = deps;
s.depsMet = dontWaitForDeps;
s.depsMet = false;
s.depsChanged = [];
deps.forEach(function(dep) {
dep.listeners.push(s);
});
each(function(dep) { dep.listeners.push(s); }, deps);
return s;
}
function stream(arg, fn, dontWaitForDeps) {
function immediate(s) {
if (s.depsMet === false) {
s.depsMet = true;
updateStream(s);
flushUpdate();
}
return s;
}
function removeListener(s, listeners) {
var idx = listeners.indexOf(s);
listeners[idx] = listeners[listeners.length - 1];
listeners.length--;
}
function detachDeps(s) {
each(function(dep) { removeListener(s, dep.listeners); }, s.deps);
s.deps.length = 0;
}
function endStream(s) {
if (s.deps) detachDeps(s);
if (s.end) detachDeps(s.end);
}
function endsOn(endS, s) {
detachDeps(s.end);
endS.listeners.push(s.end);
s.end.deps.push(endS);
return s;
}
function stream(arg, fn) {
var s, deps;
var endStream = createDependentStream([], function() { return true; });
if (arguments.length > 1) {
deps = arg.filter(function(d) { return d !== undefined; });
s = createDependentStream(deps, fn, isUndefined(dontWaitForDeps) ? false : true);
var depEndStreams = deps.filter(function(d) { return !isUndefined(d.end); })
.map(function(d) { return d.end; });
deps = arg.filter(notUndef);
s = createDependentStream(deps, fn);
s.end = endStream;
endStream.listeners.push(s);
var depEndStreams = deps.map(function(d) { return d.end; }).filter(notUndef);
endsOn(createDependentStream(depEndStreams, function() { return true; }, true), s);

@@ -215,3 +213,4 @@ updateStream(s);

s = createStream();
endsOn(createStream(), s);
s.end = endStream;
endStream.listeners.push(s);
if (arguments.length === 1) s(arg);

@@ -223,12 +222,23 @@ }

var transduce = curryN(2, function(xform, source) {
xform = xform(new StreamTransformer(stream));
return stream([source], function() {
return xform.step(undefined, source());
xform = xform(new StreamTransformer());
// Latest Ramda release still uses old transducer protocol
var stepName = xform['@@transducer/step'] ? '@@transducer/step' : 'step';
return stream([source], function(self) {
var res = xform[stepName](undefined, source());
if (res && res['@@transducer/reduced'] === true) {
self.end(true);
return res['@@transducer/value'];
} else {
return res;
}
});
});
function StreamTransformer(res) { }
function StreamTransformer() { }
StreamTransformer.prototype.init = function() { };
StreamTransformer.prototype.result = function() { };
StreamTransformer.prototype.step = function(s, v) { return v; };
StreamTransformer.prototype['@@transducer/init'] = function() { };
StreamTransformer.prototype['@@transducer/result'] = function() { };
StreamTransformer.prototype['@@transducer/step'] = function(s, v) { return v; };

@@ -357,4 +367,5 @@ // Own curry implementation snatched from Ramda

_: _,
immediate: immediate,
};
}));
{
"name": "flyd",
"version": "0.1.2",
"version": "0.1.3",
"description": "The less is more, modular, functional reactive programming library",

@@ -17,3 +17,3 @@ "main": "flyd.js",

"ramda": "^0.13.0",
"transducers.js": "^0.2.3"
"transducers.js": "0.3.x"
},

@@ -20,0 +20,0 @@ "scripts": {

@@ -56,3 +56,3 @@ [![Build Status](https://travis-ci.org/paldepind/flyd.svg?branch=master)](https://travis-ci.org/paldepind/flyd)

This is not general tutorial to functional reactive programming. For that take
This is not general introduction to functional reactive programming. For that take
a look at [The introduction to Reactive Programming you've been

@@ -63,11 +63,18 @@ missing](https://gist.github.com/staltz/868e7e9bc2a7b8c1f754) and/or [this Elm

This tutorial will introduce you to the core of Flyd and show how to use it to
build FRP abstractions.
This is not a demonstration of how you would write code with Flyd on a day to
day basis. For that take a look at the [examples](#examples).
This tutorial will however introduce you to the minimal but powerful core that
Flyd provides and show you how it can be used to build FRP abstractions.
### Creating streams
Flyd gives you streams as the building block for creating reactive dataflows.
The function `stream` creates a representation of a value that changes over time.
A stream is a function. At first sight it works a bit like a getter-setter:
They serve the same purpose as what other FRP libraries call Signals, Observables,
Properties and EventEmitters.
The function `flyd.stream` creates a representation of a value that changes
over time. The resulting stream is a function. At first sight it works a bit
like a getter-setter:
```javascript

@@ -104,4 +111,4 @@ // Create a stream with initial value 5.

as in the above examples we can pass it a list of dependencies and a function.
The function should produce a value based on its dependencies. This new value
results in a new stream.
The function should produce a value based on its dependencies. This new
returned value results in a new stream.

@@ -111,3 +118,3 @@ Flyd automatically updates the stream whenever a dependency changes. This

changes. You can think of dependent stream as streams that automatically
listens/subscribes to their dependencies.
listens to or subscribes to their dependencies.

@@ -147,4 +154,5 @@ ```javascript

The body of a dependent stream is called with two streams: itself and the last
changed stream on which it depends.
The body of a dependent stream is called with two parameters: itself and a list
of the dependencies that has changed since its last invocation (due to [atomic
updates](#atomic-updates) several streams could have changed).

@@ -158,5 +166,6 @@ ```javascript

console.log('Last sum was ' + sum());
if (changed) { // On the initial call no stream has changed
var changedName = (changed === y ? 'y' : 'x');
console.log(changedName + ' changed to ' + changed());
// On the initial call no streams has changed and `changed` will be []
changed.map(function(s) {
var changedName = (s === y ? 'y' : 'x');
console.log(changedName + ' changed to ' + s());
}

@@ -186,3 +195,4 @@ return x() + y();

`undefined`). Fortunately a streams body will not be called before all of its declared
streams has recieved a value.
streams has recieved a value (this behaviour can be cirumvented with
[flyd.immediate](#flydimmediatestream)).

@@ -208,6 +218,6 @@ ### Using promises for asynchronous operations

You've now seen the basic building block which Flyd provides. Let's see what we
can do with it. Lets write a function that takes a stream and a function and
returns a new stream with the function applied to every value emitted by the
stream. In short, a `map` function.
You've now seen most of the basic building block which Flyd provides. Let's see
what we can do with them. Lets write a function that takes a stream and a
function and returns a new stream with the function applied to every value
emitted by the stream. In short, a `map` function.

@@ -226,5 +236,5 @@ ```javascript

Flyd includes a similar map function as part of its core.
Flyd includes a similar `map` function as part of its core.
### Reducing a stream
### Scaning a stream

@@ -243,8 +253,57 @@ Lets try something else: a scan function for accumulating a stream! It could

Our scan function takes a accumulator function, in initial value and a stream.
Every time the original stream emit a value we pass it to the accumulator along
with the accumulated value.
Our scan function takes an accumulator function, in initial value and a stream.
Every time the original stream emit a value we pass it to the accumulator
function along with the accumulated value.
Flyd includes a scan function as part of its core.
Flyd includes a `scan` function as part of its core.
### Stream endings
When you create a stream with `flyd.stream` it will have an `end` property
which is also a stream. That is an _end stream_:
```javascript
var s = flyd.stream();
console.log(flyd.isStream(s.end)); // logs `true`
```
You can end a stream by pushing `true` into its end stream:
```javascript
var s = flyd.stream();
s.end(true); // this ends `s`
```
When you create a dependent stream it's end stream will initially depend on all
the ends streams of its dependencies:
```javascript
var n1 = flyd.stream();
var n2 = flyd.stream();
var sum = flyd.stream([n1, n2], function() {
return n1() + n2();
});
```
`sum.end` now depends on `n1.end` and `n2.end`. This means that whenever one of
the `sum`s dependencies end `sum` will end as well.
You can change what a streams end stream depends on with `flyd.endsOn`:
```javascript
var n1 = flyd.stream();
var n2 = flyd.stream();
var killer = flyd.stream();
var sum = flyd.endsOn([n1.end, n2.end, killer], flyd.stream([n1, n2], function() {
return n1() + n2();
}));
```
Now `sum` will end if either `n1` ends, `n2` ends or if `killer` emits a value.
The fact that a streams ending is itself a stream is a very powerful concept.
It means that we can use the full expresivenes of Flyd to control when a stream
ends. For an example, take a look at the implementation of
[`takeUntil`](https://github.com/paldepind/flyd-takeuntil).
### Fin

@@ -257,17 +316,94 @@

### flyd.stream(dependencies, body[, doesNotRequireDeps])
### flyd.stream()
Creates a new stream.
Creates a new top level stream.
__Signature__
* `dependencies` (array) – The streams on which this stream depends.
* `body` (function) – The function body of the stream.
* \[`doesNotRequireDeps`\] (boolean) – If `true` the function body can be
invoked even before all dependencies have a value.
`a -> Stream a`
__Returns__
__Example__
```javascript
var n = stream(1); // Stream with initial value `1`
var s = stream(); // Stream with no initial value
```
The created stream.
### flyd.stream(dependencies, body)
Creates a new dependent stream.
__Signature__
`[Stream *] -> (Stream b -> [Stream *] -> b) -> Stream b`
__Example__
```javascript
var n1 = flyd.stream(0);
var n2 = flyd.stream(0);
var max = flyd.stream([n1, n2], function(self, changed) {
return n1() > n2() ? n1() : n2();
});
```
###flyd.isStream(stream)
Returns `true` if the supplied argument is a Flyd stream and `false` otherwise.
__Signature__
`* -> Boolean`
__Example__
```javascript
var s = flyd.stream(1);
var n = 1;
flyd.isStream(s); //=> true
flyd.isStream(n); //=> false
```
###flyd.immediate(stream)
By default the body of a dependent stream is only called when all the streams
upon which it depends has a value. `immediate` can circumvent this behaviour.
It immediately invokes the body of a dependent stream.
__Signature__
`Stream a -> Stream a`
__Example__
```javascript
var s = flyd.stream();
var hasItems = flyd.immediate(flyd.stream([s], function() {
return s() !== undefined && s().length > 0;
});
console.log(hasItems()); // logs `false`. Had `immediate` not been
// used `hasItems()` would've returned `undefined`
s([1]);
console.log(hasItems()); // logs `true`.
s([]);
console.log(hasItems()); // logs `false`.
```
###flyd.endsOn(endStream, s)
Changes which `endsStream` should trigger the ending of `s`.
__Signature__
`Stream a -> Stream b -> Stream b`
__Example__
```javascript
var n = flyd.stream(1);
var killer = flyd.stream();
// `double` ends when `n` ends or when `killer` emits any value
var double = flyd.endsOn(flyd.merge(n.end, killer), flyd.stream([n], function() {
return 2 * n();
});
```
###flyd.map(fn, s)

@@ -348,21 +484,2 @@

###flyd.destroy(stream)
If the stream has no dependencies this will detach it from any streams it
depends on. This makes it available for garbage collection if there are no
additional references to it.
__Signature__
`Stream -> undefined`
__Example__
```javascript
var s = flyd.map(function() { /* something */ }, someStream);
flyd.destroy(s);
s = undefined;
// `s` can be garbage collected
```
###flyd.curryN(n, fn)

@@ -385,19 +502,2 @@

###flyd.isStream(stream)
Returns `true` if the supplied argument is a Flyd stream and `false` otherwise.
__Signature__
`* -> Boolean`
__Example__
```javascript
var s = flyd.stream(1);
var n = 1;
flyd.isStream(s); //=> true
flyd.isStream(n); //=> false
```
###stream()

@@ -433,2 +533,7 @@

###stream.end
A stream that emits `true` when the stream ends. If `true` is pushed down the
stream the parent stream ends.
###stream.map(f)

@@ -504,2 +609,3 @@

* [flyd-scanmerge](https://github.com/paldepind/flyd-scanmerge) – Merge and scan several streams into one.
* [flyd-takeuntil](https://github.com/paldepind/flyd-takeuntil) – Emit values from a stream until a second stream emits a value.
* Time related

@@ -513,3 +619,3 @@ * [flyd-aftersilence](https://github.com/paldepind/flyd-aftersilence) – Buffers values from a source stream in an array and emits it after a specified duration of silience from the source stream.

Consider code like the following
Consider the following example:

@@ -525,9 +631,26 @@ ```javascript

The dependency graph looks like this.
```
a
/ \
b c
\ /
d
```
Now, when a value flows down `a`, both `b` and `c` will change because they
depend on `a`. If you merely consider streams as being events you'd expect `d`
depend on `a`. If you merely consider streams as being event emitters you'd expect `d`
to be updated twice. Because `a` triggers `b` triggers `d` after which `a` also
twiggers `c` which again triggers `d`. But Flyd will handle this better.
Since only one value entered the system `d` will only be updated once with the
changed values of `b` and `c`. This avoids superfluous updates of your streams.
twiggers `c` which _again_ triggers `d`.
But Flyd handles such cases optimally. Since only one value entered the
system `d` will only be updated once with the changed values of `b` and `c`.
Flyd gurantees that when a single value enters the system every stream will
only be updated once and with all it's dependencies in their most recent state.
This avoids superfluous updates of your streams and intermediate states when
several stream change at the same time.
### Environment support

@@ -534,0 +657,0 @@

@@ -204,3 +204,4 @@ var assert = require('assert');

s.end(true);
assert(s.ended);
assert(s.end());
assert(s.end());
});

@@ -218,3 +219,3 @@ it('detaches it from dependencies', function() {

assert.equal(x.listeners.length, 0);
assert(sum.ended);
assert(sum.end());
});

@@ -231,7 +232,7 @@ it('ends its dependents', function() {

x.end(true);
assert(x.ended);
assert(x.end());
assert.equal(x.listeners.length, 0);
assert(y.ended);
assert(y.end());
assert.equal(y.listeners.length, 0);
assert(z.ended);
assert(z.end());
});

@@ -249,9 +250,9 @@ it('updates children if stream ends after recieving value', function() {

assert.equal(y(), z());
assert(!y.ended);
assert(!z.ended);
assert(!y.end());
assert(!z.end());
x(0);
assert.equal(x.listeners.length, 1);
assert(y.ended);
assert(y.end());
assert.equal(y.listeners.length, 0);
assert(z.ended);
assert(z.end());
assert.equal(2, y());

@@ -267,4 +268,26 @@ assert.equal(2, z());

x(2);
assert.equal(undefined, y.end());
assert.equal(2 * x(), y());
});
it('end stream does not have value even if base stream has initial value', function() {
var killer = stream(true);
var x = stream(1);
var y = flyd.endsOn(killer, stream([x], function(self) {
return 2 * x();
}));
assert.equal(false, y.end.hasVal);
});
it('ends stream can be changed without affecting listeners', function() {
var killer1 = stream();
var killer2 = stream();
var ended = false;
var x = stream(1);
var y = flyd.endsOn(killer1, stream([x], function(self) {
return 2 * x();
}));
flyd.map(function() { ended = true; }, y.end);
flyd.endsOn(killer2, y);
killer2(true);
assert(ended);
});
});

@@ -392,6 +415,6 @@ describe('promise integration', function() {

s1.end(true);
assert(!s1and2.ended);
assert(!s1and2.end());
s2(12)(2);
s2.end(true);
assert(s1and2.ended);
assert(s1and2.end());
assert.deepEqual(result, [12, 2, 4, 44, 1, 12, 2]);

@@ -518,2 +541,18 @@ });

});
it('handles reduced stream and ends', function() {
var result = [];
var s1 = stream();
var tx = t.compose(
t.map(function(x) { return x * 2; }),
t.take(3)
);
var s2 = flyd.transduce(tx, s1);
stream([s2], function() { result.push(s2()); });
s1(1)(2);
assert.notEqual(true, s2.end());
s1(3);
assert.equal(true, s2.end());
s1(4);
assert.deepEqual(result, [2, 4, 6]);
});
});

@@ -520,0 +559,0 @@ describe('Ramda transducer support', function() {

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc