/just

A library of dependency-free JavaScript functions that do just do one thing.

Primary LanguageJavaScriptMIT LicenseMIT

Just

A library of zero-dependency npm modules that do just one thing. A guilt-free alternative to those bulkier utility libraries. Ideal for PWA development or whenever bytes are precious.

Build status

Jump To API

We welcome contributions. Please follow our contribution guidelines.

Try 🍦

A REPL for every utility (powered by RunKit)

Read 📚

ES and CJS modules available for every utility

All packages support ES module or Common JS syntax without requiring transpilation

// esm (node / bundler)
import clone from 'just-clone'; 

// esm (native browser code)
import clone from './node_modules/just-clone/index.mjs'; 

// cjs
const clone = require('just-clone'); 

TypeScript

We're in the process of adding TypeScript definitions and tests to every Just utility. You're welcome to help us get there! Here's an example PR.

You can verify new TypeScript definitions by running yarn test-types (This also gets run as part of the yarn test script)

Browser Support 💻

Data based on available saucelabs test browsers. It's likely Just is also fully supported by some older versions not verifiable via saucelabs.

Chrome Safari Firefox Edge Node Mobile Safari Android
yes yes yes 12 6+ iOS 8+ Android OS 5+

The Modules 📦

🍦Try It

npm install just-diff-apply

Apply a diff object to an object. Pass converter to apply a http://jsonpatch.com standard patch

  import diffApply from 'just-diff-apply';

  const obj1 = {a: 3, b: 5};
  diffApply(obj1,
    [
      { "op": "remove", "path": ['b'] },
      { "op": "replace", "path": ['a'], "value": 4 },
      { "op": "add", "path": ['c'], "value": 5 }
    ]
  );
  obj1; // {a: 4, c: 5}

  // arrays (array key can be string or numeric)
  const obj3 = {a: 4, b: [1, 2, 3]};
  diffApply(obj3, [
    { "op": "replace", "path": ['a'], "value": 3 }
    { "op": "replace", "path": ['b', 2], "value": 4 }
    { "op": "add", "path": ['b', 3], "value": 9 }
  ]);
  obj3; // {a: 3, b: [1, 2, 4, 9]}

  // nested paths
  const obj4 = {a: 4, b: {c: 3}};
  diffApply(obj4, [
    { "op": "replace", "path": ['a'], "value": 5 }
    { "op": "remove", "path": ['b', 'c']}
    { "op": "add", "path": ['b', 'd'], "value": 4 }
  ]);
  obj4; // {a: 5, b: {d: 4}}

  // using converter to apply jsPatch standard paths
  // see http://jsonpatch.com
  import {diffApply, jsonPatchPathConverter} from 'just-diff-apply'

  const obj2 = {a: 3, b: 5};
  diffApply(obj2, [
    { "op": "remove", "path": '/b' },
    { "op": "replace", "path": '/a', "value": 4 }
    { "op": "add", "path": '/c', "value": 5 }
  ], jsonPatchPathConverter);
  obj2; // {a: 4, c: 5}

🍦Try It

npm install just-compare

import compare from "just-compare";

// primitives: value1 === value2
// functions: value1.toString == value2.toString
// arrays: if length, sequence and values of properties are identical
// objects: if length, names and values of properties are identical
compare([1, [2, 3]], [1, [2, 3]]); // true
compare([1, [2, 3], 4], [1, [2, 3]]); // false
compare({ a: 2, b: 3 }, { a: 2, b: 3 }); // true
compare({ a: 2, b: 3 }, { b: 3, a: 2 }); // true
compare({ a: 2, b: 3, c: 4 }, { a: 2, b: 3 }); // false
compare({ a: 2, b: 3 }, { a: 2, b: 3, c: 4 }); // false
compare([1, [2, { a: 4 }], 4], [1, [2, { a: 4 }]]); // false
compare([1, [2, { a: 4 }], 4], [1, [2, { a: 4 }], 4]); // true
compare(NaN, NaN); // true

🍦Try It

npm install just-clone

import clone from "just-clone";

// Deep copies objects and arrays, doesn't clone functions

var arr = [1, 2, 3];
var subObj = { aa: 1 };
var obj = { a: 3, b: 5, c: arr, d: subObj };
var objClone = clone(obj);
arr.push(4);
objClone.d.bb = 2;
obj; // {a: 3, b: 5, c: [1, 2, 3, 4], d: {aa: 1}}
objClone; // {a: 3, b: 5, c: [1, 2, 3], d: {aa: 1, bb: 2}}

🍦Try It

npm install just-pluck-it

import pluck from "just-pluck-it";

pluck(
  [
    { a: 1, b: 2 },
    { a: 4, b: 3 },
    { a: 2, b: 5 },
  ],
  "a"
); // [1, 4, 2]
pluck({ x: { a: 1, b: 2 }, y: { a: 4, b: 3 }, z: { a: 2, b: 5 } }, "a"); // {x: 1, y: 4, z: 2}

🍦Try It

npm install just-flush

import flush from "just-flush";

flush([1, undefined, 2, null, 3, NaN, 0]); // [1, 2, 3, NaN, 0]
flush([true, null, false, true, [null], undefined]); // [true, false, true, [null]]
flush({ a: 2, b: null, c: 4, d: undefined }); // {a: 2, c: 4}
flush("something"); // undefined
flush(); // undefined

Objects

🍦Try It

npm install just-extend

import extend from 'just-extend';

var obj = {a: 3, b: 5};
extend(obj, {a: 4, c: 8}); // {a: 4, b: 5, c: 8}
obj; // {a: 4, b: 5, c: 8}

var obj = {a: 3, b: 5};
extend({}, obj, {a: 4, c: 8}); // {a: 4, b: 5, c: 8}
obj; // {a: 3, b: 5}

var arr = [1, 2, 3];
var obj = {a: 3, b: 5};
extend(obj, {c: arr}); // {a: 3, b: 5, c: [1, 2, 3]}
arr.push(4);
obj; // {a: 3, b: 5, c: [1, 2, 3, 4]}

var arr = [1, 2, 3];
var obj = {a: 3, b: 5};
extend(true, obj, {c: arr}); // {a: 3, b: 5, c: [1, 2, 3]}
arr.push(4);
obj; // {a: 3, b: 5, c: [1, 2, 3]}

extend({a: 4, b: 5}); // {a: 4, b: 5}
extend({a: 4, b: 5}, 3); {a: 4, b: 5}
extend({a: 4, b: 5}, true); {a: 4, b: 5}
extend('hello', {a: 4, b: 5}); // throws
extend(3, {a: 4, b: 5}); // throws

🍦Try It

npm install just-merge

import merge from "just-merge";

let obj = { a: 3, b: 5 };
merge(obj, { a: 4, c: 8 }); // {a: 4, b: 5, c: 8}
obj; // {a: 4, b: 5, c: 8}

let obj = { a: 3, b: 5 };
merge({}, obj, { a: 4, c: 8 }); // {a: 4, b: 5, c: 8}
obj; // {a: 3, b: 5}

let arr = [1, 2, 3];
let obj = { a: 3, b: 5 };
merge(obj, { c: arr }); // {a: 3, b: 5, c: [1, 2, 3]}
arr.push[4];
obj; // {a: 3, b: 5, c: [1, 2, 3, 4]}

merge({ a: 4, b: 5 }); // {a: 4, b: 5}
merge(3, { a: 4, b: 5 }); // throws
merge({ a: 4, b: 5 }, 3); // throws
merge({ a: 4, b: 5 }, { b: 4, c: 5 }, "c"); // throws

🍦Try It

npm install just-values

import values from "just-values";

values({ a: 4, c: 8 }); // [4, 8]
values({ a: { aa: 2 }, b: { bb: 4 } }); // [{aa: 2}, {bb: 4}]
values({}); // []
values([1, 2, 3]); // [1, 2, 3]
values(function (a, b) {
  return a + b;
}); // []
values(String("hello")); // []
values(1); // throw exception
values(true); // throw exception
values(undefined); // throw exception
values(null); // throw exception

🍦Try It

npm install just-entries

import entries from "just-entries";

// Object:
entries({ c: 8, a: 4 }); // [['c', 8], ['a', 4]]
entries({ b: { bb: 4 }, a: { aa: 2 } }); // [['b', {bb: 4}], ['a', {aa: 2}]]
entries({}); // []

// Array:
entries([{ c: 8 }, { a: 4 }]); // [[0, {c: 8}], [1, {a: 4}]]
entries(["À", "mauvais", "ouvrier", "point", "de", "bon", "outil"]);
// [[0, 'À'], [1, 'mauvais'] ... [6, 'outil']]
entries([]); // []

🍦Try It

npm install just-pick

import pick from "just-pick";

var obj = { a: 3, b: 5, c: 9 };
pick(obj, ["a", "c"]); // {a: 3, c: 9}
pick(obj, "a", "c"); // {a: 3, c: 9}
pick(obj, ["a", "b", "d"]); // {a: 3, b: 5}
pick(obj, ["a", "a"]); // {a: 3}

🍦Try It

npm install just-omit

import omit from "just-omit";

var obj = { a: 3, b: 5, c: 9 };
omit(obj, ["a", "c"]); // {b: 5}
omit(obj, "a", "c"); // {b: 5}
omit(obj, ["a", "b", "d"]); // {c: 9}
omit(obj, ["a", "a"]); // {b: 5, c: 9}

🍦Try It

npm install just-is-empty

import isEmpty from 'just-is-empty';
 isEmpty({a: 3, b: 5}) // false
 isEmpty([1, 2]) // false
 isEmpty(new Set([1, 2, 2])) // false
 isEmpty((new Map()).set('a', 2)) // false
 isEmpty({}) // true
 isEmpty([]) // true
 isEmpty(new Set()) // true
 isEmpty(new Map()) // true
 isEmpty('abc') // false
 isEmpty('') // true
 isEmpty(0) // true
 isEmpty(1) // true
 isEmpty(true) // true
 isEmpty(Symbol('abc')); // true
 isEmpty(//); // true
 isEmpty(new String('abc')); // false
 isEmpty(new String('')); // true
 isEmpty(new Boolean(true)); // true
 isEmpty(null) // true
 isEmpty(undefined) // true

🍦Try It

npm install just-is-circular

import isCircular from "just-is-circular";

const a = {};
a.b = a;
isCircular(a); // true

const a = {};
a.b = { c: a };
isCircular(a); // true

const a = {};
a.b = { c: 4 };
isCircular(a); // false

const a = [];
a.push(a);
isCircular(a); // true

isCircular({}); // false
isCircular("hi"); // false
isCircular(undefined); // false

🍦Try It

npm install just-is-primitive

import isPrimitive from "just-is-primitive";
isPrimitive("hi"); // true
isPrimitive(3); // true
isPrimitive(true); // true
isPrimitive(false); // true
isPrimitive(null); // true
isPrimitive(undefined); // true
isPrimitive(Symbol()); // true
isPrimitive({}); // false
isPrimitive([]); // false
isPrimitive(function () {}); // false
isPrimitive(new Date()); // false
isPrimitive(/a/); // false

🍦Try It

npm install just-filter-object

import filter from "just-filter-object";

// returns a new object containing those original properties for which the predicate returns truthy
filter({ a: 3, b: 5, c: 9 }, (key, value) => value < 6); // {a: 3, b: 5}
filter({ a1: 3, b1: 5, a2: 9 }, (key, value) => key[0] == "a"); // {a1: 3, a2: 9}
filter({ a: 3, b: 5, c: null }, (key, value) => value); // {a: 3, b: 5}

🍦Try It

npm install just-map-object

import map from "just-map-object";

// DEPRECATED: use just-map-values
map({ a: 3, b: 5, c: 9 }, (key, value) => value + 1); // {a: 4, b: 6, c: 10}
map({ a: 3, b: 5, c: 9 }, (key, value) => key); // {a: 'a', b: 'b', c: 'c'}
map({ a: 3, b: 5, c: 9 }, (key, value) => key + value); // {a: 'a3', b: 'b5', c: 'c9'}

🍦Try It

npm install just-map-values

import map from "just-map-values";

// predicate updates values, receives (value, key, obj)
map({ a: 3, b: 5, c: 9 }, (value) => value + 1); // {a: 4, b: 6, c: 10}
map({ a: 3, b: 5, c: 9 }, (value, key) => value + key); // {a: 3a, b: 5b, c: 9c}
map({ a: 3, b: 5, c: 9 }, (value, key, obj) => obj.b); // {a: 5, b: 5, c: 5}

🍦Try It

npm install just-map-keys

import map from "just-map-keys";

// predicate updates keys, receives (value, key, object)
map({ a: "cow", b: "sheep", c: "pig" }, (value) => value);
// {cow: 'cow', sheep: 'sheep', pig: 'pig'}
map([4, 5, 6], (value, key) => key + 1); // {1: 4, 2: 5, 3: 6}
map({ a: 3, b: 5, c: 9 }, (value, key) => key + value); // {a3: 3, b5: 5, c9: 9}
map({ a: 3, b: 5, c: 9 }, (value, key, obj) => obj.b + value + key);
// {'8a': 3, '10b': 5, '14c': 9}

🍦Try It

npm install just-reduce-object

import reduce from "just-reduce-object";

// applies a function against an accumulator and each key-value pairs of the object
// to reduce it to a single value
reduce(
  { a: 3, b: 5, c: 9 },
  (acc, key, value, index, keys) => {
    acc[value] = key;
    return acc;
  },
  {}
); // {3: 'a', 5: 'b', 9: 'c'}

reduce({ a: 3, b: 5, c: 9 }, (acc, key, value, index, keys) => {
  acc += value;
  return acc;
}); // 17

🍦Try It

npm install just-safe-get

import get from "just-safe-get";

const obj = { a: { aa: { aaa: 2 } }, b: 4 };

get(obj, "a.aa.aaa"); // 2
get(obj, ["a", "aa", "aaa"]); // 2

get(obj, "b.bb.bbb"); // undefined
get(obj, ["b", "bb", "bbb"]); // undefined

get(obj.a, "aa.aaa"); // 2
get(obj.a, ["aa", "aaa"]); // 2

get(obj.b, "bb.bbb"); // undefined
get(obj.b, ["bb", "bbb"]); // undefined

get(obj.b, "bb.bbb", 5); // 5
get(obj.b, ["bb", "bbb"], true); // true

get(null, "a"); // undefined
get(undefined, ["a"]); // undefined

get(null, "a", 42); // 42
get(undefined, ["a"], 42); // 42

const obj = { a: {} };
const sym = Symbol();
obj.a[sym] = 4;
get(obj.a, sym); // 4

🍦Try It

npm install just-safe-set

import set from "just-safe-set";

const obj1 = {};
set(obj1, "a.aa.aaa", 4); // true
obj1; // {a: {aa: {aaa: 4}}}

const obj2 = {};
set(obj2, [a, aa, aaa], 4); // true
obj2; // {a: {aa: {aaa: 4}}}

const obj3 = { a: { aa: { aaa: 2 } } };
set(obj3, "a.aa.aaa", 3); // true
obj3; // {a: {aa: {aaa: 3}}}

// don't clobber existing
const obj4 = { a: { aa: { aaa: 2 } } };
set(obj4, "a.aa", { bbb: 7 }); // false

const obj5 = { a: {} };
const sym = Symbol();
set(obj5.a, sym, 7); // true
obj5; // {a: {Symbol(): 7}}

🍦Try It

npm install just-typeof

import typeOf from "just-typeof";

typeOf({}); // 'object'
typeOf([]); // 'array'
typeOf(function () {}); // 'function'
typeOf(/a/); // 'regexp'
typeOf(new Date()); // 'date'
typeOf(null); // 'null'
typeOf(undefined); // 'undefined'
typeOf("a"); // 'string'
typeOf(1); // 'number'
typeOf(true); // 'boolean'

🍦Try It

npm install just-flip-object

import flip from "just-flip-object";

// flip the key and value
flip({ a: "x", b: "y", c: "z" }); // {x: 'a', y: 'b', z: 'c'}
flip({ a: 1, b: 2, c: 3 }); // {'1': 'a', '2': 'b', '3': 'c'}
flip({ a: false, b: true }); // {false: 'a', true: 'b'}

🍦Try It

npm install just-has

import has from "just-has";

const obj = { a: { aa: { aaa: 2 } }, b: 4 };

has(obj, "a.aa.aaa"); // true
has(obj, ["a", "aa", "aaa"]); // true

has(obj, "b.bb.bbb"); // false
has(obj, ["b", "bb", "bbb"]); // false

has(obj.a, "aa.aaa"); // true
has(obj.a, ["aa", "aaa"]); // true

has(obj.b, "bb.bbb"); // false
has(obj.b, ["bb", "bbb"]); // false

has(null, "a"); // false
has(undefined, ["a"]); // false

const obj = { a: {} };
const sym = Symbol();
obj.a[sym] = 4;
has(obj.a, sym); // true

Arrays

🍦Try It

npm install just-cartesian-product

Takes an input of an array of arrays and returns their Cartesian product.

import cartesianProduct from "just-cartesian-product";

cartesianProduct([
  [1, 2],
  ["a", "b"],
]); // [[1, 'a'], [1, 'b'], [2, 'a'], [2, 'b']]
cartesianProduct([
  [1, 2],
  ["a", "b", "c"],
]); // [[1, 'a'], [1, 'b'], [1, 'c'], [2, 'a'], [2, 'b'], [2, 'c']]
cartesianProduct([]); // []
cartesianProduct(); // throws

🍦Try It

npm install just-unique

import unique from "just-unique";

unique([1, 2, 3, 2, 3, 4, 3, 2, 1, 3]); // [1, 2, 3, 4]

var a = { a: 3 };
var b = { b: 4 };
var c = { c: 5 };
unique([a, a, b, c, b]); // [a, b, c]

unique([1, "1", 2, "2", 3, 2]); // [1, '1', 2, '2', 3]

// declaring sorted array for performance
unique([1, 1, "1", 2, 2, 5, "5", "5"], true); // [1, '1', 2, 5, '6']

// declaring strings array for performance
unique(["a", "c", "b", "c", "a"], false, true); // ['a', 'b', 'c']

🍦Try It

npm install just-flatten-it

import flatten from "just-flatten-it";

flatten([[1, [2, 3]], [[4, 5], 6, 7, [8, 9]]]);
// [1, 2, 3, 4, 5, 6, 7, 8, 9]

flatten([[1, [2, 3]], [[4, 5], 6, 7, [8, 9]]], 1);
// [1, [2, 3], [[4, 5], 6, 7, [8, 9]]]

🍦Try It

npm install just-index

import index from "just-index";

index(
  [
    { id: "first", val: 1 },
    { id: "second", val: 2 },
  ],
  "id"
);
// {first: {id: 'first', val: 1}, second: {id: 'second', val: 2}}
index([{ id: "first", val: 1 }, null], "id"); // {first: {id: 'first', val: 1}}
index([], "id"); // {}
index([], null); // throws
index({}, "id"); // throws

🍦Try It

npm install just-insert

import insert from "just-insert";

insert([1, 2, 5, 6], ["a", "c", "e"], 2); // [1, 2, 'a', 'c', 'e', 5, 6]
insert([1, 2, 5, 6], "a", 2); // [1, 2, 'a', 5, 6]
insert([1, 2, 5, 6], ["a", "c", "e"], 0); // ['a', 'c', 'e', 1, 2, 5, 6]
insert([1, 2, 5, 6], ["a", "c", "e"]); // ['a', 'c', 'e', 1, 2, 5, 6]

🍦Try It

npm install just-intersect

import intersect from "just-intersect";

intersect([1, 2, 5, 6], [2, 3, 5, 6]); // [2, 5, 6]
intersect([1, 2, 2, 4, 5], [3, 2, 2, 5, 7]); // [2, 5]

🍦Try It

npm install just-compact

import compact from "just-compact";

compact([1, null, 2, undefined, null, NaN, 3, 4, false, 5]); // [1, 2, 3, 4, 5]
compact([1, 2, [], 4, {}]); // [1, 2, [], 4, {}]
compact([]); // []
compact({}); // throws

🍦Try It

npm install just-last

import last from "just-last";

last([1, 2, 3, 4, 5]); // 5
last([{ a: 1 }, { b: 1 }, { c: 1 }]); // {c: 1}
last([true, false, [true, false]]); // [true, false]
last([]); // undefined
last(); // throws
last(null); // throws
last(undefined); // throws

🍦Try It

npm install just-tail

import tail from "just-tail";

tail([1, 2, 3, 4, 5]); // [2, 3, 4, 5]
tail([{ a: 1 }, { b: 1 }, { c: 1 }]); // [{b: 1}, {c: 1}]
tail([true, false, [true, false]]); // [false, [true, false]]
tail([]); // []
tail(); // throws
tail(null); // throws
tail(undefined); // throws

🍦Try It

npm install just-random

import random from "just-random";

random([1, 2, 3]); // one of [1, 2, 3], at random

🍦Try It

npm install just-shuffle

import shuffle from "just-shuffle";

shuffle([1, 2, 3]);
// array with original elements randomly sorted
shuffle([1, 2, 3], { shuffleAll: true });
// array with original elements randomly sorted and all in new postions
shuffle([]); // []
shuffle([1]); // [1]
shuffle(); // undefined
shuffle(undefined); // undefined
shuffle(null); // undefined
shuffle({}); // undefined

🍦Try It

npm install just-split

import split from "just-split";

split([]); // []
split([1, 2, 3, 4, 5]); // [[1, 2, 3, 4, 5]]
split([1, 2, 3, 4, 5, 6, 7, 8, 9], 3); // [[1, 2, 3], [4, 5, 6], [7, 8, 9]];
split(["a", "b", "c", "d", "e"], 2); // [['a', 'b'], ['c', 'd'], ['e']];
split([1, 2, 3, 4, 5, 6, 7, 8], 3); // [[1, 2, 3], [4, 5, 6], [7, 8]];
split({}, 3); // throws
split(null, 3); // throws
split([1, 2, 3, 4, 5, 6], "3"); // throws

🍦Try It

npm install just-split-at

import splitAt from "just-split-at";

splitAt([1, 2, 3, 4, 5], 2); // [[1, 2], [3, 4, 5]]
splitAt([{ a: 1 }, { b: 1 }, { c: 1 }], -1); // [[{a: 1}, {b: 1}], [{c: 1}]]
splitAt([], 2); // [[], []]
splitAt(null, 1); // throws
splitAt(undefined, 1); // throws
splitAt([1, 2, 3, 4, 5], {}); // throws

🍦Try It

npm install just-sort-by

import sortBy from 'just-array-sort-by';

sortBy([10, 1, 5, 20, 15, 35, 30, 6, 8]); // [1, 5, 6, 8, 10, 15, 20, 30, 35]

sortBy([
  {user: 'fabio', details: {city: "Milan", age: 34}},
  {user: 'max', details: {city: "Munich", age: 29}},
  {user: 'zacarias', details: {city: "Sao Paulo", age: 44}},
  {user: 'robert', details: {city: "Manchester", age: 28}},
  {user: 'klaus', details: {city: "Zurich", age: 38}},
], function(o) {
  return o.details.age;
});
/*
[
  {user: 'robert', age: 28},
  {user: 'max', age: 29},
  {user: 'fabio', age: 34},
  {user: 'klaus', age: 38},
  {user: 'zacarias', age: 44},
]
*/

sortBy([
  {user: 'fabio', age: 34},
  {user: 'max', age: 29},
  {user: 'zacarias', age: 44},
  {user: 'robert', age: 28},
  {user: 'klaus', age: 38},
], 'user');
/*
[
  {user: 'fabio', age: 34},
  {user: 'klaus', age: 38},
  {user: 'max', age: 29},
  {user: 'robert', age: 28},
  {user: 'zacarias', age: 44},
]
*/

🍦Try It

npm install just-partition

import partition from "just-partition";

partition([1, 5, 2, 4, 3], (n) => n > 3); // [[5, 4],[1, 2, 3]]
partition(["a", 2, 3, "3"], (x) => typeof x == "string"); // [['a', '3'],[2, 3]]
partition([1, 2, 3, 4], (x) => typeof x == "number"); // [[1, 2, 3, 4],[]]
partition([1, 2, 3, 4], (x) => typeof x == "string"); // [[], [1, 2, 3, 4]]
partition([], (n) => n > 3); // [[], []]
partition({ a: 1, b: 2 }, (n) => n > 1); // throws
partition(null, (n) => n > 1); // throws
partition(undefined, (n) => n > 1); // throws

🍦Try It

npm install just-range

import range from "just-range";

range(1, 5); // [1, 2, 3, 4]
range(5); // [0, 1, 2, 3, 4]
range(-5); // [0, -1, -2, -3, -4]
range(0, 20, 5); // [0, 5, 10, 15]

🍦Try It

npm install just-remove

import remove from "just-remove";

remove([1, 2, 3, 4, 5, 6], [1, 3, 6]); // [2, 4, 5]

🍦Try It

npm install just-union

import union from "just-union";

union([1, 2, 5, 6], [2, 3, 4, 6]); // [1, 2, 3, 4, 5, 6]

🍦Try It

npm install just-zip-it

import zip from "just-zip-it";

zip([1, 2, 3]); // [[1], [2], [3]]
zip([1, 2, 3], ["a", "b", "c"]); // [[1, 'a'], [2, 'b'], [3, 'c']]
zip([1, 2], ["a", "b"], [true, false]); // [[1, 'a', true], [2, 'b', false]]
zip([1, 2, 3], ["a", "b"], [true]); // [[1, 'a', true], [2, 'b', undefined], [3, undefined, undefined]]
zip(undefined, {}, false, 1, "foo"); // throws
zip([1, 2], ["a", "b"], undefined, {}, false, 1, "foo"); // throws

🍦Try It

npm install just-group-by

import groupBy from "just-group-by";

groupBy([6.1, 4.2, 6.3], Math.floor); // { '4': [4.2], '6': [6.1, 6.3] }
groupBy([1, 2, 3, 4, 5, 6, 7, 8], function (i) {
  return i % 2;
}); // { '0': [2, 4, 6, 8], '1': [1, 3, 5, 7] }
groupBy("string", Math.floor); // throws
groupBy([1, 2, 3, 4], "string"); // throws

Statistics

🍦Try It

npm install just-mean

import mean from "just-mean";

mean([1, 2, 3, 2, 4, 1]); // 2.1666666667
mean(3, 2, 1); // 2
mean([4]); // 4
mean(["3", 2]); // throws
mean(); // throws

🍦Try It

npm install just-median

import median from "just-median";

median([1, 2, 3, 4, 5]); // 3
median([3, -1, 2]); // 2
median([9, 14, 14, 200, 15]); // 14
median(1, 2, 4, 3); // 2.5
median(["3", 2, 1]); // throws
median(); // throws

🍦Try It

npm install just-mode

import mode from "just-mode";

mode([1, 2, 3, 2]); // 2
mode(4, 4, 1, 4); // 4
mode(100, 100, 101, 101); // [100, 101]
mode(4, 3, 2, 1); // [1, 2, 3, 4]
mode(["1", 2, 2, 1, 2]); // throws
mode(null); // throws

🍦Try It

npm install just-percentile

import percentile from "just-percentile";

percentile([1, 2, 3], 0); // 1
percentile([1, 2, 3], 50); // 2
percentile([1, 2, 3], 100); // 3

// See https://en.wikipedia.org/wiki/Percentile (linear interpolation method)
percentile([15, 20, 35, 40, 50], 5); // 15
percentile([15, 20, 35, 40, 50], 30); // 20
percentile([15, 20, 35, 40, 50], 40); // 27.5
percentile([15, 20, 35, 40, 50], 95); // 50

percentile(1, 2, 3, 50); // throws
percentile(["1", 2, 3], 50); // throws
percentile([], 50); // throws

🍦Try It

npm install just-variance

import variance from "just-variance";

variance([1, 2, 3, 2, 4, 1]); // 1.3666666667
variance(3, 2, 1); // 1
variance([100, 100, 100.1, 100]); // 0.0025
variance(1, 2, 3, 4, 5, -6); // 15.5
variance([4]); // throws
variance(["3", 2]); // throws
variance(NaN, NaN); // throws
variance(); // throws

🍦Try It

npm install just-standard-deviation

import standardDeviation from "just-standard-deviation";

standardDeviation([1, 2, 3, 2, 4, 1]); // 1.16904519
standardDeviation(3, 2, 1); // 1
standardDeviation([100, 100, 100.1, 100]); // 0.05
standardDeviation(1, 2, 3, 4, 5, -6); // 3.9370039
standardDeviation([4]); // throws
standardDeviation(["3", 2]); // throws
standardDeviation(NaN, NaN); // throws
standardDeviation(); // throws

🍦Try It

npm install just-skewness

import skewness from "just-skewness";

// Using Pearson's second skewness coefficient
skewness(3, 2, 1); // 0
skewness([1, 2, 3, 2, 4, 1]); // 0.4276994613841504
skewness(1, 2, 3, 4, 5, -6); // -0.762000762001143
skewness([1, 2, 3, 4, 9]); // 0.7705935588815224
skewness([4]); // throws
skewness(["3", 2]); // throws
skewness(NaN, NaN); // throws
skewness(); // throws

Strings

🍦Try It

npm install just-template

import template from "just-template";

const data = {
  a: {
    aa: {
      aaa: "apple",
      bbb: "pear",
    },
    bb: "orange",
  },
  b: "plum",
};
template(
  "2 {{a.aa.aaa}}s, a {{a.aa.bbb}}, 3 {{a.bb}}s and a {{b}}. Yes 1 {{a.aa.bbb}}.",
  data
);
// '2 apples, a pear, 3 oranges and a plum. Yes 1 pear.'

🍦Try It

npm install just-truncate

truncate("when shall we three meet again", 9); // 'when s...'
truncate("when shall we three meet again", 12, " (etc)"); // 'when s (etc)'
truncate("when shall we", 15); // 'when shall we'
truncate("when shall we", 15, "(more)"); // 'when shall we'
truncate("when shall we", 10, " (etc etc etc)"); // ' (etc etc etc)'

🍦Try It

npm install just-prune

  prune('when shall we three meet again', 7); // 'when...'
  prune('when shall we three meet again', 7, ' (more)'; // 'when (more)'
  prune('when shall we', 15,); // 'when shall we'
  prune('when shall we', 15, ' (etc)'); // 'when shall we'
  prune('when shall we', 7, ' (more)'); // ' (more)'

🍦Try It

npm install just-squash

squash("the cat sat on the mat"); // 'thecatsatonthemat'
squash(" the cat sat on the mat "); // 'thecatsatonthemat'
squash("\tthe cat\n sat \fon \vthe \rmat "); // '\tthecat\nsat\fon\vthe\rmat'
squash("\tthe cat\n sat \fon \vthe \rmat ", true); // 'thecatsatonthemat'
squash(
  `the cat
sat on the mat`,
  true
); // thecatsatonthemat

🍦Try It

npm install just-left-pad

leftPad("hello", 9); // '    hello'
leftPad("hello", 3); // 'hello'
leftPad("hello", 9, "."); // '....hello'
leftPad("hello", 9, ".."); // '....hello'
leftPad("hello", 10, "ab"); // 'bababhello'
leftPad("hello", 9, "\uD83D\uDC04"); // '🐄🐄🐄🐄hello'
leftPad("hello", 10, "\uD83D\uDC11\uD83D\uDC04"), // '🐄🐑🐄🐑🐄hello'
  leftPad("hello", 7, "🐄"), // '🐄🐄hello'
  leftPad(null, 7); // throws
leftPad([], 4, "*"); // throws
leftPad("hello", 4, true); // throws
leftPad("hello", -4, true); // throws
leftPad("hello", 2.3, true); // throws

🍦Try It

npm install just-right-pad

rightPad("hello", 9); // 'hello    '
rightPad("hello", 3); // 'hello'
rightPad("hello", 9, "."); // 'hello....'
rightPad("hello", 9, ".."); // 'hello....'
rightPad("hello", 10, "ab"); // 'helloababa'
rightPad("hello", 9, "\uD83D\uDC04"); // 'hello🐄🐄🐄🐄'
rightPad("hello", 10, "\uD83D\uDC11\uD83D\uDC04"), // 'hello🐑🐄🐑🐄🐑'
  rightPad("hello", 7, "🐄"), // 'hello🐄🐄'
  rightPad(null, 7); // throws
rightPad([], 4, "*"); // throws
rightPad("hello", 4, true); // throws
rightPad("hello", -4, true); // throws
rightPad("hello", 2.3, true); // throws

🍦Try It

npm install just-camel-case

camelCase("the quick brown fox"); // 'theQuickBrownFox'
camelCase("the_quick_brown_fox"); // 'theQuickBrownFox'
camelCase("the-quick-brown-fox"); // 'theQuickBrownFox'
camelCase("theQuickBrownFox"); // 'theQuickBrownFox'
camelCase("thequickbrownfox"); // 'thequickbrownfox'
camelCase("the - quick * brown# fox"); // 'theQuickBrownFox'
camelCase("behold theQuickBrownFox"); // 'beholdTheQuickBrownFox'
camelCase("Behold theQuickBrownFox"); // 'beholdTheQuickBrownFox'
// all caps words are camel-cased
camelCase("The quick brown FOX"); // theQuickBrownFox
// all caps substrings >= 4 chars are camel-cased
camelCase("theQUickBrownFox"); // 'theQUickBrownFox'
camelCase("theQUIckBrownFox"); // 'theQUIckBrownFox'
camelCase("theQUICKBrownFox"); // 'theQuickBrownFox'

🍦Try It

npm install just-kebab-case

kebabCase("the quick brown fox"); // 'the-quick-brown-fox'
kebabCase("the-quick-brown-fox"); // 'the-quick-brown-fox'
kebabCase("the_quick_brown_fox"); // 'the-quick-brown-fox'
kebabCase("theQuickBrownFox"); // 'the-quick-brown-fox'
kebabCase("theQuickBrown Fox"); // 'the-quick-brown-fox'
kebabCase("thequickbrownfox"); // 'thequickbrownfox'
kebabCase("the - quick * brown# fox"); // 'the-quick-brown-fox'
kebabCase("theQUICKBrownFox"); // 'the-q-u-i-c-k-brown-fox'

🍦Try It

npm install just-snake-case

snakeCase("the quick brown fox"); // 'the_quick_brown_fox'
snakeCase("the-quick-brown-fox"); // 'the_quick_brown_fox'
snakeCase("the_quick_brown_fox"); // 'the_quick_brown_fox'
snakeCase("theQuickBrownFox"); // 'the_quick_brown_fox'
snakeCase("theQuickBrown Fox"); // 'the_quick_brown_Fox'
snakeCase("thequickbrownfox"); // 'thequickbrownfox'
snakeCase("the - quick * brown# fox"); // 'the_quick_brown_fox'
snakeCase("theQUICKBrownFox"); // 'the_q_u_i_c_k_brown_fox'

🍦Try It

npm install just-pascal-case

pascalCase("the quick brown fox"); // 'TheQuickBrownFox'
pascalCase("the_quick_brown_fox"); // 'TheQuickBrownFox'
pascalCase("the-quick-brown-fox"); // 'TheQuickBrownFox'
pascalCase("theQuickBrownFox"); // 'TheQuickBrownFox'
pascalCase("thequickbrownfox"); // 'Thequickbrownfox'
pascalCase("the - quick * brown# fox"); // 'TheQuickBrownFox'
pascalCase("theQUICKBrownFox"); // 'TheQUICKBrownFox'

🍦Try It

npm install just-capitalize

capitalize("capitals"); // 'Capitals'
capitalize("Capitals"); // 'Capitals'
// all remaining characters are lowercased
capitalize("CAPITALS"); // 'Capitals'
capitalize("CaPiTaLs"); // 'Capitals'
capitalize(" capitals"); // ' capitals'
capitalize("Capi tals"); // 'Capi tals'
capitalize("Capi Tals"); // 'Capi tals'
capitalize("!capitals"); // '!capitals'

🍦Try It

npm install just-replace-all

replaceAll("hello, world", "l", "q"); // 'heqqo, worqd'
replaceAll("hello, world", "l", "qq"); // 'heqqqqo, worqqd'
replaceAll("hello, world", "ll", "q"); // 'heqo, world'
replaceAll("hello, world", "", "q"); // 'hello, world'
replaceAll("hello, world", "l", ""); // 'heo, word'
replaceAll("hello, world", null, "q"); // 'hello, world'
replaceAll("hello, world", "l"); // throw
replaceAll("hello, world"); // throw
replaceAll(); // throw
replaceAll(null, "l", "q"); // throw
replaceAll("hello, world", null, "q"); // throw
replaceAll("hello, world", "l", null); // throw

Numbers

🍦Try It

npm install just-clamp

import clamp from "just-clamp";

var n = 5;
clamp(1, n, 12); // 5
clamp(3, n, 1); // 3
clamp(8, n, 9); // 8
clamp(0, n, 0); // 0

var n = -5;
clamp(1, n, 12); // 1
clamp(-7, n, -8); // -7

clamp(NaN, n, 8); // NaN
clamp(3, n, NaN); // NaN
clamp(3, NaN, 8); // NaN

clamp(undefined, n, 8); // throws
clamp(3, n, "h"); // throws
clamp(3, false, 8); // throws

🍦Try It

npm install just-is-prime

import isPrime from "just-is-prime";

isPrime(1); // false
isPrime(2); // true
isPrime(17); // true
isPrime(10); // false
isPrime(); // throws
isPrime(null); // throws
isPrime("js"); // throws
isPrime({}); // throws
isPrime(function () {}); // throws
isPrime([]); // throws

🍦Try It

npm install just-modulo

import modulo from "just-modulo";

modulo(7, 5); // 2
modulo(17, 23); // 17
modulo(16.2, 3.8); // 1
modulo(5.8, 3.4); //2.4
modulo(4, 0); // 4
modulo(-7, 5); // 3
modulo(-2, 15); // 13
modulo(-5.8, 3.4); // 1
modulo(12, -1); // NaN
modulo(-3, -8); // NaN
modulo(12, "apple"); // NaN
modulo("bee", 9); // NaN
modulo(null, undefined); // NaN

Functions

🍦Try It

npm install just-compose

import compose from "just-compose";

const sqRootBiggest = compose(Math.max, Math.sqrt, Math.trunc);
sqRootBiggest(10, 5); // 3
sqRootBiggest(7, 0, 16); // 4

🍦Try It

npm install just-curry-it

import curry from "just-curry-it";

function add(a, b, c) {
  return a + b + c;
}
curry(add)(1)(2)(3); // 6
curry(add)(1)(2)(2); // 5
curry(add)(2)(4, 3); // 9

function add(...args) {
  return args.reduce((sum, n) => sum + n, 0);
}
var curryAdd4 = curry(add, 4);
curryAdd4(1)(2, 3)(4); // 10

function converter(ratio, input) {
  return (input * ratio).toFixed(1);
}
const curriedConverter = curry(converter);
const milesToKm = curriedConverter(1.62);
milesToKm(35); // 56.7
milesToKm(10); // 16.2

🍦Try It

npm install just-demethodize

const demethodize = require("just-demethodize");

const trimFn = demethodize("".trim);
["hello ", " goodbye", "hello again"].map(trimFn);

🍦Try It

npm install just-flip

import flip from "just-flip";

flip(console.log)(1, 2, 3); // 2, 1, 3

🍦Try It

npm install just-partial-it

import partial from "just-partial-it";

const cubedRoot = partial(Math.pow, undefined, 1 / 3);
cubedRoot(64); // 4

const getRoot = partial(Math.pow, 64);
getRoot(1 / 2); // 8

🍦Try It

npm install just-permutations

import permutations from "just-permutations";

permutations([1, 2, 3]); // [[1, 2, 3], [2, 1, 3], [2, 3, 1], [1, 3, 2], [3, 1, 2], [3, 2, 1]]
permutations([]); // []
permutations(); // throws

🍦Try It

npm install just-debounce-it

import debounce from "just-debounce-it";

const fn1 = debounce(() => console.log("Hello"), 500);
fn1();
fn1();
fn1();
// 500ms later logs 'hello' once

const fn2 = debounce(() => console.log("Hello"), 500, true);
fn2(); // logs hello immediately
fn2();
fn2();
// 500ms later logs 'hello' once

const fn3 = debounce(() => console.log("Hello"), 500);
fn1();
fn1();
fn1();
fn3.cancel();
// function cancelled before 'hello' is logged

const fn4 = debounce(() => console.log("Hello"), 500);
fn4();
fn4();
fn4();
fn4.flush();
// immediately invoke the debounced function

🍦Try It

npm install just-memoize

import memoize from "just-memoize";

const sumByOne = memoize(function (value) {
  return value + 1;
});

sumByOne(10); // Returns value returned by the function
sumByOne(10); // Cache hit!

sumByOne(20); // Returns value returned by the function
sumByOne(20); // Cache hit!

// Custom cache key (key defaults to JSON stringified arguments)
var sum = memoize(
  function (a, b) {
    return a + b;
  },
  function (a, b) {
    return `${a}-${b}`;
  }
);

sum(10, 10); // Returns value returned by the function
sum(10, 20); // Returns value returned by the function
sum(10, 20); // Cache hit!

🍦Try It

npm install just-memoize-last

const memoizeLast = require('just-memoize-last')
const compare = require('just-compare')

const maxValue = memoizeLast(function(arr) {
  return Math.max(...arr)
}, function(a, b) {
  return compare(a, b);
});

maxValue([1,2,3]) // 3
maxValue([1,2,3]) // cache hit!
maxValue([1,3,4]) // 4
maxValue([1,2,3]) // 3

🍦Try It

npm install just-random

import random from 'just-random';

random();
// Produces a random number between 0 and 1

random(5);
// Produces a random number between 0 and 5

random(5, 10);
// Produces a random number between 5 and 10

🍦Try It

npm install just-throttle

import throttle from "just-throttle";

// no matter how many times the function is called, only invoke once within the given interval
// options: 
// `leading`: invoke  before interval
// `trailing`: invoke afer interval

const fn1 = throttle(() => console.log("hello"), 500, { leading: true });
setInterval(fn1, 400);
// logs 'hello' immediately and then every 500ms

const fn2 = throttle(() => console.log("hello"), 500, { trailing: true });
setInterval(fn2, 400);
// logs 'hello' after 500ms and then every 500ms

const fn3 = throttle(() => console.log("hello"), 500, {
  leading: true,
  trailing: true,
});
// forces trailing to false

const fn4 = throttle(() => console.log('hello'), 500, { leading: false });
fn4();
fn4();
fn4();
fn4.cancel();
// function cancelled before 'hello' is logged

const fn5 = throttle(() => console.log("Hello"), 500);
fn5();
fn5();
fn5();
fn5.flush();
// immediately invoke the throttled function

🍦Try It

npm install just-once

import once from "just-once";

const fn = once(() => console.log("hello"));

fn();
// logs 'hello'
fn();
// does nothing

Testing

Run all tests as a single test suite with

npm run test

Cross browser tests (via saucelabs) are in the sauce branch

Contribute!

https://github.com/angus-c/just/blob/master/CONTRIBUTING.md