Lightweight, modern utility library for node, browser, and quickjs
- Simple and lightweight
- Supports 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
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.
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';
This library also exports 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';
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.
The current collection types are defined as:
ArrayMapSetArray IteratorMap IteratorSet IteratorString IteratorGeneratorAsyncGeneratorIteratorAsyncIteratorTypedArrayBufferNodeListHeadersFormDataURLSearchParams
When using iterator 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 iterator function has the following signature:
method(iterable, iteratorFn, collection?)
Where collection is true by default. If you want to use an iterator method to iterate the properties of a single object you can set the collection argument to false:
import { each } from 'lo'; let obj = { a: true, b: false }; each(obj, (val, key) => { console.log(key, val); }, false); // a true // b false
All iterator methods support every iterable type including: Array, Map, Set, Iterator, Generator, etc.
Methods to iterate the properties of individual objects and iterables: forIn, and forOwn.
Methods for iterating collections: each, map, tap, some, every, filter, remove, drop, take, reduce, transform, find, flatMap, and iterate.
Using the forEach method works slightly different from other iterator methods. It defers to the object's own forEach method if it exists. This means it works for things like Array, Map, Set, Iterator, and Buffer, but will also work for Streams.
All iteration methods 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]
A common task during iteration is checking for nil (null or undefined) values. This package has support for filtering nil values for various iteration methods. 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, just append NotNil to the function name:
import { mapNotNil as map } from 'lo'; let arr = [1, undefined, 2, 3, null]; map(arr, val => { return val % 3 === 0 ? undefined : val; }); // [1, 2]
All iterator methods support nil filtering
Every iteration method 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 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 works great with QuickJS and includes some node API polyfills to help compile tooling and CLIs written with node into standalone binaries.
While this project doesn't intend to provide complete polyfills for the entire node API, it does include some of the more common ones:
consoleeventsfsmoduleospathprocess
To use them in your own project, you can point your bundler at the lo polyfills directory for node imports. You can see an example in the docs.
A list of methods and some documentation can be found here
Tests are currently run using mocha and chai. To execute tests run make test. To generate unit test coverage reports run make coverage
If you have any questions feel free to get in touch