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 πŸ™

Β© 2026 – Pkg Stats / Ryan Hefner

swear

v2.0.1

Published

πŸ™ Flexible promise handling with Javascript

Downloads

10,018

Readme

πŸ™ Swear npm install swear test badge gzip size

Flexible promise handling with Javascript:

import swear from "swear";

const name = await swear(fetch("/some.json")).json().user.name;
console.log(name);  // Francisco

const error = await swear(readFile("./error.log", "utf-8")).split("\n").pop();
console.log(error);  // *latest error log message*

Features:

  • Extends native Promises; you can treat them as promises with await, .then() and .catch().
  • Automatic Promise.all() for arrays.
  • Chainable interface that allows for a scripting syntax like jQuery.
  • Extends the API of the Promise value so it's intuitive to follow.
  • Can transparently wrap an async function to make it use swear().
  • Full TypeScript support with recursive generic types.

See how swear() compares to native promises when you have some async operations:

// Using this library
const value = await swear(data).map(op1).filter(op2).map(op3);

// NATIVE; the pure-javascript way of dealing with the same is a lot longer
const value = await Promise.all(data.map(op1)).then(files => files.filter(op2)).then(files => Promise.all(files.map(op3)));

// NATIVE; even when we try to make it more readable it is still longer:
let value = await Promise.all(data.map(op1));
value = value.filter(op2);
value = await Promise.all(value.map(op3));

Note that in the example above, op2 has to be sync since the native .filter() cannot deal with an async one, but with swear() you can do .filter(async item => {...}) as well! Keep reading πŸ˜„

API

The coolest bit is that you already know the API since it uses the native Javascript one! You can call the methods, properties, etc. of the value that you pass to swear() as you would do normally:

import swear from "swear";

// No need for swear in this example, but isn't it cool?
const value = await swear(getPi()).toFixed(1).split(".").map(n => n * 2).join(".");
console.log(value); // 6.2 (string)

const name = await swear(fetch("/some.json")).json().user.name;
console.log(name); // Francisco

// Native code (extra verbose for clarity)
const res = await fetch("/some.json");
const data = await res.json();
const user = data.user;
const name = user.name;
console.log(name);

Number

The Number documentation explains the native API that is available. For instance, let's see with .toFixed():

import swear from "swear";

async function getPi() { /* ... */ }

const pi = await swear(getPi()).toFixed(2);
console.log(pi);  // 3.14

You can apply other string operations as well, for instance you might want to extract some decimals:

const decimals = await swear(getPi()).toFixed(3).split(".").pop();
console.log(decimals);

String

The String documentation explains the native API that is available. For instance, let's see with .split():

import swear from "swear";

async function getCsv(url) { /* ... */ }

const first = await swear(getCsv("/some.csv")).split("\n").shift().split(",");
console.log(first);  // [a,1,6,z]

Function

If you pass a function, swear will return a function that, when called, will return a swear instance. It transparently passes the arguments (resolving them if needed!) and resolves with the returned value:

import swear from "swear";

const getSomeInfo = swear(async (file) => {
  const res = await fetch(file);
  return res.json();
});

const names = await getSomeInfo("users.json").map(user => user.name).join(",");

This is great if you want to write a library with swear; it will behave the same as the async version when treated like such; but has a lot of new useful functionality from the underlying values.

Array

We are extending native arrays by adding async and RegExp methods to them:

import swear from "swear";

// It allows the .filter() callback to return a promise
const evens = await swear([0, 1, 2]).filter(async n => n * 2 < 2);
console.log(evens); // [0, 1]

// It also accepts a Regular Expression for an array of strings
const found = await swear(["a", "b", "C"]).find(/c/i);
console.log(found); // "C"

Note: don't worry, we are not touching the prototype. These extensions are only available until you call await, .then() or .catch().

For sync methods they behave the same way as the native counterparts. For async methods you need to be aware whether each of those callbacks is called in parallel (concurrent) or in series:

  • .every(): series, "executes the provided callback function once for each element present in the array until it finds one where callback returns a falsy value" - MDN Documentation.
  • .filter(): parallel
  • .find(): series
  • .findIndex(): series
  • .forEach(): parallel
  • .map(): parallel
  • .reduce(): series
  • .reduceRight(): series
  • .some(): series, "executes the callback function once for each element present in the array until it finds one where callback returns a truthy value" - MDN Documentation.
  • .sort(): none. This method is not modified and it does not accept an async callback.

The ones called in series is because later iterations might depend on previous ones.

TypeScript

Swear is written in TypeScript and ships with full type definitions. The return type of swear() is Swear<T>, which extends Promise<T> and recursively maps all properties and methods of T into swear-wrapped equivalents, so the chain stays typed end to end:

import swear, { type Swear } from "swear";

// Property chains are fully typed
const name: string = await swear({ user: { name: "Alice" } }).user.name;

// Method chains carry their return types
const parts: string[] = await swear("hello world").split(" ");

// Async array methods accept sync or async callbacks
const evens: number[] = await swear([1, 2, 3, 4]).filter(async n => n % 2 === 0);

The Swear<T> type is exported if you need to annotate your own functions:

import swear, { type Swear } from "swear";

function getUsers(): Swear<{ id: number; name: string }[]> {
  return swear(fetch("/api/users").then(r => r.json()));
}

const names = await getUsers().map(u => u.name);

You can extend swear with custom methods using the SwearOptions type:

import swear, { type SwearOptions } from "swear";

const opts: SwearOptions<{ double: (v: string) => string }> = {
  double: (v) => v + v,
};

const result = await (swear("hi", opts) as any).double();
console.log(result); // "hihi"

Examples

This library is specially useful if we want to do things like fetching urls, mapping their arrays, working with strings, etc. For instance, let's read all the files in the current directory:

import swear from "swear";
import { readdir, readFile } from "node:fs/promises";

// You can apply `.map()` straight to the output of swear()
const files = await swear(readdir(import.meta.dirname)).map(file => readFile(file, "utf-8"));

// NATIVE; this is how you'd have to do with vanilla JS
const names = await readdir(import.meta.dirname);
const contents = await Promise.all(names.map(file => readFile(file, "utf-8")));

Retrieve a bunch of websites with valid responses:

import swear from "swear";

const urls = ["francisco.io", "serverjs.io", "umbrellajs.com"];
const websites = await swear(urls)
  .map(url => fetch(url))       // Fetch the URLs in parallel like Promise.all()
  .map(res => res.text())       // Retrieve the actual bodies
  .filter(Boolean);             // Only those bodies with content

// NATIVE; How to do this with traditional Promises + arrays
const responses = await Promise.all(urls.map(url => fetch(url)));
const websites = (await Promise.all(responses.map(res => res.text()))).filter(Boolean);

Works with any value that a promise can resolve to:

import swear from "swear";

// Get and parse a CSV file. Promise => text => array => number
const sum = await swear(fetch("example.com/data.csv").then(r => r.text()))
  .split("\n")
  .filter(Boolean)
  .map(line => line.split("\t").shift())
  .map(num => parseFloat(num))
  .reduce((total, num) => total + num, 0);

Acknowledgements

Libraries based on this:

  • atocha: run terminal commands from Node.js.
  • create-static-web: another static site generator.
  • fch: an improved version of fetch().
  • files: Node.js filesystem API easily usable with Promises and arrays.