Functional reactive programming library for TypeScript and JavaScript

Overview

Bacon.js

A functional reactive programming lib for TypeScript JavaScript, written in TypeScript.

Turns your event spaghetti into clean and declarative feng shui bacon, by switching from imperative to functional. It's like replacing nested for-loops with functional programming concepts like map and filter. Stop working on individual events and work with event streams instead. Combine your data with merge and combine. Then switch to the heavier weapons and wield flatMap and combineTemplate like a boss.

Here's the stuff.

Build Status BrowserStack Status NPM version Dependency Status devDependency Status

Install and Usage

Typescript

Bacon.js starting from version 3.0 is a Typescript library so you won't need any external types. Just Install using npm.

npm install baconjs

Then you can

import { EventStream, once } from "baconjs"

let s: EventStream<string> = once("hello")
s.log()

As you can see, the global methods, such as once are imported separately.

Check out the new API Documentation, that's now generated using Typedoc from the Typescript source code.

Modern ES6 Browser, Node.js v.12+

You can directly import Bacon.js as single aggregated ES6 module.

import * as Bacon from 'node_modules/baconjs/dist/Bacon.mjs';
Bacon.once("hello").log();

NPM, CommonJS, Node.js

If you're on to CommonJS (node.js, webpack or similar) you can install Bacon using npm.

npm install baconjs

Try it like this:

node
Bacon=require("baconjs")
Bacon.once("hello").log()

The global methods, such as once are available in the Bacon object.

Bower

For bower users:

bower install bacon

CDN / Script Tags

Both minified and unminified versions available on cdnjs.

So you can also include Bacon.js using

<script src="https://cdnjs.cloudflare.com/ajax/libs/bacon.js/2.0.9/Bacon.js"></script>
<script>
Bacon.once("hello").log()
</script>

AMD / require.js

Bacon.js is an UMD module so it should work with AMD/require.js too. Not tested lately though.

Github

Prefer to drink from the firehose? Download from Github master.

Intro

The idea of Functional Reactive Programming is quite well described by Conal Elliot at Stack Overflow.

Bacon.js is a library for functional reactive programming. Or let's say it's a library for working with events in EventStreams and dynamic values (which are called Properties in Bacon.js).

You can wrap an event source, say "mouse clicks on a DOM element" into an EventStream by saying

let $ = (selector) => document.querySelector(selector) 
var clickE = Bacon.fromEvent($("h1"), "click")

The $ helper function above could be replaced with, for instance, jQuery or Zepto.

Each EventStream represents a stream of events. It is an Observable, meaning that you can listen to events in the stream using, for instance, the onValue method with a callback. Like this:

clickE.onValue(() => alert("you clicked the h1 element") )

But you can do neater stuff too. The Bacon of Bacon.js is that you can transform, filter and combine these streams in a multitude of ways (see EventStream API). The methods map, filter, for example, are similar to same functions in functional list programming (like Underscore). So, if you say

let plusE = Bacon.fromEvent($("#plus"), "click").map(1)
let minusE = Bacon.fromEvent($("#minus"), "click").map(-1)
let bothE = plusE.merge(minusE)

.. you'll have a stream that will output the number 1 when the "plus" button is clicked and another stream outputting -1 when the "minus" button is clicked. The bothE stream will be a merged stream containing events from both the plus and minus streams. This allows you to subscribe to both streams with one handler:

bothE.onValue(val => { /* val will be 1 or -1 */ console.log(val) })

Note that you can also use the log method to log stream values to console:

bothE.log()

In addition to EventStreams, bacon.js has a thing called Property, that is almost like an EventStream, but has a "current value". So things that change and have a current state are Properties, while things that consist of discrete events are EventStreams. You could think mouse clicks as an EventStream and mouse cursor position as a Property. You can create Properties from an EventStream with scan or toProperty methods. So, let's say

let add = (x, y) => x + y
let counterP = bothE.scan(0, add)
counterP.onValue(sum => $("#sum").textContent = sum )

The counterP property will contain the sum of the values in the bothE stream, so it's practically a counter that can be increased and decreased using the plus and minus buttons. The scan method was used here to calculate the "current sum" of events in the bothE stream, by giving a "seed value" 0 and an "accumulator function" add. The scan method creates a property that starts with the given seed value and on each event in the source stream applies the accumulator function to the current property value and the new value from the stream.

Hiding and showing the result div depending on the content of the property value is equally straightforward

let hiddenIfZero = value => value == 0 ? "hidden" : "visible"
counterP.map(hiddenIfZero)
  .onValue(visibility => { $("#sum").style.visibility = visibility })

For an actual (though a bit outdated) tutorial, please check out my blog posts

API

Creating EventStreams and Properties

There's a multitude of methods for creating an EventStream from different sources, including the DOM, node callbacks and promises for example. See EventStream documentation.

Properties are usually created based on EventStreams. Some common ways are intruduced in Property documentation.

Combining multiple streams and properties

You can combine the latest value from multple sources using combine, combineAsArray, combineWith or combineTemplate.

You can merge multiple streams into one using merge or mergeAll.

You can concat streams using concat or concatAll.

If you want to get the value of an observable but emit only when another stream emits an event, you might want to use sampledBy or its cousin withLatestFrom.

Latest value of Property or EventStream

One of the common first questions people ask is "how do I get the latest value of a stream or a property". There is no getLatestValue method available and will not be either. You get the value by subscribing to the stream/property and handling the values in your callback. If you need the value of more than one source, use one of the combine methods.

Bus

Bus is an EventStream that allows you to push values into the stream. It also allows plugging other streams into the Bus.

Event

There are essentially three kinds of Events that are emitted by EventStreams and Properties:

  • Value events that convey a value. If you subscribe using onValue, you'll only deal with values. Also map, filter and most of the other operators also deal with values only.
  • Error events indicate that an error has occurred. More on errors below!
  • End event is emitted at most once, and is always the last event emitted by an Observable.

If you want to subscribe to all events from an Observable, you can use the subscribe method.

Errors

Error events are always passed through all stream operators. So, even if you filter all values out, the error events will pass through. If you use flatMap, the result stream will contain Error events from the source as well as all the spawned stream.

You can take action on errors by using onError.

See also mapError, errors, skipErrors, Bacon.retry and flatMapError.

In case you want to convert (some) value events into Error events, you may use flatMap like this:

stream = Bacon.fromArray([1,2,3,4]).flatMap(function(x) {
  if (x > 2)
    return new Bacon.Error("too big")
  else
    return x
})

Conversely, if you want to convert some Error events into value events, you may use flatMapError:

myStream.flatMapError(function(error) {
  return isNonCriticalError(error) ? handleNonCriticalError(error) : new Bacon.Error(error)
})

Note also that Bacon.js operators do not catch errors that are thrown. Especially map doesn't do so. If you want to map things and wrap caught errors into Error events, you can do the following:

wrapped = source.flatMap(Bacon.try(dangerousOperation))

For example, you can use Bacon.try to handle JSON parse errors:

var jsonStream = Bacon
  .once('{"this is invalid json"')
  .flatMap(Bacon.try(JSON.parse))

jsonStream.onError(function(err) {
  console.error("Failed to parse JSON", err)
})

An Error does not terminate the stream. The method endOnError returns a stream/property that ends immediately after the first error.

Bacon.js doesn't currently generate any Error events itself (except when converting errors using fromPromise). Error events definitely would be generated by streams derived from IO sources such as AJAX calls.

See retry for retrying on error.

Introspection and metadata

Bacon.js provides ways to get some descriptive metadata about all Observables.

See toString, deps, desc, spy.

Changes to earlier versions

Function Construction rules removed in 3.0

Function construction rules, which allowed you to use string shorthands for properties and methods, were removed in version 3.0, as they are not as useful as they used to be, due to the moderd, short lambda syntax in ES6 and Typescript, as well as libraries like Ramda and partial.lenses.

Lazy evaluation removed in 2.0

Lazy evaluation of event values has been removed in version 2.0

Cleaning up

As described above, a subscriber can signal the loss of interest in new events in any of these two ways:

  1. Return noMore from the handler function
  2. Call the dispose() function that was returned by the subscribe or onValue call.

Based on my experience, an actual side-effect subscriber in application-code almost never does this. Instead you'll use methods like takeUntil to stop listening to a source when something happens.

EventStream and Property semantics

The state of an EventStream can be defined as (t, os) where t is time and os the list of current subscribers. This state should define the behavior of the stream in the sense that

  1. When a Next event is emitted, the same event is emitted to all subscribers
  2. After an event has been emitted, it will never be emitted again, even if a new subscriber is registered. A new event with the same value may of course be emitted later.
  3. When a new subscriber is registered, it will get exactly the same events as the other subscriber, after registration. This means that the stream cannot emit any "initial" events to the new subscriber, unless it emits them to all of its subscribers.
  4. A stream must never emit any other events after End (not even another End)

The rules are deliberately redundant, explaining the constraints from different perspectives. The contract between an EventStream and its subscriber is as follows:

  1. For each new value, the subscriber function is called. The new value is wrapped into a Next event.
  2. The subscriber function returns a result which is either noMore or more. The undefined value is handled like more.
  3. In case of noMore the source must never call the subscriber again.
  4. When the stream ends, the subscriber function will be called with and End event. The return value of the subscribe function is ignored in this case.

A Property behaves similarly to an EventStream except that

  1. On a call to subscribe, it will deliver its current value (if any) to the provided subscriber function wrapped into an Initial event.
  2. This means that if the Property has previously emitted the value x to its subscribers and that is the latest value emitted, it will deliver this value to the new subscriber.
  3. Property may or may not have a current value to start with. Depends on how the Property was created.

Atomic updates

Bacon.js supports atomic updates to properties for solving a glitches problem.

Assume you have properties A and B and property C = A + B. Assume that both A and B depend on D, so that when D changes, both A and B will change too.

When D changes d1 -> d2, the value of A a1 -> a2 and B changes b1 -> b2 simultaneously, you'd like C to update atomically so that it would go directly a1+b1 -> a2+b2. And, in fact, it does exactly that. Prior to version 0.4.0, C would have an additional transitional state like a1+b1 -> a2+b1 -> a2+b2

For jQuery users

Earlier versions of Bacon.js automatically installed the asEventStream method into jQuery. Now, if you still want to use that method, initialize this integration by calling Bacon.$.init($) .

For RxJs Users

Bacon.js is quite similar to RxJs, so it should be pretty easy to pick up. The major difference is that in bacon, there are two distinct kinds of Observables: the EventStream and the Property. The former is for discrete events while the latter is for observable properties that have the concept of "current value".

Also, there are no "cold observables", which means also that all EventStreams and Properties are consistent among subscribers: when an event occurs, all subscribers will observe the same event. If you're experienced with RxJs, you've probably bumped into some wtf's related to cold observables and inconsistent output from streams constructed using scan and startWith. None of that will happen with bacon.js.

Error handling is also a bit different: the Error event does not terminate a stream. So, a stream may contain multiple errors. To me, this makes more sense than always terminating the stream on error; this way the application developer has more direct control over error handling. You can always use endOnError to get a stream that ends on the first error!

Examples

See Examples

See Specs

See Worzone demo and source

Build

First check out the Bacon.js repository and run npm install.

Then build the Typescript sources into a javascript bundle (plus typescript type definitions):

npm run dist

Result javascript files will be generated in dist directory. If your planning to develop Bacon.js yourself, you'll want to run [tests] too using npm test.

Test

Run all unit tests:

npm test

The tests are run against the javascript bundle in the dist directory. You can build the bundle using npm run dist.

This will loop thru all files under spec and build the library with the single feature and run the test.

Run browser tests locally:

npm install
npm run browsertest-bundle
npm rum browsertest-open

Run performance tests:

performance/PerformanceTest.coffee
performance/PerformanceTest.coffee flatmap

Run memory usage tests:

coffee --nodejs '--expose-gc' performance/MemoryTest.coffee

Dependencies

Runtime: none Build/test: see [package.json].

Compatibility with other libs

Bacon.js doesn't mess with prototypes or the global object, except that it exports the Bacon object as window.Bacon when installed using the <script> tag.

So, it should be pretty much compatible and a nice citizen.

I'm not sure how it works in case some other lib adds stuff to, say, Array prototype, though. Maybe add test for this later?

Compatibility with browsers

TLDR: good.

Bacon.js is not browser dependent, because it is not a UI library. It should work on all ES5-ish runtimes.

Automatically tested on each commit on modern browsers in Browserstack.

Why Bacon?

Bacon.js exists largely because I got frustrated with RxJs, which is a good library, but at that time didn't have very good documentation and wasn't open-source. Things have improved a lot in the Rx world since that. Yet, there are still compelling reasons to use Bacon.js instead. Like, for instance,

  • more consistent stream/property behavior
  • simplicity of use
  • atomic updates

If you're more into performance and less into atomic updates, you might want to check out Kefir.js!

Contribute

Use GitHub issues and Pull Requests.

Note:

  • the dist/Bacon*.js files are assembled from files in src/. After updating source files, run npm install to update the generated files. Then commit and create your Pull Request.
  • the API docs are generated from this README and docstrings in the sources in the src directory. See the baconjs.github.io repository for more info.

Sponsors

Thanks to BrowserStack for kindly providing me with free of charge automatic testing time.

Thanks also to Reaktor for supporting Bacon.js development and letting me use some of my working hours on open-source development.

Comments
  • Website (and logo)

    Website (and logo)

    I'm planning on setting up a website for bacon.js. So far, I've got some ideas.

    This is something I'll need help with. I ain't got mad skillzz with Photoshop, for instance.

    I'm thinking something more in the spirit of

    francis

    than

    mrbacon

    opened by raimohanska 37
  • Coffeescript to ES6

    Coffeescript to ES6

    What do you think if we move the project forward migrating the current coffeescript code to javascript next? I think we could transpile it using https://6to5.github.io/

    opened by GianlucaGuarini 32
  • Bacon.js 0.8

    Bacon.js 0.8

    What shall we include in the next "major" release? I'm thinking about making some (minor) breaking changes there, like

    • Get rid of the Bus().toProperty() FAQ/WTF situation (https://github.com/baconjs/bacon.js/wiki/FAQ#why-isnt-my-property-updated). Bus.toProperty should probly be a special case.
    • Get rid of issues with synchronous sources (https://github.com/baconjs/bacon.js/wiki/FAQ#why-isnt-my-subscriber-called), also #367. Streams should defer output to make sure everyone gets properly served.
    • Make onValue and friends chainable (#382)
    • Make Bacon.sequentially output first value immediately instead of delaying. Only the consequtive values should be delayed

    What do you think?

    Edit: possibly also:

    • Remove lazy evaluation (#465)
    • Simplify side-effect dispatching (#399, #470). Guarantee correct ordering. Actually removing laziness makes this easier.
    • Persist latest error on property (#548)
    • Wipe outdated value of Property (#536)

    Status:

    • Started working in the 0.8 branch
    • Chaining onX implemented
    • Bacon.once and Bacon.fromArray were changed to be async
    enhancement 0.8 
    opened by raimohanska 30
  • RangeError: Maximum call stack size exceeded

    RangeError: Maximum call stack size exceeded

    This code fails with "RangeError: Maximum call stack size exceeded" after a short time.

    var Bacon = require('baconjs');
    
    function step() {
      return Bacon.later(1, 'beep');
    }
    
    function loop() {
      var s = step();
      return s.merge(s.delay(1).flatMap(loop));
    }
    
    loop().log();
    

    Seems like I independently ran into this issue, but I don't think an issue was opened here for it.

    enhancement 
    opened by Macil 28
  • Generalized `sampledBy` for dealing with glitches by hand

    Generalized `sampledBy` for dealing with glitches by hand

    As glitches issue not fixed completely (https://github.com/baconjs/bacon.js/issues/353) I propose to introduce more generalized sampledBy for thouse people who want to deal with glitches by hand.

    Here is the signature:

    Bacon.sampledBy(
      [streamA, streamB...], 
      [samplerC, samplerD...], 
      (a, b... c, d...) ->
        ...
    )
    

    It is basically same as stream.sampledBy(sampler, fn), but with multiple streams and sampler streams.

    How it may help with glitches? For example you have four streams A, B, C, and D. And you know than A and B has common original stream (they always trigger simultaneously), and so do C and D. And you need to combine all those four streams. Having Bacon.sampledBy you can instead of doing this:

    Bacon.combineWith (a, b, c, d) ->
      ...
    , A, B, C, D
    

    do:

    Bacon.sampledBy [a, c], [b, d], (a, c, b, d) ->
      ...
    

    And have same result as with combineWith, but without need of inspecting dependencies and trying to get rid of glitches automatically.

    What do you think? :)

    opened by rpominov 25
  • Should awaiting delay its right argument?

    Should awaiting delay its right argument?

    Let's say I have to streams a and b and I define waiting = a.waiting(b).

    Now, let's say both a and b publish synchronously. The value of waiting is now true or false, where the value depends on subscription order.

    We could fix this by by defining waiting = a.waiting(b.delay(0))

    Should we make this the default behavior? It seems fairly safe to assume that in the case where both streams publish synchronously, we'd want to assume no waiting is happening.

    I ran into this issue when caching some API requests, (making them publish synchronously) , and proceeded to redefine this combinator thusly, I'd say it makes sense. What's your take?

    opened by philipnilsson 24
  • Atomic updates to Properties

    Atomic updates to Properties

    Assume you have properties A and B and property C = A + B. Assume that both A and B depend on D, so that when D changes, both A and B will change too.

    When D changes d1 -> d2, the value of A a1 -> a2 and B changes b1 -> b2 simultaneously, you'd like C to update atomically so that it would go directly a1+b1 -> a2+b2. Unfortunately, Bacon.js does not recognize simultaneous events/updates and C will have a transitional state like a1+b1 -> a2+b1 -> a2+b2

    opened by raimohanska 23
  • flatMapLatest glitch

    flatMapLatest glitch

    Consider the following setup:

    B = require 'baconjs'
    
    trace = (obs, name) ->
      obs.subscribeInternal (e) ->
        desc = if e.hasValue() then e.value() else '' + e
        console.log name + ':', desc
    
    traceAll = (obss) -> trace(obs, name) for name, obs of obss
    
    changes = new B.Bus
    
    a = changes.map '.a'
    b = changes.map '.b'
    
    ab = B.combineAsArray a, b
    
    f = ab.flatMapLatest (values) ->
      valuesDesc = "( #{ values.join ', ' } )"
      console.log 'inside flatMapLatest: ' + valuesDesc
      B.once 'f' + valuesDesc
    
    fb = B.combineAsArray f, b
    
    traceAll { a, b, ab, f, fb }
    
    changes.push
      a: 'a_0'
      b: 'b_0'
    
    console.log '-------------------------------'
    
    changes.push
      a: 'a_1'
      b: 'b_1'
    
    console.log '-------------------------------'
    
    console.log 'fb depends on f:', fb.dependsOn f
    console.log 'fb depends on b:', fb.dependsOn b
    console.log 'fb depends on ab:', fb.dependsOn ab
    console.log 'fb depends on a:', fb.dependsOn a
    console.log 'fb depends on b:', fb.dependsOn b
    

    ... and the output:

    a: a_0
    b: b_0
    ab: [ 'a_0', 'b_0' ]
    inside flatMapLatest: ( a_0, b_0 )
    f: f( a_0, b_0 )
    fb: [ 'f( a_0, b_0 )', 'b_0' ]
    -------------------------------
    a: a_1
    b: b_1
    ab: [ 'a_1', 'b_1' ]
    inside flatMapLatest: ( a_1, b_1 )
    fb: [ 'f( a_0, b_0 )', 'b_1' ]
    f: f( a_1, b_1 )
    fb: [ 'f( a_1, b_1 )', 'b_1' ]
    -------------------------------
    fb depends on f: true
    fb depends on b: true
    fb depends on ab: true
    fb depends on a: true
    fb depends on b: true
    

    Notice the glitch after the second push (fb = [ 'f( a_0, b_0 )', 'b_1' ]). Is this a correct behavior?

    If I change flatMapLatest to flatMap, the glitch disappears.

    bug 
    opened by skozin 22
  • Add flatMapWithConcurrencyLimit, flatMapConcat, bufferingThrottle, holdWhen

    Add flatMapWithConcurrencyLimit, flatMapConcat, bufferingThrottle, holdWhen

    Related to #318 I implemented a flatMapWithConcurrencyLimit method that's a flatMap variant that limits the number of open spawned streams. It buffers incoming events to keep from losing any input.

    Then I applied the new combinator to create flatMapConcat that's just a shorthand for the previous with limit==1. The default flatMap implementation can be thought of "flatMapMerge" because it merges the output of spawned streams.

    Finally, I implemented rateLimit as a one-liner on top of flatMapConcat. This is the combinator that was requested in #317 and once implemented in #82 as "limitThroughPut".

    And then I added one more thing holdWhen that's the same thing as bufferWhile in #300, also based on flatMapConcat. I chose this name not to confuse this method with the "buffer" family of methods or the takeWhile/skipWhile methods.

    DON'T MERGE YET!

    TODO: still naming..

    opened by raimohanska 22
  • Glitch-free updates

    Glitch-free updates

    A glitch in FRP is a temporary violation of an invariant.

    For instance, if you use Bacon.js 0.6.x and run this

    a = Bacon.sequentially(10, [1, 2])
    b = a.map((x) -> x * 2)
    c = Bacon.combineAsArray([a, b])
    c.log()
    

    You'll get

    [ 1, 2 ]
    [ 2, 2 ]
    [ 2, 4 ]
    

    where the pair [2,2] is a glitch that occurs because c is updated first by the changed value of a and the the changed value of b. In glitch-free FRP you should get just

    [ 1, 2 ]
    [ 2, 4 ]
    

    In the feature/dependency-graph-dispatch I'm working on an improved event dispatching mechanism that depends on a dependency-tree to guarantee glitch-free updates. This will improve the reliability of all the combine* methods as well as sampledBy and takeUntil.

    I'm planning to release version 0.7.0 with this new dispatch mechanism. Currently, it's still work-in-progress and I'd be very glad to get comments and/or pull requests to get more test coverage and fix possible bugs.

    opened by raimohanska 22
  • Add Bacon.try

    Add Bacon.try

    Bacon.try is a shorthand for

    o.flatMap(v => { 
      try {
        return f(v)
      } catch (e) {
        return new Bacon.Error(e)
      }
    })
    

    The README contains an example of how to use Bacon.try.

    Edit: renamed try to tryMap. Edit2: renamed Observable#tryMap to Bacon.try

    opened by laurilehmijoki 20
  • Bump flat and mocha

    Bump flat and mocha

    Bumps flat to 5.0.2 and updates ancestor dependency mocha. These dependencies need to be updated together.

    Updates flat from 4.1.0 to 5.0.2

    Commits
    • e5ffd66 Release 5.0.2
    • fdb79d5 Update dependencies, refresh lockfile, format with standard.
    • e52185d Test against node 14 in CI.
    • 0189cb1 Avoid arrow function syntax.
    • f25d3a1 Release 5.0.1
    • 54cc7ad use standard formatting
    • 779816e drop dependencies
    • 2eea6d3 Bump lodash from 4.17.15 to 4.17.19
    • a61a554 Bump acorn from 7.1.0 to 7.4.0
    • 20ef0ef Fix prototype pollution on unflatten
    • Additional commits viewable in compare view
    Maintainer changes

    This version was pushed to npm by timoxley, a new releaser for flat since your current version.


    Updates mocha from 7.1.1 to 10.2.0

    Release notes

    Sourced from mocha's releases.

    v10.2.0

    10.2.0 / 2022-12-11

    :tada: Enhancements

    • #4945: API: add possibility to decorate ESM name before import (@​j0tunn)

    :bug: Fixes

    :book: Documentation

    v10.1.0

    10.1.0 / 2022-10-16

    :tada: Enhancements

    :nut_and_bolt: Other

    v10.0.0

    10.0.0 / 2022-05-01

    :boom: Breaking Changes

    :nut_and_bolt: Other

    ... (truncated)

    Changelog

    Sourced from mocha's changelog.

    10.2.0 / 2022-12-11

    :tada: Enhancements

    • #4945: API: add possibility to decorate ESM name before import (@​j0tunn)

    :bug: Fixes

    :book: Documentation

    10.1.0 / 2022-10-16

    :tada: Enhancements

    :nut_and_bolt: Other

    10.0.0 / 2022-05-01

    :boom: Breaking Changes

    :nut_and_bolt: Other

    ... (truncated)

    Commits

    Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


    Dependabot commands and options

    You can trigger Dependabot actions by commenting on this PR:

    • @dependabot rebase will rebase this PR
    • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
    • @dependabot merge will merge this PR after your CI passes on it
    • @dependabot squash and merge will squash and merge this PR after your CI passes on it
    • @dependabot cancel merge will cancel a previously requested merge and block automerging
    • @dependabot reopen will reopen this PR if it is closed
    • @dependabot close will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
    • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
    • @dependabot use these labels will set the current labels as the default for future PRs for this repo and language
    • @dependabot use these reviewers will set the current reviewers as the default for future PRs for this repo and language
    • @dependabot use these assignees will set the current assignees as the default for future PRs for this repo and language
    • @dependabot use this milestone will set the current milestone as the default for future PRs for this repo and language

    You can disable automated security fix PRs for this repo from the Security Alerts page.

    dependencies 
    opened by dependabot[bot] 0
  • .withLatestFrom(later(1,

    .withLatestFrom(later(1, "foo"), …) depends on JS runtime

    B.later(1, "foo") is like B.later(0, "foo") but only when running in Node – as different from when running in browsers.

    demo code:

    const B = require('baconjs'),
       concat = (a, b) => a + b, 
       s = B.once('foo').withLatestFrom(B.later(1, 'bar'), concat);
    // let it run
    s.onValue(console.log)
    

    For a nice surprise execute that in Node, e.g. from a project shell where baconjs is installed:

    node -e "const B = require('baconjs'), concat = (a, b) => a + b, unsub = B.once('foo').withLatestFrom(B.later(1, 'bar'), concat).onValue(console.log)"
    # -> foobar
    

    whereas in browser dev tools there is no event output :

    import('./node_modules/baconjs/dist/Bacon.mjs').then(m => { globalThis.B = m; });
    var concat = (a, b) => a + b;
    var unsub = B.once("foo")
    .withLatestFrom(B.later(1, "bar"), concat)
    .onValue(s => { console.log(`sampled: "${s}"`); })
    

    I guess I have to treat synchronicity or atomic updates with a grain of salt. 🤔

    opened by semmel 0
  • Cannot use JS objects which throw on undefined property access

    Cannot use JS objects which throw on undefined property access

    An example of such an "exotic" object is the Cross-Origin WindowProxy object. It throws when trying to access (i.e. getOwnProperty) any property other than the handful of allowed properties.

    Observed behaviour:

    Combining an observable of WindowProxy with any other observable will generate a DOM SecurityError ("Blocked a frame from accessing a cross-origin frame…")

    Reason:

    The implementation of combine calls isObservable on the stream value. isObservable is simply winProxy._isObservable which fails.

    Solution:

    Can't see any. Switching to winProxy instanceof Observable from winProxy._isObservable would work, but that was in #639 deliberately introduced to support X-frame observables I guess.

    Not understanding the code, I guess combine needs to do some dependency checks and therefore inspects the incoming stream values. So no way to remove that – at first glance – useless check.

    Workaround:

    Wrap/Unwrap "exotic" objects before injecting into/when extracting from bacon streams. E.g. use (Edit:) ~~[windowProxy]~~ an object wrapper {windowProxy} as stream value.

    Edit:

    You cannot wrap the "exotic" object in a simple Array, because that gets flattened internally and it's items inspected (._isObservable) as well.

    Maybe another topic, but

    I don't expect my array-type stream events being accessed in any way (here being iterated over) by the reactive stream library for internal purposes. 😮

    I mean; isn't the deal, that I put my things into the stream, which conveys the things to my combiners and my consumers?

    Demo:

    On JSitor REPL

    B.fromEvent(button, 'click')
        .map(() => open(
          "https://example.com", 
          "demo-popup", 
          "popup,width=200,height=200"
        ))
        //.map(_ => [_])   // Edit: NO workaround
        //.map(proxy => ({proxy}))  // workaround
        .delay(2000)  // wait for example.com to respond
        .combine(B.constant("foo"), pair)
        .onValue(([, foo]) => { console.log(foo); });
    
    opened by semmel 0
  • Bump terser from 4.6.11 to 4.8.1

    Bump terser from 4.6.11 to 4.8.1

    Bumps terser from 4.6.11 to 4.8.1.

    Changelog

    Sourced from terser's changelog.

    v4.8.1 (backport)

    • Security fix for RegExps that should not be evaluated (regexp DDOS)

    v4.8.0

    • Support for numeric separators (million = 1_000_000) was added.
    • Assigning properties to a class is now assumed to be pure.
    • Fixed bug where yield wasn't considered a valid property key in generators.

    v4.7.0

    • A bug was fixed where an arrow function would have the wrong size
    • arguments object is now considered safe to retrieve properties from (useful for length, or 0) even when pure_getters is not set.
    • Fixed erroneous const declarations without value (which is invalid) in some corner cases when using collapse_vars.

    v4.6.13

    • Fixed issue where ES5 object properties were being turned into ES6 object properties due to more lax unicode rules.
    • Fixed parsing of BigInt with lowercase e in them.

    v4.6.12

    • Fixed subtree comparison code, making it see that [1,[2, 3]] is different from [1, 2, [3]]
    • Printing of unicode identifiers has been improved
    Commits

    Dependabot compatibility score

    Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


    Dependabot commands and options

    You can trigger Dependabot actions by commenting on this PR:

    • @dependabot rebase will rebase this PR
    • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
    • @dependabot merge will merge this PR after your CI passes on it
    • @dependabot squash and merge will squash and merge this PR after your CI passes on it
    • @dependabot cancel merge will cancel a previously requested merge and block automerging
    • @dependabot reopen will reopen this PR if it is closed
    • @dependabot close will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
    • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
    • @dependabot use these labels will set the current labels as the default for future PRs for this repo and language
    • @dependabot use these reviewers will set the current reviewers as the default for future PRs for this repo and language
    • @dependabot use these assignees will set the current assignees as the default for future PRs for this repo and language
    • @dependabot use this milestone will set the current milestone as the default for future PRs for this repo and language

    You can disable automated security fix PRs for this repo from the Security Alerts page.

    dependencies 
    opened by dependabot[bot] 0
  • Bump shell-quote from 1.7.2 to 1.7.3

    Bump shell-quote from 1.7.2 to 1.7.3

    Bumps shell-quote from 1.7.2 to 1.7.3.

    Changelog

    Sourced from shell-quote's changelog.

    1.7.3

    • Fix a security issue where the regex for windows drive letters allowed some shell meta-characters to escape the quoting rules. (CVE-2021-42740)
    Commits

    Dependabot compatibility score

    Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


    Dependabot commands and options

    You can trigger Dependabot actions by commenting on this PR:

    • @dependabot rebase will rebase this PR
    • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
    • @dependabot merge will merge this PR after your CI passes on it
    • @dependabot squash and merge will squash and merge this PR after your CI passes on it
    • @dependabot cancel merge will cancel a previously requested merge and block automerging
    • @dependabot reopen will reopen this PR if it is closed
    • @dependabot close will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
    • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
    • @dependabot use these labels will set the current labels as the default for future PRs for this repo and language
    • @dependabot use these reviewers will set the current reviewers as the default for future PRs for this repo and language
    • @dependabot use these assignees will set the current assignees as the default for future PRs for this repo and language
    • @dependabot use this milestone will set the current milestone as the default for future PRs for this repo and language

    You can disable automated security fix PRs for this repo from the Security Alerts page.

    dependencies 
    opened by dependabot[bot] 0
  • Bump minimist from 1.2.5 to 1.2.6

    Bump minimist from 1.2.5 to 1.2.6

    Bumps minimist from 1.2.5 to 1.2.6.

    Commits

    Dependabot compatibility score

    Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


    Dependabot commands and options

    You can trigger Dependabot actions by commenting on this PR:

    • @dependabot rebase will rebase this PR
    • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
    • @dependabot merge will merge this PR after your CI passes on it
    • @dependabot squash and merge will squash and merge this PR after your CI passes on it
    • @dependabot cancel merge will cancel a previously requested merge and block automerging
    • @dependabot reopen will reopen this PR if it is closed
    • @dependabot close will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
    • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
    • @dependabot use these labels will set the current labels as the default for future PRs for this repo and language
    • @dependabot use these reviewers will set the current reviewers as the default for future PRs for this repo and language
    • @dependabot use these assignees will set the current assignees as the default for future PRs for this repo and language
    • @dependabot use this milestone will set the current milestone as the default for future PRs for this repo and language

    You can disable automated security fix PRs for this repo from the Security Alerts page.

    dependencies 
    opened by dependabot[bot] 0
Owner
baconjs
Bacon.js library and related stuff
baconjs
Ultra-high performance reactive programming

________________________________ ___ |/ /_ __ \_ ___/__ __/ __ /|_/ /_ / / /____ \__ / _ / / / / /_/ /____/ /_ / /_/ /_/ \____/__

The Javascript Architectural Toolkit 3.5k Dec 28, 2022
State management that tailored for react, it is simple, predictable, progressive and efficient.

English | 简体中文 ⚡️ State management that tailored for react, it is simple, predictable, progressive and efficient. ?? Introduction Concent is an amazin

cencentjs 1.1k Dec 28, 2022
Marble.js - functional reactive Node.js framework for building server-side applications, based on TypeScript and RxJS.

Functional reactive Node.js framework for building server-side applications, based on TypeScript and RxJS. Ecosystem Name Description @marblejs/core F

Marble.js 2.1k Dec 16, 2022
Functional reactive UI library

reflex Reflex is a functional reactive UI library that is heavily inspired by (pretty much is a port of) elm and it's amazingly simple yet powerful ar

Mozilla 364 Oct 31, 2022
A reactive programming library for JavaScript

RxJS: Reactive Extensions For JavaScript RxJS 7 (beta) FOR 6.X PLEASE GO TO THE 6.x BRANCH Reactive Extensions Library for JavaScript. This is a rewri

ReactiveX 28.2k Dec 28, 2022
A functional and reactive JavaScript framework for predictable code

Cycle.js A functional and reactive JavaScript framework for predictable code Website | Packages | Contribute | Chat | Support Welcome Question Answer

Cycle.js 10.2k Jan 4, 2023
Grupprojekt för kurserna 'Javascript med Ramverk' och 'Agil Utveckling'

JavaScript-med-Ramverk-Laboration-3 Grupprojektet för kurserna Javascript med Ramverk och Agil Utveckling. Utvecklingsguide För information om hur utv

Svante Jonsson IT-Högskolan 3 May 18, 2022
Hemsida för personer i Sverige som kan och vill erbjuda boende till människor på flykt

Getting Started with Create React App This project was bootstrapped with Create React App. Available Scripts In the project directory, you can run: np

null 4 May 3, 2022
Kurs-repo för kursen Webbserver och Databaser

Webbserver och databaser This repository is meant for CME students to access exercises and codealongs that happen throughout the course. I hope you wi

null 14 Jan 3, 2023
Typescript library for functional programming.

Sa Lambda Typescript library for functional programming. Document TODO Either Maybe Iterator Pipe & Flow Task (Promise-Like) some math utils Installat

SoraLib 9 Dec 6, 2022
Ultra-high performance reactive programming

________________________________ ___ |/ /_ __ \_ ___/__ __/ __ /|_/ /_ / / /____ \__ / _ / / / / /_/ /____/ /_ / /_/ /_/ \____/__

The Javascript Architectural Toolkit 3.5k Dec 28, 2022
A RabbitMQ client for TypeScript, with functional programming in mind.

RabbitMQ-fp Lets feed our Rabbit' nicely ?? This repository contains a wrapper over amqplib written in Typescript with an accent of functionnal progra

MansaGroup 3 Sep 6, 2022
Plain functions for a more functional Deku approach to creating stateless React components, with functional goodies such as compose, memoize, etc... for free.

"Keo" is the Vietnamese translation for glue. Plain functions for a more functional Deku approach to creating stateless React components, with functio

Adam Timberlake 225 Sep 24, 2022
Hardcore Functional Programming for JavaScript

#Preλude-js A truly modular implementation of Haskell's Prelude library in ES6 check out the docs for modules details (WORK IN PROGRESS) install npm i

Alan Soares 96 Jan 1, 2023
Collection of benchmarks of functional programming languages and proof assistants.

Functional Benchmarks This repository contains a collection of benchmarks of functional programming languages and proof assistants. It is split in two

null 22 Dec 12, 2022
Jargon from the functional programming world in simple terms!

Functional Programming Jargon Functional programming (FP) provides many advantages, and its popularity has been increasing as a result. However, each

hemanth.hm 18.1k Jan 4, 2023
Fun λ functional programming in JS

fp-js JavaScript Functional Programming Motivation This purposed for learning functional programming (just that). Features Auto-Curry Option Tooling s

RiN 6 Feb 4, 2022
Functional Programming with NestJS, Prisma. immutable, pure, stateless

Functional-NestJS Functional Programming with NestJS, Prisma. immutable, pure, stateless. 1. Introduction A production ready typescript backend reposi

y0on2q 40 Dec 6, 2022
A tiny, reactive JavaScript library for structured state and tabular data.

A JavaScript library for structured state. Using plain old JavaScript objects to manage data gets old very quickly. It's error-prone, tricky to track

tinyplex 1.4k Jan 1, 2023