Nigel  Uys

Nigel Uys

1680158640

Files: Building the best file manager experience for Windows

Files

Introducing Files, the ultimate file manager app for Windows. With its sleek and intuitive design, navigating through your files has never been easier. Files features tabs for easy switching between different folders, a column view for quick file browsing, and dual pane support for efficient file management. In addition, you can easily create and extract archives with just a few clicks, making file compression and decompression a breeze.

Files also offers advanced features such as file tagging for easy organization, support for QuickLook for previewing files without opening them, and the ability to customize the background color to match your personal style. Whether you're a power user or just looking for a better way to manage your files, Files has everything you need to keep your files organized and easily accessible. With its combination of powerful features and ease of use, Files is the ultimate file management solution for Windows.

Building from source

1. Prerequisites

  • Visual Studio 2022 with the following individual components:
    • Windows 11 SDK (10.0.22621.0)
    • .NET 7 SDK
    • MSVC v143 - VS 2022 C++ x64/x86 or ARM64 build tools (latest)
    • C++ ATL for latest v143 build tools (x86 & x64 or ARM64)
    • Git for Windows
  • Windows App SDK 1.2

2. Clone the repository

git clone https://github.com/files-community/Files

This will create a local copy of the repository.

3. Build the project

To build Files for development, open the Files.sln item in Visual Studio. Right-click on the Files.Package packaging project in solution explorer and select β€˜Set as Startup item’.

In the top pane, select the items which correspond to your desired build mode and the processor architecture of your device like below: image

Contributors

Want to contribute to this project? Let us know with an issue that communicates your intent to create a pull request. Also, view our contributing guidelines to make sure you're up to date on the coding conventions.

Looking for a place to start? Check out the task board, where you can sort tasks by size and priority.

Screenshots

Files


Download Details:

Author: Files-community
Source Code: https://github.com/files-community/Files 
License: MIT license

#csharp #windows #productivity #files #xaml #utilities #dotnet 

Files: Building the best file manager experience for Windows

Julia Utilities for The Conic Benchmark Format

ConicBenchmarkUtilities

Utitilies to convert between CBF and MathProgBase conic format.

How to read and solve a CBF instance:

dat = readcbfdata("/path/to/instance.cbf") # .cbf.gz extension also accepted

# In MathProgBase format:
c, A, b, con_cones, var_cones, vartypes, sense, objoffset = cbftompb(dat)
# Note: The sense in MathProgBase form is always minimization, and the objective offset is zero.
# If sense == :Max, you should flip the sign of c before handing off to a solver.

# Given the data in MathProgBase format, you can solve it using any corresponding solver which supports the cones present in the problem.
# To use ECOS, for example,
using ECOS
solver = ECOSSolver()
# Now load and solve
m = MathProgBase.ConicModel(ECOSSolver(verbose=0))
MathProgBase.loadproblem!(m, c, A, b, con_cones, var_cones)
# Continuous solvers need not implement setvartype!
if !all(vartypes .== :Cont)
    MathProgBase.setvartype!(m, vartypes)
end
MathProgBase.optimize!(m)
# Solution accessible through:
x_sol = MathProgBase.getsolution(m)
objval = MathProgBase.getobjval(m)
# If PSD vars are present, you can use the following utility to extract the solution in CBF form:
scalar_solution, psdvar_solution = ConicBenchmarkUtilities.mpb_sol_to_cbf(dat,x_sol)

How to write a CBF instance:

newdat = mpbtocbf("example", c, A, b, con_cones, var_cones, vartypes, sense)
writecbfdata("example.cbf",newdat,"# Comment for the CBF header")

Note that because MathProgBase conic format is more general than CBF in specifying the mapping between variables and cones, the order of the variables in the CBF file may not match the original order. No reordering takes place if var_cones is trivial, i.e., [(:Free,1:N)] where N is the total number of variables.

How to write a JuMP model to CBF form:

m = JuMP.Model()
@variable(m, x[1:2])
@variable(m, t)
@constraint(m, norm(x) <= t)
ConicBenchmarkUtilities.jump_to_cbf(m, "soctest", "soctest.cbf")

Download Details:

Author: JuliaOpt
Source Code: https://github.com/JuliaOpt/ConicBenchmarkUtilities.jl 
License: View license

#julia #utilities 

Julia Utilities for The Conic Benchmark Format
Lawrence  Lesch

Lawrence Lesch

1675450140

Env-cmd: Setting Environment Variables From A File

env-cmd

A simple node program for executing commands using an environment from an env file.

πŸ’Ύ Install

npm install env-cmd or npm install -g env-cmd

⌨️ Basic Usage

Environment file ./.env

# This is a comment
ENV1=THANKS
ENV2=FOR ALL
ENV3=THE FISH

Package.json

{
  "scripts": {
    "test": "env-cmd mocha -R spec"
  }
}

Terminal

./node_modules/.bin/env-cmd node index.js

Using custom env file path

To use a custom env filename or path, pass the -f flag. This is a major breaking change from prior versions < 9.0.0

Terminal

./node_modules/.bin/env-cmd -f ./custom/path/.env node index.js

πŸ“œ Help

Usage: _ [options] <command> [...args]

Options:
  -v, --version                       output the version number
  -e, --environments [env1,env2,...]  The rc file environment(s) to use
  -f, --file [path]                   Custom env file path (default path: ./.env)
  --fallback                          Fallback to default env file path, if custom env file path not found
  --no-override                       Do not override existing environment variables
  -r, --rc-file [path]                Custom rc file path (default path: ./.env-cmdrc(|.js|.json)
  --silent                            Ignore any env-cmd errors and only fail on executed program failure.
  --use-shell                         Execute the command in a new shell with the given environment
  --verbose                           Print helpful debugging information
  -x, --expand-envs                   Replace $var in args and command with environment variables
  -h, --help                          output usage information

πŸ”¬ Advanced Usage

.rc file usage

For more complex projects, a .env-cmdrc file can be defined in the root directory and supports as many environments as you want. Simply use the -e flag and provide which environments you wish to use from the .env-cmdrc file. Using multiple environment names will merge the environment variables together. Later environments overwrite earlier ones in the list if conflicting environment variables are found.

.rc file ./.env-cmdrc

{
  "development": {
    "ENV1": "Thanks",
    "ENV2": "For All"
  },
  "test": {
    "ENV1": "No Thanks",
    "ENV3": "!"
  },
  "production": {
    "ENV1": "The Fish"
  }
}

Terminal

./node_modules/.bin/env-cmd -e production node index.js
# Or for multiple environments (where `production` vars override `test` vars,
# but both are included)
./node_modules/.bin/env-cmd -e test,production node index.js

--no-override option

Prevents overriding of existing environment variables on process.env and within the current environment.

--fallback file usage option

If the .env file does not exist at the provided custom path, then use the default fallback location ./.env env file instead.

--use-shell

Executes the command within a new shell environment. This is useful if you want to string multiple commands together that share the same environment variables.

Terminal

./node_modules/.bin/env-cmd -f ./test/.env --use-shell "npm run lint && npm test"

Asynchronous env file support

EnvCmd supports reading from asynchronous .env files. Instead of using a .env file, pass in a .js file that exports either an object or a Promise resolving to an object ({ ENV_VAR_NAME: value, ... }). Asynchronous .rc files are also supported using .js file extension and resolving to an object with top level environment names ({ production: { ENV_VAR_NAME: value, ... } }).

Terminal

./node_modules/.bin/env-cmd -f ./async-file.js node index.js

-x expands vars in arguments

EnvCmd supports expanding $var values passed in as arguments to the command. The allows a user to provide arguments to a command that are based on environment variable values at runtime.

NOTE: You must escape the $ character with \ or your terminal might try to auto expand it before passing it to env-cmd.

Terminal

# $VAR will be expanded into the env value it contains at runtime
./node_modules/.bin/env-cmd -x node index.js --arg=\$VAR

or in package.json (use \\ to insert a literal backslash)

{
  "script": {
    "start": "env-cmd -x node index.js --arg=\\$VAR"
  }
}

--silent suppresses env-cmd errors

EnvCmd supports the --silent flag the suppresses all errors generated by env-cmd while leaving errors generated by the child process and cli signals still usable. This flag is primarily used to allow env-cmd to run in environments where the .env file might not be present, but still execute the child process without failing due to a missing file.

πŸ’Ώ Examples

You can find examples of how to use the various options above by visiting the examples repo env-cmd-examples.

πŸ’½οΈ Environment File Formats

These are the currently accepted environment file formats. If any other formats are desired please create an issue.

  • .env as key=value
  • .env.json Key/value pairs as JSON
  • .env.js JavaScript file exporting an object or a Promise that resolves to an object
  • .env-cmdrc as valid json or .env-cmdrc.json in execution directory with at least one environment { "dev": { "key1": "val1" } }
  • .env-cmdrc.js JavaScript file exporting an object or a Promise that resolves to an object that contains at least one environment

πŸ—‚ Path Rules

This lib attempts to follow standard bash path rules. The rules are as followed:

Home Directory = /Users/test

Working Directory = /Users/test/Development/app

TypeInput PathExpanded Path
Absolute/some/absolute/path.env/some/absolute/path.env
Home Directory with ~~/starts/on/homedir/path.env/Users/test/starts/on/homedir/path.env
Relative./some/relative/path.env or some/relative/path.env/Users/test/Development/app/some/relative/path.env
Relative with parent dir../some/relative/path.env/Users/test/Development/some/relative/path.env

πŸ›  API Usage

EnvCmd

A function that executes a given command in a new child process with the given environment and options

  • options { object }
    • command { string }: The command to execute (node, mocha, ...)
    • commandArgs { string[] }: List of arguments to pass to the command (['-R', 'Spec'])
    • envFile { object }
      • filePath { string }: Custom path to .env file to read from (defaults to: ./.env)
      • fallback { boolean }: Should fall back to default ./.env file if custom path does not exist
    • rc { object }
      • environments { string[] }: List of environment to read from the .rc file
      • filePath { string }: Custom path to the .rc file (defaults to: ./.env-cmdrc(|.js|.json))
    • options { object }
      • expandEnvs { boolean }: Expand $var values passed to commandArgs (default: false)
      • noOverride { boolean }: Prevent .env file vars from overriding existing process.env vars (default: false)
      • silent { boolean }: Ignore any errors thrown by env-cmd, used to ignore missing file errors (default: false)
      • useShell { boolean }: Runs command inside a new shell instance (default: false)
      • verbose { boolean }: Prints extra debug logs to console.info (default: false)
    • Returns { Promise<object> }: key is env var name and value is the env var value

GetEnvVars

A function that parses environment variables from a .env or a .rc file

  • options { object }
    • envFile { object }
      • filePath { string }: Custom path to .env file to read from (defaults to: ./.env)
      • fallback { boolean }: Should fall back to default ./.env file if custom path does not exist
    • rc { object }
      • environments { string[] }: List of environment to read from the .rc file
      • filePath { string }: Custom path to the .rc file (defaults to: ./.env-cmdrc(|.js|.json))
    • verbose { boolean }: Prints extra debug logs to console.info (default: false)
  • Returns { Promise<object> }: key is env var name and value is the env var value

πŸ§™ Why

Because sometimes it is just too cumbersome passing a lot of environment variables to scripts. It is usually just easier to have a file with all the vars in them, especially for development and testing.

🚨Do not commit sensitive environment data to a public git repo! 🚨

🧬 Related Projects

cross-env - Cross platform setting of environment scripts

🎊 Special Thanks

Special thanks to cross-env for inspiration (uses the same cross-spawn lib underneath too).

πŸ“‹ Contributing Guide

I welcome all pull requests. Please make sure you add appropriate test cases for any features added. Before opening a PR please make sure to run the following scripts:

  • npm run lint checks for code errors and format according to ts-standard
  • npm test make sure all tests pass
  • npm run test-cover make sure the coverage has not decreased from current master

Download Details:

Author: Toddbluhm
Source Code: https://github.com/toddbluhm/env-cmd 
License: MIT license

#typescript #nodejs #utilities #crossplatform 

Env-cmd: Setting Environment Variables From A File
Rupert  Beatty

Rupert Beatty

1669921740

Drop These Old Utilities for Modern Alternatives with Linux

These traditional Linux utilities have been revitalized with modern replacements.

Linux has a good track record for software support. There are about 60 commands in man section 1 of Unix 1st edition, and the majority still work today. Still, progress stops for no one. Thanks to vast global participation in open source, new commands are frequently developed. Sometimes a new command gains popularity, usually because it offers new features, or the same features but with consistent maintenance. Here are ten old commands that have recently been reinvented.

1. Replace man with cheat or tealdeer

The man page is functional, and it works well for what it does. However, man pages aren't always the most succinct at demonstrating how to use the command you're trying to reference. If you're looking for something a little more to the point, try cheat or tealdeer.

2. Replace ifconfig with ip

The ifconfig command provides information about your network interfaces, whether they're physical or virtual.

$ ifconfig
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
  inet 10.1.2.34  netmask 255.255.255.0  broadcast 10.0.1.255
  inet6 fe80::f452:f8e1:7f05:7514  prefixlen 64
  ether d8:5e:d3:2d:d5:68  txqueuelen 1000  (Ethernet)
  [...]

tun0: flags=4305<UP,POINTOPOINT,RUNNING,NOARP,MULTICAST>  mtu 1360
  inet 10.2.3.45  netmask 255.255.254.0  destination 10.2.14.15
  inet6 2620:52:4:1109::100e  prefixlen 64  scopeid 0x0<global>
  unspec 00-00-00-00-00-00-00-00-[...]0-00  txqueuelen 500  (UNSPEC)
  [...]

The newer ip command provides similar information:

$ ip -4 address
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    inet 127.0.0.1/8 scope host lo
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    inet 10.1.2.34/24 brd 10.0.1.255 scope global noprefixroute eth0
4: virbr0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
    inet 192.168.122.1/24 brd 192.168.122.255 scope global virbr0
5: tun0: <POINTOPOINT,MULTICAST,NOARP,UP,LOWER_UP> mtu 1360 qdisc pfifo_fast state UNKNOWN group default qlen 500
    inet 10.2.3.45/23 brd 10.2.15.255 scope global noprefixroute tun0

3. Replace yum with dnf and apt-get with apt

Package managers tend to be slow to change, and when they do they often work hard to maintain backward compatibility. Both the yum command and the apt-get command have had improvements lately. The changes are usually aliased or designed to work in both their old and new syntax:

$ sudo yum install foo
$ sudo dnf install foo
$ sudo apt-get install foo
$ sudo apt install foo

4. Replace repoquery with dnf

Before there was dnf there were a variety of utilities for yum to help users get reports on their packaging system configuration. Most of those extra functions got included by default with dnf. For instance, repoquery is a subcommand of dnf, and it provides a list of all installed packages:

$ sudo dnf repoquery

5. Replace pip with pip

The pip command is a package manager for Python. It hasn't been replaced, but the preferred syntax has been updated. The old command:

$ pip install yamllint

The new syntax:

$ python3 -m pip install yamllint

6. Replace ls with exa

The ls command hasn't been replaced.

Rather, it hasn't been replaced again.

The ls command was originally its own binary application, and it's still available as one. Eventually, though, the Bash shell included its own ls built-in command, which by default overrides any installed ls command.

Recently, the exa command has been developed as, depending on your preferences, a better ls. Read about it in Sudeshna Sur's exa command article, and then try it for yourself.

7. Replace du with dust or ncdu

There's nothing wrong with the du, which reports on how much disk space is used on your hard drives. It does its job well, but to be fair it's pretty minimal.

If you're looking for a little variety, try the ncdu command or the dust command.

8. Replace cat with bat

The cat command is, aside from being overused by the best of us, is a simple and direct command. It reads the contents of any number of files, and outputs it to standard input.

Its output is pretty basic, so if you're looking for something with syntax highlighting and flexible output options, try the bat command instead.

Does bat also replace the tac command? No, don't worry, for now at least tac is safe in its position as the command that outputs a file in reverse. (Unless, that is, you count sed.)

9. Replace netstat with ss

The netstat command has largely been replaced by the ss command, although of all the commands on this list it's possibly the most hotly debated. The ss command provides much of the same functionality, but as Jose Vicente Nunez points out in his six deprecated commands article, there are gaps and differences in functionality. Before switching wholesale to ss, try it and compare it with how you use netstat now.

10. Replace find with fd

I use find to located files, as an input source for GNU Parallel, and more. I'm pretty familiar with it, but I have to admit that its syntax is a little clunky. The fd command seeks to improve upon that. For instance, suppose you're looking for a file called example, but you can't remember what file extension you used. With find, the syntax might look something like this:

$ find . -name "*example*"
/home/tux/example.adoc
/home/tux/example.sh

With fd, the syntax is:

$ fd example
/home/tux/example.adoc
/home/tux/example.sh

And suppose you want to grep command to search through the results for the phrase "zombie apocalypse". Using find:

$ find . -name "*example*" -exec grep "zombie apocalypse" {} \;
zombie apocalypse

Using fd instead:

$ fd txt -x grep zombie
zombie apocalypse

Read more about it in Sudeshna Sur's fd article, and then try it for yourself.

For even more updates to classic commands, download our cheat sheet below.

Original article source at: https://opensource.com/

#linux #utilities 

Drop These Old Utilities for Modern Alternatives with Linux
Lawrence  Lesch

Lawrence Lesch

1668077768

Utility-types: Collection Of Utility Types

utility-types

Collection of utility types, complementing TypeScript built-in mapped types and aliases (think "lodash" for static types).

Found it useful? Want more updates? 


What's new?

πŸŽ‰ Now updated to support TypeScript v3.7 πŸŽ‰


Features

Goals

  • Quality - thoroughly tested for type correctness with type-testing library dts-jest
  • Secure and minimal - no third-party dependencies
  • No runtime cost - it's type-level only

Installation

# NPM
npm install utility-types

# YARN
yarn add utility-types

Compatibility Notes

TypeScript support

  • v3.x.x - TypeScript v3.1+
  • v2.x.x - TypeScript v2.8.1+
  • v1.x.x - TypeScript v2.7.2+

Funding Issues

Utility-Types is an open-source project created by people investing their time for the benefit of our community.

Issues like bug fixes or feature requests can be very quickly resolved when funded through the IssueHunt platform.

I highly recommend adding a bounty to the issue that you're waiting for to attract some contributors willing to work on it.

Let's fund issues in this repository

Contributing

We are open for contributions. If you're planning to contribute please make sure to read the contributing guide as it can save you from wasting your time: CONTRIBUTING.md


  • (built-in) - types built-in TypeScript, no need to import

Table of Contents

Aliases & Type Guards

Union operators

Object operators

Special operators

Flow's Utility Types

Deprecated API (use at own risk)

  • getReturnOfExpression() - from TS v2.0 it's better to use type-level ReturnType instead

Primitive

Type representing primitive types in JavaScript, and thus TypeScript: string | number | bigint | boolean | symbol | null | undefined

You can test for singular of these types with typeof

isPrimitive

This is a TypeScript Typeguard for the Primitive type.

This can be useful to control the type of a parameter as the program flows. Example:

const consumer = (param: Primitive[] | Primitive): string => {
    if (isPrimitive(param)) {
        // typeof param === Primitive
        return String(param) + ' was Primitive';
    }
    // typeof param === Primitive[]
    const resultArray = param
        .map(consumer)
        .map(rootString => '\n\t' + rootString);
    return resultArray.reduce((comm, newV) => comm + newV, 'this was nested:');
};

Falsy

Type representing falsy values in TypeScript: false | "" | 0 | null | undefined

Except NaN which cannot be represented as a type literal

isFalsy

const consumer = (param: Falsy | string): string => {
    if (isFalsy(param)) {
        // typeof param === Falsy
        return String(param) + ' was Falsy';
    }
    // typeof param === string
    return param.toString();
};

Nullish

Type representing nullish values in TypeScript: null | undefined

isNullish

const consumer = (param: Nullish | string): string => {
    if (isNullish(param)) {
        // typeof param === Nullish
        return String(param) + ' was Nullish';
    }
    // typeof param === string
    return param.toString();
};

SetIntersection<A, B> (same as Extract)

Set intersection of given union types A and B

Usage:

import { SetIntersection } from 'utility-types';

// Expect: "2" | "3"
type ResultSet = SetIntersection<'1' | '2' | '3', '2' | '3' | '4'>;
// Expect: () => void
type ResultSetMixed = SetIntersection<string | number | (() => void), Function>;

SetDifference<A, B> (same as Exclude)

Set difference of given union types A and B

Usage:

import { SetDifference } from 'utility-types';

// Expect: "1"
type ResultSet = SetDifference<'1' | '2' | '3', '2' | '3' | '4'>;
// Expect: string | number
type ResultSetMixed = SetDifference<string | number | (() => void), Function>;

SetComplement<A, A1>

Set complement of given union types A and (it's subset) A1

Usage:

import { SetComplement } from 'utility-types';

// Expect: "1"
type ResultSet = SetComplement<'1' | '2' | '3', '2' | '3'>;

SymmetricDifference<A, B>

Set difference of union and intersection of given union types A and B

Usage:

import { SymmetricDifference } from 'utility-types';

// Expect: "1" | "4"
type ResultSet = SymmetricDifference<'1' | '2' | '3', '2' | '3' | '4'>;

NonNullable<A>

Exclude null and undefined from set A

NonUndefined<A>

Exclude undefined from set A

Exclude<A, B>

Exclude subset B from set A

Extract<A, B>

Extract subset B from set A

Operations on objects

FunctionKeys<T>

Get union type of keys that are functions in object type T

Usage:

import { FunctionKeys } from 'utility-types';

type MixedProps = { name: string; setName: (name: string) => void };

// Expect: "setName"
type Keys = FunctionKeys<MixedProps>;

NonFunctionKeys<T>

Get union type of keys that are non-functions in object type T

Usage:

import { NonFunctionKeys } from 'utility-types';

type MixedProps = { name: string; setName: (name: string) => void };

// Expect: "name"
type Keys = NonFunctionKeys<MixedProps>;

MutableKeys<T>

Get union type of keys that are mutable (not readonly) in object type T

Alias: WritableKeys<T>

Usage:

import { MutableKeys } from 'utility-types';

type Props = { readonly foo: string; bar: number };

// Expect: "bar"
type Keys = MutableKeys<Props>;

ReadonlyKeys<T>

Get union type of keys that are readonly in object type T

Usage:

import { ReadonlyKeys } from 'utility-types';

type Props = { readonly foo: string; bar: number };

// Expect: "foo"
type Keys = ReadonlyKeys<Props>;

RequiredKeys<T>

Get union type of keys that are required in object type T

Usage:

import { RequiredKeys } from 'utility-types';

type Props = { req: number; reqUndef: number | undefined; opt?: string; optUndef?: number | undefined; };

// Expect: "req" | "reqUndef"
type Keys = RequiredKeys<Props>;

OptionalKeys<T>

Get union type of keys that are optional in object type T

Usage:

import { OptionalKeys } from 'utility-types';

type Props = { req: number; reqUndef: number | undefined; opt?: string; optUndef?: number | undefined; };

// Expect: "opt" | "optUndef"
type Keys = OptionalKeys<Props>;

Optional<T, K>

From T make a set of properties by key K become optional

Usage:

import { Optional } from 'utility-types';

type Props = { name: string; age: number; visible: boolean; };

// Expect: { name?: string; age?: number; visible?: boolean; }
type Props = Optional<Props>
// Expect: { name: string; age?: number; visible?: boolean; }
type Props = Optional<Props, 'age' | 'visible'>;

Pick<T, K> (built-in)

From T pick a set of properties by key K

Usage:

type Props = { name: string; age: number; visible: boolean };

// Expect: { age: number; }
type Props = Pick<Props, 'age'>;

PickByValue<T, ValueType>

From T pick a set of properties by value matching ValueType. (Credit: Piotr Lewandowski)

Usage:

import { PickByValue } from 'utility-types';

type Props = { req: number; reqUndef: number | undefined; opt?: string; };

// Expect: { req: number }
type Props = PickByValue<Props, number>;
// Expect: { req: number; reqUndef: number | undefined; }
type Props = PickByValue<Props, number | undefined>;

PickByValueExact<T, ValueType>

From T pick a set of properties by value matching exact ValueType.

Usage:

import { PickByValueExact } from 'utility-types';

type Props = { req: number; reqUndef: number | undefined; opt?: string; };

// Expect: { req: number }
type Props = PickByValueExact<Props, number>;
// Expect: { reqUndef: number | undefined; }
type Props = PickByValueExact<Props, number | undefined>;

Omit<T, K>

From T remove a set of properties by key K

Usage:

import { Omit } from 'utility-types';

type Props = { name: string; age: number; visible: boolean };

// Expect: { name: string; visible: boolean; }
type Props = Omit<Props, 'age'>;

OmitByValue<T, ValueType>

From T remove a set of properties by value matching ValueType. (Credit: Piotr Lewandowski)

Usage:

import { OmitByValue } from 'utility-types';

type Props = { req: number; reqUndef: number | undefined; opt?: string; };

// Expect: { reqUndef: number | undefined; opt?: string; }
type Props = OmitByValue<Props, number>;
// Expect: { opt?: string; }
type Props = OmitByValue<Props, number | undefined>;

OmitByValueExact<T, ValueType>

From T remove a set of properties by value matching exact ValueType.

Usage:

import { OmitByValueExact } from 'utility-types';

type Props = { req: number; reqUndef: number | undefined; opt?: string; };

// Expect: { reqUndef: number | undefined; opt?: string; }
type Props = OmitByValueExact<Props, number>;
// Expect: { req: number; opt?: string }
type Props = OmitByValueExact<Props, number | undefined>;

Intersection<T, U>

From T pick properties that exist in U

Usage:

import { Intersection } from 'utility-types';

type Props = { name: string; age: number; visible: boolean };
type DefaultProps = { age: number };

// Expect: { age: number; }
type DuplicatedProps = Intersection<Props, DefaultProps>;

Diff<T, U>

From T remove properties that exist in U

Usage:

import { Diff } from 'utility-types';

type Props = { name: string; age: number; visible: boolean };
type DefaultProps = { age: number };

// Expect: { name: string; visible: boolean; }
type RequiredProps = Diff<Props, DefaultProps>;

Subtract<T, T1>

From T remove properties that exist in T1 (T1 has a subset of the properties of T)

Usage:

import { Subtract } from 'utility-types';

type Props = { name: string; age: number; visible: boolean };
type DefaultProps = { age: number };

// Expect: { name: string; visible: boolean; }
type RequiredProps = Subtract<Props, DefaultProps>;

Overwrite<T, U>

From U overwrite properties to T

Usage:

import { Overwrite } from 'utility-types';

type Props = { name: string; age: number; visible: boolean };
type NewProps = { age: string; other: string };

// Expect: { name: string; age: string; visible: boolean; }
type ReplacedProps = Overwrite<Props, NewProps>;

Assign<T, U>

From U assign properties to T (just like object assign)

Usage:

import { Assign } from 'utility-types';

type Props = { name: string; age: number; visible: boolean };
type NewProps = { age: string; other: string };

// Expect: { name: string; age: string; visible: boolean; other: string; }
type ExtendedProps = Assign<Props, NewProps>;

ValuesType<T>

Get the union type of all the values in an object, tuple, array or array-like type T.

Usage:

import { ValuesType } from 'utility-types';

type Props = { name: string; age: number; visible: boolean };
// Expect: string | number | boolean
type PropsValues = ValuesType<Props>;

type NumberArray = number[];
// Expect: number
type NumberItems = ValuesType<NumberArray>;

type ReadonlyNumberTuple = readonly [1, 2];
// Expect: 1 | 2
type AnotherNumberUnion = ValuesType<NumberTuple>;

type BinaryArray = Uint8Array;
// Expect: number
type BinaryItems = ValuesType<BinaryArray>;

Partial<T>

Make all properties of object type optional

Required<T, K>

From T make a set of properties by key K become required

Usage:

import { Required } from 'utility-types';

type Props = { name?: string; age?: number; visible?: boolean; };

// Expect: { name: string; age: number; visible: boolean; }
type Props = Required<Props>
// Expect: { name?: string; age: number; visible: boolean; }
type Props = Required<Props, 'age' | 'visible'>;

Readonly<T>

Make all properties of object type readonly

Mutable<T>

From T make all properties become mutable

Alias: Writable<T>

import { Mutable } from 'utility-types';

type Props = {
  readonly name: string;
  readonly age: number;
  readonly visible: boolean;
};

// Expect: { name: string; age: number; visible: boolean; }
Mutable<Props>;

ReturnType<T>

Obtain the return type of a function

InstanceType<T>

Obtain the instance type of a class

Unionize<T>

Disjoin object to form union of objects, each with single property

Usage:

import { Unionize } from 'utility-types';

type Props = { name: string; age: number; visible: boolean };

// Expect: { name: string; } | { age: number; } | { visible: boolean; }
type UnionizedType = Unionize<Props>;

PromiseType<T>

Obtain Promise resolve type

Usage:

import { PromiseType } from 'utility-types';

// Expect: string
type Response = PromiseType<Promise<string>>;

DeepReadonly<T>

Readonly that works for deeply nested structures

Usage:

import { DeepReadonly } from 'utility-types';

type NestedProps = {
  first: {
    second: {
      name: string;
    };
  };
};

// Expect: {
//   readonly first: {
//     readonly second: {
//       readonly name: string;
//     };
//   };
// }
type ReadonlyNestedProps = DeepReadonly<NestedProps>;

DeepRequired<T>

Required that works for deeply nested structures

Usage:

import { DeepRequired } from 'utility-types';

type NestedProps = {
  first?: {
    second?: {
      name?: string;
    };
  };
};

// Expect: {
//   first: {
//     second: {
//       name: string;
//     };
//   };
// }
type RequiredNestedProps = DeepRequired<NestedProps>;

DeepNonNullable<T>

NonNullable that works for deeply nested structure

Usage:

import { DeepNonNullable } from 'utility-types';

type NestedProps = {
  first?: null | {
    second?: null | {
      name?: string | null | undefined;
    };
  };
};

// Expect: {
//   first: {
//     second: {
//       name: string;
//     };
//   };
// }
type RequiredNestedProps = DeepNonNullable<NestedProps>;

DeepPartial<T>

Partial that works for deeply nested structures

Usage:

import { DeepPartial } from 'utility-types';

type NestedProps = {
  first: {
    second: {
      name: string;
    };
  };
};

// Expect: {
//   first?: {
//     second?: {
//       name?: string;
//     };
//   };
// }
type PartialNestedProps = DeepPartial<NestedProps>;

Brand<T, U>

Define nominal type of U based on type of T. Similar to Opaque types in Flow.

Usage:

import { Brand } from 'utility-types';

type USD = Brand<number, "USD">
type EUR = Brand<number, "EUR">

const tax = 5 as USD;
const usd = 10 as USD;
const eur = 10 as EUR;

function gross(net: USD): USD {
  return (net + tax) as USD;
}

gross(usd); // ok
gross(eur); // Type '"EUR"' is not assignable to type '"USD"'.

UnionToIntersection<U>

Get intersection type given union type U

Usage:

import { UnionToIntersection } from 'utility-types';

// Expect: { name: string } & { age: number } & { visible: boolean }
UnionToIntersection<{ name: string } | { age: number } | { visible: boolean }>

Flow's Utility Types

$Keys<T>

get the union type of all the keys in an object type T
https://flow.org/en/docs/types/utilities/#toc-keys

Usage:

import { $Keys } from 'utility-types';

type Props = { name: string; age: number; visible: boolean };

// Expect: "name" | "age" | "visible"
type PropsKeys = $Keys<Props>;

$Values<T>

get the union type of all the values in an object type T
https://flow.org/en/docs/types/utilities/#toc-values

Usage:

import { $Values } from 'utility-types';

type Props = { name: string; age: number; visible: boolean };

// Expect: string | number | boolean
type PropsValues = $Values<Props>;

$ReadOnly<T>

get the read-only version of a given object type T
https://flow.org/en/docs/types/utilities/#toc-readonly

Usage:

import { $ReadOnly } from 'utility-types';

type Props = { name: string; age: number; visible: boolean };

// Expect: Readonly<{ name: string; age: number; visible: boolean; }>
type ReadOnlyProps = $ReadOnly<Props>;

$Diff<T, U>

get the set difference of a given object types T and U (T \ U)
https://flow.org/en/docs/types/utilities/#toc-diff

Usage:

import { $Diff } from 'utility-types';

type Props = { name: string; age: number; visible: boolean };
type DefaultProps = { age: number };

// Expect: { name: string; visible: boolean; }
type RequiredProps = $Diff<Props, DefaultProps>;

$PropertyType<T, K>

get the type of property of an object at a given key K
https://flow.org/en/docs/types/utilities/#toc-propertytype

Usage:

import { $PropertyType } from 'utility-types';

type Props = { name: string; age: number; visible: boolean };
// Expect: string
type NameType = $PropertyType<Props, 'name'>;

type Tuple = [boolean, number];
// Expect: boolean
type A = $PropertyType<Tuple, '0'>;
// Expect: number
type B = $PropertyType<Tuple, '1'>;

$ElementType<T, K>

get the type of elements inside of array, tuple or object of type T, that matches the given index type K
https://flow.org/en/docs/types/utilities/#toc-elementtype

Usage:

import { $ElementType } from 'utility-types';

type Props = { name: string; age: number; visible: boolean };
// Expect: string
type NameType = $ElementType<Props, 'name'>;

type Tuple = [boolean, number];
// Expect: boolean
type A = $ElementType<Tuple, 0>;
// Expect: number
type B = $ElementType<Tuple, 1>;

type Arr = boolean[];
// Expect: boolean
type ItemsType = $ElementType<Arr, number>;

type Obj = { [key: string]: number };
// Expect: number
type ValuesType = $ElementType<Obj, string>;

$Call<T>

get the return type of a given expression type
https://flow.org/en/docs/types/utilities/#toc-call

The built-in ReturnType can be used to accomplish the same goal, although it may have some subtle differences.

Usage:

import { $Call } from 'utility-types';

// Common use-case
const add = (amount: number) => ({ type: 'ADD' as 'ADD', payload: amount });
type AddAction = $Call<typeof add>; // { type: 'ADD'; payload: number }

// Examples migrated from Flow docs
type ExtractPropType<T extends { prop: any }> = (arg: T) => T['prop'];
type Obj = { prop: number };
type PropType = $Call<ExtractPropType<Obj>>; // number
// type Nope = $Call<ExtractPropType<{ nope: number }>>; // Error: argument doesn't match `Obj`.

type ExtractReturnType<T extends () => any> = (arg: T) => ReturnType<T>;
type Fn = () => number;
type FnReturnType = $Call<ExtractReturnType<Fn>>; // number

$Shape<T>

Copies the shape of the type supplied, but marks every field optional.
https://flow.org/en/docs/types/utilities/#toc-shape

Usage:

import { $Shape } from 'utility-types';

type Props = { name: string; age: number; visible: boolean };

// Expect: Partial<Props>
type PartialProps = $Shape<Props>;

$NonMaybeType<T>

Converts a type T to a non-maybe type. In other words, the values of $NonMaybeType<T> are the values of T except for null and undefined.
https://flow.org/en/docs/types/utilities/#toc-nonmaybe

Usage:

import { $NonMaybeType } from 'utility-types';

type MaybeName = string | null;

// Expect: string
type Name = $NonMaybeType<MaybeName>;

Class<T>

Given a type T representing instances of a class C, the type Class is the type of the class C
https://flow.org/en/docs/types/utilities/#toc-class * Differs from original Flow's util - implements only constructor part and won't include any static members. Additionally classes in Typescript are not treated as nominal

Usage:

import { Class } from 'utility-types';


function makeStore(storeClass: Class<Store>): Store {
  return new storeClass();
}

mixed

An arbitrary type that could be anything (same as unknown)
https://flow.org/en/docs/types/mixed


Related Projects

  • ts-toolbelt - Higher type safety for TypeScript
  • $mol_type - Collection of TypeScript meta types for complex logic

Download Details:

Author: piotrwitek
Source Code: https://github.com/piotrwitek/utility-types 
License: MIT license

#typescript #utilities #static #type 

Utility-types: Collection Of Utility Types
Dexter  Goodwin

Dexter Goodwin

1667394180

Type-fest: A Collection Of Essential TypeScript Types

type-fest

A collection of essential TypeScript types

Many of the types here should have been built-in. You can help by suggesting some of them to the TypeScript project.

Either add this package as a dependency or copy-paste the needed types. No credit required. πŸ‘Œ

PR welcome for additional commonly needed types and docs improvements. Read the contributing guidelines first.

Help wanted with reviewing proposals and pull requests.

Install

npm install type-fest

Requires TypeScript >=4.7

Usage

import type {Except} from 'type-fest';

type Foo = {
	unicorn: string;
	rainbow: boolean;
};

type FooWithoutRainbow = Except<Foo, 'rainbow'>;
//=> {unicorn: string}

API

Click the type names for complete docs.

Basic

Utilities

  • EmptyObject - Represents a strictly empty plain object, the {} value.
  • IsEmptyObject - Returns a boolean for whether the type is strictly equal to an empty plain object, the {} value.
  • Except - Create a type from an object type without certain keys. This is a stricter version of Omit.
  • Writable - Create a type that strips readonly from all or some of an object's keys. The inverse of Readonly<T>.
  • Merge - Merge two types into a new type. Keys of the second type overrides keys of the first type.
  • MergeDeep - Merge two objects or two arrays/tuples recursively into a new type.
  • MergeExclusive - Create a type that has mutually exclusive keys.
  • RequireAtLeastOne - Create a type that requires at least one of the given keys.
  • RequireExactlyOne - Create a type that requires exactly a single key of the given keys and disallows more.
  • RequireAllOrNone - Create a type that requires all of the given keys or none of the given keys.
  • OmitIndexSignature - Omit any index signatures from the given object type, leaving only explicitly defined properties.
  • PickIndexSignature - Pick only index signatures from the given object type, leaving out all explicitly defined properties.
  • PartialDeep - Create a deeply optional version of another type. Use Partial<T> if you only need one level deep.
  • PartialOnUndefinedDeep - Create a deep version of another type where all keys accepting undefined type are set to optional.
  • ReadonlyDeep - Create a deeply immutable version of an object/Map/Set/Array type. Use Readonly<T> if you only need one level deep.
  • LiteralUnion - Create a union type by combining primitive types and literal types without sacrificing auto-completion in IDEs for the literal type part of the union. Workaround for Microsoft/TypeScript#29729.
  • Opaque - Create an opaque type.
  • UnwrapOpaque - Revert an opaque type back to its original type.
  • InvariantOf - Create an invariant type, which is a type that does not accept supertypes and subtypes.
  • SetOptional - Create a type that makes the given keys optional.
  • SetRequired - Create a type that makes the given keys required.
  • SetNonNullable - Create a type that makes the given keys non-nullable.
  • ValueOf - Create a union of the given object's values, and optionally specify which keys to get the values from.
  • ConditionalKeys - Extract keys from a shape where values extend the given Condition type.
  • ConditionalPick - Like Pick except it selects properties from a shape where the values extend the given Condition type.
  • ConditionalPickDeep - Like ConditionalPick except that it selects the properties deeply.
  • ConditionalExcept - Like Omit except it removes properties from a shape where the values extend the given Condition type.
  • UnionToIntersection - Convert a union type to an intersection type.
  • LiteralToPrimitive - Convert a literal type to the primitive type it belongs to.
  • Stringified - Create a type with the keys of the given type changed to string type.
  • IterableElement - Get the element type of an Iterable/AsyncIterable. For example, an array or a generator.
  • Entry - Create a type that represents the type of an entry of a collection.
  • Entries - Create a type that represents the type of the entries of a collection.
  • SetReturnType - Create a function type with a return type of your choice and the same parameters as the given function type.
  • Simplify - Useful to flatten the type output to improve type hints shown in editors. And also to transform an interface into a type to aide with assignability.
  • Get - Get a deeply-nested property from an object using a key path, like Lodash's .get() function.
  • StringKeyOf - Get keys of the given type as strings.
  • Schema - Create a deep version of another object type where property values are recursively replaced into a given value type.
  • Exact - Create a type that does not allow extra properties.
  • OptionalKeysOf - Extract all optional keys from the given type.
  • HasOptionalKeys - Create a true/false type depending on whether the given type has any optional fields.
  • RequiredKeysOf - Extract all required keys from the given type.
  • HasRequiredKeys - Create a true/false type depending on whether the given type has any required fields.
  • Spread - Mimic the type inferred by TypeScript when merging two objects or two arrays/tuples using the spread syntax.

JSON

Async

  • Promisable - Create a type that represents either the value or the value wrapped in PromiseLike.
  • AsyncReturnType - Unwrap the return type of a function that returns a Promise.
  • Asyncify - Create an async version of the given function type.

String

  • Trim - Remove leading and trailing spaces from a string.
  • Split - Represents an array of strings split using a given character or character set.
  • Replace - Represents a string with some or all matches replaced by a replacement.

Array

  • Includes - Returns a boolean for whether the given array includes the given item.
  • Join - Join an array of strings and/or numbers using the given string as a delimiter.
  • LastArrayElement - Extracts the type of the last element of an array.
  • FixedLengthArray - Create a type that represents an array of the given type and length.
  • MultidimensionalArray - Create a type that represents a multidimensional array of the given type and dimensions.
  • MultidimensionalReadonlyArray - Create a type that represents a multidimensional readonly array of the given type and dimensions.
  • ReadonlyTuple - Create a type that represents a read-only tuple of the given type and length.
  • TupleToUnion - Convert a tuple into a union type of its elements.

Numeric

Change case

Miscellaneous

Declined types

If we decline a type addition, we will make sure to document the better solution here.

  • Diff and Spread - The pull request author didn't provide any real-world use-cases and the PR went stale. If you think this type is useful, provide some real-world use-cases and we might reconsider.
  • Dictionary - You only save a few characters (Dictionary<number> vs Record<string, number>) from Record, which is more flexible and well-known. Also, you shouldn't use an object as a dictionary. We have Map in JavaScript now.
  • ExtractProperties and ExtractMethods - The types violate the single responsibility principle. Instead, refine your types into more granular type hierarchies.
  • Url2Json - Inferring search parameters from a URL string is a cute idea, but not very useful in practice, since search parameters are usually dynamic and defined separately.
  • Nullish - The type only saves a couple of characters, not everyone knows what "nullish" means, and I'm also trying to get away from null.
  • TitleCase - It's not solving a common need and is a better fit for a separate package.
  • ExtendOr and ExtendAnd - The benefits don't outweigh having to learn what they mean.
  • PackageJsonExtras - There are too many possible configurations that can be put into package.json. If you would like to extend PackageJson to support an additional configuration in your project, please see the Extending existing types section below.

Alternative type names

If you know one of our types by a different name, add it here for discovery.

Tips

Extending existing types

PackageJson - There are a lot of tools that place extra configurations inside the package.json file. You can extend PackageJson to support these additional configurations.

Example

Playground

import type {PackageJson as BasePackageJson} from 'type-fest';
 import type {Linter} from 'eslint';

 type PackageJson = BasePackageJson & {eslintConfig?: Linter.Config};

Related

Built-in types

There are many advanced types most users don't know about.

Partial<T> - Make all properties in T optional.

Example

Playground

 interface NodeConfig {
 		appName: string;
 		port: number;
 }

 class NodeAppBuilder {
 		private configuration: NodeConfig = {
 				appName: 'NodeApp',
 				port: 3000
 		};

 		private updateConfig<Key extends keyof NodeConfig>(key: Key, value: NodeConfig[Key]) {
 				this.configuration[key] = value;
 		}

 		config(config: Partial<NodeConfig>) {
 				type NodeConfigKey = keyof NodeConfig;

 				for (const key of Object.keys(config) as NodeConfigKey[]) {
 						const updateValue = config[key];

 						if (updateValue === undefined) {
 								continue;
 						}

 						this.updateConfig(key, updateValue);
 				}

 				return this;
 		}
 }

 // `Partial<NodeConfig>`` allows us to provide only a part of the
 // NodeConfig interface.
 new NodeAppBuilder().config({appName: 'ToDoApp'});

Required<T> - Make all properties in T required.

Example

Playground

 interface ContactForm {
 		email?: string;
 		message?: string;
 }

 function submitContactForm(formData: Required<ContactForm>) {
 		// Send the form data to the server.
 }

 submitContactForm({
 		email: 'ex@mple.com',
 		message: 'Hi! Could you tell me more about…',
 });

 // TypeScript error: missing property 'message'
 submitContactForm({
 		email: 'ex@mple.com',
 });

Readonly<T> - Make all properties in T readonly.

Example

Playground

 enum LogLevel {
 		Off,
 		Debug,
 		Error,
 		Fatal
 };

 interface LoggerConfig {
 		name: string;
 		level: LogLevel;
 }

 class Logger {
 		config: Readonly<LoggerConfig>;

 		constructor({name, level}: LoggerConfig) {
 				this.config = {name, level};
 				Object.freeze(this.config);
 		}
 }

 const config: LoggerConfig = {
 	name: 'MyApp',
 	level: LogLevel.Debug
 };

 const logger = new Logger(config);

 // TypeScript Error: cannot assign to read-only property.
 logger.config.level = LogLevel.Error;

 // We are able to edit config variable as we please.
 config.level = LogLevel.Error;

Pick<T, K> - From T, pick a set of properties whose keys are in the union K.

Example

Playground

 interface Article {
 		title: string;
 		thumbnail: string;
 		content: string;
 }

 // Creates new type out of the `Article` interface composed
 // from the Articles' two properties: `title` and `thumbnail`.
 // `ArticlePreview = {title: string; thumbnail: string}`
 type ArticlePreview = Pick<Article, 'title' | 'thumbnail'>;

 // Render a list of articles using only title and description.
 function renderArticlePreviews(previews: ArticlePreview[]): HTMLElement {
 		const articles = document.createElement('div');

 		for (const preview of previews) {
 				// Append preview to the articles.
 		}

 		return articles;
 }

 const articles = renderArticlePreviews([
 		{
 			title: 'TypeScript tutorial!',
 			thumbnail: '/assets/ts.jpg'
 		}
 ]);

Record<K, T> - Construct a type with a set of properties K of type T.

Example

Playground

 // Positions of employees in our company.
 type MemberPosition = 'intern' | 'developer' | 'tech-lead';

 // Interface describing properties of a single employee.
 interface Employee {
 		firstName: string;
 		lastName: string;
 		yearsOfExperience: number;
 }

 // Create an object that has all possible `MemberPosition` values set as keys.
 // Those keys will store a collection of Employees of the same position.
 const team: Record<MemberPosition, Employee[]> = {
 		intern: [],
 		developer: [],
 		'tech-lead': [],
 };

 // Our team has decided to help John with his dream of becoming Software Developer.
 team.intern.push({
 	firstName: 'John',
 	lastName: 'Doe',
 	yearsOfExperience: 0
 });

 // `Record` forces you to initialize all of the property keys.
 // TypeScript Error: "tech-lead" property is missing
 const teamEmpty: Record<MemberPosition, null> = {
 		intern: null,
 		developer: null,
 };

Exclude<T, U> - Exclude from T those types that are assignable to U.

Example

Playground

 interface ServerConfig {
 	port: null | string | number;
 }

 type RequestHandler = (request: Request, response: Response) => void;

 // Exclude `null` type from `null | string | number`.
 // In case the port is equal to `null`, we will use default value.
 function getPortValue(port: Exclude<ServerConfig['port'], null>): number {
 	if (typeof port === 'string') {
 		return parseInt(port, 10);
 	}

 	return port;
 }

 function startServer(handler: RequestHandler, config: ServerConfig): void {
 	const server = require('http').createServer(handler);

 	const port = config.port === null ? 3000 : getPortValue(config.port);
 	server.listen(port);
 }

Extract<T, U> - Extract from T those types that are assignable to U.

Example

Playground

 declare function uniqueId(): number;

 const ID = Symbol('ID');

 interface Person {
 	[ID]: number;
 	name: string;
 	age: number;
 }

 // Allows changing the person data as long as the property key is of string type.
 function changePersonData<
 	Obj extends Person,
 	Key extends Extract<keyof Person, string>,
 	Value extends Obj[Key]
 > (obj: Obj, key: Key, value: Value): void {
 	obj[key] = value;
 }

 // Tiny Andrew was born.
 const andrew = {
 	[ID]: uniqueId(),
 	name: 'Andrew',
 	age: 0,
 };

 // Cool, we're fine with that.
 changePersonData(andrew, 'name', 'Pony');

 // Goverment didn't like the fact that you wanted to change your identity.
 changePersonData(andrew, ID, uniqueId());

NonNullable<T> - Exclude null and undefined from T.

ExampleWorks with strictNullChecks set to true.

Playground

 type PortNumber = string | number | null;

 /** Part of a class definition that is used to build a server */
 class ServerBuilder {
 		portNumber!: NonNullable<PortNumber>;

 		port(this: ServerBuilder, port: PortNumber): ServerBuilder {
 				if (port == null) {
 						this.portNumber = 8000;
 				} else {
 						this.portNumber = port;
 				}

 				return this;
 		}
 }

 const serverBuilder = new ServerBuilder();

 serverBuilder
 		.port('8000')   // portNumber = '8000'
 		.port(null)     // portNumber =  8000
 		.port(3000);    // portNumber =  3000

 // TypeScript error
 serverBuilder.portNumber = null;

Parameters<T> - Obtain the parameters of a function type in a tuple.

Example

Playground

 function shuffle(input: any[]): void {
 	// Mutate array randomly changing its' elements indexes.
 }

 function callNTimes<Fn extends (...args: any[]) => any> (func: Fn, callCount: number) {
 	// Type that represents the type of the received function parameters.
 	type FunctionParameters = Parameters<Fn>;

 	return function (...args: FunctionParameters) {
 		for (let i = 0; i < callCount; i++) {
 			func(...args);
 		}
 	}
 }

 const shuffleTwice = callNTimes(shuffle, 2);

ConstructorParameters<T> - Obtain the parameters of a constructor function type in a tuple.

Example

Playground

 class ArticleModel {
 	title: string;
 	content?: string;

 	constructor(title: string) {
 		this.title = title;
 	}
 }

 class InstanceCache<T extends (new (...args: any[]) => any)> {
 	private ClassConstructor: T;
 	private cache: Map<string, InstanceType<T>> = new Map();

 	constructor (ctr: T) {
 		this.ClassConstructor = ctr;
 	}

 	getInstance (...args: ConstructorParameters<T>): InstanceType<T> {
 		const hash = this.calculateArgumentsHash(...args);

 		const existingInstance = this.cache.get(hash);
 		if (existingInstance !== undefined) {
 			return existingInstance;
 		}

 		return new this.ClassConstructor(...args);
 	}

 	private calculateArgumentsHash(...args: any[]): string {
 		// Calculate hash.
 		return 'hash';
 	}
 }

 const articleCache = new InstanceCache(ArticleModel);
 const amazonArticle = articleCache.getInstance('Amazon forests burining!');

ReturnType<T> - Obtain the return type of a function type.

Example

Playground

 /** Provides every element of the iterable `iter` into the `callback` function and stores the results in an array. */
 function mapIter<
 		Elem,
 		Func extends (elem: Elem) => any,
 		Ret extends ReturnType<Func>
 >(iter: Iterable<Elem>, callback: Func): Ret[] {
 		const mapped: Ret[] = [];

 		for (const elem of iter) {
 				mapped.push(callback(elem));
 		}

 		return mapped;
 }

 const setObject: Set<string> = new Set();
 const mapObject: Map<number, string> = new Map();

 mapIter(setObject, (value: string) => value.indexOf('Foo')); // number[]

 mapIter(mapObject, ([key, value]: [number, string]) => {
 		return key % 2 === 0 ? value : 'Odd';
 }); // string[]

InstanceType<T> - Obtain the instance type of a constructor function type.

Example

Playground

 class IdleService {
 		doNothing (): void {}
 }

 class News {
 		title: string;
 		content: string;

 		constructor(title: string, content: string) {
 				this.title = title;
 				this.content = content;
 		}
 }

 const instanceCounter: Map<Function, number> = new Map();

 interface Constructor {
 		new(...args: any[]): any;
 }

 // Keep track how many instances of `Constr` constructor have been created.
 function getInstance<
 		Constr extends Constructor,
 		Args extends ConstructorParameters<Constr>
 >(constructor: Constr, ...args: Args): InstanceType<Constr> {
 		let count = instanceCounter.get(constructor) || 0;

 		const instance = new constructor(...args);

 		instanceCounter.set(constructor, count + 1);

 		console.log(`Created ${count + 1} instances of ${Constr.name} class`);

 		return instance;
 }


 const idleService = getInstance(IdleService);
 // Will log: `Created 1 instances of IdleService class`
 const newsEntry = getInstance(News, 'New ECMAScript proposals!', 'Last month...');
 // Will log: `Created 1 instances of News class`

Omit<T, K> - Constructs a type by picking all properties from T and then removing K.

Example

Playground

 interface Animal {
 		imageUrl: string;
 		species: string;
 		images: string[];
 		paragraphs: string[];
 }

 // Creates new type with all properties of the `Animal` interface
 // except 'images' and 'paragraphs' properties. We can use this
 // type to render small hover tooltip for a wiki entry list.
 type AnimalShortInfo = Omit<Animal, 'images' | 'paragraphs'>;

 function renderAnimalHoverInfo (animals: AnimalShortInfo[]): HTMLElement {
 		const container = document.createElement('div');
 		// Internal implementation.
 		return container;
 }

Uppercase<S extends string> - Transforms every character in a string into uppercase.

Example

 type T = Uppercase<'hello'>;  // 'HELLO'

 type T2 = Uppercase<'foo' | 'bar'>;  // 'FOO' | 'BAR'

 type T3<S extends string> = Uppercase<`aB${S}`>;
 type T4 = T3<'xYz'>;  // 'ABXYZ'

 type T5 = Uppercase<string>;  // string
 type T6 = Uppercase<any>;  // any
 type T7 = Uppercase<never>;  // never
 type T8 = Uppercase<42>;  // Error, type 'number' does not satisfy the constraint 'string'

Lowercase<S extends string> - Transforms every character in a string into lowercase.

Example

 type T = Lowercase<'HELLO'>;  // 'hello'

 type T2 = Lowercase<'FOO' | 'BAR'>;  // 'foo' | 'bar'

 type T3<S extends string> = Lowercase<`aB${S}`>;
 type T4 = T3<'xYz'>;  // 'abxyz'

 type T5 = Lowercase<string>;  // string
 type T6 = Lowercase<any>;  // any
 type T7 = Lowercase<never>;  // never
 type T8 = Lowercase<42>;  // Error, type 'number' does not satisfy the constraint 'string'

Capitalize<S extends string> - Transforms the first character in a string into uppercase.

Example

 type T = Capitalize<'hello'>;  // 'Hello'

 type T2 = Capitalize<'foo' | 'bar'>;  // 'Foo' | 'Bar'

 type T3<S extends string> = Capitalize<`aB${S}`>;
 type T4 = T3<'xYz'>;  // 'ABxYz'

 type T5 = Capitalize<string>;  // string
 type T6 = Capitalize<any>;  // any
 type T7 = Capitalize<never>;  // never
 type T8 = Capitalize<42>;  // Error, type 'number' does not satisfy the constraint 'string'

Uncapitalize<S extends string> - Transforms the first character in a string into lowercase.

  • Example
 type T = Uncapitalize<'Hello'>;  // 'hello'

 type T2 = Uncapitalize<'Foo' | 'Bar'>;  // 'foo' | 'bar'

 type T3<S extends string> = Uncapitalize<`AB${S}`>;
 type T4 = T3<'xYz'>;  // 'aBxYz'

 type T5 = Uncapitalize<string>;  // string
 type T6 = Uncapitalize<any>;  // any
 type T7 = Uncapitalize<never>;  // never
 type T8 = Uncapitalize<42>;  // Error, type 'number' does not satisfy the constraint 'string'

You can find some examples in the TypeScript docs.

Maintainers

Download Details:

Author: Sindresorhus
Source Code: https://github.com/sindresorhus/type-fest 
License: CC0-1.0, MIT licenses found

#typescript #utilities #type 

Type-fest: A Collection Of Essential TypeScript Types
Rupert  Beatty

Rupert Beatty

1665917700

Hidden: An Ultra-light MacOS Utility That Helps Hide Menu Bar Icons

Hidden Bar

Hidden Bar lets you hide menu bar items to give your Mac a cleaner look.

πŸš€ Install

ο£Ώ App Store

AppStore

Others

The Hidden Bar is notarized before distributed out side App Store. It's safe to use πŸ‘

Using Homebrew

brew install --cask hiddenbar

Manual download

  • Download latest version
  • Open and drag the app to the Applications folder.
  • Launch Hidden and drag the icon in your menu bar (hold CMD) to the right so it is between some other icons.

πŸ•Ή Usage

  • ⌘ + drag to move the Hidden icons around in the menu bar.
  • Click the Arrow icon to hide menu bar items.

✨Contributors

This project exists thanks to all the people who contribute. Thank you guys so much πŸ‘

Please read this before you make a contribution.

Requirements

macOS version >= 10.13

You may also like

  • Blurred - A macOS utility that helps reduce distraction by dimming your inactive noise
  • Micro Sniff - An ultra-light macOS utility that notify whenever your micro-device is being used
  • VimMotion Vim style shortcut for MacOS

Download Details:

Author: Dwarvesf
Source Code: https://github.com/dwarvesf/hidden 
License: MIT license

#swift #macos #utilities 

Hidden: An Ultra-light MacOS Utility That Helps Hide Menu Bar Icons

10 Favorite Go Libraries for Utilities, Tools To Make Your Life Easier

In today's post we will learn about 10 Favorite Go Libraries for General utilities and tools to make your life easier. 

Table of contents:

  • APM - Process manager for Golang applications with an HTTP API.
  • Backscanner - A scanner similar to bufio.Scanner, but it reads and returns lines in reverse order, starting at a given position and going backward.
  • Beyond - The Go tool that will drive you to the AOP world!
  • Blank - Verify or remove blanks and whitespace from strings.
  • Bleep - Perform any number of actions on any set of OS signals in Go.
  • Boilr - Blazingly fast CLI tool for creating projects from boilerplate templates.
  • Changie - Automated changelog tool for preparing releases with lots of customization options.
  • Chyle - Changelog generator using a git repository with multiple configuration possibilities.
  • Circuit - An efficient and feature complete Hystrix like Go implementation of the circuit breaker pattern.
  • Circuitbreaker - Circuit Breakers in Go.

1 - APM:

Process manager for Golang applications with an HTTP API.

A(guia) P(rocess) M(anager)

APM - Aguia Process Manager APM is a lightweight process manager written in Golang for Golang applications. It helps you keep your applications alive forever, reload and start them from the source code.

Starting an application is easy:

$ ./apm bin app-name --source="github.com/topfreegames/apm"

This will basically compile your project source code and start it as a daemon in the background. The application will have already be downloaded into GOPATH issuing something like

go get github.com/topfreegames/apm

You will probably be able to run anything in any directory, as long as it is under GOPATH

Install APM

$ go get github.com/topfreegames/apm

Start APM

In order to properly use APM, you always need to start a server. This will be changed in the next version, but in the meantime you need to run the command bellow to start using APM.

$ apm serve

If no config file is provided, it will default to a folder '.apmenv' where apm is first started.

Stop APM

$ apm serve-stop

View on Github

2 - Backscanner:

A scanner similar to bufio.Scanner, but it reads and returns lines in reverse order, starting at a given position and going backward.

Ever needed or wondered how to efficiently search for something in a log file, but starting at the end and going backward? Here's your solution.

Package backscanner provides a scanner similar to bufio.Scanner, but it reads and returns lines in reverse order, starting at a given position (which may be the end of the input) and going backward.

This library only uses the standard library, but the test uses an external package. To install this library (along with the test dependency), simply run:

go get -t github.com/icza/backscanner

Advancing and accessing lines of the input is done by calling Scanner.Line(), which returns the next line (previous in the source) as a string.

For maximum efficiency there is Scanner.LineBytes(). It returns the next line as a byte slice, which shares its backing array with the internal buffer of Scanner. This is because no copy is made from the line data; but this also means you can only inspect or search in the slice before calling Line() or LineBytes() again, as the content of the internal buffer–and thus slices returned by LineBytes()–may be overwritten. If you need to retain the line data, make a copy of it or use Line().

Example using it:

input := "Line1\nLine2\nLine3"
scanner := backscanner.New(strings.NewReader(input), len(input))
for {
	line, pos, err := scanner.Line()
	if err != nil {
		fmt.Println("Error:", err)
		break
	}
	fmt.Printf("Line position: %2d, line: %q\n", pos, line)
}

Output:

Line position: 12, line: "Line3"
Line position:  6, line: "Line2"
Line position:  0, line: "Line1"
Error: EOF

Using it to efficiently scan a file, finding last occurrence of a string ("error"):

f, err := os.Open("mylog.txt")
if err != nil {
	panic(err)
}
fi, err := f.Stat()
if err != nil {
	panic(err)
}
defer f.Close()

scanner := backscanner.New(f, int(fi.Size()))
what := []byte("error")
for {
	line, pos, err := scanner.LineBytes()
	if err != nil {
		if err == io.EOF {
			fmt.Printf("%q is not found in file.\n", what)
		} else {
			fmt.Println("Error:", err)
		}
		break
	}
	if bytes.Contains(line, what) {
		fmt.Printf("Found %q at line position: %d, line: %q\n", what, pos, line)
		break
	}
}

View on Github

3 - Beyond:

The Go tool that will drive you to the AOP world!

What's AOP?

In computing, aspect-oriented programming (AOP) is a programming paradigm that aims to increase modularity by allowing the separation of cross-cutting concerns. It does so by adding additional behavior to existing code (an advice) without modifying the code itself, instead separately specifying which code is modified via a "pointcut" specification

Getting Started

Install beyond

go get -u github.com/wesovilabs/beyond

Add beyond to your project

Add beyond to go.mod.

go.mod

module github.com/myrepository/myapp
...
require github.com/wesovilabs/beyond v0.0.1
...

Documentation

Beyond Documentation is published at http://wesovilabs.github.io/beyond

View on Github

4 - Blank:

Verify or remove blanks and whitespace from strings.

The Blank package offers two main functionalities.

Blank can remove whitespace from a string. The package defines whitepsace as a character that is not typically visible. These characters range anywhere from the ordinary space to a less common vertical tab.

Blank can check if a string is blank. The package considers a string to be blank if it is comprised solely of whitespace.

Installation

If you do not have Go installed yet, you can find installation instructions here.

To pull the most recent version of Blank, use go get.

go get -u github.com/Henry-Sarabia/blank

Then import the package into your project.

import "github.com/Henry-Sarabia/blank"

Usage

Whitespace Removal

The package considers whitespace to be any character that is not typically visible. The most common of these characters are: space, tab, newline, return, formfeed, nonbreaking space, and vertical tab. For more information, visit the unicode package and the unicode seperator category.

To remove the whitespace from a string, use the Remove function.

phrase := "this is a phrase"

str := blank.Remove(phrase)

fmt.Println(str)
// output: "thisisaphrase"

Blank Detection

The package considers a string to be blank if it is comprised solely of whitespace.

For example, assume we are creating a search function that takes a string as a search query. We want to avoid searching for blank queries. Blank queries can be detected using the Is function.

func search(qry string) error {
	if blank.Is(qry) {
		// return error
	}
	
	// rest of code
}

Similarly, the Has function can process an entire slice of strings; it will check if any of the strings are blank.

Let's slightly alter our example. Assume the search function takes a slice of strings as a list of queries. We still want to avoid seraching for blank queries. Blank queries can be detected using the Has function.

func search(qrs []string) error {
	if blank.Has(qrs) {
		// return error
	}
	
	// rest of code
}

View on Github

5 - Bleep:

Perform any number of actions on any set of OS signals in Go.

Bleep is used to peform actions on OS signals. It is highly extensible and goroutine safe. It is possible to add any number of actions and all of them are guaranteed to be performed simultaneously on the OS signals that Bleep will be listening for.

Installation

go get github.com/sinhashubham95/bleep

How to Use

The Bleep package allows you to create a new instance of the handler and also has a default handler in place that can be used directly.

Creating separate Bleep instances can be useful, when you want to perform different set of actions for different set of OS signals.

Create a New OS Signal Handler

This is used to create a new handler for performing actions on OS Signals.

import (
  "os"
  "github.com/sinhashubham95/bleep"
)

func New() {
  handler := bleep.New()
  // now this handler can be used to add or remove actions and listen to the OS signals
}

Add an Action

This is used to add an action to be executed on the OS signal listening for.

import (
  "os"
  "github.com/sinhashubham95/bleep"
)

fun Add() {
  key := bleep.Add(func (s os.Signal) {
    // do something
  })
  // this key is the unique identifier for your added action
}

Remove an Action

This is used to remove an action added to Bleep.

import (
  "github.com/sinhashubham95/bleep"
)

func Remove() {
  action := bleep.Remove("some-key")  // this key should be the same as the one returned during adding the action
  // the returned action is the one that was added using this key
}

View on Github

6 - Boilr:

Blazingly fast CLI tool for creating projects from boilerplate templates.

Features

  • No dependencies (NodeJS, Python Interpreter etc.) - Boilr is a single statically linked binary. Grab the one that fits your architecture, and you're all set to save time by using templates!
  • Full Power of Golang Templates - Golang has powerful templating constructs which are very easy to learn and powerful.
  • Dead-Simple Template Creation - Creating boilerplate templates are very easy, check out the license template to see a simple, but very useful template for adding licenses to new projects with a single command.

Installation

Binaries for Linux & OSX are built automatically by Travis every release. You can download them directly or run the installation script.

Please see Installation page for more information.

Getting Started with Boilr

Use boilr help to get the list of available commands.

Download a Template

In order to download a template from a github repository, use the following command:

boilr template download <github-repo-path> <template-tag>
boilr template download tmrts/boilr-license license

The downloaded template will be saved to local boilr registry.

Save a Local Template

In order to save a template from filesystem to the template registry use the following command:

boilr template save <template-path> <template-tag>
boilr template save ~/boilr-license license

The saved template will be saved to local boilr registry.

Use a Template

For a Boilr template with the given directory structure:

.
β”œβ”€β”€ project.json
β”œβ”€β”€ README.md
└── template
    └── LICENSE

And the following project.json context file:

{
    "Author": "Tamer Tas",
    "Year": "2015",
    "License": [
        "Apache Software License 2.0",
        "MIT",
        "GNU GPL v3.0"
    ]
}

When using the template with the following command:

boilr template use <template-tag> <target-dir>
boilr template use license /workspace/tmrts/example-project/

The user will be prompted as follows:

[?] Please choose an option for "License"
    1 -  "Apache Software License 2.0"
    2 -  "MIT"
    3 -  "GNU GPL v3.0"
    Select from 1..3 [default: 1]: 2
[?] Please choose a value for "Year" [default: "2015"]:
[?] Please choose a value for "Author" [default: "Tamer Tas"]:
[βœ”] Created /workspace/tmrts/example-project/LICENSE
[βœ”] Successfully executed the project template license in /workspace/tmrts/example-project

For more information please take a look at Usage and Creating Templates pages in the wiki.

View on Github

7 - Changie:

Automated changelog tool for preparing releases with lots of customization options.

Features

  • File based changelog management keeps your commit history and release notes separate.
  • Track changes while you work while the knowledge is fresh.
  • Extensive configuration options to fit your project.
  • Language and framework agnostic using a single go binary.

Getting Started

  • User documentation is available on the website.
  • Specifically, the guide is a good place to start.
  • View Changie's Changelog for an example.

Need help?

Use the discussions page for help requests and how-to questions.

Please open GitHub issues for bugs and feature requests. File an issue before creating a pull request, unless it is something simple like a typo.

Media

Want to Contribute?

If you want to contribute through code or documentation, the Contributing guide is the place to start. If you need additional help create an issue or post on discussions.

View on Github

8 - Chyle:

Changelog generator using a git repository with multiple configuration possibilities.

Chyle produces a changelog from a git repository.

Usage

Create a changelog from your commit history

Usage:
  chyle [command]

Available Commands:
  config      Configuration prompt
  create      Create a new changelog
  help        Help about any command

Flags:
      --debug   enable debugging
  -h, --help    help for chyle

Use "chyle [command] --help" for more information about a command.

config

Run a serie of prompt to help generate quickly and easily a configuration.

create

Generate changelog.

How it works ?

Chyle fetch a range of commits using given criterias from a git repository. From those commits you can extract relevant datas from commit message, author, and so on, and add it to original payload. You can afterwards if needed, enrich your payload with various useful datas contacting external apps (shell command, apis, ....) and finally, you can publish what you harvested (to an external api, stdout, ....). You can mix all steps together, avoid some, combine some, it's up to you.

Setup

Download from release page according to your architecture chyle binary : https://github.com/antham/chyle/releases

Look at the documentation and examples, run chyle config to launch the configuration prompt.

View on Github

9 - Circuit:

An efficient and feature complete Hystrix like Go implementation of the circuit breaker pattern.

Circuit is an efficient and feature complete Hystrix like Go implementation of the circuit breaker pattern. Learn more about the problems Hystrix and other circuit breakers solve on the Hystrix Wiki. A short summary of advantages are:

  • A downstream service failed and all requests hang forever. Without a circuit, your service would also hang forever. Because you have a circuit, you detect this failure quickly and can return errors quickly while waiting for the downstream service to recover.
  • Circuits make great monitoring and metrics boundaries, creating common metric names for the common downstream failure types. This package goes further to formalize this in a SLO tracking pattern.
  • Circuits create a common place for downstream failure fallback logic.
  • Downstream services sometimes fail entirely when overloaded. While in a degraded state, circuits allow you to push downstream services to the edge between absolute failure and mostly working.
  • Open/Close state of a circuit is a clear early warning sign of downstream failures.
  • Circuits allow you to protect your dependencies from abnormal rushes of traffic.

Usage

Hello world circuit

This example shows how to create a hello-world circuit from the circuit manager

// Manages all our circuits
h := circuit.Manager{}
// Create a circuit with a unique name
c := h.MustCreateCircuit("hello-world")
// Call the circuit
errResult := c.Execute(context.Background(), func(ctx context.Context) error {
  return nil
}, nil)
fmt.Println("Result of execution:", errResult)
// Output: Result of execution: <nil>

Hello world fallback

This example shows how fallbacks execute to return alternate errors or provide logic when the circuit is open.

// You can create circuits without using the manager
c := circuit.NewCircuitFromConfig("hello-world-fallback", circuit.Config{})
errResult := c.Execute(context.Background(), func(ctx context.Context) error {
	return errors.New("this will fail")
}, func(ctx context.Context, err error) error {
	fmt.Println("Circuit failed with error, but fallback returns nil")
	return nil
})
fmt.Println("Execution result:", errResult)
// Output: Circuit failed with error, but fallback returns nil
// Execution result: <nil>

Running inside a Goroutine

It is recommended to use circuit.Execute and a context aware function. If, however, you want to exit your run function early and leave it hanging (possibly forever), then you can call circuit.Go.

h := circuit.Manager{}
c := h.MustCreateCircuit("untrusting-circuit", circuit.Config{
  Execution: circuit.ExecutionConfig{
    // Time out the context after a few ms
    Timeout: time.Millisecond * 30,
  },
})

errResult := c.Go(context.Background(), func(ctx context.Context) error {
  // Sleep 30 seconds, way longer than our timeout
  time.Sleep(time.Second * 30)
  return nil
}, nil)
fmt.Printf("err=%v", errResult)
// Output: err=context deadline exceeded

View on Github

10 - Circuitbreaker:

Circuit Breakers in Go.

Circuitbreaker provides an easy way to use the Circuit Breaker pattern in a Go program.

Circuit breakers are typically used when your program makes remote calls. Remote calls can often hang for a while before they time out. If your application makes a lot of these requests, many resources can be tied up waiting for these time outs to occur. A circuit breaker wraps these remote calls and will trip after a defined amount of failures or time outs occur. When a circuit breaker is tripped any future calls will avoid making the remote call and return an error to the caller. In the meantime, the circuit breaker will periodically allow some calls to be tried again and will close the circuit if those are successful.

Installation

  go get github.com/rubyist/circuitbreaker

Examples

Here is a quick example of what circuitbreaker provides

// Creates a circuit breaker that will trip if the function fails 10 times
cb := circuit.NewThresholdBreaker(10)

events := cb.Subscribe()
go func() {
  for {
    e := <-events
    // Monitor breaker events like BreakerTripped, BreakerReset, BreakerFail, BreakerReady
  }
}()

cb.Call(func() error {
	// This is where you'll do some remote call
	// If it fails, return an error
}, 0)

Circuitbreaker can also wrap a time out around the remote call.

// Creates a circuit breaker that will trip after 10 failures
// using a time out of 5 seconds
cb := circuit.NewThresholdBreaker(10)

cb.Call(func() error {
  // This is where you'll do some remote call
  // If it fails, return an error
}, time.Second * 5) // This will time out after 5 seconds, which counts as a failure

// Proceed as above

Circuitbreaker can also trip based on the number of consecutive failures.

// Creates a circuit breaker that will trip if 10 consecutive failures occur
cb := circuit.NewConsecutiveBreaker(10)

// Proceed as above

Circuitbreaker can trip based on the error rate.

// Creates a circuit breaker based on the error rate
cb := circuit.NewRateBreaker(0.95, 100) // trip when error rate hits 95%, with at least 100 samples

// Proceed as above

View on Github

Thank you for following this article.

Related videos:

Learn Go Programming by Building 11 Projects – Full Course

#go #golang #utilities #tools 

10 Favorite Go Libraries for Utilities, Tools To Make Your Life Easier
Lawrence  Lesch

Lawrence Lesch

1662126600

The Best JavaScript & Node.js Logging Service & Logging Npm Package

Cabin is the best JavaScript and Node.js logging service and logging npm package 
Supports Node v6.4+, Browsers (IE 10+), Express, Koa, and Lad


Cabin is a drop-in replacement and the best alternative to Sentry, Timber, Airbrake, Papertrail, Loggly, Bugsnag, or <service>


❀️ Love this project? Support @niftylettuce's FOSS on Patreon or PayPal :unicorn:

Quick Start

npm install cabin
const express = require('express');
const Cabin = require('cabin');     // <-- step 1
const app = express();
const cabin = new Cabin();          // <-- step 2
app.use(cabin.middleware);          // <-- step 3
app.listen(3000);

See our Usage section below for a much more detailed and feature-rich example setup.

Features

Security, Privacy, and Business Focused

Cabin will automatically detect and mask the following list of extremely sensitive types of data in your logs:

*Credit card numbers from the following providers are automatically detected and masked: Visa, Mastercard, American Express, Diners Club, Discover, JCB, UnionPay, Maestro, Mir, Elo, Hiper, Hipercard

Reduce Disk Storage Costs

Reduce your disk storage costs through Cabin's automatic conversion of Streams, Buffers, and ArrayBuffers to simplified, descriptive-only objects that otherwise would be unreadable (and obviously pollute your log files and disk storage).

Before:

{
  "request": {
    "body": {
      "file": {
        "type": "Buffer",
        "data": [
          76,
          111,
          114,
          101,
          109,
          32,
          105,
          112,
          115,
          117,
          109,
          32,
          100,
          111,
          108,
          111,
          114,
          32,
          115,
          105,
          116,
          '...'
        ]
      }
    }
  }
}

After

{
  "request": {
    "body": {
      "file": {
        "type": "Buffer",
        "byteLength": 2787
      }
    }
  }
}

Cross-Platform and Cross-Browser Compatible

Cabin works with the most popular Node.js HTTP frameworks (e.g. Express and Koa), request body handling packages (e.g. multer and body-parser), and the passport authentication framework.

It supports Node v6.4+ and IE 10+ out of the box, and its browser-ready bundle is only 39 KB (minified and gzipped).

npx browserslist
and_chr 74
and_ff 66
and_qq 1.2
and_uc 11.8
android 67
baidu 7.12
bb 10
bb 7
chrome 74
chrome 73
chrome 72
edge 18
edge 17
firefox 66
firefox 65
ie 11
ie 10
ie_mob 11
ie_mob 10
ios_saf 12.2
ios_saf 12.0-12.1
kaios 2.5
op_mini all
op_mob 46
op_mob 12.1
opera 58
opera 57
safari 12.1
safari 12
samsung 9.2
samsung 8.2

Integrate with Slack Using Custom Logging Hooks

Axe is the underlying logging add-on that allows you to record, store, back-up, and customize your log handling over HTTP or with your own custom logic.

You will find an entire example for logging errors (and more) to your Slack channel under its section Send Logs To Slack.

Bring Your Own Logger ("BYOL")

Cabin was built by an expert based off best practices; over a decade of experience in logging and application development – and most importantly from their agony with existing tools, services, packages, and platforms.

It was made to be both a simple and quick drop-in replacement for existing services. You can even bring your own logger! Want to use Axe, pino, signale, morgan, bunyan, winston, or another logger? No problem.

Drop-in Replacement and Alternative to Bunyan

We built this with Bunyan-style compatibility – this means you won't have to change your logging argument style from log(meta, message) to log(message, meta); we automatically detect Bunyan style (Metadata first, message second) and flip the order for you.

As of v6.1.1 we have added support for Bunyan style (meta, message, [, ...args]) usage (e.g. logger.info({ some: 'obj' }, 'message with format specifiers %s and %d', 'foobar', 100)), prior to v6.1.1 we only supported (meta, message) usage.

Save Time With Easy Debugging

No need for rubber duck debugging – Cabin makes everything transparent at a glance.

Rich metadata is automatically added to your logs, so that you can easily record, analyze, and detect user behavior and application events, errors, and more:

Example Application:

const express = require('express');
const Cabin = require('cabin');
const multer = require('multer');
const requestReceived = require('request-received');
const responseTime = require('response-time');
const requestId = require('express-request-id');

const app = express();
const cabin = new Cabin();
const upload = multer();

app.use(requestReceived);
app.use(responseTime());
app.use(requestId());
app.use(cabin.middleware);

app.post(
  '/',
  upload.fields([
    {
      name: 'avatar',
      maxCount: 1
    },
    {
      name: 'boop',
      maxCount: 2
    }
  ]),
  (req, res) => {
    req.logger.info('visited home page');
    res.send('hello world');
  }
});

app.listen(3000);

Example Console Output (using Signale):

β„Ή  info      visited home page { id: '5d1b9e484ebd2adcdfd29bf4',
  timestamp: '2019-07-02T18:11:20.000Z',
  request:
   { method: 'POST',
     query: { foo: 'bar', beep: 'boop' },
     headers:
      { host: '127.0.0.1:55370',
        'accept-encoding': 'gzip, deflate',
        'user-agent': 'node-superagent/3.8.3',
        authorization: 'Basic ********************',
        accept: 'application/json',
        cookie: 'foo=bar;beep=boop',
        'content-type':
         'multipart/form-data; boundary=--------------------------028474125060986605281677',
        'content-length': '1599',
        connection: 'close' },
     cookies: { foo: 'bar', beep: 'boop' },
     url: '/?foo=bar&beep=boop',
     body:
      '{"product_id":"5d0350ef2ca74d11ee6e4f00","name":"nifty","surname":"lettuce","bank_account_number":"**********","card":{"number":"****-****-****-****"},"stripe_token":"***************","favorite_color":"green"}',
     timestamp: '2019-07-02T18:11:20.331Z',
     id: '33afc3c5-1571-4249-b024-876b6f687b65',
     http_version: '1.1',
     files:
      '{"avatar":[{"fieldName":"avatar","originalName":"avatar.png","clientReportedMimeType":"image/png","clientReportedFileExtension":".png","path":"/var/folders/t_/4vd3m1h92zsc953ll8r_4s_h0000gn/T/N6NE8A8","size":216,"detectedMimeType":"image/png","detectedFileExtension":".png","stream":{"type":"Stream"}}],"boop":[{"fieldName":"boop","originalName":"boop-1.txt","clientReportedMimeType":"text/plain","clientReportedFileExtension":".txt","path":"/var/folders/t_/4vd3m1h92zsc953ll8r_4s_h0000gn/T/PCB8YTR","size":7,"detectedMimeType":{},"detectedFileExtension":"","stream":{"type":"Stream"}},{"fieldName":"boop","originalName":"boop-2.txt","clientReportedMimeType":"text/plain","clientReportedFileExtension":".txt","path":"/var/folders/t_/4vd3m1h92zsc953ll8r_4s_h0000gn/T/EKMAKXR","size":7,"detectedMimeType":{},"detectedFileExtension":"","stream":{"type":"Stream"}}]}' },
  user: { ip_address: '::ffff:127.0.0.1' },
  duration: 1.741299,
  app:
   { name: 'parse-request',
     version: '2.0.1',
     node: 'v10.15.3',
     hash: '75783ef9d0a9c1c71f83ee352754a14ead0a3138',
     tag: 'v2.0.1',
     environment: 'test',
     hostname: 'jacks-MacBook-Pro.local',
     pid: 56543 } }
β„Ή  info      ::ffff:127.0.0.1 user POST /?foo=bar&beep=boop HTTP/1.1 200 1951 - 67.819 ms { id: '5d1b9e484ebd2adcdfd29bf5',
  timestamp: '2019-07-02T18:11:20.000Z',
  request:
   { method: 'POST',
     query: { foo: 'bar', beep: 'boop' },
     headers:
      { host: '127.0.0.1:55370',
        'accept-encoding': 'gzip, deflate',
        'user-agent': 'node-superagent/3.8.3',
        authorization: 'Basic ********************',
        accept: 'application/json',
        cookie: 'foo=bar;beep=boop',
        'content-type':
         'multipart/form-data; boundary=--------------------------028474125060986605281677',
        'content-length': '1599',
        connection: 'close' },
     cookies: { foo: 'bar', beep: 'boop' },
     url: '/?foo=bar&beep=boop',
     body:
      '{"product_id":"5d0350ef2ca74d11ee6e4f00","name":"nifty","surname":"lettuce","bank_account_number":"**********","card":{"number":"****-****-****-****"},"stripe_token":"***************","favorite_color":"green"}',
     timestamp: '2019-07-02T18:11:20.331Z',
     id: '33afc3c5-1571-4249-b024-876b6f687b65',
     http_version: '1.1',
     files:
      '{"avatar":[{"fieldName":"avatar","originalName":"avatar.png","clientReportedMimeType":"image/png","clientReportedFileExtension":".png","path":"/var/folders/t_/4vd3m1h92zsc953ll8r_4s_h0000gn/T/N6NE8A8","size":216,"detectedMimeType":"image/png","detectedFileExtension":".png","stream":{"type":"Stream"}}],"boop":[{"fieldName":"boop","originalName":"boop-1.txt","clientReportedMimeType":"text/plain","clientReportedFileExtension":".txt","path":"/var/folders/t_/4vd3m1h92zsc953ll8r_4s_h0000gn/T/PCB8YTR","size":7,"detectedMimeType":{},"detectedFileExtension":"","stream":{"type":"Stream"}},{"fieldName":"boop","originalName":"boop-2.txt","clientReportedMimeType":"text/plain","clientReportedFileExtension":".txt","path":"/var/folders/t_/4vd3m1h92zsc953ll8r_4s_h0000gn/T/EKMAKXR","size":7,"detectedMimeType":{},"detectedFileExtension":"","stream":{"type":"Stream"}}]}' },
  user: { ip_address: '::ffff:127.0.0.1' },
  response:
   { headers:
      { 'x-request-id': '33afc3c5-1571-4249-b024-876b6f687b65',
        'content-type': 'application/json; charset=utf-8',
        'content-length': '1951',
        'x-response-time': '67.819ms',
        date: 'Tue, 02 Jul 2019 18:11:20 GMT',
        connection: 'close' },
     http_version: '1.1',
     status_code: 200,
     reason_phrase: 'OK',
     timestamp: '2019-07-02T18:11:20.000Z',
     duration: 67.819 },
  duration: 2.320237,
  app:
   { name: 'parse-request',
     version: '2.0.1',
     node: 'v10.15.3',
     hash: '75783ef9d0a9c1c71f83ee352754a14ead0a3138',
     tag: 'v2.0.1',
     environment: 'test',
     hostname: 'jacks-MacBook-Pro.local',
     pid: 56543 } }

Install

npm:

npm install cabin

yarn:

yarn add cabin

Usage

Don't want to configure this yourself? You can simply use Lad which has this all built-in for you.

Logging

const Cabin = require('cabin');
const cabin = new Cabin();
cabin.info('hello world');
cabin.error(new Error('oops!'));

Each log level should be invoked with two arguments message and meta.

  • message (String or Error) - this should be either a String or an Error object
  • meta (Object or Error) - this is optional and will automatically be set to an object that inherits properties from config.meta and requests parsed. If this is an Error object, then this error will be automatically added and transformed to the meta object's meta.err property (e.g. { err: <Error>, ... })

Route Middleware

app.use(cabin.middleware);

See either the Node or Browser instructions below for further route middleware usage and proper setup.

Node

The examples below show how to use Cabin in combination with Axe, Signale logging utility (for development), Pino logging utility (for production), and how to add an accurate X-Response-Time response time metric to your logs and response headers automatically.

Koa

Don't want to configure this yourself? We highly recommend to use Lad instead of configuring this yourself as it has all of this pre-configured for you with best-practices. However if you already have an existing Koa based project the example below will sufficiently serve as a guide for implementation.

Install required and recommended dependencies:

npm install koa cabin signale pino request-received koa-better-response-time koa-better-request-id

Implement the example code below (also found here):

const Koa = require('koa');
const Cabin = require('cabin');
const Router = require('koa-router');
const requestReceived = require('request-received');
const responseTime = require('koa-better-response-time');
const requestId = require('koa-better-request-id');
const { Signale } = require('signale');
const pino = require('pino')({
  customLevels: {
    log: 30
  },
  hooks: {
    // <https://github.com/pinojs/pino/blob/master/docs/api.md#logmethod>
    logMethod(inputArgs, method) {
      return method.call(this, {
        // <https://github.com/pinojs/pino/issues/854>
        // message: inputArgs[0],
        msg: inputArgs[0],
        meta: inputArgs[1]
      });
    }
  }
});

const env = process.env.NODE_ENV || 'development';

const app = new Koa();
const router = new Router();
const cabin = new Cabin({
  // (optional: your free API key from https://cabinjs.com)
  // key: 'YOUR-CABIN-API-KEY',
  axe: {
    logger: env === 'production' ? pino : new Signale()
  }
});

// adds request received hrtime and date symbols to request object
// (which is used by Cabin internally to add `request.timestamp` to logs
app.use(requestReceived);

// adds `X-Response-Time` header to responses
app.use(responseTime());

// adds or re-uses `X-Request-Id` header
app.use(requestId());

// use the cabin middleware (adds request-based logging and helpers)
app.use(cabin.middleware);

// add your user/session management middleware here (e.g. passport)
// ...

// an example home page route
router.get('/', ctx => {
  ctx.logger.info('visited home page');
  ctx.body = 'hello world';
});

// this assumes that you are using passport which
// exposes `ctx.logout` to log out the logged in user
router.get('/logout', ctx => {
  ctx.logger.warn('Logged out');
  ctx.logout();
  ctx.redirect('/');
});

app.use(router.routes());
app.use(router.allowedMethods());

app.listen(3000, () => {
  cabin.info('app started');
});

See Koa convenience methods below for helper utilities you can use while writing code.

Express

Install required and recommended dependencies:

npm install express cabin signale pino request-received response-time express-request-id

Implement the example code below (also found here):

const express = require('express');
const Cabin = require('cabin');
const requestReceived = require('request-received');
const responseTime = require('response-time');
const requestId = require('express-request-id');
const { Signale } = require('signale');
const pino = require('pino')({
  customLevels: {
    log: 30
  },
  hooks: {
    // <https://github.com/pinojs/pino/blob/master/docs/api.md#logmethod>
    logMethod(inputArgs, method) {
      return method.call(this, {
        // <https://github.com/pinojs/pino/issues/854>
        // message: inputArgs[0],
        msg: inputArgs[0],
        meta: inputArgs[1]
      });
    }
  }
});

const env = process.env.NODE_ENV || 'development';

const app = express();
const cabin = new Cabin({
  // (optional: your free API key from https://cabinjs.com)
  // key: 'YOUR-CABIN-API-KEY',
  axe: {
    logger: env === 'production' ? pino : new Signale()
  }
});

// adds request received hrtime and date symbols to request object
// (which is used by Cabin internally to add `request.timestamp` to logs
app.use(requestReceived);

// adds `X-Response-Time` header to responses
app.use(responseTime());

// adds or re-uses `X-Request-Id` header
app.use(requestId());

// use the cabin middleware (adds request-based logging and helpers)
app.use(cabin.middleware);

// add your user/session management middleware here (e.g. passport)
// ...

// an example home page route
app.get('/', (req, res) => {
  req.logger.info('visited home page');
  res.send('hello world');
});

// this assumes that you are using passport which
// exposes `req.logout` to log out the logged in user
app.get('/logout', (req, res) => {
  req.logger.warn('logged out');
  req.logout();
  res.redirect('/');
});

app.listen(3000, () => {
  cabin.info('app started');
});

See Express convenience methods below for helper utilities you can use while writing code.

Convenience Methods

In order to easily interact and use the logger utility function exposed by app.use(cabin.middleware), we expose convenient helper methods in Express and Koa:

Express

  • req.log
  • req.logger
  • res.log
  • res.logger

Koa

  • ctx.log
  • ctx.logger
  • ctx.request.log
  • ctx.request.logger
  • ctx.response.log
  • ctx.response.logger

Browser

VanillaJS

This is the solution for you if you're just using <script> tags everywhere!

<script src="https://polyfill.io/v3/polyfill.min.js?features=es6,es7,Map,Map.prototype,Math.sign,Promise,Reflect,Symbol,Uint32Array,window.crypto,Array.from,Object.getOwnPropertySymbols,Object.assign,navigator.mimeTypes,Set,BigInt,WeakMap,WeakRef,WeakSet"></script>
<script src="https://unpkg.com/cabin"></script>
<script type="text/javascript">
  (function() {
    var cabin = new Cabin({ key: 'YOUR-CABIN-API-KEY', capture: true });
    cabin.setUser({
      id: '1',
      email: 'niftylettuce@gmail.com',
      full_name: 'niftylettuce'
    });
    cabin.info('viewed docs');
  })();
</script>

Required Browser Features

We recommend using https://polyfill.io (specifically with the bundle mentioned in VanillaJS above):

<script src="https://polyfill.io/v3/polyfill.min.js?features=es6,es7,Map,Map.prototype,Math.sign,Promise,Reflect,Symbol,Uint32Array,window.crypto,Array.from,Object.getOwnPropertySymbols,Object.assign,navigator.mimeTypes,Set,BigInt,WeakMap,WeakRef,WeakSet"></script>
  • Map is not supported in IE 10
  • Map.prototype() is not supported in IE 10
  • Math.sign() is not supported in IE 10
  • Promise is not supported in Opera Mobile 12.1, Opera Mini all, IE Mobile 10, IE 10, Blackberry Browser 7
  • Reflect is not supported in IE 10
  • Symbol is not supported in IE 10
  • Uint32Array is not supported in IE Mobile 10, IE 10, Blackberry Browser 7
  • window.crypto() is not supported in IE 10
  • Array.from() is not supported in IE 10
  • Object.getOwnPropertySymbols() is not supported in IE 10
  • Object.assign() is not supported in IE 10
  • navigator.mimeTypes() is not supported in Edge 18
  • Set is not supported in IE 10
  • BigInt is not supported in IE 10
  • WeakMap is not supported in IE 10
  • WeakRef is not supported in Opera 81, IE 10
  • WeakSet is not supported in IE 10

Bundler

This assumes you are using browserify, webpack, rollup, or another bundler.

const Cabin = require('cabin');

const cabin = new Cabin({ key: 'YOUR-CABIN-API-KEY' });

cabin.setUser({
  id: '1',
  email: 'niftylettuce@gmail.com',
  full_name: 'niftylettuce'
});

cabin.info('viewed docs');

Automatic Request Logging

Server

For server-side logging of requests, the Cabin middleware cabin.middleware will automatically log requests for you upon completion. Just make sure you are using express-request-id middleware like in the examples above in order for the X-Request-Id header to be set (and re-used if already exists, e.g. generated from client side as in below). If you're using Koa make sure to use koa-better-request-id as shown in the examples above.

Browser

We strongly recommend that you implement one of the following code snippets with xhook (for either VanillaJS or Bundler approaches) so that all your XHR requests have a X-Request-Id automatically added (which in turn ensures both client and server have matching request ID's). Imagine how awesome your logs will be when you can see the full trace starting with the client!

HTML

<script src="https://polyfill.io/v3/polyfill.min.js?features=es6,es7,Map,Map.prototype,Math.sign,Promise,Reflect,Symbol,Uint32Array,window.crypto,Array.from,Object.getOwnPropertySymbols,Object.assign,navigator.mimeTypes,Set,BigInt,WeakMap,WeakRef,WeakSet"></script>
<script src="https://unpkg.com/xhook"></script>
<script src="https://unpkg.com/cabin"></script>
<script src="https://unpkg.com/parse-request"></script>
<script src="https://unpkg.com/cuid"></script>
<script>
  (function() {
    var cabin = new Cabin({ key: 'YOUR-CABIN-API-KEY', capture: true });
    cabin.setUser({
      id: '1',
      email: 'niftylettuce@gmail.com',
      full_name: 'niftylettuce'
    });
    xhook.before(function(req) {
      if (typeof req.headers !== 'object') req.headers = {};

      if (!req.headers['X-Request-Id'])
        req.headers['X-Request-Id'] = cuid();

      if (!req.headers['User-Agent'])
        req.headers['User-Agent'] = window.navigator.userAgent;

      if (!req.headers['Referer'])
        req.headers['Referer'] = window.document.referrer;

      if (!req.headers['Cookie'])
        req.headers['Cookie'] = window.document.cookie;

      cabin.info('xhr', parseRequest({ req: req }));
    });
  })();
</script>

Pug

You can do a similar approach with React, EJS, or another templating language.

script(src='https://polyfill.io/v3/polyfill.min.js?features=es6,es7,Map,Map.prototype,Math.sign,Promise,Reflect,Symbol,Uint32Array,window.crypto,Array.from,Object.getOwnPropertySymbols,Object.assign,navigator.mimeTypes,Set,BigInt,WeakMap,WeakRef,WeakSet')
script(src='https://unpkg.com/xhook')
script(src='https://unpkg.com/cabin')
script(src='https://unpkg.com/parse-request')
script(src='https://unpkg.com/cuid')
script.
  (function() {
    var cabin = new Cabin({ key: 'YOUR-CABIN-API-KEY', capture: true });
    cabin.setUser({
      id: '1',
      email: 'niftylettuce@gmail.com',
      full_name: 'niftylettuce'
    });
    xhook.before(function(req) {
      if (typeof req.headers !== 'object') req.headers = {};

      if (!req.headers['X-Request-Id'])
        req.headers['X-Request-Id'] = cuid();

      if (!req.headers['X-Request-Id'])
        req.headers['X-Request-Id'] = cuid();

      if (!req.headers['User-Agent'])
        req.headers['User-Agent'] = window.navigator.userAgent;

      if (!req.headers['Referer'])
        req.headers['Referer'] = window.document.referrer;

      if (!req.headers['Cookie'])
        req.headers['Cookie'] = window.document.cookie;

      cabin.info('xhr', parseRequest({ req: req }));
    });
  })();

Bundler

npm:

npm install cabin xhook cuid

yarn:

yarn add cabin xhook cuid
const Cabin = require('cabin');
const xhook = require('xhook');
const parseRequest = require('parse-request');
const cuid = require('cuid');

const cabin = new Cabin({ key: 'YOUR-CABIN-API-KEY', capture: true });

cabin.setUser({
  id: '1',
  email: 'niftylettuce@gmail.com',
  full_name: 'niftylettuce'
});

xhook.before(req => {
  if (typeof req.headers !== 'object') req.headers = {};

  if (!req.headers['X-Request-Id'])
    req.headers['X-Request-Id'] = cuid();

  //
  // NOTE: you may want to add User-Agent, Referer, and Cookie (see above)
  //

  cabin.info('xhr', parseRequest({ req: req }));
});

Stack Traces and Error Handling

We leave it up to you to decide how you wish to handle stack traces and errors, but we've documented our approaches for Node and Browser environments below.

Node

If you're using Lad, then you don't need to worry about error handling, as it's built-in (complete with graceful reloading, even for database connections).

However you can otherwise use a tool such as uncaught to listen for errors, or bind purely to process events emitted as shown below:

const Cabin = require('cabin');

const cabin = new Cabin({ key: 'YOUR-CABIN-API-KEY' });

process.on('uncaughtException', err => {
  cabin.error(err);
  process.exit(1);
});

process.on('unhandledRejection', err => {
  cabin.error(err);
});

Browser

Since cross-browser support is very limited and unstandardized for errors and stack traces, we highly recommend to use StackTrace.

StackTrace

We recommend to use StackTrace instead of TraceKit as it is a more modern alternative and provides much similarity between your Browser and your Node errors (stackframes are basically similar to representations in Gecko and V8, aka the ones you get with Node).

It does require you to have a polyfill if you're using it in the browser (only if you're supporting browsers that don't support standardized Promises/JSON). You'll basically need es6-promise and json3 polyfills for browsers you wish to support that don't have them. The example below shows you how to polyfill, don't worry! You can reference Caniuse data on Promises and JSON respectively if you need.

The example below demonstrates using StackTrace with uncaught to catch global errors below, but note that uncaught only supports IE11+.

If you're curious why it won't work in IE11, please see this great documentation on JavaScript errors cross-browser here - in particular the section on "No Error object provided".

<script src="https://polyfill.io/v3/polyfill.min.js?features=es6,es7,Map,Map.prototype,Math.sign,Promise,Reflect,Symbol,Uint32Array,window.crypto,Array.from,Object.getOwnPropertySymbols,Object.assign,navigator.mimeTypes,Set,BigInt,WeakMap,WeakRef,WeakSet"></script>
<script src="https://unpkg.com/stackframe"></script>
<script src="https://unpkg.com/stacktrace-js"></script>
<!-- Use this instead of the above if you need to polyfill for IE11 support -->
<!-- <script src="https://unpkg.com/stacktrace-js/dist/stacktrace-with-promises-and-json-polyfills.js"></script> -->
<script src="https://unpkg.com/uncaught"></script>
<script src="https://unpkg.com/cabin"></script>
<script src="https://unpkg.com/prepare-stack-trace"></script>

<script type="text/javascript">
  (function() {
    //
    // Sourced from the StackTrace example from CabinJS docs
    // <https://github.com/cabinjs/cabin#stacktrace>
    //
    var cabin = new Cabin({ key: 'YOUR-CABIN-API-KEY' });

    // Use cabin globally in your app (instead of `console`)
    window.cabin = cabin;

    // Bind event listeners
    uncaught.start();
    uncaught.addListener(function(err, event) {
      if (!err) {
        if (typeof ErrorEvent === 'function' && event instanceof ErrorEvent)
          return cabin.error(event.message, { event: event });
        cabin.error({ event: event });
        return;
      }
      // this will transform the error's `stack` property
      // to be consistently similar to Gecko and V8 stackframes
      StackTrace.fromError(err)
        .then(function(stackframes) {
          err.stack = prepareStackTrace(err, stackframes);
          cabin.error(err);
        })
        .catch(function(err2) {
          cabin.error(err);
          cabin.error(err2);
        });
    });
  })();
</script>

Display Metadata and Stack Traces

Under the hood, Cabin uses Axe which provides us with several options, including one to show metadata (e.g. request headers, body, and user) and another to show stack traces for errors.

You can pass these options through the axe option (see Options below), or you could pass environment flags when you need to.

By default, Axe does not output any metadata and only outputs stack traces in non-production environments.

Show/Hide Metadata

To show or hide metadata, pass a true or false value for the process environment variables SHOW_META (defaults to true), SHOW_META_APP (defaults to false), or specify a comma separated list of fields to selectively omit via OMIT_META_FIELDS (e.g. OMIT_META_FIELDS=user to omit meta.user from output).

We have configured default metadata output in console logs to be sensible defaults as to not pollute your debugging experience. We welcome suggestions for how to improve this as well.

(e.g. SHOW_META=0 or SHOW_META=false before running your script, such as SHOW_META=false node app).

Similarly if you pass a truthy value of 1 or true it will show metadata (which is the default behavior).

Show/Hide Stack Traces

To hide stack traces, pass a falsey value for the process environment variable SHOW_STACK.

(e.g. SHOW_STACK=0 or SHOW_STACK=false before running your script, such as SHOW_STACK=false node app).

Similarly if you pass a truthy value of 1 or true it will show metadata (which is the default behavior).

Options

  • key (String) - defaults to an empty string, this is where you put your Cabin API key, which you can get for free at Cabin
  • capture (Boolean) - defaults to false in browser (all environments) and server-side (non-production only) environments, whether or not to POST logs to the endpoint (see Axe docs for more info)
  • axe (Object) - defaults to an empty Object {}, but you can pass options here for Axe
  • logger (Object) - if you have a custom logger you wish to use instead of Axe, but note that Axe accepts a logger option, so you should use that instead, see Axe docs for more info
  • meta (Object) - defaults to an empty object - this will get passed as metadata (e.g. you could set a custom meta.user object here for every request)
  • parseRequest (Object) - defaults to an empty object, which means it will use the defaults from parse-request (see Metadata below)
  • errorProps (Array) - a list of properties to cherry-pick from the error object parsed out of err thanks to parse-err (by default all properties are returned; even non-enumerable ones and ones on the prototype object) (see Metadata below)
  • message (Function) - inspired by morgan, and defaults to a dev-friendly format (or if in production mode, then it uses a standard Apache common log format)). – when requests finish, it will utilize logger to output an error, warn, or info level log based off the status code, and this function is used to determine the string sent to the logger. It accepts one argument options, which is comprised of options.level, options.req, options.res, and optionally (if and only if Koa) options.ctx. It is required that this function return a String. See src/message.js for the default message function. Note that both dev-friendly and Apache common log formats are stripped of basic auth lines for obvious security reasons.

Metadata

We use the package parse-request to parse the request metadata for you autoamaticaly.

Here's an example of a parsed metadata object:

{
  request: {
    method: 'POST',
    query: {
      foo: 'bar',
      beep: 'boop'
    },
    headers: {
      host: '127.0.0.1:63955',
      'accept-encoding': 'gzip, deflate',
      'user-agent': 'node-superagent/3.8.3',
      authorization: 'Basic ********************',
      accept: 'application/json',
      cookie: 'foo=bar;beep=boop',
      'content-type': 'multipart/form-data; boundary=--------------------------930511303948232291410214',
      'content-length': '1599',
      connection: 'close'
    },
    cookies: {
      foo: 'bar',
      beep: 'boop'
    },
    body: '{"product_id":"5d0350ef2ca74d11ee6e4f00","name":"nifty","surname":"lettuce","bank_account_number":"1234567890","card":{"number":"****-****-****-****"},"stripe_token":"***************","favorite_color":"green"}',
    url: '/?foo=bar&beep=boop',
    timestamp: '2019-06-14T07:46:55.568Z',
    id: 'fd6225ed-8db0-4862-8566-0c0ad6f4c7c9',
    http_version: '1.1',
    files: '{"avatar":[{"fieldname":"avatar","originalname":"avatar.png","encoding":"7bit","mimetype":"image/png","buffer":{"type":"Buffer","byteLength":216},"size":216}],"boop":[{"fieldname":"boop","originalname":"boop-1.txt","encoding":"7bit","mimetype":"text/plain","buffer":{"type":"Buffer","byteLength":7},"size":7},{"fieldname":"boop","originalname":"boop-2.txt","encoding":"7bit","mimetype":"text/plain","buffer":{"type":"Buffer","byteLength":7},"size":7}]}'
  },
  user: {
    ip_address: '::ffff:127.0.0.1'
  },
  id: '5d0350ef2ca74d11ee6e4f01',
  timestamp: '2019-06-14T07:46:55.000Z',
  duration: 6.651317
}

Related

  • Forward Email - Free, encrypted, and open-source email forwarding service for custom domains
  • bree - The best job scheduler for Node.js
  • lad - Scaffold a Koa webapp and API framework for Node.js
  • koa-better-error-handler - A better error-handler for Lad and Koa. Makes ctx.throw awesome!
  • axe - Logging utility for Node and Browser environments. Chop up your logs!
  • lass - Scaffold a modern boilerplate for Node.js
  • lipo - Free image manipulation API service built on top of Sharp

Contributors

NameWebsite
Nick Baughhttp://niftylettuce.com/

Trademark Notice

Axe, Lad, Lass, Cabin, Lipo, and their respective logos are trademarks of Niftylettuce LLC. These trademarks may not be reproduced, distributed, transmitted, or otherwise used, except with the prior written permission of Niftylettuce LLC. If you are seeking permission to use these trademarks, then please contact us.

Download Details:

Author: Cabinjs
Source Code: https://github.com/cabinjs/cabin 
License: MIT license

#javascript #react #utilities #node 

The Best JavaScript & Node.js Logging Service & Logging Npm Package
Nat  Grady

Nat Grady

1660856760

Lettercase: Utilities for Turning Characters into Various Cases

Lettercase    

Utilities for formatting strings and character vectors to for capitalization, word break and white space. Supported formats are: snake_case, spine-case, camelCase, PascalCase, Title Case, UPPERCASE, lowercase, Sentence case or combinations thereof. 'lettercase' strives to provide a simple, consistent, intuitive and high performing interface.

Installation

Latest Release:

install.packages('lettercase')

Development Version:

install.packages('devtools')
devtools::install_github('decisionpatterns/lettercase')

Download Details:

Author: Decisionpatterns
Source Code: https://github.com/decisionpatterns/lettercase 
License: View license

#r #utilities 

Lettercase: Utilities for Turning Characters into Various Cases
Lawrence  Lesch

Lawrence Lesch

1659664140

List Of JavaScript Methods Which You Can Use Natively + ESLint Plugin

You don't (may not) need Lodash/Underscore

Lodash and Underscore are great modern JavaScript utility libraries, and they are widely used by Front-end developers. However, when you are targeting modern browsers, you may find out that there are many methods which are already supported natively thanks to ECMAScript5 [ES5] and ECMAScript2015 [ES6]. If you want your project to require fewer dependencies, and you know your target browser clearly, then you may not need Lodash/Underscore.

You are welcome to contribute with more items provided below.

If you are targeting legacy JavaScript engine with those ES5 methods, you can use es5-shim

Please note that, the examples used below are just showing you the native alternative of performing certain tasks. For some functions, Lodash provides you more options than native built-ins. This list is not a 1:1 comparison.

Please send a PR if you want to add or modify the code. No need to open an issue unless it's something big and you want to discuss.

Voice of Developers

Make use of native JavaScript object and array utilities before going big.

β€”Cody Lindley, Author of jQuery Cookbook and JavaScript Enlightenment

You probably don't need Lodash. Nice List of JavaScript methods which you can use natively.

β€”Daniel Lamb, Computer Scientist, Technical Reviewer of Secrets of the JavaScript Ninja and Functional Programming in JavaScript

I guess not, but I want it.

β€”Tero Parviainen, Author of build-your-own-angular

I'll admit, I've been guilty of overusing #lodash. Excellent resource.

β€”@therebelrobot, Maker of web things, Facilitator for Node.js/io.js

ESLint Plugin    

If you're using ESLint, you can install a plugin that will help you identify places in your codebase where you don't (may not) need Lodash/Underscore.

Install the plugin...

npm install --save-dev eslint-plugin-you-dont-need-lodash-underscore

...then update your config

"extends" : ["plugin:you-dont-need-lodash-underscore/compatible"],

For more information, see Configuring the ESLint Plugin

❗Important: Note that, while many Lodash methods are null safe (e.g. _.keys, _.entries), this is not necessarily the case for their Native equivalent. If null safety is critical for your application, we suggest that you take extra precautions [e.g. consider using the native Object.keys as Object.keys(value || {})].

Collection*

❗Important: Note that most native equivalents are array methods, and will not work with objects. If this functionality is needed and no object method is provided, then Lodash/Underscore might be the better option. Bear in mind however, that all iterable objects can easily be converted to an array by use of the spread operator.

Array

_.chunk

Creates an array of elements split into groups the length of size.

// Underscore/Lodash
_.chunk(['a', 'b', 'c', 'd'], 2);
// => [['a', 'b'], ['c', 'd']]

_.chunk(['a', 'b', 'c', 'd'], 3);
// => [['a', 'b', 'c'], ['d']]


// Native

const chunk = (input, size) => {
  return input.reduce((arr, item, idx) => {
    return idx % size === 0
      ? [...arr, [item]]
      : [...arr.slice(0, -1), [...arr.slice(-1)[0], item]];
  }, []);
};

chunk(['a', 'b', 'c', 'd'], 2);
// => [['a', 'b'], ['c', 'd']]

chunk(['a', 'b', 'c', 'd'], 3);
// => [['a', 'b', 'c'], ['d']]

Browser Support for Spread in array literals

![Chrome][chrome-image]![Edge][edge-image]![Firefox][firefox-image]![IE][ie-image]![Opera][opera-image]![Safari][safari-image]
46.0 βœ”12.0 βœ”16.0 βœ”βœ–37.0 βœ”8.0 βœ”

⬆ back to top

_.compact

Creates an array with all falsy values removed.

// Underscore/Lodash
_.compact([0, 1, false, 2, '', 3]);

// Native
[0, 1, false, 2, '', 3].filter(Boolean)

Browser Support for array.prototype.filter

![Chrome][chrome-image]![Edge][edge-image]![Firefox][firefox-image]![IE][ie-image]![Opera][opera-image]![Safari][safari-image]
βœ”βœ”1.5 βœ”9.0 βœ”βœ”βœ”

⬆ back to top

_.concat

Creates a new array concatenating array with any additional arrays and/or values.

// Underscore/Lodash
var array = [1]
var other = _.concat(array, 2, [3], [[4]])

console.log(other)
// output: [1, 2, 3, [4]]

// Native
var array = [1]
var other = array.concat(2, [3], [[4]])

console.log(other)
// output: [1, 2, 3, [4]]

Browser Support for Array.prototype.concat()

![Chrome][chrome-image]![Edge][edge-image]![Firefox][firefox-image]![IE][ie-image]![Opera][opera-image]![Safari][safari-image]
1.0 βœ”βœ”1.0 βœ”5.5 βœ”βœ”βœ”

⬆ back to top

_.difference

Similar to without, but returns the values from array that are not present in the other arrays.

// Underscore/Lodash
console.log(_.difference([1, 2, 3, 4, 5], [5, 2, 10]))
// output: [1, 3, 4]

// Native
var arrays = [[1, 2, 3, 4, 5], [5, 2, 10]];
console.log(arrays.reduce(function(a, b) {
  return a.filter(function(value) {
    return !b.includes(value);
  });
}));
// output: [1, 3, 4]

// ES6
let arrays = [[1, 2, 3, 4, 5], [5, 2, 10]];
console.log(arrays.reduce((a, b) => a.filter(c => !b.includes(c))));
// output: [1, 3, 4]

Browser Support for Array.prototype.reduce()

![Chrome][chrome-image]![Edge][edge-image]![Firefox][firefox-image]![IE][ie-image]![Opera][opera-image]![Safari][safari-image]
βœ”βœ”3.0 βœ”9.0 βœ”10.5 βœ”4.0 βœ”

⬆ back to top

_.drop

Creates a slice of array with n elements dropped from the beginning.

// Underscore/Lodash
_.drop([1, 2, 3]);
// => [2, 3]

_.drop([1, 2, 3], 2);
// => [3]

// Native
[1, 2, 3].slice(1);
// => [2, 3]

[1, 2, 3].slice(2);
// => [3]

Browser Support for Array.prototype.slice()

![Chrome][chrome-image]![Edge][edge-image]![Firefox][firefox-image]![IE][ie-image]![Opera][opera-image]![Safari][safari-image]
1.0 βœ”βœ”1.0 βœ”βœ”βœ”βœ”

⬆ back to top

_.dropRight

Creates a slice of array with n elements dropped at the end.

// Underscore/Lodash
_.dropRight([1, 2, 3]);
// => [1, 2]

_.dropRight([1, 2, 3], 2);
// => [1]

// Native
[1, 2, 3].slice(0, -1);
// => [1, 2]

[1, 2, 3].slice(0, -2);
// => [1]

Browser Support for Array.prototype.slice()

![Chrome][chrome-image]![Edge][edge-image]![Firefox][firefox-image]![IE][ie-image]![Opera][opera-image]![Safari][safari-image]
1.0 βœ”βœ”1.0 βœ”βœ”βœ”βœ”

⬆ back to top

_.fill

Fills elements of array with value from start up to, but not including, end. Note that fill is a mutable method in both native and Lodash/Underscore.

// Underscore/Lodash
var array = [1, 2, 3]

_.fill(array, 'a')

console.log(array)
// output: ['a', 'a', 'a']

_.fill(Array(3), 2)
// output: [2, 2, 2]

_.fill([4, 6, 8, 10], '*', 1, 3)
// output: [4, '*', '*', 10]

// Native
var array = [1, 2, 3]

array.fill('a')

console.log(array)
// output: ['a', 'a', 'a']

Array(3).fill(2)
// output: [2, 2, 2]

[4, 6, 8, 10].fill('*', 1, 3)
// output: [4, '*', '*', 10]

Browser Support for Array.prototype.fill()

![Chrome][chrome-image]![Edge][edge-image]![Firefox][firefox-image]![IE][ie-image]![Opera][opera-image]![Safari][safari-image]
45.0 βœ”βœ”31.0 βœ”βœ–32.0 βœ”8 βœ”

⬆ back to top

_.find

Returns the value of the first element in the array that satisfies the provided testing function. Otherwise undefined is returned.

// Underscore/Lodash
var users = [
  { 'user': 'barney',  'age': 36, 'active': true },
  { 'user': 'fred',    'age': 40, 'active': false },
  { 'user': 'pebbles', 'age': 1,  'active': true }
]

_.find(users, function (o) { return o.age < 40; })
// output: object for 'barney'

// Native
var users = [
  { 'user': 'barney',  'age': 36, 'active': true },
  { 'user': 'fred',    'age': 40, 'active': false },
  { 'user': 'pebbles', 'age': 1,  'active': true }
]

users.find(function (o) { return o.age < 40; })
// output: object for 'barney'

Browser Support for Array.prototype.find()

![Chrome][chrome-image]![Edge][edge-image]![Firefox][firefox-image]![IE][ie-image]![Opera][opera-image]![Safari][safari-image]
45.0 βœ”βœ”25.0 βœ”βœ–32.0 βœ”7.1 βœ”

⬆ back to top

_.findIndex

Returns the index of the first element in the array that satisfies the provided testing function. Otherwise -1 is returned.

// Underscore/Lodash
var users = [
  { 'user': 'barney',  'age': 36, 'active': true },
  { 'user': 'fred',    'age': 40, 'active': false },
  { 'user': 'pebbles', 'age': 1,  'active': true }
]

var index = _.findIndex(users, function (o) { return o.age >= 40; })
console.log(index)
// output: 1

// Native
var users = [
  { 'user': 'barney',  'age': 36, 'active': true },
  { 'user': 'fred',    'age': 40, 'active': false },
  { 'user': 'pebbles', 'age': 1,  'active': true }
]

var index = users.findIndex(function (o) { return o.age >= 40; })
console.log(index)
// output: 1

Browser Support for Array.prototype.findIndex()

![Chrome][chrome-image]![Edge][edge-image]![Firefox][firefox-image]![IE][ie-image]![Opera][opera-image]![Safari][safari-image]
45.0 βœ”βœ”25.0 βœ”βœ–32.0 βœ”7.1 βœ”

⬆ back to top

_.first

Returns the first element of an array. Passing n will return the first n elements of the array.

// Underscore/Lodash
_.first([1, 2, 3, 4, 5]);
// => 1

// Underscore
_.first([1, 2, 3, 4, 5], 2);
// => [1, 2]

// Native
[1, 2, 3, 4, 5][0];
// => 1
//or
[].concat(1, 2, 3, 4, 5).shift()
// => 1
//or
[].concat([1, 2, 3, 4, 5]).shift()
// => 1

// Native (works even with potentially undefined/null, like _.first)
[].concat(undefined).shift()
// => undefined

[1, 2, 3, 4, 5].slice(0, 2);
// => [1, 2]

Browser Support for Array.prototype.slice()

![Chrome][chrome-image]![Edge][edge-image]![Firefox][firefox-image]![IE][ie-image]![Opera][opera-image]![Safari][safari-image]
1.0 βœ”βœ”1.0 βœ”βœ”βœ”βœ”

⬆ back to top

_.flatten

Flattens array a single level deep.

// Underscore/Lodash
_.flatten([1, [2, [3, [4]], 5]]);
// => [1, 2, [3, [4]], 5]

// Native
const flatten = [1, [2, [3, [4]], 5]].reduce( (a, b) => a.concat(b), [])
// => [1, 2, [3, [4]], 5]

const flatten = [].concat(...[1, [2, [3, [4]], 5]])
// => [1, 2, [3, [4]], 5]

// Native(ES2019)
const flatten = [1, [2, [3, [4]], 5]].flat()
// => [1, 2, [3, [4]], 5]

const flatten = [1, [2, [3, [4]], 5]].flatMap(number => number)
// => [1, 2, [3, [4]], 5]

Browser Support for Array.prototype.reduce()

![Chrome][chrome-image]![Edge][edge-image]![Firefox][firefox-image]![IE][ie-image]![Opera][opera-image]![Safari][safari-image]
46.0 βœ”βœ”3.0 βœ”9.0 βœ”10.5 βœ”4 βœ”

Browser Support for Array.prototype.flat()

![Chrome][chrome-image]![Edge][edge-image]![Firefox][firefox-image]![IE][ie-image]![Opera][opera-image]![Safari][safari-image]
69 βœ”βœ–62 βœ”βœ–56 βœ”12 βœ”

Browser Support for Array.prototype.flatMap()

![Chrome][chrome-image]![Edge][edge-image]![Firefox][firefox-image]![IE][ie-image]![Opera][opera-image]![Safari][safari-image]
69 βœ”βœ–62 βœ”βœ–56 βœ”12 βœ”

⬆ back to top

_.flattenDeep

Recursively flattens array.

// Underscore/Lodash
_.flattenDeep([1, [2, [3, [4]], 5]]);
// => [1, 2, 3, 4, 5]

// Native
const flattenDeep = (arr) => Array.isArray(arr)
  ? arr.reduce( (a, b) => a.concat(flattenDeep(b)) , [])
  : [arr]

flattenDeep([1, [[2], [3, [4]], 5]])
// => [1, 2, 3, 4, 5]

// Native(ES2019)
[1, [2, [3, [4]], 5]].flat(Infinity)
// => [1, 2, 3, 4, 5]

const flattenDeep = (arr) => arr.flatMap((subArray, index) => Array.isArray(subArray) ? flattenDeep(subArray) : subArray)

flattenDeep([1, [[2], [3, [4]], 5]])
// => [1, 2, 3, 4, 5]

Browser Support

![Chrome][chrome-image]![Edge][edge-image]![Firefox][firefox-image]![IE][ie-image]![Opera][opera-image]![Safari][safari-image]
46.0 βœ”βœ”16.0 βœ”βœ–37.0 βœ”7.1 βœ”

Browser Support for Array.prototype.flat()

![Chrome][chrome-image]![Edge][edge-image]![Firefox][firefox-image]![IE][ie-image]![Opera][opera-image]![Safari][safari-image]
69 βœ”βœ–62 βœ”βœ–56 βœ”12 βœ”

Browser Support for Array.prototype.flatMap()

![Chrome][chrome-image]![Edge][edge-image]![Firefox][firefox-image]![IE][ie-image]![Opera][opera-image]![Safari][safari-image]
69 βœ”βœ–62 βœ”βœ–56 βœ”12 βœ”

⬆ back to top

_.fromPairs

Returns an object composed from key-value pairs.

// Underscore/Lodash
_.fromPairs([['a', 1], ['b', 2]]);
// => { 'a': 1, 'b': 2 }

// Native
const fromPairs = function(arr) {
  return arr.reduce(function(accumulator, value) {
    accumulator[value[0]] = value[1];
    return accumulator;
  }, {})
}

// Compact form
const fromPairs = (arr) => arr.reduce((acc, val) => (acc[val[0]] = val[1], acc), {})

fromPairs([['a', 1], ['b', 2]]);
// => { 'a': 1, 'b': 2 }

// Native(ES2019)
Object.fromEntries([['a', 1], ['b', 2]])
// => { 'a': 1, 'b': 2 }

Browser Support for Array.prototype.reduce()

![Chrome][chrome-image]![Edge][edge-image]![Firefox][firefox-image]![IE][ie-image]![Opera][opera-image]![Safari][safari-image]
βœ”βœ”3.0 βœ”9.0 βœ”10.5 βœ”4.0 βœ”

Browser Support for Object.fromEntries()

![Chrome][chrome-image]![Edge][edge-image]![Firefox][firefox-image]![IE][ie-image]![Opera][opera-image]![Safari][safari-image]
73.0 βœ”79.0 βœ”63.0 βœ”βœ–60 βœ”12.1 βœ”

⬆ back to top

_.head and _.tail

Gets the first element or all but the first element.

const array = [1, 2, 3]

// Underscore: _.first, _.head, _.take
// Lodash: _.first, _.head
_.head(array)
// output: 1

// Underscore: _.rest, _.tail, _.drop
// Lodash: _.tail
_.tail(array)
// output: [2, 3]


// Native
const [ head, ...tail ] = array
console.log(head)
// output: 1
console.log(tail)
// output [2, 3]

Browser Support for Spread in array literals

![Chrome][chrome-image]![Edge][edge-image]![Firefox][firefox-image]![IE][ie-image]![Opera][opera-image]![Safari][safari-image]
46.0 βœ”12.0 βœ”16.0 βœ”βœ–37.0 βœ”8.0 βœ”

⬆ back to top

_.indexOf

Returns the first index at which a given element can be found in the array, or -1 if it is not present.

// Underscore/Lodash
var array = [2, 9, 9]
var result = _.indexOf(array, 2)
console.log(result)
// output: 0

// Native
var array = [2, 9, 9]
var result = array.indexOf(2)
console.log(result)
// output: 0

Browser Support for Array.prototype.indexOf()

![Chrome][chrome-image]![Edge][edge-image]![Firefox][firefox-image]![IE][ie-image]![Opera][opera-image]![Safari][safari-image]
βœ”βœ”1.5 βœ”9.0 βœ”βœ”βœ”

⬆ back to top

_.intersection

Returns an array that is the intersection of all the arrays. Each value in the result is present in each of the arrays.

// Underscore/Lodash
console.log(_.intersection([1, 2, 3], [101, 2, 1, 10], [2, 1]))
// output: [1, 2]

// Native
var arrays = [[1, 2, 3], [101, 2, 1, 10], [2, 1]];
console.log(arrays.reduce(function(a, b) {
  return a.filter(function(value) {
    return b.includes(value);
  });
}));
// output: [1, 2]

// ES6
let arrays = [[1, 2, 3], [101, 2, 1, 10], [2, 1]];
console.log(arrays.reduce((a, b) => a.filter(c => b.includes(c))));
// output: [1, 2]

Browser Support for Array.prototype.reduce()

![Chrome][chrome-image]![Edge][edge-image]![Firefox][firefox-image]![IE][ie-image]![Opera][opera-image]![Safari][safari-image]
βœ”βœ”3.0 βœ”9.0 βœ”10.5 βœ”4.0 βœ”

⬆ back to top

_.takeRight

Creates a slice of array with n elements taken from the end. :heavy_exclamation_mark: Native slice does not behave entirely the same as the Lodash method. See example below to understand why.

// Underscore/Lodash
_.takeRight([1, 2, 3]);
// => [3]

_.takeRight([1, 2, 3], 2);
// => [2, 3]

_.takeRight([1, 2, 3], 5);
// => [1, 2, 3]

// Native
[1, 2, 3].slice(-1);
// => [3]

[1, 2, 3].slice(-2);
// => [2, 3]

[1, 2, 3].slice(-5);
// => [1, 2, 3]

// Difference in compatibility

// Lodash
_.takeRight([1, 2, 3], 0);
// => []

// Native
[1, 2, 3].slice(0);
// => [1, 2, 3]

Browser Support for Array.prototype.slice()

![Chrome][chrome-image]![Edge][edge-image]![Firefox][firefox-image]![IE][ie-image]![Opera][opera-image]![Safari][safari-image]
1.0 βœ”βœ”1.0 βœ”βœ”βœ”βœ”

⬆ back to top

_.isArray

Returns true if given value is an array.

// Lodash
var array = []
console.log(_.isArray(array))
// output: true

// Native
var array = []
console.log(Array.isArray(array));
// output: true

Browser Support for Array.isArray()

![Chrome][chrome-image]![Edge][edge-image]![Firefox][firefox-image]![IE][ie-image]![Opera][opera-image]![Safari][safari-image]
5.0 βœ”βœ”4.0 βœ”9.0 βœ”10.5 βœ”5.0 βœ”

⬆ back to top

_.isArrayBuffer

Checks if value is classified as an ArrayBuffer object.

// Lodash
_.isArrayBuffer(new ArrayBuffer(2));
// output: true

// Native
console.log(new ArrayBuffer(2) instanceof ArrayBuffer);
// output: true

:warning: You will get the wrong result if you get ArrayBuffer from another realm. See details.

Browser Support for instanceof

![Chrome][chrome-image]![Edge][edge-image]![Firefox][firefox-image]![IE][ie-image]![Opera][opera-image]![Safari][safari-image]
βœ”βœ”1.0 βœ”βœ”βœ”βœ”

⬆ back to top

_.join

:heavy_exclamation_mark:Not in Underscore.js Joins a list of elements in an array with a given separator.

// Lodash
var result = _.join(['one', 'two', 'three'], '--')
console.log(result)
// output: 'one--two--three'

// Native
var result = ['one', 'two', 'three'].join('--')
console.log(result)
// output: 'one--two--three'

Browser Support for Array.prototype.join()

![Chrome][chrome-image]![Edge][edge-image]![Firefox][firefox-image]![IE][ie-image]![Opera][opera-image]![Safari][safari-image]
1.0 βœ”βœ”1.0 βœ”5.5 βœ”βœ”βœ”

⬆ back to top

_.last

Returns the last element of an array. Passing n will return the last n elements of the array.

// Underscore/Lodash
const numbers = [1, 2, 3, 4, 5];
_.last(numbers);
// => 5

// Underscore
_.last(numbers, 2);
// => [4, 5]

// Native
const numbers = [1, 2, 3, 4, 5];
numbers[numbers.length - 1];
// => 5
//or
numbers.slice(-1)[0];
// => 5
//or
[].concat(numbers).pop()
// => 5

// Native (works even with potentially undefined/null)
[].concat(undefined).pop()
// => undefined

numbers.slice(-2);
// => [4, 5]

Browser Support for Array.prototype.concat()

![Chrome][chrome-image]![Edge][edge-image]![Firefox][firefox-image]![IE][ie-image]![Opera][opera-image]![Safari][safari-image]
1.0 βœ”βœ”1.0 βœ”5.5 βœ”βœ”βœ”

⬆ back to top

_.lastIndexOf

Returns the index of the last occurrence of value in the array, or -1 if value is not present.

// Underscore/Lodash
var array = [2, 9, 9, 4, 3, 6]
var result = _.lastIndexOf(array, 9)
console.log(result)
// output: 2

// Native
var array = [2, 9, 9, 4, 3, 6]
var result = array.lastIndexOf(9)
console.log(result)
// output: 2

Browser Support for Array.prototype.lastIndexOf()

![Chrome][chrome-image]![Edge][edge-image]![Firefox][firefox-image]![IE][ie-image]![Opera][opera-image]![Safari][safari-image]
βœ”βœ”1.5 βœ”9.0 βœ”βœ”βœ”

⬆ back to top

_.reverse

:heavy_exclamation_mark:Not in Underscore.js Reverses array so that the first element becomes the last, the second element becomes the second to last, and so on.

// Lodash
var array = [1, 2, 3]
console.log(_.reverse(array))
// output: [3, 2, 1]

// Native
var array = [1, 2, 3]
console.log(array.reverse())
// output: [3, 2, 1]

Voice from the Lodash author:

Lodash's _.reverse just calls Array#reverse and enables composition like _.map(arrays, _.reverse). It's exposed on _ because previously, like Underscore, it was only exposed in the chaining syntax. --- jdalton

Browser Support for Array.prototype.reverse()

![Chrome][chrome-image]![Edge][edge-image]![Firefox][firefox-image]![IE][ie-image]![Opera][opera-image]![Safari][safari-image]
βœ”βœ”1.5 βœ”9 βœ”βœ”βœ”

⬆ back to top

_.slice

Returns a shallow copy of a portion of an array into a new array object selected from begin to end (end not included)

// Lodash
var array = [1, 2, 3, 4]
console.log(_.slice(array, 1, 3))
// output: [2, 3]

// Native
var array = [1, 2, 3, 4]
console.log(array.slice(1, 3));
// output: [2, 3]

Browser Support for Array.prototype.slice()

![Chrome][chrome-image]![Edge][edge-image]![Firefox][firefox-image]![IE][ie-image]![Opera][opera-image]![Safari][safari-image]
1.0 βœ”βœ”1.0 βœ”βœ”βœ”βœ”

⬆ back to top

_.without

:heavy_exclamation_mark:Not in Underscore.js Returns an array where matching items are filtered.

// Lodash
var array = [1, 2, 3]
console.log(_.without(array, 2))
// output: [1, 3]

// Native
var array = [1, 2, 3]
console.log(array.filter(function(value) {
  return value !== 2;
}));
// output: [1, 3]

Browser Support for Array.prototype.filter()

![Chrome][chrome-image]![Edge][edge-image]![Firefox][firefox-image]![IE][ie-image]![Opera][opera-image]![Safari][safari-image]
1.0 βœ”βœ”1.5 βœ”9 βœ”βœ”βœ”

⬆ back to top

_.initial

Returns everything but the last entry of the array. Pass n to exclude the last n elements from the result.

// Underscore
var array = [5, 4, 3, 2, 1]
console.log(_.initial(array, 2))
// output: [5, 4, 3]

// Native
var array = [5, 4, 3, 2, 1]
console.log(array.slice(0, -2));
// output: [5, 4, 3]

Browser Support for Array.prototype.slice()

![Chrome][chrome-image]![Edge][edge-image]![Firefox][firefox-image]![IE][ie-image]![Opera][opera-image]![Safari][safari-image]
1.0 βœ”βœ”1.0 βœ”βœ”βœ”βœ”

⬆ back to top

_.pull

Removes all provided values from the given array using strict equality for comparisons, i.e. ===.

// Lodash
const array = [1, 2, 3, 1, 2, 3];
_.pull(array, 2, 3);
console.log(array); // output: [1, 1]
// Native JS
const array = [1, 2, 3, 1, 2, 3];
function pull(arr, ...removeList){
    var removeSet = new Set(removeList)
    return arr.filter(function(el){
        return !removeSet.has(el)
    })
}
console.log(pull(array, 2, 3)); // output: [1, 1]
console.log(array); // still [1, 2, 3, 1, 2, 3]. This is not in place, unlike lodash!
// TypeScript
const array = [1, 2, 3, 1, 2, 3];
const pull = <T extends unknown>(sourceArray: T[], ...removeList: T[]): T[] => {
  const removeSet = new Set(removeList);
  return sourceArray.filter(el => !removeSet.has(el));
};
console.log(pull(array, 2, 3)); // output: [1, 1]
console.log(array); // still [1, 2, 3, 1, 2, 3]. This is not in place, unlike lodash!

Browser Support for Array.prototype.filter()

![Chrome][chrome-image]![Edge][edge-image]![Firefox][firefox-image]![IE][ie-image]![Opera][opera-image]![Safari][safari-image]
1.0 βœ”βœ”1.5 βœ”9 βœ”βœ”βœ”

Browser Support for Set.prototype.has()

![Chrome][chrome-image]![Edge][edge-image]![Firefox][firefox-image]![IE][ie-image]![Opera][opera-image]![Safari][safari-image]
38 βœ”12 βœ”13 βœ”11 βœ”25 βœ”8 βœ”

⬆ back to top

_.unionBy

Creates an array of unique values, taking an iteratee to compute uniqueness with (note that to iterate by a key in an object you must use x => x.key instead of key for the iteratee)

// Lodash
var array1 = [2.1];
var array2 = [1.2, 2.3];
var result = _.unionBy(array1, array2, Math.floor)
console.log(result)
// output: [2.1, 1.2]

// Native
var array1 = [2.1];
var array2 = [1.2, 2.3];
function unionBy(...arrays) {
    const iteratee = (arrays).pop();

    if (Array.isArray(iteratee)) {
        return []; // return empty if iteratee is missing
    }

    return [...arrays].flat().filter(
        (set => (o) => set.has(iteratee(o)) ? false : set.add(iteratee(o)))(new Set()),
    );
};
console.log(unionBy(array1, array2, Math.floor))
// output: [2.1, 1.2]

Browser Support for Array.prototype.flat()

![Chrome][chrome-image]![Edge][edge-image]![Firefox][firefox-image]![IE][ie-image]![Opera][opera-image]![Safari][safari-image]
69 βœ”βœ–62 βœ”βœ–56 βœ”12 βœ”

Browser Support for Array.isArray()

![Chrome][chrome-image]![Edge][edge-image]![Firefox][firefox-image]![IE][ie-image]![Opera][opera-image]![Safari][safari-image]
5.0 βœ”βœ”4.0 βœ”9.0 βœ”10.5 βœ”5.0 βœ”

Browser Support for Set.prototype.has()

![Chrome][chrome-image]![Edge][edge-image]![Firefox][firefox-image]![IE][ie-image]![Opera][opera-image]![Safari][safari-image]
38 βœ”12 βœ”13 βœ”11 βœ”25 βœ”8 βœ”

⬆ back to top

Collection*

:heavy_exclamation_mark:Important: Note that most native equivalents are array methods, and will not work with objects. If this functionality is needed and no object method is provided, then Lodash/Underscore is the better option.

_.each

Iterates over a list of elements, yielding each in turn to an iteratee function.

// Underscore/Lodash
//For arrays
_.each([1, 2, 3], function (value, index) {
  console.log(value)
})
// output: 1 2 3

//For objects
_.each({'one':1, 'two':2, 'three':3}, function(value) {
  console.log(value)
})
// output: 1 2 3

// Native
//For arrays
[1, 2, 3].forEach(function (value, index) {
  console.log(value)
})
// output: 1 2 3

//For objects
Object.entries({'one':1, 'two':2, 'three':3}).forEach(function([key,value],index) {
  console.log(value)
})
//output: 1 2 3

Browser Support for Array.prototype.forEach()

![Chrome][chrome-image]![Edge][edge-image]![Firefox][firefox-image]![IE][ie-image]![Opera][opera-image]![Safari][safari-image]
βœ”βœ”1.5 βœ”9.0 βœ”βœ”βœ”

Browser Support for Object.entries().forEach()

![Chrome][chrome-image]![Edge][edge-image]![Firefox][firefox-image]![IE][ie-image]![Opera][opera-image]![Safari][safari-image]
54 βœ”14 βœ”47 βœ”βœ–41 βœ”10.1βœ”

⬆ back to top

_.every

Tests whether all elements in the array pass the test implemented by the provided function.

// Underscore/Lodash
function isLargerThanTen (element, index, array) {
  return element >= 10
}
var array = [10, 20, 30]
var result = _.every(array, isLargerThanTen)
console.log(result)
// output: true

// Native
function isLargerThanTen (element, index, array) {
  return element >= 10
}

var array = [10, 20, 30]
var result = array.every(isLargerThanTen)
console.log(result)
// output: true

Browser Support fpr Array.prototype.every()

![Chrome][chrome-image]![Edge][edge-image]![Firefox][firefox-image]![IE][ie-image]![Opera][opera-image]![Safari][safari-image]
βœ”βœ”1.5 βœ”9.0 βœ”βœ”βœ”

⬆ back to top

_.filter

Creates a new array with all elements that pass the test implemented by the provided function.

// Underscore/Lodash
function isBigEnough (value) {
  return value >= 10
}
var array = [12, 5, 8, 130, 44]
var filtered = _.filter(array, isBigEnough)
console.log(filtered)
// output: [12, 130, 44]

// Native
function isBigEnough (value) {
  return value >= 10
}
var array = [12, 5, 8, 130, 44]
var filtered = array.filter(isBigEnough)
console.log(filtered)
// output: [12, 130, 44]

Browser Support for Array.prototype.filter()

![Chrome][chrome-image]![Edge][edge-image]![Firefox][firefox-image]![IE][ie-image]![Opera][opera-image]![Safari][safari-image]
βœ”βœ”1.5 βœ”9 βœ”βœ”βœ”

⬆ back to top

_.groupBy

Group items by key.

// Underscore/Lodash
var grouped = _.groupBy(['one', 'two', 'three'], 'length')
console.log(grouped)
// output: {3: ["one", "two"], 5: ["three"]}

// Native
var grouped = ['one', 'two', 'three'].reduce((r, v, i, a, k = v.length) => ((r[k] || (r[k] = [])).push(v), r), {})
console.log(grouped)
// output: {3: ["one", "two"], 5: ["three"]}
// Underscore/Lodash
var grouped = _.groupBy([1.3, 2.1, 2.4], num => Math.floor(num))
console.log(grouped)
// output: {1: [1.3], 2: [2.1, 2.4]}

// Native
var grouped = [1.3, 2.1, 2.4].reduce((r, v, i, a, k = Math.floor(v)) => ((r[k] || (r[k] = [])).push(v), r), {})
console.log(grouped)
// output: {1: [1.3], 2: [2.1, 2.4]}

Browser Support for Array.prototype.reduce()

![Chrome][chrome-image]![Edge][edge-image]![Firefox][firefox-image]![IE][ie-image]![Opera][opera-image]![Safari][safari-image]
βœ”βœ”3.0 βœ”9.0 βœ”10.5 βœ”4.0 βœ”

⬆ back to top

_.includes

Checks if a value is in collection.

var array = [1, 2, 3]
// Underscore/Lodash - also called _.contains
_.includes(array, 1)
// output: true

// Native
var array = [1, 2, 3]
array.includes(1)
// output: true

// Native (does not use same value zero)
var array = [1, 2, 3]
array.indexOf(1) > -1
// output: true

Browser Support for Array.prototype.includes

![Chrome][chrome-image]![Edge][edge-image]![Firefox][firefox-image]![IE][ie-image]![Opera][opera-image]![Safari][safari-image]
47.0 βœ”14.0 βœ”43.0 βœ”βœ–34.0 βœ”9.0 βœ”

Browser Support for Array.prototype.indexOf

![Chrome][chrome-image]![Edge][edge-image]![Firefox][firefox-image]![IE][ie-image]![Opera][opera-image]![Safari][safari-image]
βœ”βœ”1.5 βœ”9.0 βœ”βœ”βœ”

⬆ back to top

_.keyBy

:heavy_exclamation_mark: Not in Underscore.js Creates an object composed of keys generated from the results of running each element of collection through iteratee.

// Lodash
console.log(_.keyBy(['a', 'b', 'c']))
// output: { a: 'a', b: 'b', c: 'c' }
console.log(_.keyBy([{ id: 'a1', title: 'abc' }, { id: 'b2', title: 'def' }], 'id'))
// output: { a1: { id: 'a1', title: 'abc' }, b2: { id: 'b2', title: 'def' } }
console.log(_.keyBy({ data: { id: 'a1', title: 'abc' }}, 'id'))
// output: { a1: { id: 'a1', title: 'abc' }}

// keyBy for array only
const keyBy = (array, key) => (array || []).reduce((r, x) => ({ ...r, [key ? x[key] : x]: x }), {});

// Native
console.log(keyBy(['a', 'b', 'c']))
// output: { a: 'a', b: 'b', c: 'c' }
console.log(keyBy([{ id: 'a1', title: 'abc' }, { id: 'b2', title: 'def' }], 'id'))
// output: { a1: { id: 'a1', title: 'abc' }, b2: { id: 'b2', title: 'def' } }
console.log(keyBy(Object.values({ data: { id: 'a1', title: 'abc' }}), 'id'))
// output: { a1: { id: 'a1', title: 'abc' }}

// keyBy for array and object
const collectionKeyBy = (collection, key) => {
  const c = collection || {};
  return c.isArray() ? keyBy(c, key) : Object.values(keyBy(c, key));
}

Browser Support for Array.prototype.reduce()

![Chrome][chrome-image]![Edge][edge-image]![Firefox][firefox-image]![IE][ie-image]![Opera][opera-image]![Safari][safari-image]
βœ”12.0 βœ”3.0 βœ”9.0 βœ”10.5 βœ”4.0 βœ”

⬆ back to top

_.map

Translates all items in an array or object to new array of items.

// Underscore/Lodash
var array1 = [1, 2, 3]
var array2 = _.map(array1, function (value, index) {
  return value * 2
})
console.log(array2)
// output: [2, 4, 6]

// Native
var array1 = [1, 2, 3]
var array2 = array1.map(function (value, index) {
  return value * 2
})
console.log(array2)
// output: [2, 4, 6]
// Underscore/Lodash
var object1 = { 'a': 1, 'b': 2, 'c': 3 }
var object2 = _.map(object1, function (value, index) {
  return value * 2
})
console.log(object2)
// output: [2, 4, 6]

// Native
var object1 = { 'a': 1, 'b': 2, 'c': 3 }
var object2 = Object.entries(object1).map(function ([key, value], index) {
  return value * 2
})
console.log(object2)
// output: [2, 4, 6]

Browser Support for Object.entries() and destructuring

![Chrome][chrome-image]![Edge][edge-image]![Firefox][firefox-image]![IE][ie-image]![Opera][opera-image]![Safari][safari-image]
βœ”βœ”1.5 βœ”βœ–βœ”βœ”

Browser Support for Array.prototype.map()

![Chrome][chrome-image]![Edge][edge-image]![Firefox][firefox-image]![IE][ie-image]![Opera][opera-image]![Safari][safari-image]
βœ”βœ”1.5 βœ”9.0 βœ”βœ”βœ”

⬆ back to top

_.minBy and _.maxBy

Use Array#reduce for find the maximum or minimum collection item

// Underscore/Lodash
var data = [{ value: 6 }, { value: 2 }, { value: 4 }]
var minItem = _.minBy(data, 'value')
var maxItem = _.maxBy(data, 'value')
console.log(minItem, maxItem)
// output: { value: 2 } { value: 6 }

// Native
var data = [{ value: 6 }, { value: 2 }, { value: 4 }]
var minItem = data.reduce(function(a, b) { return a.value <= b.value ? a : b }, {})
var maxItem = data.reduce(function(a, b) { return a.value >= b.value ? a : b }, {})
console.log(minItem, maxItem)
// output: { value: 2 }, { value: 6 }

Extract a functor and use es2015 for better code

// utils
const makeSelect = (comparator) => (a, b) => comparator(a, b) ? a : b
const minByValue = makeSelect((a, b) => a.value <= b.value)
const maxByValue = makeSelect((a, b) => a.value >= b.value)

// main logic
const data = [{ value: 6 }, { value: 2 }, { value: 4 }]
const minItem = data.reduce(minByValue, {})
const maxItem = data.reduce(maxByValue, {})

console.log(minItem, maxItem)
// output: { value: 2 }, { value: 6 }

// or also more universal and little slower variant of minBy
const minBy = (collection, key) => {
  // slower because need to create a lambda function for each call...
  const select = (a, b) => a[key] <= b[key] ? a : b
  return collection.reduce(select, {})
}

console.log(minBy(data, 'value'))
// output: { value: 2 }

Browser Support for Array.prototype.reduce()

![Chrome][chrome-image]![Edge][edge-image]![Firefox][firefox-image]![IE][ie-image]![Opera][opera-image]![Safari][safari-image]
βœ”βœ”3.0 βœ”9.0 βœ”10.5 βœ”4.0 βœ”

⬆ back to top

_.pluck

array.map or _.map can also be used to replace _.pluck. Lodash v4.0 removed _.pluck in favor of _.map with iteratee shorthand. Details can be found in Changelog

// Underscore/Lodash
var array1 = [{name: "Alice"}, {name: "Bob"}, {name: "Jeremy"}]
var names = _.pluck(array1, "name")
console.log(names)
// output: ["Alice", "Bob", "Jeremy"]

// Native
var array1 = [{name: "Alice"}, {name: "Bob"}, {name: "Jeremy"}]
var names = array1.map(function(x){
  return x.name
})
console.log(names)
// output: ["Alice", "Bob", "Jeremy"]

Browser Support for Array.prototype.map()

![Chrome][chrome-image]![Edge][edge-image]![Firefox][firefox-image]![IE][ie-image]![Opera][opera-image]![Safari][safari-image]
βœ”βœ”1.5 βœ”9.0 βœ”βœ”βœ”

⬆ back to top

_.reduce

Applies a function against an accumulator and each value of the array (from left-to-right) to reduce it to a single value.

// Underscore/Lodash
var array = [0, 1, 2, 3, 4]
var result = _.reduce(array, function (previousValue, currentValue, currentIndex, array) {
  return previousValue + currentValue
})
console.log(result)
// output: 10

// Native
var array = [0, 1, 2, 3, 4]
var result = array.reduce(function (previousValue, currentValue, currentIndex, array) {
  return previousValue + currentValue
})
console.log(result)
// output: 10

Browser Support for Array.prototype.reduce()

![Chrome][chrome-image]![Edge][edge-image]![Firefox][firefox-image]![IE][ie-image]![Opera][opera-image]![Safari][safari-image]
βœ”βœ”3.0 βœ”9.0 βœ”10.5 βœ”4.0 βœ”

⬆ back to top

_.range

Creates an array of numbers progressing from start up to.

// Underscore/Lodash
_.range(4)  // output: [0, 1, 2, 3]
_.range(-4) // output: [0, -1, -2, -3]
_.range(1, 5)     // output: [1, 2, 3, 4]
_.range(0, 20, 5) // output: [0, 5, 10, 15]

// Native ( solution with Array.from )
Array.from({length: 4}, (_, i) => i)  // output: [0, 1, 2, 3]
Array.from({length: 4}, (_, i) => -i) // output: [-0, -1, -2, -3]
Array.from({length: 4}, (_, i) => i + 1) // output: [1, 2, 3, 4]
Array.from({length: 4}, (_, i) => i * 5) // output: [0, 5, 10, 15]

// Native ( solution with keys() and spread )
[...Array(4).keys()]  // output: [0, 1, 2, 3]
[...Array(4).keys()].map(k => -k) // output: [-0, -1, -2, -3]
[...Array(4).keys()].map(k => k + 1)  // output: [1, 2, 3, 4]
[...Array(4).keys()].map(k => k * 5)  // output: [0, 5, 10, 15]

Browser Support for Array.from()

![Chrome][chrome-image]![Edge][edge-image]![Firefox][firefox-image]![IE][ie-image]![Opera][opera-image]![Safari][safari-image]
45.0 βœ”βœ”32.0 βœ”βœ–βœ”9.0 βœ”

Browser Support for keys and spread in Array literals

![Chrome][chrome-image]![Edge][edge-image]![Firefox][firefox-image]![IE][ie-image]![Opera][opera-image]![Safari][safari-image]
46.0 βœ”12.0 βœ”16.0 βœ”βœ–37.0 βœ”7.1 βœ”

⬆ back to top

_.reduceRight

This method is like _.reduce except that it iterates over elements of collection from right to left.

// Underscore/Lodash
var array = [0, 1, 2, 3, 4]
var result = _.reduceRight(array, function (previousValue, currentValue, currentIndex, array) {
  return previousValue - currentValue
})
console.log(result)
// output: -2

// Native
var array = [0, 1, 2, 3, 4]
var result = array.reduceRight(function (previousValue, currentValue, currentIndex, array) {
  return previousValue - currentValue
})
console.log(result)
// output: -2

Browser Support for Array.prototype.reduceRight()

![Chrome][chrome-image]![Edge][edge-image]![Firefox][firefox-image]![IE][ie-image]![Opera][opera-image]![Safari][safari-image]
βœ”βœ”3.0 βœ”9.0 βœ”10.5 βœ”4.0 βœ”

⬆ back to top

_.reject

The opposite of _.filter; this method returns the elements of collection that predicate does not return truthy for.

// Underscore/Lodash
var array = [1, 2, 3, 4, 5];
var result = _.reject(array, function (x) {
  return x % 2 === 0;
});
// output: [1, 3, 5]

// Native
var array = [1, 2, 3, 4, 5];

var reject = function (arr, predicate) {
  var complement = function (f) {
    return function (x) {
      return !f(x);
    }
  };

  return arr.filter(complement(predicate));
};
// output: [1, 3, 5]

Browser Support for Array.prototype.filter()

![Chrome][chrome-image]![Edge][edge-image]![Firefox][firefox-image]![IE][ie-image]![Opera][opera-image]![Safari][safari-image]
βœ”12 βœ”1.5 βœ”9.0 βœ”9.5 βœ”3.0 βœ”

⬆ back to top

_.sample

Gets a random element from array.

// Underscore/Lodash
const array = [0, 1, 2, 3, 4]
const result = _.sample(array)
console.log(result)
// output: 2

// Native
const array = [0, 1, 2, 3, 4]
const sample = arr => {
  const len = arr == null ? 0 : arr.length
  return len ? arr[Math.floor(Math.random() * len)] : undefined
}

const result = sample(array)
console.log(result)
// output: 2

Browser Support for Array.prototype.length() and Math.random()

![Chrome][chrome-image]![Edge][edge-image]![Firefox][firefox-image]![IE][ie-image]![Opera][opera-image]![Safari][safari-image]
βœ”βœ”1.0 βœ”βœ”βœ”βœ”

⬆ back to top

_.size

Returns the number of values in the collection.

// Underscore/Lodash
var result = _.size({one: 1, two: 2, three: 3})
console.log(result)
// output: 3

// Native
var result2 = Object.keys({one: 1, two: 2, three: 3}).length
console.log(result2)
// output: 3

Browser Support for Object.keys()

![Chrome][chrome-image]![Edge][edge-image]![Firefox][firefox-image]![IE][ie-image]![Opera][opera-image]![Safari][safari-image]
5.0 βœ”βœ”4.0 βœ”9.0 βœ”12.0 βœ”5.0 βœ”

⬆ back to top

_.some

Tests whether any of the elements in the array pass the test implemented by the provided function.

// Underscore/Lodash
function isLargerThanTen (element, index, array) {
  return element >= 10
}
var array = [10, 9, 8]
var result = _.some(array, isLargerThanTen)
console.log(result)
// output: true

// Native
function isLargerThanTen (element, index, array) {
  return element >= 10
}

var array = [10, 9, 8]
var result = array.some(isLargerThanTen)
console.log(result)
// output: true

Browser Support for Array.prototype.some()

![Chrome][chrome-image]![Edge][edge-image]![Firefox][firefox-image]![IE][ie-image]![Opera][opera-image]![Safari][safari-image]
βœ”βœ”1.5 βœ”βœ” 9.0βœ”βœ”

⬆ back to top

_.sortBy and _.orderBy

Sorts an array of object based on an object key provided by a parameter (note this is more limited than Underscore/Lodash).

const fruits = [
  {name:"banana", amount: 2},
  {name:"apple", amount: 4},
  {name:"pineapple", amount: 2},
  {name:"mango", amount: 1}
];

// Underscore
_.sortBy(fruits, 'name');
// => [{name:"apple", amount: 4}, {name:"banana", amount: 2}, {name:"mango", amount: 1}, {name:"pineapple", amount: 2}]

// Lodash
_.orderBy(fruits, ['name'],['asc']);
// => [{name:"apple", amount: 4}, {name:"banana", amount: 2}, {name:"mango", amount: 1}, {name:"pineapple", amount: 2}]

// Native
const sortBy = (key) => {
  return (a, b) => (a[key] > b[key]) ? 1 : ((b[key] > a[key]) ? -1 : 0);
};

// The native sort modifies the array in place. `_.orderBy` and `_.sortBy` do not, so we use `.concat()` to
// copy the array, then sort.
fruits.concat().sort(sortBy("name"));
// => [{name:"apple", amount: 4}, {name:"banana", amount: 2}, {name:"mango", amount: 1}, {name:"pineapple", amount: 2}]

Browser Support for Array.prototype.concat() and Array.prototype.sort()

![Chrome][chrome-image]![Edge][edge-image]![Firefox][firefox-image]![IE][ie-image]![Opera][opera-image]![Safari][safari-image]
1.0 βœ”βœ”1.0 βœ”5.5 βœ”βœ”βœ”

⬆ back to top

_.uniq

Produces a duplicate-free version of the array, using === to test object equality.

// Underscore/Lodash
var array = [1, 2, 1, 4, 1, 3]
var result = _.uniq(array)
console.log(result)
// output: [1, 2, 4, 3]

// Native
var array = [1, 2, 1, 4, 1, 3];
var result = [...new Set(array)];
console.log(result)
// output: [1, 2, 4, 3]

Browser Support for Spread in array literals

![Chrome][chrome-image]![Edge][edge-image]![Firefox][firefox-image]![IE][ie-image]![Opera][opera-image]![Safari][safari-image]
46.0 βœ”12.0 βœ”16.0 βœ”βœ–37.0 βœ”8.0 βœ”

⬆ back to top

Function

_.after

:heavy_exclamation_mark:Note this is an alternative implementation Creates a version of the function that will only be run after first being called count times. Useful for grouping asynchronous responses, where you want to be sure that all the async calls have finished, before proceeding.

var notes = ['profile', 'settings']
// Underscore/Lodash
var renderNotes = _.after(notes.length, render)
notes.forEach(function (note) {
  console.log(note)
  renderNotes()
})

// Native
notes.forEach(function (note, index) {
  console.log(note)
  if (notes.length === (index + 1)) {
    render()
  }
})

Browser Support for Array.prototype.forEach()

![Chrome][chrome-image]![Edge][edge-image]![Firefox][firefox-image]![IE][ie-image]![Opera][opera-image]![Safari][safari-image]
βœ”βœ”1.5 βœ”9.0 βœ”βœ”βœ”

⬆ back to top

_.bind

Create a new function that calls func with thisArg and args.

var objA = {
  x: 66,
  offsetX: function(offset) {
    return this.x + offset;
  }
}

var objB = {
  x: 67
};

// Underscore/Lodash
var boundOffsetX = _.bind(objA.offsetX, objB, 0);

// Native
var boundOffsetX = objA.offsetX.bind(objB, 0);

Browser Support for Function.prototype.bind()

![Chrome][chrome-image]![Edge][edge-image]![Firefox][firefox-image]![IE][ie-image]![Opera][opera-image]![Safari][safari-image]
7.0 βœ”βœ”4.0 βœ”9.0 βœ”11.6 βœ”5.1 βœ”

⬆ back to top

_.isFunction

Checks if value is classified as a Function object.

// Lodash
_.isFunction(console.log);
// => true

_.isFunction(/abc/);
// => false

// Native
function isFunction(func) {
  return typeof func === "function";
}

isFunction(setTimeout);
// => true

isFunction(123);
// => false

Browser Support

![Chrome][chrome-image]![Edge][edge-image]![Firefox][firefox-image]![IE][ie-image]![Opera][opera-image]![Safari][safari-image]
βœ”βœ”βœ”βœ”βœ”βœ”

⬆ back to top

_.debounce

Create a new function that calls func with thisArg and args.

 function debounce(func, wait, immediate) {
  var timeout;
  return function() {
      var context = this, args = arguments;
      clearTimeout(timeout);
      timeout = setTimeout(function() {
          timeout = null;
          if (!immediate) func.apply(context, args);
      }, wait);
      if (immediate && !timeout) func.apply(context, args);
  };
}

// Avoid costly calculations while the window size is in flux.
jQuery(window).on('resize', debounce(calculateLayout, 150));

Browser Support for debounce

![Chrome][chrome-image]![Edge][edge-image]![Firefox][firefox-image]![IE][ie-image]![Opera][opera-image]![Safari][safari-image]
7.0 βœ”βœ”4.0 βœ”9.0 βœ”11.6 βœ”5.1 βœ”

⬆ back to top

_.partial

Create a new function that calls func with args.

// Lodash
function greet(greeting, name) {
  return greeting + ' ' + name;
}
var sayHelloTo = _.partial(greet, 'Hello');
var result = sayHelloTo('Jose')
console.log(result)
// output: 'Hello Jose'

// Native
function greet(greeting, name) {
  return greeting + ' ' + name;
}
var sayHelloTo = (...args) => greet('Hello', ...args)
var result = sayHelloTo('Jose')
console.log(result)
// output: 'Hello Jose'

// Native
const partial = (func, ...boundArgs) => (...remainingArgs) => func(...boundArgs, ...remainingArgs)
var sayHelloTo = partial(greet, 'Hello');
var result = sayHelloTo('Jose')
console.log(result)
// output: 'Hello Jose'

Browser Support for Spread

![Chrome][chrome-image]![Edge][edge-image]![Firefox][firefox-image]![IE][ie-image]![Opera][opera-image]![Safari][safari-image]
46.0 βœ”12.0 βœ”16.0 βœ”βœ–37.0 βœ”8.0 βœ”

⬆ back to top

_.throttle

Create a new function that limits calls to func to once every given timeframe.

function throttle(func, timeFrame) {
  var lastTime = 0;
  return function (...args) {
      var now = new Date();
      if (now - lastTime >= timeFrame) {
          func(...args);
          lastTime = now;
      }
  };
}

// Avoid running the same function twice within the specified timeframe.
jQuery(window).on('resize', throttle(calculateLayout, 150));

Browser Support for throttle

![Chrome][chrome-image]![Edge][edge-image]![Firefox][firefox-image]![IE][ie-image]![Opera][opera-image]![Safari][safari-image]
5.0 βœ”12.0 βœ”3.0 βœ”9.0 βœ”10.5 βœ”4.0 βœ”

⬆ back to top

Lang

_.castArray

Puts the value into an array of length one if it is not already an array.

// Underscore
console.log(_.castArray(5))
// output: [5]
console.log(_.castArray([2]))
// output: [2]

// Native
function castArray(arr) {
  return Array.isArray(arr) ? arr : [arr]
}
// output: true
console.log(castArray(5));
// output: [5]
console.log(castArray([2]));
// output: [2]

Browser Support for Array.isArray()

![Chrome][chrome-image]![Edge][edge-image]![Firefox][firefox-image]![IE][ie-image]![Opera][opera-image]![Safari][safari-image]
5.0 βœ”βœ”4.0 βœ”9.0 βœ”10.5 βœ”5.0 βœ”

⬆ back to top

_.isDate

Checks if value is classified as a Date object.

// Lodash
console.log(_.isDate(new Date));
// output: true

// Native
console.log(Object.prototype.toString.call(new Date) === "[object Date]");
// output: true

Browser Support for String.prototype.toString.call()

![Chrome][chrome-image]![Edge][edge-image]![Firefox][firefox-image]![IE][ie-image]![Opera][opera-image]![Safari][safari-image]
βœ”βœ”βœ”βœ”βœ”βœ”

⬆ back to top

_.gt

Checks if value is greater than other.

// Lodash
console.log(_.gt(3, 1))
// output: true

// Native
console.log(3 > 1);
// output: true

Browser Support

![Chrome][chrome-image]![Edge][edge-image]![Firefox][firefox-image]![IE][ie-image]![Opera][opera-image]![Safari][safari-image]
βœ”βœ”βœ”βœ”βœ”βœ”

⬆ back to top

_.gte

Checks if value is greater than or equal to other.

// Lodash
console.log(_.gte(3, 1))
// output: true

// Native
console.log(3 >= 1);
// output: true

Browser Support

![Chrome][chrome-image]![Edge][edge-image]![Firefox][firefox-image]![IE][ie-image]![Opera][opera-image]![Safari][safari-image]
βœ”βœ”βœ”βœ”βœ”βœ”

⬆ back to top

_.isEmpty

Checks if value is an empty object or collection.

:heavy_exclamation_mark:Note that the Native version does not support evaluating a Set or a Map

// Lodash
console.log(_.isEmpty(null))
// output: true
console.log(_.isEmpty(''))
// output: true
console.log(_.isEmpty({}))
// output: true
console.log(_.isEmpty([]))
// output: true
console.log(_.isEmpty({a: '1'}))
// output: false

// Native
const isEmpty = obj => [Object, Array].includes((obj || {}).constructor) && !Object.entries((obj || {})).length;

console.log(isEmpty(null))
// output: true
console.log(isEmpty(''))
// output: true
console.log(isEmpty({}))
// output: true
console.log(isEmpty([]))
// output: true
console.log(isEmpty({a: '1'}))
// output: false

Browser Support for Array.prototype.includes()

![Chrome][chrome-image]![Edge][edge-image]![Firefox][firefox-image]![IE][ie-image]![Opera][opera-image]![Safari][safari-image]
47.0 βœ”14.0 βœ”43.0 βœ”βœ–34.0 βœ”9.0 βœ”

⬆ back to top

_.isFinite

Checks if value is a finite primitive number.

// Lodash
console.log(_.isFinite('3'))
// output: false
console.log(_.isFinite(3))
// output: true

// Native
console.log(Number.isFinite('3'))
// output: false
console.log(Number.isFinite(3))
// output: true

Browser Support for Number.isFinite()

![Chrome][chrome-image]![Edge][edge-image]![Firefox][firefox-image]![IE][ie-image]![Opera][opera-image]![Safari][safari-image]
19.0 βœ”βœ”16.0 βœ”βœ–15.0 βœ”9.0 βœ”

⬆ back to top

_.isInteger

Checks if value is an integer.

// Lodash
console.log(_.isInteger(3))
// output: true
console.log(_.isInteger('3'))
// output: false

// Native
console.log(Number.isInteger(3))
// output: true
console.log(Number.isInteger('3'))
// output: false

Browser Support for Number.isInteger()

![Chrome][chrome-image]![Edge][edge-image]![Firefox][firefox-image]![IE][ie-image]![Opera][opera-image]![Safari][safari-image]
βœ”12 βœ”16.0 βœ”βœ–βœ”βœ”

⬆ back to top

_.isNaN

Checks if a value is NaN.

// Underscore/Lodash
console.log(_.isNaN(NaN))
// output: true

// Native
console.log(isNaN(NaN))
// output: true

// ES6
console.log(Number.isNaN(NaN))
// output: true

MDN:

In comparison to the global isNaN() function, Number.isNaN() doesn't suffer the problem of forcefully converting the parameter to a number. This means it is now safe to pass values that would normally convert to NaN, but aren't actually the same value as NaN. This also means that only values of the type number, that are also NaN, return true. Number.isNaN()

Voice from the Lodash author:

Lodash's _.isNaN is equiv to ES6 Number.isNaN which is different than the global isNaN. --- jdalton

Browser Support for isNaN

![Chrome][chrome-image]![Edge][edge-image]![Firefox][firefox-image]![IE][ie-image]![Opera][opera-image]![Safari][safari-image]
βœ”βœ”1.0 βœ”βœ”βœ”βœ”

Browser Support for Number.isNaN

![Chrome][chrome-image]![Edge][edge-image]![Firefox][firefox-image]![IE][ie-image]![Opera][opera-image]![Safari][safari-image]
25.0 βœ”βœ”15.0 βœ”βœ–βœ”9.0 βœ”

⬆ back to top

_.isNil

:heavy_exclamation_mark:Not in Underscore.js Checks if value is null or undefined.

// Lodash
console.log(_.isNil(null))
// output: true
console.log(_.isNil(NaN))
// output: false
console.log(_.isNil(undefined))
// output: true

// Native
console.log(null == null);
// output: true
console.log(NaN == null);
// output: false
console.log(undefined == null)
// output: true

Browser Support

![Chrome][chrome-image]![Edge][edge-image]![Firefox][firefox-image]![IE][ie-image]![Opera][opera-image]![Safari][safari-image]
βœ”βœ”βœ”βœ”βœ”βœ”

⬆ back to top

_.isNull

Checks if value is null or undefined.

// Underscore/Lodash
console.log(_.isNull(null))
// output: true
console.log(_.isNull(void 0))
// output: false

// Native
console.log(null === null);
// output: true
console.log(void 0 === null);
// output: false

Browser Support

![Chrome][chrome-image]![Edge][edge-image]![Firefox][firefox-image]![IE][ie-image]![Opera][opera-image]![Safari][safari-image]
βœ”βœ”βœ”βœ”βœ”βœ”

⬆ back to top

_.isUndefined

Checks if value is undefined.

// Underscore/Lodash
console.log(_.isUndefined(a))
// output: true

// Native
console.log(typeof a === 'undefined');
// output: true
console.log(a === undefined);
// output: true

Browser Support

![Chrome][chrome-image]![Edge][edge-image]![Firefox][firefox-image]![IE][ie-image]![Opera][opera-image]![Safari][safari-image]
βœ”βœ”1 βœ”βœ”βœ”βœ”

⬆ back to top

Object

_.assign

The method is used to copy the values of all enumerable own properties from one or more source objects to a target object.

// Underscore: _.extendOwn
// Lodash
function Foo() {
  this.c = 3;
}
function Bar() {
  this.e = 5;
}
Foo.prototype.d = 4;
Bar.prototype.f = 6;
var result = _.assign(new Foo, new Bar);
console.log(result);
// output: { 'c': 3, 'e': 5 }

// Native
function Foo() {
  this.c = 3;
}
function Bar() {
  this.e = 5;
}
Foo.prototype.d = 4;
Bar.prototype.f = 6;
var result = Object.assign({}, new Foo, new Bar);
console.log(result);
// output: { 'c': 3, 'e': 5 }

Browser Support for Object.assign()

![Chrome][chrome-image]![Edge][edge-image]![Firefox][firefox-image]![IE][ie-image]![Opera][opera-image]![Safari][safari-image]
45.0 βœ”βœ”34.0 βœ”βœ–32.0 βœ”9.0 βœ”

⬆ back to top

_.defaults

The method is used to apply new values over an object with default values for keys.

// Underscore: _.defaults
// Lodash
const newValues = {a: 3};
const defaultValues = {a: 1, b: 2}
const appliedValues = _.defaults(newValues, defaultValues);
console.log(appliedValues)
// output { a: 3, b: 2 }

// Native
const newValues = {a: 3};
const defaultValues = {a: 1, b: 2}
const appliedValues = Object.assign({}, defaultValues, newValues);
// output { a: 3, b: 2 }

Browser Support for Object.assign()

![Chrome][chrome-image]![Edge][edge-image]![Firefox][firefox-image]![IE][ie-image]![Opera][opera-image]![Safari][safari-image]
45.0 βœ”βœ”34.0 βœ”βœ–32.0 βœ”9.0 βœ”

⬆ back to top

_.extend

The method is used to copy the values of all enumerable own and inherited properties from one or more source objects to a target object.

// Underscore
// Lodash: _.assignIn
function Foo() {
  this.c = 3;
}
function Bar() {
  this.e = 5;
}
Foo.prototype.d = 4;
Bar.prototype.f = 6;
var result = _.extend({}, new Foo, new Bar);
console.log(result);
// output: { 'c': 3, 'd': 4, 'e': 5, 'f': 6 }

// Native
function Foo() {
  this.c = 3;
}
function Bar() {
  this.e = 5;
}
Foo.prototype.d = 4;
Bar.prototype.f = 6;
var result = Object.assign({}, new Foo, Foo.prototype, new Bar, Bar.prototype);
console.log(result);
// output: { 'c': 3, 'd': 4, 'e': 5, 'f': 6 }

//Or using a function
const extend = (target, ...sources) => {
 const length = sources.length;

  if (length < 1 || target == null) return target;
  for (let i = 0; i < length; i++) {
    const source = sources[i];

    for (const key in source) {
      target[key] = source[key];
    }
  }
  return target;
};
console.log(extend({}, new Foo, new Bar));
// output: { 'c': 3, 'd': 4, 'e': 5, 'f': 6 }

Browser Support for Object.assign()

![Chrome][chrome-image]![Edge][edge-image]![Firefox][firefox-image]![IE][ie-image]![Opera][opera-image]![Safari][safari-image]
45.0 βœ”βœ”34.0 βœ”βœ–32.0 βœ”9.0 βœ”

⬆ back to top

_.has

Checks if key is a direct property of object. Key may be a path of a value separated by .

// Lodash
var object = { a: 1, b: 'settings', c: { d: 'test' } };

var hasA = _.has(object, 'a');
var hasCWhichHasD = _.has(object, 'c.d')

console.log(hasA);
// output: true
console.log(hasCWhichHasD);
// output: true

// Native
const has = function (obj, key) {
  var keyParts = key.split('.');

  return !!obj && (
    keyParts.length > 1
      ? has(obj[key.split('.')[0]], keyParts.slice(1).join('.'))
      : hasOwnProperty.call(obj, key)
  );
};

var object = { a: 1, b: 'settings' };
var result = has(object, 'a');
// output: true

Browser Support for Object .hasOwnProperty

![Chrome][chrome-image]![Edge][edge-image]![Firefox][firefox-image]![IE][ie-image]![Opera][opera-image]![Safari][safari-image]
βœ”12 βœ”βœ”5.5 βœ”5 βœ”3 βœ”

⬆ back to top

_.get

Gets the value at path of object. Note: If provided path does not exist inside the object js will generate error.

// Lodash
var object = { a: [{ b: { c: 3 } }] };
var result = _.get(object, 'a[0].b.c', 1);
console.log(result);
// output: 3

// Native (ES6 - IE not supported)
var object = { a: [{ b: { c: 3 } }] };
var { a: [{ b: { c: result = 1 } = {} } = {}] = [] } = object;
console.log(result);
// output: 3

// Native (ES11)
var object = { a: [{ b: { c: 3 } }] };
var result = object?.a?.[0]?.b?.c ?? 1;
console.log(result);
// output: 3

// Native
const get = (obj, path, defaultValue = undefined) => {
  const travel = regexp =>
    String.prototype.split
      .call(path, regexp)
      .filter(Boolean)
      .reduce((res, key) => (res !== null && res !== undefined ? res[key] : res), obj);
  const result = travel(/[,[\]]+?/) || travel(/[,[\].]+?/);
  return result === undefined || result === obj ? defaultValue : result;
};

var object = { a: [{ b: { c: 3 } }] };
var result = get(object, 'a[0].b.c', 1);
// output: 3

Browser Support for Object destructing

![Chrome][chrome-image]![Edge][edge-image]![Firefox][firefox-image]![IE][ie-image]![Opera][opera-image]![Safari][safari-image]
49.0 βœ”14.0 βœ”41.0 βœ”βœ–41.0 βœ”8.0 βœ”

Browser Support for optional chaining ?.

![Chrome][chrome-image]![Edge][edge-image]![Firefox][firefox-image]![IE][ie-image]![Opera][opera-image]![Safari][safari-image]
80.0 βœ”80.0 βœ”74.0 βœ”βœ–67.0 βœ”13.1 βœ”

Browser Support for nullish coalescing operator ??

![Chrome][chrome-image]![Edge][edge-image]![Firefox][firefox-image]![IE][ie-image]![Opera][opera-image]![Safari][safari-image]
80.0 βœ”80.0 βœ”72.0 βœ”βœ–βœ–13.1 βœ”

⬆ back to top

_.keys

Retrieves all the names of the object's own enumerable properties.

// Underscore/Lodash
var result = _.keys({one: 1, two: 2, three: 3})
console.log(result)
// output: ["one", "two", "three"]

// Native
var result2 = Object.keys({one: 1, two: 2, three: 3})
console.log(result2)
// output: ["one", "two", "three"]

Browser Support for Object.keys()

![Chrome][chrome-image]![Edge][edge-image]![Firefox][firefox-image]![IE][ie-image]![Opera][opera-image]![Safari][safari-image]
5.0 βœ”βœ”4.0 βœ”9.0 βœ”12.0 βœ”5.0 βœ”

⬆ back to top

_.omit

Returns a copy of the object, filtered to omit the keys specified.

var object = { 'a': 1, 'b': '2', 'c': 3 };

// Underscore/Lodash
var result = _.omit(object, ['a', 'c']);
console.log(result)
// output: { 'b': '2' }

// Native
var { a, c, ...result2 } = object;
console.log(result2)
// output: { 'b': '2' }

Browser Support for Spread in object literals

![Chrome][chrome-image]![Edge][edge-image]![Firefox][firefox-image]![IE][ie-image]![Opera][opera-image]![Safari][safari-image]
60.0 βœ”βœ–55.0 βœ”βœ–37.0 βœ”βœ–

⬆ back to top

_.pick

Creates an object composed of the object properties predicate returns truthy for.

var object = { 'a': 1, 'b': '2', 'c': 3 };

// Underscore/Lodash
var result = _.pick(object, ['a', 'c']);
console.log(result)
// output: {a: 1, c: 3}

// Native
const { a, c } = object;
const result = { a, c};
console.log(result);
// output: {a: 1, c: 3}
// for an array of this object --> array.map(({a, c}) => ({a, c}));

// Native
function pick(object, keys) {
  return keys.reduce((obj, key) => {
     if (object && object.hasOwnProperty(key)) {
        obj[key] = object[key];
     }
     return obj;
   }, {});
}
var result = pick(object, ['a', 'c']);
console.log(result)
// output: {a: 1, c: 3}

Browser Support

![Chrome][chrome-image]![Edge][edge-image]![Firefox][firefox-image]![IE][ie-image]![Opera][opera-image]![Safari][safari-image]
38.0 βœ”βœ”13.0 βœ”12.0 βœ”25.0 βœ”7.1 βœ”

⬆ back to top

_.pickBy

Creates an object composed of the object properties predicate returns truthy for.

var object = { 'a': 1, 'b': null, 'c': 3, 'd': false, 'e': undefined };

// Underscore/Lodash
var result = _.pickBy(object);
console.log(result)
// output: {a: 1, c: 3}

// Native
function pickBy(object) {
    const obj = {};
    for (const key in object) {
        if (object[key]) {
            obj[key] = object[key];
        }
    }
    return obj;
}
var result = pickBy(object);
console.log(result)
// output: {a: 1, c: 3}

Browser Support

![Chrome][chrome-image]![Edge][edge-image]![Firefox][firefox-image]![IE][ie-image]![Opera][opera-image]![Safari][safari-image]
βœ”βœ”βœ”6.0 βœ”βœ”βœ”

⬆ back to top

_.toPairs

Retrieves all the given object's own enumerable property [ key, value ] pairs.

// Underscore - also called _.pairs
// Lodash - also called _.entries
var result = _.toPairs({one: 1, two: 2, three: 3})
console.log(result)
// output: [["one", 1], ["two", 2], ["three", 3]]

// Native
var result2 = Object.entries({one: 1, two: 2, three: 3})
console.log(result2)
// output: [["one", 1], ["two", 2], ["three", 3]]

Browser Support for Object.entries()

![Chrome][chrome-image]![Edge][edge-image]![Firefox][firefox-image]![IE][ie-image]![Opera][opera-image]![Safari][safari-image]
54.0 βœ”14.0 βœ”47.0 βœ”βœ–41.0 βœ”10.1 βœ”

⬆ back to top

_.values

Retrieves all the given object's own enumerable property values.

// Underscore/Lodash
var result = _.values({one: 1, two: 2, three: 3})
console.log(result)
// output: [1, 2, 3]

// Native
var result2 = Object.values({one: 1, two: 2, three: 3})
console.log(result2)
// output: [1, 2, 3]

Browser Support for Object.values()

![Chrome][chrome-image]![Edge][edge-image]![Firefox][firefox-image]![IE][ie-image]![Opera][opera-image]![Safari][safari-image]
54.0 βœ”14.0 βœ”47.0 βœ”βœ–41.0 βœ”10.1 βœ”

⬆ back to top

String

_.capitalize

:heavy_exclamation_mark:Not in Underscore.js Converts the first character of string to upper case and the remaining to lower case.

// Lodash
var result = _.capitalize('FRED');
console.log(result);
// => 'Fred'

// Native
const capitalize = (string) => {
  return string ? string.charAt(0).toUpperCase() + string.slice(1).toLowerCase() : '';
};

var result = capitalize('FRED');
console.log(result);
// => 'Fred'

Browser Support

![Chrome][chrome-image]![Edge][edge-image]![Firefox][firefox-image]![IE][ie-image]![Opera][opera-image]![Safari][safari-image]
βœ”βœ”βœ”βœ”βœ”βœ”

_.endsWith

:heavy_exclamation_mark:Not in Underscore.js Checks if string ends with the given target string.

// Lodash
_.endsWith('abc', 'c');
// => true

_.endsWith('abc', 'b');
// => false

_.endsWith('abc', 'b', 2);
// => true

// Native
'abc'.endsWith('c');
// => true

'abc'.endsWith('b');
// => false

'abc'.endsWith('b', 2);
// => true

Browser Support for String.prototype.endsWith()

![Chrome][chrome-image]![Edge][edge-image]![Firefox][firefox-image]![IE][ie-image]![Opera][opera-image]![Safari][safari-image]
41.0 βœ”βœ”17.0 βœ”βœ–28.0 βœ”9.0 βœ”

_.isString

Checks if value is classified as a String primitive or object.

// Lodash
_.isString('abc');
// => true

_.isString(123);
// => false

// Native
function isString(str){
  if (str != null && typeof str.valueOf() === "string") {
    return true
  }
  return false
}

isString('abc');
// => true

isString(123);
// => false

Browser Support

![Chrome][chrome-image]![Edge][edge-image]![Firefox][firefox-image]![IE][ie-image]![Opera][opera-image]![Safari][safari-image]
βœ”βœ”βœ”βœ”βœ”βœ”

_.lowerFirst

:heavy_exclamation_mark:Not in Underscore.js Converts the first character of string to lower case.

// Lodash
var result = _.lowerFirst('Fred')
console.log(result)
// output: 'fred'

// Native
const lowerFirst = (string) => {
  return string ? string.charAt(0).toLowerCase() + string.slice(1) : ''
}

var result = lowerFirst('Fred')
console.log(result)
// output: 'fred'
![Chrome][chrome-image]![Edge][edge-image]![Firefox][firefox-image]![IE][ie-image]![Opera][opera-image]![Safari][safari-image]
βœ”βœ”βœ”βœ”βœ”βœ”

_.padStart and _.padEnd

:heavy_exclamation_mark:Not in Underscore.js Pads the current string with another string (multiple times, if needed) until the resulting string reaches the given length.

// Lodash
console.log(_.padStart('123', 5, '0'))
// output: '00123'

console.log(_.padEnd('123', 5, '0'))
// output: '12300'

// Native
console.log('123'.padStart(5, '0'))
// output: '00123'

console.log('123'.padEnd(5, '0'))
// output: '12300'

Browser Support for String.prototype.padStart() and String.prototype.padEnd()

![Chrome][chrome-image]![Edge][edge-image]![Firefox][firefox-image]![IE][ie-image]![Opera][opera-image]![Safari][safari-image]
57.0 βœ”15.0 βœ”48.0 βœ”βœ–44.0 βœ”10.0 βœ”

_.repeat

:heavy_exclamation_mark:Not in Underscore.js Repeats the given string n times.

// Lodash
var result = _.repeat('abc', 2)
console.log(result)
// output: 'abcabc'

// Native
var result = 'abc'.repeat(2)
console.log(result)
// output: 'abcabc'

Browser Support for String.prototype.repeat()

![Chrome][chrome-image]![Edge][edge-image]![Firefox][firefox-image]![IE][ie-image]![Opera][opera-image]![Safari][safari-image]
41.0 βœ”βœ”24.0 βœ”βœ–28.0 βœ”9.0 βœ”

_.replace

returns a new string with some or all matches of a pattern replaced by a replacement

// Lodash
var re = /apples/gi;
var str = 'Apples are round, and apples are juicy.';
var newstr = _.replace(str, re, 'oranges');
console.log(newstr);
// output: 'oranges are round, and oranges are juicy.'

// Native
var re = /apples/gi;
var str = 'Apples are round, and apples are juicy.';
var result = str.replace(re, 'oranges');
console.log(result);
// output: 'oranges are round, and oranges are juicy.'

Browser Support for String.prototype.replace()

![Chrome][chrome-image]![Edge][edge-image]![Firefox][firefox-image]![IE][ie-image]![Opera][opera-image]![Safari][safari-image]
βœ”βœ”1.0 βœ”βœ”βœ”βœ”

_.split

:heavy_exclamation_mark:Not in Underscore.js Splits string by separator.

// Lodash
var result = _.split('a-b-c', '-', 2)
  console.log(result)
// output: ['a','b']

// Native
var result = 'a-b-c'.split('-', 2)
console.log(result)
// output: ['a','b']

Browser Support for String.prototype.split()

![Chrome][chrome-image]![Edge][edge-image]![Firefox][firefox-image]![IE][ie-image]![Opera][opera-image]![Safari][safari-image]
βœ”βœ”1.0 βœ”βœ”βœ”βœ”

_.startsWith

:heavy_exclamation_mark:Not in Underscore.js Checks if string starts with the given target string.

// Lodash
var result = _.startsWith('abc', 'b', 1)
console.log(result)
// output: true

// Native
var result = 'abc'.startsWith('b', 1)
console.log(result)
// output: true

Browser Support for String.prototype.startsWith()

![Chrome][chrome-image]![Edge][edge-image]![Firefox][firefox-image]![IE][ie-image]![Opera][opera-image]![Safari][safari-image]
41.0 βœ”βœ”17.0 βœ”βœ–28.0 βœ”9.0 βœ”

_.template

:heavy_exclamation_mark: Note this is an alternative implementation. Native template literals not escape html.

Create a template function.

// Lodash/Underscore
const compiled = _.template('hello <%= user %>!');
var result = compiled({ 'user': 'fred' });
console.log(result);
// output: 'hello fred'

// Native
const templateLiteral = (value) => `hello ${value.user}`;
var result = templateLiteral({ 'user': 'fred' });
console.log(result);
// output: 'hello fred'

Browser Support for String (template) literals

![Chrome][chrome-image]![Edge][edge-image]![Firefox][firefox-image]![IE][ie-image]![Opera][opera-image]![Safari][safari-image]
41.0 βœ”12.0 βœ”34.0 βœ”βœ–28.0 βœ”9.0 βœ”

_.toLower

:heavy_exclamation_mark:Not in Underscore.js Lowercases a given string.

// Lodash
var result = _.toLower('FOOBAR')
console.log(result)
// output: 'foobar'

// Native
var result = 'FOOBAR'.toLowerCase()
console.log(result)
// output: 'foobar'

Browser Support for String.prototype.toLowerCase()

![Chrome][chrome-image]![Edge][edge-image]![Firefox][firefox-image]![IE][ie-image]![Opera][opera-image]![Safari][safari-image]
βœ”βœ”1.0 βœ”βœ”βœ”βœ”

_.toUpper

:heavy_exclamation_mark:Not in Underscore.js Uppercases a given string.

// Lodash
var result = _.toUpper('foobar')
console.log(result)
// output: 'FOOBAR'

// Native
var result = 'foobar'.toUpperCase()
console.log(result)
// output: 'FOOBAR'

Browser Support for String.prototype.toUpperCase()

![Chrome][chrome-image]![Edge][edge-image]![Firefox][firefox-image]![IE][ie-image]![Opera][opera-image]![Safari][safari-image]
βœ”βœ”1.0 βœ”βœ”βœ”βœ”

_.trim

:heavy_exclamation_mark:Not in Underscore.js Removes the leading and trailing whitespace characters from a string.

// Lodash
var result = _.trim(' abc ')
console.log(result)
// output: 'abc'

// Native
var result = ' abc '.trim()
console.log(result)
// output: 'abc'

Browser Support for String.prototype.trim()

![Chrome][chrome-image]![Edge][edge-image]![Firefox][firefox-image]![IE][ie-image]![Opera][opera-image]![Safari][safari-image]
5.0 βœ”βœ”3.5 βœ”9.0 βœ”10.5 βœ”5.0 βœ”

_.upperFirst

:heavy_exclamation_mark:Not in Underscore.js Uppercases the first letter of a given string

// Lodash
var result = _.upperFirst('george')
console.log(result)
// output: 'George'

// Native
const upperFirst = (string) => {
  return string ? string.charAt(0).toUpperCase() + string.slice(1) : ''
}

var result = upperFirst('george')
console.log(result)
// output: 'George'
![Chrome][chrome-image]![Edge][edge-image]![Firefox][firefox-image]![IE][ie-image]![Opera][opera-image]![Safari][safari-image]
βœ”βœ”βœ”βœ”βœ”βœ”

Reference

_.uniqWith

similar to _.uniq except that it accepts comparator which is invoked to compare elements of array. The order of result values is determined by the order they occur in the array.

// Lodash
const objects = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }, { 'x': 1, 'y': 2 }];
const result = _.uniqWith(objects, _.isEqual);
console.log(result);
// output: [{ x: 1, y: 2 }, { x: 2, y: 1 }]

// Native
const uniqWith = (arr, fn) => arr.filter((element, index) => arr.findIndex((step) => fn(element, step)) === index);

const array = [1, 2, 2, 3, 4, 5, 2];
const result = uniqWith(array, (a, b) => a === b);
console.log(result);
// output: [1, 2, 3, 4, 5]

const objects = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }, { 'x': 1, 'y': 2 }];
const result = uniqWith(objects, (a, b) => JSON.stringify(a) === JSON.stringify(b));
console.log(result);
// output: [{ x: 1, y: 2 }, { x: 2, y: 1 }]

Browser Support for Array.prototype.filter() and Array.prototype.findIndex()

![Chrome][chrome-image]![Edge][edge-image]![Firefox][firefox-image]![IE][ie-image]![Opera][opera-image]![Safari][safari-image]
45.0 βœ”12.0 βœ”25.0 βœ”βœ–32.0 βœ”8.0 βœ”

Util

_.times

Invokes the iteratee n times, returning an array of the results of each invocation.

// Lodash
var result = _.times(10)
console.log(result)
// output: '[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]'

// Native
var result = Array.from({length: 10}, (_,x) => x)
console.log(result)
// output: '[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]'

// Native
var result = [...Array(10).keys()]
console.log(result)
// output: '[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]'

Browser Support for Array.from()

![Chrome][chrome-image]![Edge][edge-image]![Firefox][firefox-image]![IE][ie-image]![Opera][opera-image]![Safari][safari-image]
45.0 βœ”βœ”32.0 βœ”βœ–βœ”9.0 βœ”

Number

_.clamp

Clamps number within the inclusive lower and upper bounds.

// Lodash
_.clamp(-10, -5, 5);
// => -5

_.clamp(10, -5, 5);
// => 5

_.clamp(10, -5);
// => -5

_.clamp(10, 99);
// => 10

// Native
const clamp = (number, boundOne, boundTwo) => {
  if (!boundTwo) {
    return Math.max(number, boundOne) === boundOne ? number : boundOne;
  } else if (Math.min(number, boundOne) === number) {
    return boundOne;
  } else if (Math.max(number, boundTwo) === number) {
    return boundTwo;
  }
  return number;
};

clamp(-10, -5, 5);
// => -5

clamp(10, -5, 5);
// => 5

clamp(10, -5);
// => -5

clamp(10, 99);
// => 10

Browser Support for Math.min() and Math.max()

![Chrome][chrome-image]![Edge][edge-image]![Firefox][firefox-image]![IE][ie-image]![Opera][opera-image]![Safari][safari-image]
βœ”βœ”βœ”βœ”βœ”βœ”

_.inRange

Checks if n is between start and up to, but not including, end. If end is not specified, it's set to start with start then set to 0. If start is greater than end the params are swapped to support negative ranges.

  // Lodash
  _.inRange(3, 2, 4);
  // output: true
  _.inRange(-3, -2, -6);
  // output: true

  //Native
  const inRange = (num, init, final) => {
    if(final === undefined){
      final = init;
      init = 0;
    }
    return (num >= Math.min(init, final) && num < Math.max(init, final));
  }

  //Native
  const inRange = (num, a, b=0) => (Math.min(a,b) <= num && num < Math.max(a,b));

  inRange(3, 2, 4);
  // output: true
  inRange(-3, -2, -6);
  // output: true

Browser Support for Math.min() and Math.max()

![Chrome][chrome-image]![Edge][edge-image]![Firefox][firefox-image]![IE][ie-image]![Opera][opera-image]![Safari][safari-image]
βœ”βœ”βœ”βœ”βœ”βœ”

_.random

Produces a random number between the inclusive lower and upper bounds. If only one argument is provided a number between 0 and the given number is returned. If floating is true, or either lower or upper are floats, a floating-point number is returned instead of an integer.

  // Lodash
  _.random(0, 5);
  // => an integer between 0 and 5

  _.random(5);
  // => also an integer between 0 and 5

  _.random(5, true);
  // => a floating-point number between 0 and 5

  _.random(1.2, 5.2);
  // => a floating-point number between 1.2 and 5.2

  //Native ES6
  const random = (a = 1, b = 0) => {
    const lower = Math.min(a, b);
    const upper = Math.max(a, b);
    return lower + Math.random() * (upper - lower);
  };

  const randomInt = (a = 1, b = 0) => {
    const lower = Math.ceil(Math.min(a, b));
    const upper = Math.floor(Math.max(a, b));
    return Math.floor(lower + Math.random() * (upper - lower + 1))
  };

  random();
  // => a floating-point number between 0 and 1

  random(5);
  // => a floating-point number between 0 and 5

  random(0, 5);
  // => also a floating-point number between 0 and 5

  random(1.2, 5.2);
  // => a floating-point number between 1.2 and 5.2

  randomInt();
  // => just 0 or 1

  randomInt(5);
  // => an integer between 0 and 5

  randomInt(0, 5);
  // => also an integer between 0 and 5

  randomInt(1.2, 5.2);
  // => an integer between 2 and 5

Browser Support for Math.random()

![Chrome][chrome-image]![Edge][edge-image]![Firefox][firefox-image]![IE][ie-image]![Opera][opera-image]![Safari][safari-image]
βœ”βœ”βœ”βœ”βœ”βœ”

Inspired by:

Author: You-dont-need
Source Code: https://github.com/you-dont-need/You-Dont-Need-Lodash-Underscore 
License: MIT license

#javascript #utilities #native 

List Of JavaScript Methods Which You Can Use Natively + ESLint Plugin
Awesome  Rust

Awesome Rust

1648654560

Command Line Interface to Manage Clipboard Written In Rust

cb 

Command line interface to manage clipboard

How to install

Pre-Compiled

you can download a pre-compiled executable, then you should copy that executable to /usr/bin or add it to your $PATH env. Do not forget to chmod +x cb.

Distribution packages

Users of Arch Linux can install package from AUR:

  • Precompiled release: cb-bin (Only x64 is supported)
  • Build latest release: cb
  • Build from master: cb-git

Build Manually

  • Install rust: curl -sSf https://sh.rustup.rs | sh
  • Install packages: xorg-dev and build-essential
  • Run make && sudo make install

How to use

  • Copy text: cb -t "Text to be copied"
  • Paste copied text: cb -p
  • Copy from stdin: cat file | cb

Usage

Usage: cb [OPTIONS]

Optional arguments:
  -h, --help       Prints the help message
  -V, --version    Prints the version
  -p, --paste      Pastes the content of clipboard
  -c, --clear      Clears the content of clipboard
  -s, --server     Starts server as a daemon
  -r, --raw        Do not print newline after pasting the content
  -t, --text TEXT  Store TEXT into clipboard

Download Details:
Author: yaa110
Source Code: https://github.com/yaa110/cb
License: View license

#rust  #utilities 

Command Line Interface to Manage Clipboard Written In Rust
Awesome  Rust

Awesome Rust

1648647180

Vaultwarden: Unofficial Bitwarden Compatible Server Written in Rust

Alternative implementation of the Bitwarden server API written in Rust and compatible with upstream Bitwarden clients*, perfect for self-hosted deployment where running the official resource-heavy service might not be ideal.

πŸ“’ Note: This project was known as Bitwarden_RS and has been renamed to separate itself from the official Bitwarden server in the hopes of avoiding confusion and trademark/branding issues. Please see #1642 for more explanation.

Image is based on Rust implementation of Bitwarden API.

This project is not associated with the Bitwarden project nor 8bit Solutions LLC.

⚠️IMPORTANT⚠️: When using this server, please report any bugs or suggestions to us directly (look at the bottom of this page for ways to get in touch), regardless of whatever clients you are using (mobile, desktop, browser...). DO NOT use the official support channels.

Features

Basically full implementation of Bitwarden API is provided including:

  • Organizations support
  • Attachments
  • Vault API support
  • Serving the static files for Vault interface
  • Website icons API
  • Authenticator and U2F support
  • YubiKey and Duo support

Installation

Pull the docker image and mount a volume from the host for persistent storage:

docker pull vaultwarden/server:latest docker run -d --name vaultwarden -v /vw-data/:/data/ -p 80:80 vaultwarden/server:latest

This will preserve any persistent data under /vw-data/, you can adapt the path to whatever suits you.

IMPORTANT: Some web browsers, like Chrome, disallow the use of Web Crypto APIs in insecure contexts. In this case, you might get an error like Cannot read property 'importKey'. To solve this problem, you need to access the web vault from HTTPS.

This can be configured in vaultwarden directly or using a third-party reverse proxy (some examples).

If you have an available domain name, you can get HTTPS certificates with Let's Encrypt, or you can generate self-signed certificates with utilities like mkcert. Some proxies automatically do this step, like Caddy (see examples linked above).

Usage

See the vaultwarden wiki for more information on how to configure and run the vaultwarden server.

Get in touch

To ask a question, offer suggestions or new features or to get help configuring or installing the software, please use the forum.

If you spot any bugs or crashes with vaultwarden itself, please create an issue. Make sure there aren't any similar issues open, though!

If you prefer to chat, we're usually hanging around at #vaultwarden:matrix.org room on Matrix. Feel free to join us!

Sponsors

Thanks for your contribution to the project!

Download Details:
Author: dani-garcia
Source Code: https://github.com/dani-garcia/vaultwarden#readme
License: GPL-3.0 License

#rust  #utilities 

Vaultwarden: Unofficial Bitwarden Compatible Server Written in Rust
Awesome  Rust

Awesome Rust

1648639740

Verco: A Simple Git, Mercurial & PlasticSCM Tui Client

verco

A simple Git/Mercurial/PlasticSCM tui client based on keyboard shortcuts

Screenshots

log screen

verco workflow

Features

  • One interface for many version control backends
  • Support for Git, Mercurial (Hg) and Plastic SCM
  • Supported actions:
    • status
    • revision history
    • revision details
    • discard changes
    • checkout revision
    • checkin changes
    • branch and tag management (list/create/delete)
    • merge
    • push/pull/fetch
  • Everything accessible through at most two keys

Goals

  • implement everyday version control actions (opinionated)
  • cross-platform (Windows, Linux, BSD, Mac)
  • responsive ui even when it's executing some heavy operation
  • zero dependencies (besides platform libs)

Non Goals

  • cover all api surface of a given version control
  • custom keybindings (we implement redundant keybindings, though)
  • configuration file/environment var (cli options is fine)
  • clone, repo init and complex actions (should be left for their respective cli)
  • rebase support

Platforms

This project uses Cargo and pure Rust stable and works on latest versions of Windows, Mac, Linux and BSD.

Its only dependencies are:

Install

You can either install it via cargo or download the binaries from github releases.

If you go the cargo route, you need to have it installed (usually using rustup). In a terminal, run this command to install verco:

cargo install verco

Then you'll be able to run verco from whichever directory you in.

Packaging status

Fedora (COPR)

sudo dnf copr enable atim/verco -y
sudo dnf install verco

Arch Linux (AUR)

verco can be installed from the available AUR packages using an AUR helper. For example:

paru -S verco

Usage

In a terminal in a repository folder, type in the verco command. It will launch verco's tui and you'll be able to interface with Git/Mercurial/PlasticSCM.

Download Details:
Author: vamolessa
Source Code: https://github.com/vamolessa/verco
License: GPL-3.0 License

#rust  #utilities 

Verco: A Simple Git, Mercurial & PlasticSCM Tui Client
Awesome  Rust

Awesome Rust

1648632360

Freepass: The Free Password Manager for Power Users Written in Rust

NOTE: if you've been using freepass before June 03, 2017: you need to checkout the serde-migration git tag, build the CLI, and mergein your vault into a new one using that particular version.

freepass 

The free password manager for power users.

X11 screencast gif

What's going on?

  • A password manager.
  • Based on the Master Password algorithm, generates the same passwords as the Master Password apps.
  • But wait, there's more! Why stop at passwords? It generates...
    • Ed25519 digital signature keys for...
      • OpenSSH: Freepass adds private keys directly to a running ssh-agent & exports public keys in OpenSSH format!
      • signify: Freepass signs files & exports public keys in signify format!
      • TODO SQRL
    • Raw 256-bit keys for symmetric ciphers.
    • TODO BIP39-compatible passphrases.
  • Yes, all of the above is derived from your master password and full name, you can always recover it by entering the same data!
  • The generator settings (site names, counters) are stored in vault files:
    • Serialized into CBOR.
    • Encrypted with NaCl secretbox for each entry + AES for the whole file.
    • (Keys are derived from the master password like the generated passwords.)
    • Every time you save a vault file, its size changes randomly. That's a feature. Some random junk is added to make it a bit harder to count how many passwords you have without opening the file.
  • You can also store passwords and text in these vault files (for stuff that can't be generated).
  • You can merge two vault files (e.g. from sync conflicts).
  • You can import KeePass 2 (kdbx) files.

How?

  • Freepass is written in the Rust programming language and uses libsodium as the crypto library.
  • Very modular code, easy to audit.
    • You can separately check that the core library does everything correctly, and that the user interface passes your data to the core library, not to an evil server.
  • Some parts were written as completely separate Rust crates:
  • Completely free software: public domain / Unlicense.

Where?

Freepass is (going to be) available on different platforms:

  • cli: for UNIX-like systems
  • A desktop GUI and mobile apps will be available in the future.

Each version has its own README!

Contributing

By participating in this project you agree to follow the Contributor Code of Conduct.

The list of contributors is available on GitHub.

Download Details:
Author: unrelentingtech
Source Code: https://github.com/unrelentingtech/freepass
License: Unlicense License

#rust  #utilities 

Freepass: The Free Password Manager for Power Users Written in Rust