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

naushon

v0.6.6

Published

Pipelined transformations using AsyncIterators

Downloads

4

Readme

naushon

A tool for incrementally transforming data in node and the browser using AsyncIterators.

Installation

$ npm install naushon

Usage

// Create a generator that produces an endless collection of arbitrarly-large
// integers. Arbitrary-sized integers can be larger than Integer.MAX_VALUE,
// with no upper-bound on their size. There is no way the set of all integers
// would fit in memory, so this is a good use case for naushon
function * integers () {
  let i = 0n
  while (true) {
    yield i++
  }
}

const { eduction, filter, map, partitionAll, pipe, take } = require('naushon')

const xform = pipe(
  filter(n => n % 2 === 0),  // filter out odd numbers
  partitionAll(3),
  map(nums => nums.join(', ')),
  take(3))

for await (const block of eduction(xform, integers())) {
  console.log(block)
}
// Logs:
//  "2, 4, 6"
//  "8, 10, 12"
//  "14, 16, 18"
// then closes

const result = await sequence(xform, integers())
// ["2, 4, 6", "8, 10, 12", "14, 16, 18"]

This is fine for truncating an infinitely-large theoretical data set, but what if we want to operate on a huge real data set?

const { parseFile } = require('fast-csv')
const { eduction, distinct, filter, interpose, map, pipe, count } = require('naushon')

// A stream of rows from a huge list of addresses in a CSV file:
function addresses () {
  return parseFile('./statewide.csv', { headers: true })
}

// Create a filter transformer that yields only eligible addresses by checking
// that the addresses are in qualifying cities and states:
const eligibleAddress = filter(({ city, state }) => 
  eligibleStates.has(state) && eligibleCities.has(city))

// Convert the record into a string because we are going to write it to a file
const addressify = map(({ house_number_and_street, city, state, postcode }) =>
  `${house_number_and_street}, ${city}, ${state} ${postcode}`)

const xform = pipe(
  eligibleAddress, // filter out ineligible addresses
  addressify,      // convert data object into a string
  distinct,        // remove duplicate addresses
  interpose('\n')) // insert newlines between records

// Read each row from the CSV, transforming it with xform, and writing it to
// the output file:
Readable.from(eduction(xform, addresses())).pipe(createWriteStream('./out.txt'))

// Or: if we just want to know how many eligible addresses:
// Consumes the address file a little bit at a time without consuming a ton
// of memory!
const ct = await count(xform, addresses())

Rationale

Very often, a node program will need to read or write sets of data larger than the available memory size. Node Streams do a good job of defining the source and destination primitives for node processes, but writing transformation streams is awkward and hard to compose. Streams also don't exist in the browser, where processing large sets of data will become more-and-more common as we expect more out of web applications.

Naushon attempts to address this need by using a fundamental language primitive, the AsyncIterator, to create composable pipelines. These pipelines can operate on in-memory data structures like arrays and strings, but also database cursors, and audio, video, or filesystem stream objects.

The inspiration for the library is the Clojure transducers library, which is evident in the function names.

Etymology

Naushon is an island off the coast of Massachusetts. The island is one side of Woods Hole, a place where the tide passes through at great speed when the ocean level is higher on one side than the other. The island links to other small islands with bridges, under which some of this water passes, and where it is held in tidal coves. This seems an appropriate metaphor for the intended use of the naushon library: given a massive flow, partition and transform it across many discrete steps.

a photo taken on naushon