Skip to content

Repository files navigation

Lo

Lightweight, modern utility library for node, browser, and quickjs

Features:

  • Simple and lightweight
  • First-class support for node, browser, and quickjs
  • Native ESM
  • Treeshakeable by default
  • Support for all iterable types
  • Support for async iterables and async iterator functions
  • Nominal type system
  • 0 dependencies

About

A lightweight, modern utility library. This package is different from other utility libraries in that it avoids duck-typing and implements a simple nominal type system at it's core. This allows for very fast and accurate type checking. Information about types is also cached at start up and used to provide advanced functionalities like iteration support for every iterable type, including async iterables, generators, and async iterator functions.

You can read more about the design philosophy in the docs.

Usage

Add lo as a dependency and install via npm

npm install lo@danmasta/lo --save

Install a specific version

npm install lo@danmasta/lo#semver:^v0.0.0 --save

See documentation regarding git dependencies here

Import functions

import lo, { each, map } from 'lo';

Browser

This library also exposes a browser entrypoint, which excludes functions that depend on node specific APIs, and includes some browser specific types. If you use a bundler it should be able to automatically resolve the browser entrypoint. If you want to explicity import it, you can do that too:

import lo from 'lo/browser';

Collections

This package defines specific collection types for iteration. By default, if it is not a collection type, it is iterated as a one-object collection.

Collection Types

The current collection types are defined as:

Default (always registered)
  • Array
  • Map
  • Set
  • TypedArray (and subtypes Int8Array, Uint8Array, etc)
  • Array Iterator
  • String Iterator
  • Map Iterator
  • Set Iterator
  • RegExp String Iterator
  • Iterator
  • AsyncIterator
  • Generator
  • AsyncGenerator
  • URLSearchParams
  • Headers
  • FormData
  • ReadableStream
Node (node entrypoint)
  • Buffer
Browser (browser entrypoint)
  • NodeList
  • HTMLCollection
  • DOMTokenList
  • FileList
  • NamedNodeMap

Iteration

When using iteration functions like: each, map, tap, some, every, filter, remove, reduce, transform, etc, the default mode is to iterate as a collection. This means they will iterate on collections only, and not on the properties of a single object. For iterating the properties of a single object, you can use the functions forIn and forOwn.

This means if you pass a single object instead of a collection type, it will treat the object as a one-object collection and iterate one time:

import { each } from 'lo';

let obj = { a: true, b: false };

each(obj, (val, key) => {
    console.log(key, val);
});

// 0 { a: true, b: false }

Each iteration function has the following signature and accepts a trailing options object:

method(obj, fn, arg?, { entries, notNil })

Functions like take/drop, reduce/transform, and flatMap accept an extra positional argument

The entries option is false by default, and non-collection values are iterated as a one-object collection. If you want to iterate the properties/entries of a single object, you can set the entries option to true:

import { each } from 'lo';

let obj = { a: true, b: false };

each(obj, (val, key) => {
    console.log(key, val);
}, { entries: true });

// a true
// b false

All iteration functions support every iterable type including: Array, Map, Set, Iterator, Generator, etc.

Iterate Objects

Functions to iterate the properties of individual objects and iterables: forIn, and forOwn.

Iterate Collections

Functions for iterating collections: each, map, tap, some, every, filter, remove, drop, take, reduce, transform, find, flatMap, and iterate.

forEach

The forEach function is an alias for each. It iterates any collection type, including async iterables like Streams, and supports the same options.

Break Iteration Early

All iteration functions can be stopped early by returning the BREAK symbol:

import { map, BREAK } from 'lo';

let arr = [1, 2, 3, 4];

map(arr, val => {
    return val % 3 === 0 ? BREAK : val * 2;
});

// [2, 4]

Nil Filtering

A common task during iteration is checking for nil (null or undefined) values. This package has support for filtering nil values for various iteration functions. It will ignore nil values before the iterator function is called. It will also filter return values for functions that return, such as map, some, every, etc. To use, pass the notNil option:

import { map } from 'lo';

let arr = [1, undefined, 2, 3, null];

map(arr, val => {
    return val % 3 === 0 ? undefined : val;
}, { notNil: true });

// [1, 2]

All iteration functions support nil filtering

Async Iteration

Every iteration function also supports both async iterables and async iterator functions. You don't need to do anything special, just use them like normal:

import { map } from 'lo';

async function* list () {
    yield 1;
    yield 2;
    yield 3;
}

await map(list(), async val => {
    return val * 2;
});

// [2, 4, 6]

QuickJS

QuickJS is a small, embeddable javascript engine written in C that supports the latest ECMAScript specification including modules, async/await, iterators, generators, proxies, etc. It can also be used to compile and package javascript code into standalone executables.

This library includes first-class support for QuickJS. The lo/qjs entrypoint runs natively on the engine with no polyfills or bundling required. It uses the engine's own primitives (qjs:os, qjs:std) to provide things like console, argv, env, and cwd. So you can write tooling and CLIs with Lo and QuickJS, and compile straight to standalone executables.

import { console, argv, env } from 'lo/qjs';

Node compat polyfills

The library also ships an optional compatibility layer for running scripts written with node APIs. This isn't meant to be a complete polyfill of node, but it does cover some of the more common modules:

  • console
  • events
  • fs
  • module
  • os
  • path
  • process

To use them, point your bundler at the Lo polyfills directory for node imports. You can see an example in the docs.

Documentation

A list of functions and some documentation can be found here

Testing

Tests are currently run using mocha and chai. To execute tests run make test. To generate unit test coverage reports run make coverage

Contact

If you have any questions feel free to get in touch

About

Lightweight, modern utility library for node, browser, and quickjs

Topics

Resources

Stars

2 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages