npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

fremit

v0.1.0

Published

An FRP-style event-stream-to-collections interface toolkit

Downloads

17

Readme

frēmit

An FRP-style event-stream-to-collections interface toolkit

Here's the basic idea. Your application can be expressed as a series of reactions to inputs or events. This is the idea behind event-driven programming. The idea behind this library is to organize your program in such a way that tracing the reaction to events becomes possible if not trivial.

Example

Let's illustrate. "Hello World!" is always convenient:

<body>
	<button class="hello">Hello, Computer!</button>
</body>
import emit from 'fremit';
// this is the singleton stream that is the embodiment of 
// how our app responds to events
const stream = emit.stream.share()

window.addEventListener('click', emit);
//ideally you'd listen for all events on window and/or document

stream
    .filter(e => e.target.classList.contains('hello'))
    .forEach(e => alert('Hello, Person!'));

It should be pretty clear how to use the stream. There are more details on the API below. It's an explicit design decision to allow one stream per app. This is a core difference between this library and RxJS.

The other half of this library is how to use emit. One should use emit to publish system events such as user input or messages received from the server to the stream. It is the integration point for frēmit. The interface is simple: one function, one argument. The argument is an event object, which usually has a type property to allow differentiation in the stream handler.

Here's an (rather long-ish) example for AJAX (assuming a DOM with the right stuff in it):

import $ from 'jquery';
import emit from 'fremit';
// this is the singleton stream that is the embodiment of 
// how our app responds to events
const stream = emit.stream.share()

// Register a handler to be called when the first Ajax request begins. This is an Ajax Event.
$(document).ajaxStart(() => emit({type: 'jqXHRStart'}));

// Attach a function to be executed before an Ajax request is sent. This is an Ajax Event.
$(document).ajaxSend((event, jqXHR, ajaxOptions) => emit({
    event, jqXHR, ajaxOptions, type: 'jqXHRSend'
}));

// Attach a function to be executed whenever an Ajax request completes successfully. This is an Ajax Event.
$(document).ajaxSuccess((event, jqXHR, ajaxOptions, data) => emit({
    event, jqXHR, ajaxOptions, data, type: 'jqXHRSuccess'
}));

// Register a handler to be called when Ajax requests complete with an error. This is an Ajax Event.
$(document).ajaxError((event, jqXHR, ajaxOptions, thrownError) => emit({
    event, jqXHR, ajaxOptions, thrownError, type: 'jqXHRError'
}));

// Register a handler to be called when Ajax requests complete. This is an AjaxEvent.
$(document).ajaxComplete((event, jqXHR, ajaxOptions) => emit({
    event, jqXHR, ajaxOptions, type: 'jqXHRComplete'
}));

// Register a handler to be called when all Ajax requests have completed. This is an Ajax Event.
$(document).ajaxStop(() => emit({type: 'jqXHRStop'}));



////////////////////////////////////////////////////////
//
// The stream part
//
//

stream
    .filter(e => e.type === 'jqXHRStart')
    .forEach(e => $('.loading').show());

stream
    .filter(e => e.type === 'jqXHRStop')
    .forEach(e => $('.loading').hide());

stream
    .filter(e => e.type === 'jqXHRSuccess' || e.type === 'jqXHRError')
    .forEach(e => {
        //do something to handle success and errors...
        pushDataIntoStore(e.data || e.thrownError);
        queueRender();
    });

// We don't currently do anything with Send or Complete...   
// stream
//    .filter(e => e.type === 'jqXHRSend')
// stream
//    .filter(e => e.type === 'jqXHRComplete')

Note the general emphasis on listening for global events, rather than listening to particular requests or to particular DOM elements.

API

API documentation is currently a work in progress... bare with me.

.share()

Share this stream, which means that any further handlers attached to this stream will create new child streams, rather than returning this one. This makes the branching builder-style approach seen above possible.

If you don't share the stream, any handlers you attach will return a reference to this stream, which means that if you filter events, they will be filtered from the rest of the handlers.

This makes an interesting use case possible that I'll explain later.

.filter (fn(event))

Return true from your fn if handlers later in the stream should handle this event.

.map (fn(event))

return an object that is a function of the event, and handlers further down the stream will make use of the newly returned object.

.unwind (path)

Looks for an array at the specified path, creates a new cloned event for each element of the array and pushes them further into the stream.

See MongoDB's definition of $unwind, and lodash's definition of path

.forEach (fn(event))

Calls the given function for any event. This is your imperative release valve if you need it.

Roadmap

  • 0.1: Get it out there. Get some commentary
  • 0.5: Make any essential interface changes, get more commentary
  • 0.9: Incorporate all feedback, release-candidate level quality for docs and testing
  • 1.0: Full release, production ready. No more API changes
  • 1.x: Add additional handlers as needed or convenient
  • 2.0: (Hopefully not necessary) Any additional API changes. Semver FTW, baby!