code:
# kind-of [![NPM version](https://img.shields.io/npm/v/kind-of.svg?style=flat)](https://www.npmjs.com/package/kind-of) [![NPM monthly downloads](https://img.shields.io/npm/dm/kind-of.svg?style=flat)](https://npmjs.org/package/kind-of) [![NPM total downloads](https://img.shields.io/npm/dt/kind-of.svg?style=flat)](https://npmjs.org/package/kind-of) [![Linux Build Status](https://img.shields.io/travis/jonschlinkert/kind-of.svg?style=flat&label=Travis)](https://travis-ci.org/jonschlinkert/kind-of)

> Get the native type of a value.

Please consider following this project's author, [Jon Schlinkert](https://github.com/jonschlinkert), and consider starring the project to show your :heart: and support.

## Install

Install with [npm](https://www.npmjs.com/):

```sh
$ npm install --save kind-of
```

Install with [bower](https://bower.io/)

```sh
$ bower install kind-of --save
```

## Why use this?

1. [it's fast](#benchmarks) | [optimizations](#optimizations)
2. [better type checking](#better-type-checking)

## Usage

> es5, es6, and browser ready

```js
var kindOf = require('kind-of');

kindOf(undefined);
//=> 'undefined'

kindOf(null);
//=> 'null'

kindOf(true);
//=> 'boolean'

kindOf(false);
//=> 'boolean'

kindOf(new Buffer(''));
//=> 'buffer'

kindOf(42);
//=> 'number'

kindOf('str');
//=> 'string'

kindOf(arguments);
//=> 'arguments'

kindOf({});
//=> 'object'

kindOf(Object.create(null));
//=> 'object'

kindOf(new Test());
//=> 'object'

kindOf(new Date());
//=> 'date'

kindOf([1, 2, 3]);
//=> 'array'

kindOf(/foo/);
//=> 'regexp'

kindOf(new RegExp('foo'));
//=> 'regexp'

kindOf(new Error('error'));
//=> 'error'

kindOf(function () {});
//=> 'function'

kindOf(function * () {});
//=> 'generatorfunction'

kindOf(Symbol('str'));
//=> 'symbol'

kindOf(new Map());
//=> 'map'

kindOf(new WeakMap());
//=> 'weakmap'

kindOf(new Set());
//=> 'set'

kindOf(new WeakSet());
//=> 'weakset'

kindOf(new Int8Array());
//=> 'int8array'

kindOf(new Uint8Array());
//=> 'uint8array'

kindOf(new Uint8ClampedArray());
//=> 'uint8clampedarray'

kindOf(new Int16Array());
//=> 'int16array'

kindOf(new Uint16Array());
//=> 'uint16array'

kindOf(new Int32Array());
//=> 'int32array'

kindOf(new Uint32Array());
//=> 'uint32array'

kindOf(new Float32Array());
//=> 'float32array'

kindOf(new Float64Array());
//=> 'float64array'
```

## Benchmarks

Benchmarked against [typeof](http://github.com/CodingFu/typeof) and [type-of](https://github.com/ForbesLindesay/type-of).

```bash
# arguments (32 bytes)
  kind-of x 17,024,098 ops/sec ±1.90% (86 runs sampled)
  lib-type-of x 11,926,235 ops/sec ±1.34% (83 runs sampled)
  lib-typeof x 9,245,257 ops/sec ±1.22% (87 runs sampled)

  fastest is kind-of (by 161% avg)

# array (22 bytes)
  kind-of x 17,196,492 ops/sec ±1.07% (88 runs sampled)
  lib-type-of x 8,838,283 ops/sec ±1.02% (87 runs sampled)
  lib-typeof x 8,677,848 ops/sec ±0.87% (87 runs sampled)

  fastest is kind-of (by 196% avg)

# boolean (24 bytes)
  kind-of x 16,841,600 ops/sec ±1.10% (86 runs sampled)
  lib-type-of x 8,096,787 ops/sec ±0.95% (87 runs sampled)
  lib-typeof x 8,423,345 ops/sec ±1.15% (86 runs sampled)

  fastest is kind-of (by 204% avg)

# buffer (38 bytes)
  kind-of x 14,848,060 ops/sec ±1.05% (86 runs sampled)
  lib-type-of x 3,671,577 ops/sec ±1.49% (87 runs sampled)
  lib-typeof x 8,360,236 ops/sec ±1.24% (86 runs sampled)

  fastest is kind-of (by 247% avg)

# date (30 bytes)
  kind-of x 16,067,761 ops/sec ±1.58% (86 runs sampled)
  lib-type-of x 8,954,436 ops/sec ±1.40% (87 runs sampled)
  lib-typeof x 8,488,307 ops/sec ±1.51% (84 runs sampled)

  fastest is kind-of (by 184% avg)

# error (36 bytes)
  kind-of x 9,634,090 ops/sec ±1.12% (89 runs sampled)
  lib-type-of x 7,735,624 ops/sec ±1.32% (86 runs sampled)
  lib-typeof x 7,442,160 ops/sec ±1.11% (90 runs sampled)

  fastest is kind-of (by 127% avg)

# function (34 bytes)
  kind-of x 10,031,494 ops/sec ±1.27% (86 runs sampled)
  lib-type-of x 9,502,757 ops/sec ±1.17% (89 runs sampled)
  lib-typeof x 8,278,985 ops/sec ±1.08% (88 runs sampled)

  fastest is kind-of (by 113% avg)

# null (24 bytes)
  kind-of x 18,159,808 ops/sec ±1.92% (86 runs sampled)
  lib-type-of x 12,927,635 ops/sec ±1.01% (88 runs sampled)
  lib-typeof x 7,958,234 ops/sec ±1.21% (89 runs sampled)

  fastest is kind-of (by 174% avg)

# number (22 bytes)
  kind-of x 17,846,779 ops/sec ±0.91% (85 runs sampled)
  lib-type-of x 3,316,636 ops/sec ±1.19% (86 runs sampled)
  lib-typeof x 2,329,477 ops/sec ±2.21% (85 runs sampled)

  fastest is kind-of (by 632% avg)

# object-plain (47 bytes)
  kind-of x 7,085,155 ops/sec ±1.05% (88 runs sampled)
  lib-type-of x 8,870,930 ops/sec ±1.06% (83 runs sampled)
  lib-typeof x 8,716,024 ops/sec ±1.05% (87 runs sampled)

  fastest is lib-type-of (by 112% avg)

# regex (25 bytes)
  kind-of x 14,196,052 ops/sec ±1.65% (84 runs sampled)
  lib-type-of x 9,554,164 ops/sec ±1.25% (88 runs sampled)
  lib-typeof x 8,359,691 ops/sec ±1.07% (87 runs sampled)

  fastest is kind-of (by 158% avg)

# string (33 bytes)
  kind-of x 16,131,428 ops/sec ±1.41% (85 runs sampled)
  lib-type-of x 7,273,172 ops/sec ±1.05% (87 runs sampled)
  lib-typeof x 7,382,635 ops/sec ±1.17% (85 runs sampled)

  fastest is kind-of (by 220% avg)

# symbol (34 bytes)
  kind-of x 17,011,537 ops/sec ±1.24% (86 runs sampled)
  lib-type-of x 3,492,454 ops/sec ±1.23% (89 runs sampled)
  lib-typeof x 7,471,235 ops/sec ±2.48% (87 runs sampled)

  fastest is kind-of (by 310% avg)

# template-strings (36 bytes)
  kind-of x 15,434,250 ops/sec ±1.46% (83 runs sampled)
  lib-type-of x 7,157,907 ops/sec ±0.97% (87 runs sampled)
  lib-typeof x 7,517,986 ops/sec ±0.92% (86 runs sampled)

  fastest is kind-of (by 210% avg)

# undefined (29 bytes)
  kind-of x 19,167,115 ops/sec ±1.71% (87 runs sampled)
  lib-type-of x 15,477,740 ops/sec ±1.63% (85 runs sampled)
  lib-typeof x 19,075,495 ops/sec ±1.17% (83 runs sampled)

  fastest is lib-typeof,kind-of

```

## Optimizations

In 7 out of 8 cases, this library is 2x-10x faster than other top libraries included in the benchmarks. There are a few things that lead to this performance advantage, none of them hard and fast rules, but all of them simple and repeatable in almost any code library:

1. Optimize around the fastest and most common use cases first. Of course, this will change from project-to-project, but I took some time to understand how and why `typeof` checks were being used in my own libraries and other libraries I use a lot.
2. Optimize around bottlenecks - In other words, the order in which conditionals are implemented is significant, because each check is only as fast as the failing checks that came before it. Here, the biggest bottleneck by far is checking for plain objects (an object that was created by the `Object` constructor). I opted to make this check happen by process of elimination rather than brute force up front (e.g. by using something like `val.constructor.name`), so that every other type check would not be penalized it.
3. Don't do uneccessary processing - why do `.slice(8, -1).toLowerCase();` just to get the word `regex`? It's much faster to do `if (type === '[object RegExp]') return 'regex'`
4. There is no reason to make the code in a microlib as terse as possible, just to win points for making it shorter. It's always better to favor performant code over terse code. You will always only be using a single `require()` statement to use the library anyway, regardless of how the code is written.

## Better type checking

kind-of seems to be more consistently "correct" than other type checking libs I've looked at. For example, here are some differing results from other popular libs:

### [typeof](https://github.com/CodingFu/typeof) lib

Incorrectly identifies instances of custom constructors (pretty common):

```js
var typeOf = require('typeof');
function Test() {}
console.log(typeOf(new Test()));
//=> 'test'
```

Returns `object` instead of `arguments`:

```js
function foo() {
  console.log(typeOf(arguments)) //=> 'object'
}
foo();
```

### [type-of](https://github.com/ForbesLindesay/type-of) lib

Incorrectly returns `object` for generator functions, buffers, `Map`, `Set`, `WeakMap` and `WeakSet`:

```js
function * foo() {}
console.log(typeOf(foo));
//=> 'object'
console.log(typeOf(new Buffer('')));
//=> 'object'
console.log(typeOf(new Map()));
//=> 'object'
console.log(typeOf(new Set()));
//=> 'object'
console.log(typeOf(new WeakMap()));
//=> 'object'
console.log(typeOf(new WeakSet()));
//=> 'object'
```

## About

Contributing

Pull requests and stars are always welcome. For bugs and feature requests, [please create an issue](../../issues/new).

Running Tests

Running and reviewing unit tests is a great way to get familiarized with a library and its API. You can install dependencies and run tests with the following command:

```sh
$ npm install && npm test
```

Building docs

_(This project's readme.md is generated by [verb](https://github.com/verbose/verb-generate-readme), please don't edit the readme directly. Any changes to the readme must be made in the [.verb.md](.verb.md) readme template.)_

To generate the readme, run the following command:

```sh
$ npm install -g verbose/verb#dev verb-generate-readme && verb
```

### Related projects

You might also be interested in these projects:

* [is-glob](https://www.npmjs.com/package/is-glob): Returns `true` if the given string looks like a glob pattern or an extglob pattern… [more](https://github.com/micromatch/is-glob) | [homepage](https://github.com/micromatch/is-glob "Returns `true` if the given string looks like a glob pattern or an extglob pattern. This makes it easy to create code that only uses external modules like node-glob when necessary, resulting in much faster code execution and initialization time, and a bet")
* [is-number](https://www.npmjs.com/package/is-number): Returns true if a number or string value is a finite number. Useful for regex… [more](https://github.com/jonschlinkert/is-number) | [homepage](https://github.com/jonschlinkert/is-number "Returns true if a number or string value is a finite number. Useful for regex matches, parsing, user input, etc.")
* [is-primitive](https://www.npmjs.com/package/is-primitive): Returns `true` if the value is a primitive.  | [homepage](https://github.com/jonschlinkert/is-primitive "Returns `true` if the value is a primitive. ")

### Contributors

| **Commits** | **Contributor** |
| --- | --- |
| 102 | [jonschlinkert](https://github.com/jonschlinkert) |
| 3   | [aretecode](https://github.com/aretecode) |
| 2   | [miguelmota](https://github.com/miguelmota) |
| 1   | [doowb](https://github.com/doowb) |
| 1   | [dtothefp](https://github.com/dtothefp) |
| 1   | [ianstormtaylor](https://github.com/ianstormtaylor) |
| 1   | [ksheedlo](https://github.com/ksheedlo) |
| 1   | [pdehaan](https://github.com/pdehaan) |
| 1   | [laggingreflex](https://github.com/laggingreflex) |
| 1   | [tunnckoCore](https://github.com/tunnckoCore) |
| 1   | [xiaofen9](https://github.com/xiaofen9) |

### Author

**Jon Schlinkert**

* [GitHub Profile](https://github.com/jonschlinkert)
* [Twitter Profile](https://twitter.com/jonschlinkert)
* [LinkedIn Profile](https://linkedin.com/in/jonschlinkert)

### License

Copyright © 2020, [Jon Schlinkert](https://github.com/jonschlinkert).
Released under the [MIT License](LICENSE).

***

_This file was generated by [verb-generate-readme](https://github.com/verbose/verb-generate-readme), v0.8.0, on January 16, 2020._


code:
var toString = Object.prototype.toString;

module.exports = function kindOf(val) {
  if (val === void 0) return 'undefined';
  if (val === null) return 'null';

  var type = typeof val;
  if (type === 'boolean') return 'boolean';
  if (type === 'string') return 'string';
  if (type === 'number') return 'number';
  if (type === 'symbol') return 'symbol';
  if (type === 'function') {
    return isGeneratorFn(val) ? 'generatorfunction' : 'function';
  }

  if (isArray(val)) return 'array';
  if (isBuffer(val)) return 'buffer';
  if (isArguments(val)) return 'arguments';
  if (isDate(val)) return 'date';
  if (isError(val)) return 'error';
  if (isRegexp(val)) return 'regexp';

  switch (ctorName(val)) {
    case 'Symbol': return 'symbol';
    case 'Promise': return 'promise';

    // Set, Map, WeakSet, WeakMap
    case 'WeakMap': return 'weakmap';
    case 'WeakSet': return 'weakset';
    case 'Map': return 'map';
    case 'Set': return 'set';

    // 8-bit typed arrays
    case 'Int8Array': return 'int8array';
    case 'Uint8Array': return 'uint8array';
    case 'Uint8ClampedArray': return 'uint8clampedarray';

    // 16-bit typed arrays
    case 'Int16Array': return 'int16array';
    case 'Uint16Array': return 'uint16array';

    // 32-bit typed arrays
    case 'Int32Array': return 'int32array';
    case 'Uint32Array': return 'uint32array';
    case 'Float32Array': return 'float32array';
    case 'Float64Array': return 'float64array';
  }

  if (isGeneratorObj(val)) {
    return 'generator';
  }

  // Non-plain objects
  type = toString.call(val);
  switch (type) {
    case '[object Object]': return 'object';
    // iterators
    case '[object Map Iterator]': return 'mapiterator';
    case '[object Set Iterator]': return 'setiterator';
    case '[object String Iterator]': return 'stringiterator';
    case '[object Array Iterator]': return 'arrayiterator';
  }

  // other
  return type.slice(8, -1).toLowerCase().replace(/\s/g, '');
};

function ctorName(val) {
  return typeof val.constructor === 'function' ? val.constructor.name : null;
}

function isArray(val) {
  if (Array.isArray) return Array.isArray(val);
  return val instanceof Array;
}

function isError(val) {
  return val instanceof Error || (typeof val.message === 'string' && val.constructor && typeof val.constructor.stackTraceLimit === 'number');
}

function isDate(val) {
  if (val instanceof Date) return true;
  return typeof val.toDateString === 'function'
    && typeof val.getDate === 'function'
    && typeof val.setDate === 'function';
}

function isRegexp(val) {
  if (val instanceof RegExp) return true;
  return typeof val.flags === 'string'
    && typeof val.ignoreCase === 'boolean'
    && typeof val.multiline === 'boolean'
    && typeof val.global === 'boolean';
}

function isGeneratorFn(name, val) {
  return ctorName(name) === 'GeneratorFunction';
}

function isGeneratorObj(val) {
  return typeof val.throw === 'function'
    && typeof val.return === 'function'
    && typeof val.next === 'function';
}

function isArguments(val) {
  try {
    if (typeof val.length === 'number' && typeof val.callee === 'function') {
      return true;
    }
  } catch (err) {
    if (err.message.indexOf('callee') !== -1) {
      return true;
    }
  }
  return false;
}

/**
 * If you need to support Safari 5-7 (8-10 yr-old browser),
 * take a look at https://github.com/feross/is-buffer
 */

function isBuffer(val) {
  if (val.constructor && typeof val.constructor.isBuffer === 'function') {
    return val.constructor.isBuffer(val);
  }
  return false;
}

license: mit


kind-of

description: Get the native type of a value.

repository: jonschlinkert/kind-of

license: MIT

test: mocha

prepublish: browserify -o browser.js -e index.js -s index --bare

keywords: arguments array boolean check date function is is-type is-type-of kind kind-of number object of regexp string test type type-of typeof types

layout: default

list: is-glob is-number is-primitive

reflinks: type-of typeof verb


code:
function klona(x) {
	if (typeof x !== 'object') return x;

	var k, tmp, str=Object.prototype.toString.call(x);

	if (str === '[object Object]') {
		if (x.constructor !== Object && typeof x.constructor === 'function') {
			tmp = new x.constructor();
			for (k in x) {
				if (x.hasOwnProperty(k) && tmp[k] !== x[k]) {
					tmp[k] = klona(x[k]);
				}
			}
		} else {
			tmp = {}; // null
			for (k in x) {
				if (k === '__proto__') {
					Object.defineProperty(tmp, k, {
						value: klona(x[k]),
						configurable: true,
						enumerable: true,
						writable: true,
					});
				} else {
					tmp[k] = klona(x[k]);
				}
			}
		}
		return tmp;
	}

	if (str === '[object Array]') {
		k = x.length;
		for (tmp=Array(k); k--;) {
			tmp[k] = klona(x[k]);
		}
		return tmp;
	}

	if (str === '[object Set]') {
		tmp = new Set;
		x.forEach(function (val) {
			tmp.add(klona(val));
		});
		return tmp;
	}

	if (str === '[object Map]') {
		tmp = new Map;
		x.forEach(function (val, key) {
			tmp.set(klona(key), klona(val));
		});
		return tmp;
	}

	if (str === '[object Date]') {
		return new Date(+x);
	}

	if (str === '[object RegExp]') {
		tmp = new RegExp(x.source, x.flags);
		tmp.lastIndex = x.lastIndex;
		return tmp;
	}

	if (str === '[object DataView]') {
		return new x.constructor( klona(x.buffer) );
	}

	if (str === '[object ArrayBuffer]') {
		return x.slice(0);
	}

	// ArrayBuffer.isView(x)
	// ~> `new` bcuz `Buffer.slice` => ref
	if (str.slice(-6) === 'Array]') {
		return new x.constructor(x);
	}

	return x;
}

exports.klona = klona;


code:
export function klona(x) {
	if (typeof x !== 'object') return x;

	var k, tmp, str=Object.prototype.toString.call(x);

	if (str === '[object Object]') {
		if (x.constructor !== Object && typeof x.constructor === 'function') {
			tmp = new x.constructor();
			for (k in x) {
				if (x.hasOwnProperty(k) && tmp[k] !== x[k]) {
					tmp[k] = klona(x[k]);
				}
			}
		} else {
			tmp = {}; // null
			for (k in x) {
				if (k === '__proto__') {
					Object.defineProperty(tmp, k, {
						value: klona(x[k]),
						configurable: true,
						enumerable: true,
						writable: true,
					});
				} else {
					tmp[k] = klona(x[k]);
				}
			}
		}
		return tmp;
	}

	if (str === '[object Array]') {
		k = x.length;
		for (tmp=Array(k); k--;) {
			tmp[k] = klona(x[k]);
		}
		return tmp;
	}

	if (str === '[object Set]') {
		tmp = new Set;
		x.forEach(function (val) {
			tmp.add(klona(val));
		});
		return tmp;
	}

	if (str === '[object Map]') {
		tmp = new Map;
		x.forEach(function (val, key) {
			tmp.set(klona(key), klona(val));
		});
		return tmp;
	}

	if (str === '[object Date]') {
		return new Date(+x);
	}

	if (str === '[object RegExp]') {
		tmp = new RegExp(x.source, x.flags);
		tmp.lastIndex = x.lastIndex;
		return tmp;
	}

	if (str === '[object DataView]') {
		return new x.constructor( klona(x.buffer) );
	}

	if (str === '[object ArrayBuffer]') {
		return x.slice(0);
	}

	// ArrayBuffer.isView(x)
	// ~> `new` bcuz `Buffer.slice` => ref
	if (str.slice(-6) === 'Array]') {
		return new x.constructor(x);
	}

	return x;
}


code: export function klona<T>(input: T): T;


code:
function set(obj, key, val) {
	if (typeof val.value === 'object') val.value = klona(val.value);
	if (!val.enumerable || val.get || val.set || !val.configurable || !val.writable || key === '__proto__') {
		Object.defineProperty(obj, key, val);
	} else obj[key] = val.value;
}

function klona(x) {
	if (typeof x !== 'object') return x;

	var i=0, k, list, tmp, str=Object.prototype.toString.call(x);

	if (str === '[object Object]') {
		tmp = Object.create(x.__proto__ || null);
	} else if (str === '[object Array]') {
		tmp = Array(x.length);
	} else if (str === '[object Set]') {
		tmp = new Set;
		x.forEach(function (val) {
			tmp.add(klona(val));
		});
	} else if (str === '[object Map]') {
		tmp = new Map;
		x.forEach(function (val, key) {
			tmp.set(klona(key), klona(val));
		});
	} else if (str === '[object Date]') {
		tmp = new Date(+x);
	} else if (str === '[object RegExp]') {
		tmp = new RegExp(x.source, x.flags);
	} else if (str === '[object DataView]') {
		tmp = new x.constructor( klona(x.buffer) );
	} else if (str === '[object ArrayBuffer]') {
		tmp = x.slice(0);
	} else if (str.slice(-6) === 'Array]') {
		// ArrayBuffer.isView(x)
		// ~> `new` bcuz `Buffer.slice` => ref
		tmp = new x.constructor(x);
	}

	if (tmp) {
		for (list=Object.getOwnPropertySymbols(x); i < list.length; i++) {
			set(tmp, list[i], Object.getOwnPropertyDescriptor(x, list[i]));
		}

		for (i=0, list=Object.getOwnPropertyNames(x); i < list.length; i++) {
			if (Object.hasOwnProperty.call(tmp, k=list[i]) && tmp[k] === x[k]) continue;
			set(tmp, k, Object.getOwnPropertyDescriptor(x, k));
		}
	}

	return tmp || x;
}

exports.klona = klona;


code:
function set(obj, key, val) {
	if (typeof val.value === 'object') val.value = klona(val.value);
	if (!val.enumerable || val.get || val.set || !val.configurable || !val.writable || key === '__proto__') {
		Object.defineProperty(obj, key, val);
	} else obj[key] = val.value;
}

export function klona(x) {
	if (typeof x !== 'object') return x;

	var i=0, k, list, tmp, str=Object.prototype.toString.call(x);

	if (str === '[object Object]') {
		tmp = Object.create(x.__proto__ || null);
	} else if (str === '[object Array]') {
		tmp = Array(x.length);
	} else if (str === '[object Set]') {
		tmp = new Set;
		x.forEach(function (val) {
			tmp.add(klona(val));
		});
	} else if (str === '[object Map]') {
		tmp = new Map;
		x.forEach(function (val, key) {
			tmp.set(klona(key), klona(val));
		});
	} else if (str === '[object Date]') {
		tmp = new Date(+x);
	} else if (str === '[object RegExp]') {
		tmp = new RegExp(x.source, x.flags);
	} else if (str === '[object DataView]') {
		tmp = new x.constructor( klona(x.buffer) );
	} else if (str === '[object ArrayBuffer]') {
		tmp = x.slice(0);
	} else if (str.slice(-6) === 'Array]') {
		// ArrayBuffer.isView(x)
		// ~> `new` bcuz `Buffer.slice` => ref
		tmp = new x.constructor(x);
	}

	if (tmp) {
		for (list=Object.getOwnPropertySymbols(x); i < list.length; i++) {
			set(tmp, list[i], Object.getOwnPropertyDescriptor(x, list[i]));
		}

		for (i=0, list=Object.getOwnPropertyNames(x); i < list.length; i++) {
			if (Object.hasOwnProperty.call(tmp, k=list[i]) && tmp[k] === x[k]) continue;
			set(tmp, k, Object.getOwnPropertyDescriptor(x, k));
		}
	}

	return tmp || x;
}


code:
function klona(val) {
	var k, out, tmp;

	if (Array.isArray(val)) {
		out = Array(k=val.length);
		while (k--) out[k] = (tmp=val[k]) && typeof tmp === 'object' ? klona(tmp) : tmp;
		return out;
	}

	if (Object.prototype.toString.call(val) === '[object Object]') {
		out = {}; // null
		for (k in val) {
			if (k === '__proto__') {
				Object.defineProperty(out, k, {
					value: klona(val[k]),
					configurable: true,
					enumerable: true,
					writable: true,
				});
			} else {
				out[k] = (tmp=val[k]) && typeof tmp === 'object' ? klona(tmp) : tmp;
			}
		}
		return out;
	}

	return val;
}

exports.klona = klona;


code:
export function klona(val) {
	var k, out, tmp;

	if (Array.isArray(val)) {
		out = Array(k=val.length);
		while (k--) out[k] = (tmp=val[k]) && typeof tmp === 'object' ? klona(tmp) : tmp;
		return out;
	}

	if (Object.prototype.toString.call(val) === '[object Object]') {
		out = {}; // null
		for (k in val) {
			if (k === '__proto__') {
				Object.defineProperty(out, k, {
					value: klona(val[k]),
					configurable: true,
					enumerable: true,
					writable: true,
				});
			} else {
				out[k] = (tmp=val[k]) && typeof tmp === 'object' ? klona(tmp) : tmp;
			}
		}
		return out;
	}

	return val;
}


code:
function klona(x) {
	if (typeof x !== 'object') return x;

	var k, tmp, str=Object.prototype.toString.call(x);

	if (str === '[object Object]') {
		if (x.constructor !== Object && typeof x.constructor === 'function') {
			tmp = new x.constructor();
			for (k in x) {
				if (x.hasOwnProperty(k) && tmp[k] !== x[k]) {
					tmp[k] = klona(x[k]);
				}
			}
		} else {
			tmp = {}; // null
			for (k in x) {
				if (k === '__proto__') {
					Object.defineProperty(tmp, k, {
						value: klona(x[k]),
						configurable: true,
						enumerable: true,
						writable: true,
					});
				} else {
					tmp[k] = klona(x[k]);
				}
			}
		}
		return tmp;
	}

	if (str === '[object Array]') {
		k = x.length;
		for (tmp=Array(k); k--;) {
			tmp[k] = klona(x[k]);
		}
		return tmp;
	}

	if (str === '[object Date]') {
		return new Date(+x);
	}

	if (str === '[object RegExp]') {
		tmp = new RegExp(x.source, x.flags);
		tmp.lastIndex = x.lastIndex;
		return tmp;
	}

	return x;
}

exports.klona = klona;


code: !function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t(e.klona={})}(this,(function(e){e.klona=function e(t){if("object"!=typeof t)return t;var o,n,r=Object.prototype.toString.call(t);if("[object Object]"===r){if(t.constructor!==Object&&"function"==typeof t.constructor)for(o in n=new t.constructor,t)t.hasOwnProperty(o)&&n[o]!==t[o]&&(n[o]=e(t[o]));else for(o in n={},t)"__proto__"===o?Object.defineProperty(n,o,{value:e(t[o]),configurable:!0,enumerable:!0,writable:!0}):n[o]=e(t[o]);return n}if("[object Array]"===r){for(o=t.length,n=Array(o);o--;)n[o]=e(t[o]);return n}return"[object Date]"===r?new Date(+t):"[object RegExp]"===r?((n=new RegExp(t.source,t.flags)).lastIndex=t.lastIndex,n):t}}));


code:
export function klona(x) {
	if (typeof x !== 'object') return x;

	var k, tmp, str=Object.prototype.toString.call(x);

	if (str === '[object Object]') {
		if (x.constructor !== Object && typeof x.constructor === 'function') {
			tmp = new x.constructor();
			for (k in x) {
				if (x.hasOwnProperty(k) && tmp[k] !== x[k]) {
					tmp[k] = klona(x[k]);
				}
			}
		} else {
			tmp = {}; // null
			for (k in x) {
				if (k === '__proto__') {
					Object.defineProperty(tmp, k, {
						value: klona(x[k]),
						configurable: true,
						enumerable: true,
						writable: true,
					});
				} else {
					tmp[k] = klona(x[k]);
				}
			}
		}
		return tmp;
	}

	if (str === '[object Array]') {
		k = x.length;
		for (tmp=Array(k); k--;) {
			tmp[k] = klona(x[k]);
		}
		return tmp;
	}

	if (str === '[object Date]') {
		return new Date(+x);
	}

	if (str === '[object RegExp]') {
		tmp = new RegExp(x.source, x.flags);
		tmp.lastIndex = x.lastIndex;
		return tmp;
	}

	return x;
}


klona

repository: lukeed/klona

description: A tiny (240B to 501B) and fast utility to "deep clone" Objects, Arrays, Dates, RegExps, and more!

files: *.d.ts dist full json lite

build: bundt

pretest: npm run build

postbuild: echo "lite full json" | xargs -n1 cp -v index.d.ts

test: uvu -r esm test -i suites

keywords: clone copy deep extend recursive object


code:
A tiny (240B to 501B) and fast utility to "deep clone" Objects, Arrays, Dates, RegExps, and more!

## Features

* Super tiny and [performant](#benchmarks)
* Deep clone / recursive copies
* Safely handles complex data types

    _Array, Date, Map, Object, RegExp, Set, TypedArray, and more_

Unlike a "shallow copy" (eg, `Object.assign`), a "deep clone" recursively traverses a source input and copies its _values_ — instead of _references_ to its values — into a new instance of that input. The result is a structurally equivalent clone that operates independently of the original source and controls its own values.

> **Why "klona"?** It's "clone" in Swedish.

> **What's with the sheep?** [Dolly](https://en.wikipedia.org/wiki/Dolly_(sheep)).

## Install

```
$ npm install --save klona
```

## Modes

There are multiple "versions" of `klona` available, which allows you to bring only the functionality you need!

#### `klona/json`
> **Size (gzip):** 240 bytes

> **Availability:** [CommonJS](https://unpkg.com/klona/json/index.js), [ES Module](https://unpkg.com/klona/json/index.mjs), [UMD](https://unpkg.com/klona/json/index.min.js)

> **Ability:** JSON data types

```js
import { klona } from 'klona/json';
```

#### `klona/lite`
> **Size (gzip):** 354 bytes

> **Availability:** [CommonJS](https://unpkg.com/klona/lite/index.js), [ES Module](https://unpkg.com/klona/lite/index.mjs), [UMD](https://unpkg.com/klona/lite/index.min.js)

> **Ability:** extends `klona/json` with support for custom class, Date, and RegExp

```js
import { klona } from 'klona/lite';
```

#### `klona`
> **Size (gzip):** 451 bytes

> **Availability:** [CommonJS](https://unpkg.com/klona/dist/index.js), [ES Module](https://unpkg.com/klona/dist/index.mjs), [UMD](https://unpkg.com/klona/dist/index.min.js)

> **Ability:** extends `klona/lite` with support for Map, Set, DataView, ArrayBuffer, TypedArray

```js
import { klona } from 'klona';
```

#### `klona/full`
> **Size (gzip):** 501 bytes

> **Availability:** [CommonJS](https://unpkg.com/klona/full/index.js), [ES Module](https://unpkg.com/klona/full/index.mjs), [UMD](https://unpkg.com/klona/full/index.min.js)

> **Ability:** extends `klona` with support for Symbol properties and and non-enumerable properties

```js
import { klona } from 'klona/full';
```

## Usage

```js
import { klona } from 'klona';

const input = {
  foo: 1,
  bar: {
    baz: 2,
    bat: {
      hello: 'world'
    }
  }
};

const output = klona(input);

// exact copy of original
assert.deepStrictEqual(input, output);

// applying deep updates...
output.bar.bat.hola = 'mundo';
output.bar.baz = 99;

// ...doesn't affect source!
console.log(
  JSON.stringify(input, null, 2)
);
// {
//   "foo": 1,
//   "bar": {
//     "baz": 2,
//     "bat": {
//       "hello": "world"
//     }
//   }
// }
```

## API

### klona(input)
Returns: `typeof input`

Returns a deep copy/clone of the input.

## Benchmarks

> Running Node v12.18.3

The benchmarks can be found in the [`/bench`](/bench) directory. They are separated into multiple categories:

* `JSON` – compares an array of objects comprised of JSON data types (`String`, `Number`, `null`, `Array`, `Object`)
* `LITE` – like `JSON`, but adds `RegExp`, `Date` and `undefined` values
* `DEFAULT` – object with `RegExp`, `Date`, `Array`, `Map`, `Set`, custom class, `Int8Array`, `DataView`, `Buffer` values
* `FULL` – like `DEFAULT`, but adds `Symbol` and non-enumerable properties

> **Important:** Only candidates that pass validation step(s) are listed.
However, `lodash` and `clone` are kept to highlight important differences.

> **Note:** The `clone/include` candidate refers to its [`includeNonEnumerable` option](https://www.npmjs.com/package/clone#api) enabled.

```
Load times:
  lodash/clonedeep   29.257ms
  rfdc                0.511ms
  clone               0.576ms
  clone-deep          2.494ms
  deep-copy           0.451ms
  klona/full          0.408ms
  klona               0.265ms
  klona/lite          0.308ms
  klona/json          0.263ms

Benchmark :: JSON
  JSON.stringify      x   53,899 ops/sec ±0.76% (92 runs sampled)
  lodash              x   46,800 ops/sec ±0.86% (90 runs sampled)
  rfdc                x  221,456 ops/sec ±0.88% (92 runs sampled)
  clone               x   39,537 ops/sec ±0.68% (92 runs sampled)
  clone/include       x   25,488 ops/sec ±1.06% (88 runs sampled)
  clone-deep          x   99,998 ops/sec ±0.91% (93 runs sampled)
  deep-copy           x  141,270 ops/sec ±0.95% (92 runs sampled)
  klona/full          x   55,016 ops/sec ±0.68% (94 runs sampled)
  klona               x  281,215 ops/sec ±0.77% (93 runs sampled)
  klona/lite          x  318,481 ops/sec ±0.72% (91 runs sampled)
  klona/json          x  334,932 ops/sec ±0.66% (93 runs sampled)

Benchmark :: LITE
  lodash              x   36,992 ops/sec ±0.65% (91 runs sampled)
  clone               x   35,974 ops/sec ±1.13% (88 runs sampled)
  clone/include       x   22,609 ops/sec ±1.02% (91 runs sampled)
  clone-deep          x   92,846 ops/sec ±0.66% (93 runs sampled)
  klona/full          x   47,873 ops/sec ±0.83% (88 runs sampled)
  klona               x  226,638 ops/sec ±1.16% (93 runs sampled)
  klona/lite          x  257,900 ops/sec ±0.82% (93 runs sampled)

Benchmark :: DEFAULT
  lodash              x   55,914 ops/sec ±0.75% (93 runs sampled)
    ✘ Buffer
    ✘ Map keys
  clone               x   92,127 ops/sec ±0.83% (94 runs sampled)
    ✘ DataView
  clone/include       x   62,052 ops/sec ±0.88% (93 runs sampled)
    ✘ DataView
  klona/full          x   90,308 ops/sec ±0.68% (89 runs sampled)
  klona               x  230,257 ops/sec ±0.71% (91 runs sampled)

Benchmark :: FULL
  lodash              x   60,361 ops/sec ±0.65% (91 runs sampled)
    ✘ Buffer
    ✘ Map keys
    ✘ Missing non-enumerable Properties
  clone/include       x   47,263 ops/sec ±0.85% (93 runs sampled)
    ✘ DataView
    ✘ Incorrect non-enumerable Properties
  klona/full          x   82,346 ops/sec ±0.62% (93 runs sampled)
```

## Related

* [dlv](https://github.com/developit/dlv) – safely **read** from deep properties in 120 bytes
* [dset](https://github.com/lukeed/dset) – safely **write** into deep properties in 160 bytes
* [dequal](https://github.com/lukeed/dequal) – safely check for deep equality in 304 to 489 bytes

## License

MIT © [Luke Edwards](https://lukeed.com)


code:
const url = require('url')
const path = require('path')
const launch = require('launch-editor')

module.exports = (specifiedEditor, srcRoot, onErrorCallback) => {
  if (typeof specifiedEditor === 'function') {
    onErrorCallback = specifiedEditor
    specifiedEditor = undefined
  }

  if (typeof srcRoot === 'function') {
    onErrorCallback = srcRoot
    srcRoot = undefined
  }

  srcRoot = srcRoot || process.cwd()

  return function launchEditorMiddleware (req, res) {
    const { file } = url.parse(req.url, true).query || {}
    if (!file) {
      res.statusCode = 500
      res.end(`launch-editor-middleware: required query param "file" is missing.`)
    } else {
      launch(path.resolve(srcRoot, file), specifiedEditor, onErrorCallback)
      res.end()
    }
  }
}


launch-editor-middleware

description: express middleware for launching editor

type: git

keywords: express middleware editor

author: Evan You


code:
module.exports = {
  atom: 'atom',
  Brackets: 'brackets',
  'code-insiders': 'code-insiders',
  code: 'code',
  vscodium: 'vscodium',
  codium: 'codium',
  emacs: 'emacs',
  gvim: 'gvim',
  'idea.sh': 'idea',
  'phpstorm.sh': 'phpstorm',
  'pycharm.sh': 'pycharm',
  'rubymine.sh': 'rubymine',
  sublime_text: 'subl',
  vim: 'vim',
  'webstorm.sh': 'webstorm',
  'goland.sh': 'goland',
  'rider.sh': 'rider'
}


code:
module.exports = {
  '/Applications/Atom.app/Contents/MacOS/Atom': 'atom',
  '/Applications/Atom Beta.app/Contents/MacOS/Atom Beta':
    '/Applications/Atom Beta.app/Contents/MacOS/Atom Beta',
  '/Applications/Brackets.app/Contents/MacOS/Brackets': 'brackets',
  '/Applications/Sublime Text.app/Contents/MacOS/Sublime Text':
    '/Applications/Sublime Text.app/Contents/SharedSupport/bin/subl',
  '/Applications/Sublime Text.app/Contents/MacOS/sublime_text':
    '/Applications/Sublime Text.app/Contents/SharedSupport/bin/subl',
  '/Applications/Sublime Text 2.app/Contents/MacOS/Sublime Text 2':
    '/Applications/Sublime Text 2.app/Contents/SharedSupport/bin/subl',
  '/Applications/Sublime Text Dev.app/Contents/MacOS/Sublime Text':
    '/Applications/Sublime Text Dev.app/Contents/SharedSupport/bin/subl',
  '/Applications/Visual Studio Code.app/Contents/MacOS/Electron': 'code',
  '/Applications/Visual Studio Code - Insiders.app/Contents/MacOS/Electron':
    'code-insiders',
  '/Applications/VSCodium.app/Contents/MacOS/Electron': 'codium',
  '/Applications/Cursor.app/Contents/MacOS/Cursor': 'cursor',
  '/Applications/AppCode.app/Contents/MacOS/appcode':
    '/Applications/AppCode.app/Contents/MacOS/appcode',
  '/Applications/CLion.app/Contents/MacOS/clion':
    '/Applications/CLion.app/Contents/MacOS/clion',
  '/Applications/IntelliJ IDEA.app/Contents/MacOS/idea':
    '/Applications/IntelliJ IDEA.app/Contents/MacOS/idea',
  '/Applications/IntelliJ IDEA Ultimate.app/Contents/MacOS/idea':
    '/Applications/IntelliJ IDEA Ultimate.app/Contents/MacOS/idea',
  '/Applications/IntelliJ IDEA Community Edition.app/Contents/MacOS/idea':
    '/Applications/IntelliJ IDEA Community Edition.app/Contents/MacOS/idea',
  '/Applications/PhpStorm.app/Contents/MacOS/phpstorm':
    '/Applications/PhpStorm.app/Contents/MacOS/phpstorm',
  '/Applications/PyCharm.app/Contents/MacOS/pycharm':
    '/Applications/PyCharm.app/Contents/MacOS/pycharm',
  '/Applications/PyCharm CE.app/Contents/MacOS/pycharm':
    '/Applications/PyCharm CE.app/Contents/MacOS/pycharm',
  '/Applications/RubyMine.app/Contents/MacOS/rubymine':
    '/Applications/RubyMine.app/Contents/MacOS/rubymine',
  '/Applications/WebStorm.app/Contents/MacOS/webstorm':
    '/Applications/WebStorm.app/Contents/MacOS/webstorm',
  '/Applications/MacVim.app/Contents/MacOS/MacVim': 'mvim',
  '/Applications/GoLand.app/Contents/MacOS/goland':
    '/Applications/GoLand.app/Contents/MacOS/goland',
  '/Applications/Rider.app/Contents/MacOS/rider':
    '/Applications/Rider.app/Contents/MacOS/rider',
  '/Applications/Zed.app/Contents/MacOS/zed': 'zed'
}


code:
module.exports = [
  'Brackets.exe',
  'Code.exe',
  'Code - Insiders.exe',
  'VSCodium.exe',
  'atom.exe',
  'sublime_text.exe',
  'notepad++.exe',
  'clion.exe',
  'clion64.exe',
  'idea.exe',
  'idea64.exe',
  'phpstorm.exe',
  'phpstorm64.exe',
  'pycharm.exe',
  'pycharm64.exe',
  'rubymine.exe',
  'rubymine64.exe',
  'webstorm.exe',
  'webstorm64.exe',
  'goland.exe',
  'goland64.exe',
  'rider.exe',
  'rider64.exe'
]


code:
const path = require('path')

// normalize file/line numbers into command line args for specific editors
module.exports = function getArgumentsForPosition (
  editor,
  fileName,
  lineNumber,
  columnNumber = 1
) {
  const editorBasename = path.basename(editor).replace(/\.(exe|cmd|bat)$/i, '')
  switch (editorBasename) {
    case 'atom':
    case 'Atom':
    case 'Atom Beta':
    case 'subl':
    case 'sublime':
    case 'sublime_text':
    case 'wstorm':
    case 'charm':
    case 'zed':
      return [`${fileName}:${lineNumber}:${columnNumber}`]
    case 'notepad++':
      return ['-n' + lineNumber, '-c' + columnNumber, fileName]
    case 'vim':
    case 'mvim':
      return [`+call cursor(${lineNumber}, ${columnNumber})`, fileName]
    case 'joe':
    case 'gvim':
      return ['+' + `${lineNumber}`, fileName]
    case 'emacs':
    case 'emacsclient':
      return [`+${lineNumber}:${columnNumber}`, fileName]
    case 'rmate':
    case 'mate':
    case 'mine':
      return ['--line', lineNumber, fileName]
    case 'code':
    case 'Code':
    case 'code-insiders':
    case 'Code - Insiders':
    case 'codium':
    case 'cursor':
    case 'vscodium':
    case 'VSCodium':
      return ['-r', '-g', `${fileName}:${lineNumber}:${columnNumber}`]
    case 'appcode':
    case 'clion':
    case 'clion64':
    case 'idea':
    case 'idea64':
    case 'phpstorm':
    case 'phpstorm64':
    case 'pycharm':
    case 'pycharm64':
    case 'rubymine':
    case 'rubymine64':
    case 'webstorm':
    case 'webstorm64':
    case 'goland':
    case 'goland64':
    case 'rider':
    case 'rider64':
      return ['--line', lineNumber, '--column', columnNumber, fileName]
  }

  if (process.env.LAUNCH_EDITOR) {
    return [fileName, lineNumber, columnNumber]
  }

  // For all others, drop the lineNumber until we have
  // a mapping above, since providing the lineNumber incorrectly
  // can result in errors or confusing behavior.
  return [fileName]
}


code:
const path = require('path')
const shellQuote = require('shell-quote')
const childProcess = require('child_process')

// Map from full process name to binary that starts the process
// We can't just re-use full process name, because it will spawn a new instance
// of the app every time
const COMMON_EDITORS_MACOS = require('./editor-info/macos')
const COMMON_EDITORS_LINUX = require('./editor-info/linux')
const COMMON_EDITORS_WIN = require('./editor-info/windows')

module.exports = function guessEditor (specifiedEditor) {
  if (specifiedEditor) {
    return shellQuote.parse(specifiedEditor)
  }

  if (process.env.LAUNCH_EDITOR) {
    return [process.env.LAUNCH_EDITOR]
  }

  if (process.versions.webcontainer) {
    return [process.env.EDITOR || 'code']
  }

  // We can find out which editor is currently running by:
  // `ps x` on macOS and Linux
  // `Get-Process` on Windows
  try {
    if (process.platform === 'darwin') {
      const output = childProcess
        .execSync('ps x -o comm=', {
          stdio: ['pipe', 'pipe', 'ignore']
        })
        .toString()
      const processNames = Object.keys(COMMON_EDITORS_MACOS)
      const processList = output.split('\n')
      for (let i = 0; i < processNames.length; i++) {
        const processName = processNames[i]
        // Find editor by exact match.
        if (processList.includes(processName)) {
          return [COMMON_EDITORS_MACOS[processName]]
        }
        const processNameWithoutApplications = processName.replace('/Applications', '')
        // Find editor installation not in /Applications.
        if (output.indexOf(processNameWithoutApplications) !== -1) {
          // Use the CLI command if one is specified
          if (processName !== COMMON_EDITORS_MACOS[processName]) {
            return [COMMON_EDITORS_MACOS[processName]]
          }
          // Use a partial match to find the running process path.  If one is found, use the
          // existing path since it can be running from anywhere.
          const runningProcess = processList.find((procName) => procName.endsWith(processNameWithoutApplications))
          if (runningProcess !== undefined) {
            return [runningProcess]
          }
        }
      }
    } else if (process.platform === 'win32') {
      const output = childProcess
        .execSync(
          'powershell -NoProfile -Command "Get-CimInstance -Query \\"select executablepath from win32_process where executablepath is not null\\" | % { $_.ExecutablePath }"',
          {
            stdio: ['pipe', 'pipe', 'ignore']
          }
        )
        .toString()
      const runningProcesses = output.split('\r\n')
      for (let i = 0; i < runningProcesses.length; i++) {
        const fullProcessPath = runningProcesses[i].trim()
        const shortProcessName = path.basename(fullProcessPath)

        if (COMMON_EDITORS_WIN.indexOf(shortProcessName) !== -1) {
          return [fullProcessPath]
        }
      }
    } else if (process.platform === 'linux') {
      // --no-heading No header line
      // x List all processes owned by you
      // -o comm Need only names column
      const output = childProcess
        .execSync('ps x --no-heading -o comm --sort=comm', {
          stdio: ['pipe', 'pipe', 'ignore']
        })
        .toString()
      const processNames = Object.keys(COMMON_EDITORS_LINUX)
      for (let i = 0; i < processNames.length; i++) {
        const processName = processNames[i]
        if (output.indexOf(processName) !== -1) {
          return [COMMON_EDITORS_LINUX[processName]]
        }
      }
    }
  } catch (ignoreError) {
    // Ignore...
  }

  // Last resort, use old skool env vars
  if (process.env.VISUAL) {
    return [process.env.VISUAL]
  } else if (process.env.EDITOR) {
    return [process.env.EDITOR]
  }

  return [null]
}


code:
/**
 * Copyright (c) 2015-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file at
 * https://github.com/facebookincubator/create-react-app/blob/master/LICENSE
 *
 * Modified by Yuxi Evan You
 */

const fs = require('fs')
const os = require('os')
const path = require('path')
const colors = require('picocolors')
const childProcess = require('child_process')

const guessEditor = require('./guess')
const getArgumentsForPosition = require('./get-args')

function wrapErrorCallback (cb) {
  return (fileName, errorMessage) => {
    console.log()
    console.log(
      colors.red('Could not open ' + path.basename(fileName) + ' in the editor.')
    )
    if (errorMessage) {
      if (errorMessage[errorMessage.length - 1] !== '.') {
        errorMessage += '.'
      }
      console.log(
        colors.red('The editor process exited with an error: ' + errorMessage)
      )
    }
    console.log()
    if (cb) cb(fileName, errorMessage)
  }
}

function isTerminalEditor (editor) {
  switch (editor) {
    case 'vim':
    case 'emacs':
    case 'nano':
      return true
  }
  return false
}

const positionRE = /:(\d+)(:(\d+))?$/
function parseFile (file) {
  const fileName = file.replace(positionRE, '')
  const match = file.match(positionRE)
  const lineNumber = match && match[1]
  const columnNumber = match && match[3]
  return {
    fileName,
    lineNumber,
    columnNumber
  }
}

let _childProcess = null

function launchEditor (file, specifiedEditor, onErrorCallback) {
  const parsed = parseFile(file)
  let { fileName } = parsed
  const { lineNumber, columnNumber } = parsed

  if (!fs.existsSync(fileName)) {
    return
  }

  if (typeof specifiedEditor === 'function') {
    onErrorCallback = specifiedEditor
    specifiedEditor = undefined
  }

  onErrorCallback = wrapErrorCallback(onErrorCallback)

  const [editor, ...args] = guessEditor(specifiedEditor)
  if (!editor) {
    onErrorCallback(fileName, null)
    return
  }

  if (
    process.platform === 'linux' &&
    fileName.startsWith('/mnt/') &&
    /Microsoft/i.test(os.release())
  ) {
    // Assume WSL / "Bash on Ubuntu on Windows" is being used, and
    // that the file exists on the Windows file system.
    // `os.release()` is "4.4.0-43-Microsoft" in the current release
    // build of WSL, see: https://github.com/Microsoft/BashOnWindows/issues/423#issuecomment-221627364
    // When a Windows editor is specified, interop functionality can
    // handle the path translation, but only if a relative path is used.
    fileName = path.relative('', fileName)
  }

  // cmd.exe on Windows is vulnerable to RCE attacks given a file name of the
  // form "C:\Users\myusername\Downloads\& curl 172.21.93.52". Use a safe file
  // name pattern to validate user-provided file names. This doesn't cover the
  // entire range of valid file names but should cover almost all of them in practice.
  // (Backport of
  // https://github.com/facebook/create-react-app/pull/4866
  // and
  // https://github.com/facebook/create-react-app/pull/5431)

  // Allows alphanumeric characters, periods, dashes, slashes, and underscores.
  const WINDOWS_CMD_SAFE_FILE_NAME_PATTERN = /^([A-Za-z]:[/\\])?[\p{L}0-9/.\-_\\]+$/u
  if (
    process.platform === 'win32' &&
    !WINDOWS_CMD_SAFE_FILE_NAME_PATTERN.test(fileName.trim())
  ) {
    console.log()
    console.log(
      colors.red('Could not open ' + path.basename(fileName) + ' in the editor.')
    )
    console.log()
    console.log(
      'When running on Windows, file names are checked against a safe file name ' +
        'pattern to protect against remote code execution attacks. File names ' +
        'may consist only of alphanumeric characters (all languages), periods, ' +
        'dashes, slashes, and underscores.'
    );
    console.log()
    return
  }

  if (lineNumber) {
    const extraArgs = getArgumentsForPosition(editor, fileName, lineNumber, columnNumber)
    args.push.apply(args, extraArgs)
  } else {
    args.push(fileName)
  }

  if (_childProcess && isTerminalEditor(editor)) {
    // There's an existing editor process already and it's attached
    // to the terminal, so go kill it. Otherwise two separate editor
    // instances attach to the stdin/stdout which gets confusing.
    _childProcess.kill('SIGKILL')
  }

  if (process.platform === 'win32') {
    // On Windows, launch the editor in a shell because spawn can only
    // launch .exe files.
    _childProcess = childProcess.spawn(
      'cmd.exe',
      ['/C', editor].concat(args),
      { stdio: 'inherit' }
    )
  } else {
    _childProcess = childProcess.spawn(editor, args, { stdio: 'inherit' })
  }
  _childProcess.on('exit', function (errorCode) {
    _childProcess = null

    if (errorCode) {
      onErrorCallback(fileName, '(code ' + errorCode + ')')
    }
  })

  _childProcess.on('error', function (error) {
    let { code, message } = error
    if ('ENOENT' === code) {
      message = `${message} ('${editor}' command does not exist in 'PATH')`
    }
    onErrorCallback(fileName, message);
  })
}

module.exports = launchEditor


launch-editor

description: launch editor from node.js

keywords: launch editor


code:
# levn [![Build Status](https://travis-ci.org/gkz/levn.png)](https://travis-ci.org/gkz/levn) <a name="levn" />
__Light ECMAScript (JavaScript) Value Notation__
Levn is a library which allows you to parse a string into a JavaScript value based on an expected type. It is meant for short amounts of human entered data (eg. config files, command line arguments).

Levn aims to concisely describe JavaScript values in text, and allow for the extraction and validation of those values. Levn uses [type-check](https://github.com/gkz/type-check) for its type format, and to validate the results. MIT license. Version 0.4.1.

__How is this different than JSON?__ levn is meant to be written by humans only, is (due to the previous point) much more concise, can be validated against supplied types, has regex and date literals, and can easily be extended with custom types. On the other hand, it is probably slower and thus less efficient at transporting large amounts of data, which is fine since this is not its purpose.

    npm install levn

For updates on levn, [follow me on twitter](https://twitter.com/gkzahariev).

## Quick Examples

```js
var parse = require('levn').parse;
parse('Number', '2');      // 2
parse('String', '2');      // '2'
parse('String', 'levn');   // 'levn'
parse('String', 'a b');    // 'a b'
parse('Boolean', 'true');  // true

parse('Date', '#2011-11-11#'); // (Date object)
parse('Date', '2011-11-11');   // (Date object)
parse('RegExp', '/[a-z]/gi');  // /[a-z]/gi
parse('RegExp', 're');         // /re/
parse('Int', '2');             // 2

parse('Number | String', 'str'); // 'str'
parse('Number | String', '2');   // 2

parse('[Number]', '[1,2,3]');                      // [1,2,3]
parse('(String, Boolean)', '(hi, false)');         // ['hi', false]
parse('{a: String, b: Number}', '{a: str, b: 2}'); // {a: 'str', b: 2}

// at the top level, you can ommit surrounding delimiters
parse('[Number]', '1,2,3');                      // [1,2,3]
parse('(String, Boolean)', 'hi, false');         // ['hi', false]
parse('{a: String, b: Number}', 'a: str, b: 2'); // {a: 'str', b: 2}

// wildcard - auto choose type
parse('*', '[hi,(null,[42]),{k: true}]'); // ['hi', [null, [42]], {k: true}]
```
## Usage

`require('levn');` returns an object that exposes three properties. `VERSION` is the current version of the library as a string. `parse` and `parsedTypeParse` are functions.

```js
// parse(type, input, options);
parse('[Number]', '1,2,3'); // [1, 2, 3]

// parsedTypeParse(parsedType, input, options);
var parsedType = require('type-check').parseType('[Number]');
parsedTypeParse(parsedType, '1,2,3'); // [1, 2, 3]
```

### parse(type, input, options)

`parse` casts the string `input` into a JavaScript value according to the specified `type` in the [type format](https://github.com/gkz/type-check#type-format) (and taking account the optional `options`) and returns the resulting JavaScript value.

##### arguments
* type - `String` - the type written in the [type format](https://github.com/gkz/type-check#type-format) which to check against
* input - `String` - the value written in the [levn format](#levn-format)
* options - `Maybe Object` - an optional parameter specifying additional [options](#options)

##### returns
`*` - the resulting JavaScript value

##### example
```js
parse('[Number]', '1,2,3'); // [1, 2, 3]
```

### parsedTypeParse(parsedType, input, options)

`parsedTypeParse` casts the string `input` into a JavaScript value according to the specified `type` which has already been parsed (and taking account the optional `options`) and returns the resulting JavaScript value. You can parse a type using the [type-check](https://github.com/gkz/type-check) library's `parseType` function.

##### arguments
* type - `Object` - the type in the parsed type format which to check against
* input - `String` - the value written in the [levn format](#levn-format)
* options - `Maybe Object` - an optional parameter specifying additional [options](#options)

##### returns
`*` - the resulting JavaScript value

##### example
```js
var parsedType = require('type-check').parseType('[Number]');
parsedTypeParse(parsedType, '1,2,3'); // [1, 2, 3]
```

## Levn Format

Levn can use the type information you provide to choose the appropriate value to produce from the input. For the same input, it will choose a different output value depending on the type provided. For example, `parse('Number', '2')` will produce the number `2`, but `parse('String', '2')` will produce the string `"2"`.

If you do not provide type information, and simply use `*`, levn will parse the input according the unambiguous "explicit" mode, which we will now detail - you can also set the `explicit` option to true manually in the [options](#options).

* `"string"`, `'string'` are parsed as a String, eg. `"a msg"` is `"a msg"`
* `#date#` is parsed as a Date, eg. `#2011-11-11#` is `new Date('2011-11-11')`
* `/regexp/flags` is parsed as a RegExp, eg. `/re/gi` is `/re/gi`
* `undefined`, `null`, `NaN`, `true`, and `false` are all their JavaScript equivalents
* `[element1, element2, etc]` is an Array, and the casting procedure is recursively applied to each element. Eg. `[1,2,3]` is `[1,2,3]`.
* `(element1, element2, etc)` is an tuple, and the casting procedure is recursively applied to each element. Eg. `(1, a)` is `(1, a)` (is `[1, 'a']`).
* `{key1: val1, key2: val2, ...}` is an Object, and the casting procedure is recursively applied to each property. Eg. `{a: 1, b: 2}` is `{a: 1, b: 2}`.
* Any test which does not fall under the above, and which does not contain special characters (`[``]``(``)``{``}``:``,`) is a string, eg. `$12- blah` is `"$12- blah"`.

If you do provide type information, you can make your input more concise as the program already has some information about what it expects. Please see the [type format](https://github.com/gkz/type-check#type-format) section of [type-check](https://github.com/gkz/type-check) for more information about how to specify types. There are some rules about what levn can do with the information:

* If a String is expected, and only a String, all characters of the input (including any special ones) will become part of the output. Eg. `[({})]` is `"[({})]"`, and `"hi"` is `'"hi"'`.
* If a Date is expected, the surrounding `#` can be omitted from date literals. Eg. `2011-11-11` is `new Date('2011-11-11')`.
* If a RegExp is expected, no flags need to be specified, and the regex is not using any of the special characters,the opening and closing `/` can be omitted - this will have the affect of setting the source of the regex to the input. Eg. `regex` is `/regex/`.
* If an Array is expected, and it is the root node (at the top level), the opening `[` and closing `]` can be omitted. Eg. `1,2,3` is `[1,2,3]`.
* If a tuple is expected, and it is the root node (at the top level), the opening `(` and closing `)` can be omitted. Eg. `1, a` is `(1, a)` (is `[1, 'a']`).
* If an Object is expected, and it is the root node (at the top level), the opening `{` and closing `}` can be omitted. Eg `a: 1, b: 2` is `{a: 1, b: 2}`.

If you list multiple types (eg. `Number | String`), it will first attempt to cast to the first type and then validate - if the validation fails it will move on to the next type and so forth, left to right. You must be careful as some types will succeed with any input, such as String. Thus put String at the end of your list. In non-explicit mode, Date and RegExp will succeed with a large variety of input - also be careful with these and list them near the end if not last in your list.

Whitespace between special characters and elements is inconsequential.

## Options

Options is an object. It is an optional parameter to the `parse` and `parsedTypeParse` functions.

### Explicit

A `Boolean`. By default it is `false`.

__Example:__

```js
parse('RegExp', 're', {explicit: false});          // /re/
parse('RegExp', 're', {explicit: true});           // Error: ... does not type check...
parse('RegExp | String', 're', {explicit: true});  // 're'
```

`explicit` sets whether to be in explicit mode or not. Using `*` automatically activates explicit mode. For more information, read the [levn format](#levn-format) section.

### customTypes

An `Object`. Empty `{}` by default.

__Example:__

```js
var options = {
  customTypes: {
    Even: {
      typeOf: 'Number',
      validate: function (x) {
        return x % 2 === 0;
      },
      cast: function (x) {
        return {type: 'Just', value: parseInt(x)};
      }
    }
  }
}
parse('Even', '2', options); // 2
parse('Even', '3', options); // Error: Value: "3" does not type check...
```

__Another Example:__
```js
function Person(name, age){
  this.name = name;
  this.age = age;
}
var options = {
  customTypes: {
    Person: {
      typeOf: 'Object',
      validate: function (x) {
        x instanceof Person;
      },
      cast: function (value, options, typesCast) {
        var name, age;
        if ({}.toString.call(value).slice(8, -1) !== 'Object') {
          return {type: 'Nothing'};
        }
        name = typesCast(value.name, [{type: 'String'}], options);
        age = typesCast(value.age, [{type: 'Numger'}], options);
        return {type: 'Just', value: new Person(name, age)};
    }
  }
}
parse('Person', '{name: Laura, age: 25}', options); // Person {name: 'Laura', age: 25}
```

`customTypes` is an object whose keys are the name of the types, and whose values are an object with three properties, `typeOf`, `validate`, and `cast`. For more information about `typeOf` and `validate`, please see the [custom types](https://github.com/gkz/type-check#custom-types) section of type-check.

`cast` is a function which receives three arguments, the value under question, options, and the typesCast function. In `cast`, attempt to cast the value into the specified type. If you are successful, return an object in the format `{type: 'Just', value: CAST-VALUE}`, if you know it won't work, return `{type: 'Nothing'}`.  You can use the `typesCast` function to cast any child values. Remember to pass `options` to it. In your function you can also check for `options.explicit` and act accordingly.

## Technical About

`levn` is written in [LiveScript](http://livescript.net/) - a language that compiles to JavaScript. It uses [type-check](https://github.com/gkz/type-check) to both parse types and validate values. It also uses the [prelude.ls](http://preludels.com/) library.


code:
// Generated by LiveScript 1.6.0
(function(){
  var parsedTypeCheck, types, toString$ = {}.toString;
  parsedTypeCheck = require('type-check').parsedTypeCheck;
  types = {
    '*': function(value, options){
      switch (toString$.call(value).slice(8, -1)) {
      case 'Array':
        return typeCast(value, {
          type: 'Array'
        }, options);
      case 'Object':
        return typeCast(value, {
          type: 'Object'
        }, options);
      default:
        return {
          type: 'Just',
          value: typesCast(value, [
            {
              type: 'Undefined'
            }, {
              type: 'Null'
            }, {
              type: 'NaN'
            }, {
              type: 'Boolean'
            }, {
              type: 'Number'
            }, {
              type: 'Date'
            }, {
              type: 'RegExp'
            }, {
              type: 'Array'
            }, {
              type: 'Object'
            }, {
              type: 'String'
            }
          ], (options.explicit = true, options))
        };
      }
    },
    Undefined: function(it){
      if (it === 'undefined' || it === void 8) {
        return {
          type: 'Just',
          value: void 8
        };
      } else {
        return {
          type: 'Nothing'
        };
      }
    },
    Null: function(it){
      if (it === 'null') {
        return {
          type: 'Just',
          value: null
        };
      } else {
        return {
          type: 'Nothing'
        };
      }
    },
    NaN: function(it){
      if (it === 'NaN') {
        return {
          type: 'Just',
          value: NaN
        };
      } else {
        return {
          type: 'Nothing'
        };
      }
    },
    Boolean: function(it){
      if (it === 'true') {
        return {
          type: 'Just',
          value: true
        };
      } else if (it === 'false') {
        return {
          type: 'Just',
          value: false
        };
      } else {
        return {
          type: 'Nothing'
        };
      }
    },
    Number: function(it){
      return {
        type: 'Just',
        value: +it
      };
    },
    Int: function(it){
      return {
        type: 'Just',
        value: +it
      };
    },
    Float: function(it){
      return {
        type: 'Just',
        value: +it
      };
    },
    Date: function(value, options){
      var that;
      if (that = /^\#([\s\S]*)\#$/.exec(value)) {
        return {
          type: 'Just',
          value: new Date(+that[1] || that[1])
        };
      } else if (options.explicit) {
        return {
          type: 'Nothing'
        };
      } else {
        return {
          type: 'Just',
          value: new Date(+value || value)
        };
      }
    },
    RegExp: function(value, options){
      var that;
      if (that = /^\/([\s\S]*)\/([gimy]*)$/.exec(value)) {
        return {
          type: 'Just',
          value: new RegExp(that[1], that[2])
        };
      } else if (options.explicit) {
        return {
          type: 'Nothing'
        };
      } else {
        return {
          type: 'Just',
          value: new RegExp(value)
        };
      }
    },
    Array: function(value, options){
      return castArray(value, {
        of: [{
          type: '*'
        }]
      }, options);
    },
    Object: function(value, options){
      return castFields(value, {
        of: {}
      }, options);
    },
    String: function(it){
      var replace, that;
      if (toString$.call(it).slice(8, -1) !== 'String') {
        return {
          type: 'Nothing'
        };
      }
      replace = function(value, quote){
        return value.replace(/\\([^u]|u[0-9a-fA-F]{4})/g, function(all, escaped){
          switch (escaped[0]) {
          case quote:
            return quote;
          case '\\':
            return '\\';
          case 'b':
            return '\b';
          case 'f':
            return '\f';
          case 'n':
            return '\n';
          case 'r':
            return '\r';
          case 't':
            return '\t';
          case 'u':
            return JSON.parse("\"" + all + "\"");
          default:
            return escaped;
          }
        });
      };
      if (that = it.match(/^'([\s\S]*)'$/)) {
        return {
          type: 'Just',
          value: replace(that[1], "'")
        };
      } else if (that = it.match(/^"([\s\S]*)"$/)) {
        return {
          type: 'Just',
          value: replace(that[1], '"')
        };
      } else {
        return {
          type: 'Just',
          value: it
        };
      }
    }
  };
  function castArray(node, type, options){
    var typeOf, element;
    if (toString$.call(node).slice(8, -1) !== 'Array') {
      return {
        type: 'Nothing'
      };
    }
    typeOf = type.of;
    return {
      type: 'Just',
      value: (function(){
        var i$, ref$, len$, results$ = [];
        for (i$ = 0, len$ = (ref$ = node).length; i$ < len$; ++i$) {
          element = ref$[i$];
          results$.push(typesCast(element, typeOf, options));
        }
        return results$;
      }())
    };
  }
  function castTuple(node, type, options){
    var result, i, i$, ref$, len$, types, cast;
    if (toString$.call(node).slice(8, -1) !== 'Array') {
      return {
        type: 'Nothing'
      };
    }
    result = [];
    i = 0;
    for (i$ = 0, len$ = (ref$ = type.of).length; i$ < len$; ++i$) {
      types = ref$[i$];
      cast = typesCast(node[i], types, options);
      if (toString$.call(cast).slice(8, -1) !== 'Undefined') {
        result.push(cast);
      }
      i++;
    }
    if (node.length <= i) {
      return {
        type: 'Just',
        value: result
      };
    } else {
      return {
        type: 'Nothing'
      };
    }
  }
  function castFields(node, type, options){
    var typeOf, key, value;
    if (toString$.call(node).slice(8, -1) !== 'Object') {
      return {
        type: 'Nothing'
      };
    }
    typeOf = type.of;
    return {
      type: 'Just',
      value: (function(){
        var ref$, resultObj$ = {};
        for (key in ref$ = node) {
          value = ref$[key];
          resultObj$[typesCast(key, [{
            type: 'String'
          }], options)] = typesCast(value, typeOf[key] || [{
            type: '*'
          }], options);
        }
        return resultObj$;
      }())
    };
  }
  function typeCast(node, typeObj, options){
    var type, structure, castFunc, ref$;
    type = typeObj.type, structure = typeObj.structure;
    if (type) {
      castFunc = ((ref$ = options.customTypes[type]) != null ? ref$.cast : void 8) || types[type];
      if (!castFunc) {
        throw new Error("Type not defined: " + type + ".");
      }
      return castFunc(node, options, typesCast);
    } else {
      switch (structure) {
      case 'array':
        return castArray(node, typeObj, options);
      case 'tuple':
        return castTuple(node, typeObj, options);
      case 'fields':
        return castFields(node, typeObj, options);
      }
    }
  }
  function typesCast(node, types, options){
    var i$, len$, type, ref$, valueType, value;
    for (i$ = 0, len$ = types.length; i$ < len$; ++i$) {
      type = types[i$];
      ref$ = typeCast(node, type, options), valueType = ref$.type, value = ref$.value;
      if (valueType === 'Nothing') {
        continue;
      }
      if (parsedTypeCheck([type], value, {
        customTypes: options.customTypes
      })) {
        return value;
      }
    }
    throw new Error("Value " + JSON.stringify(node) + " does not type check against " + JSON.stringify(types) + ".");
  }
  module.exports = function(node, types, options){
    if (!options.explicit && types.length === 1 && types[0].type === 'String') {
      return node;
    }
    return typesCast(node, types, options);
  };
}).call(this);


code:
// Generated by LiveScript 1.6.0
(function(){
  var parseString, cast, parseType, VERSION, parsedTypeParse, parse;
  parseString = require('./parse-string');
  cast = require('./cast');
  parseType = require('type-check').parseType;
  VERSION = '0.4.1';
  parsedTypeParse = function(parsedType, string, options){
    options == null && (options = {});
    options.explicit == null && (options.explicit = false);
    options.customTypes == null && (options.customTypes = {});
    return cast(parseString(parsedType, string, options), parsedType, options);
  };
  parse = function(type, string, options){
    return parsedTypeParse(parseType(type), string, options);
  };
  module.exports = {
    VERSION: VERSION,
    parse: parse,
    parsedTypeParse: parsedTypeParse
  };
}).call(this);


code:
// Generated by LiveScript 1.6.0
(function(){
  var reject, special, tokenRegex;
  reject = require('prelude-ls').reject;
  function consumeOp(tokens, op){
    if (tokens[0] === op) {
      return tokens.shift();
    } else {
      throw new Error("Expected '" + op + "', but got '" + tokens[0] + "' instead in " + JSON.stringify(tokens) + ".");
    }
  }
  function maybeConsumeOp(tokens, op){
    if (tokens[0] === op) {
      return tokens.shift();
    }
  }
  function consumeList(tokens, arg$, hasDelimiters){
    var open, close, result, untilTest;
    open = arg$[0], close = arg$[1];
    if (hasDelimiters) {
      consumeOp(tokens, open);
    }
    result = [];
    untilTest = "," + (hasDelimiters ? close : '');
    while (tokens.length && (hasDelimiters && tokens[0] !== close)) {
      result.push(consumeElement(tokens, untilTest));
      maybeConsumeOp(tokens, ',');
    }
    if (hasDelimiters) {
      consumeOp(tokens, close);
    }
    return result;
  }
  function consumeArray(tokens, hasDelimiters){
    return consumeList(tokens, ['[', ']'], hasDelimiters);
  }
  function consumeTuple(tokens, hasDelimiters){
    return consumeList(tokens, ['(', ')'], hasDelimiters);
  }
  function consumeFields(tokens, hasDelimiters){
    var result, untilTest, key;
    if (hasDelimiters) {
      consumeOp(tokens, '{');
    }
    result = {};
    untilTest = "," + (hasDelimiters ? '}' : '');
    while (tokens.length && (!hasDelimiters || tokens[0] !== '}')) {
      key = consumeValue(tokens, ':');
      consumeOp(tokens, ':');
      result[key] = consumeElement(tokens, untilTest);
      maybeConsumeOp(tokens, ',');
    }
    if (hasDelimiters) {
      consumeOp(tokens, '}');
    }
    return result;
  }
  function consumeValue(tokens, untilTest){
    var out;
    untilTest == null && (untilTest = '');
    out = '';
    while (tokens.length && -1 === untilTest.indexOf(tokens[0])) {
      out += tokens.shift();
    }
    return out;
  }
  function consumeElement(tokens, untilTest){
    switch (tokens[0]) {
    case '[':
      return consumeArray(tokens, true);
    case '(':
      return consumeTuple(tokens, true);
    case '{':
      return consumeFields(tokens, true);
    default:
      return consumeValue(tokens, untilTest);
    }
  }
  function consumeTopLevel(tokens, types, options){
    var ref$, type, structure, origTokens, result, finalResult, x$, y$;
    ref$ = types[0], type = ref$.type, structure = ref$.structure;
    origTokens = tokens.concat();
    if (!options.explicit && types.length === 1 && ((!type && structure) || (type === 'Array' || type === 'Object'))) {
      result = structure === 'array' || type === 'Array'
        ? consumeArray(tokens, tokens[0] === '[')
        : structure === 'tuple'
          ? consumeTuple(tokens, tokens[0] === '(')
          : consumeFields(tokens, tokens[0] === '{');
      finalResult = tokens.length ? consumeElement(structure === 'array' || type === 'Array'
        ? (x$ = origTokens, x$.unshift('['), x$.push(']'), x$)
        : (y$ = origTokens, y$.unshift('('), y$.push(')'), y$)) : result;
    } else {
      finalResult = consumeElement(tokens);
    }
    return finalResult;
  }
  special = /\[\]\(\)}{:,/.source;
  tokenRegex = RegExp('("(?:\\\\"|[^"])*")|(\'(?:\\\\\'|[^\'])*\')|(/(?:\\\\/|[^/])*/[a-zA-Z]*)|(#.*#)|([' + special + '])|([^\\s' + special + '](?:\\s*[^\\s' + special + ']+)*)|\\s*');
  module.exports = function(types, string, options){
    var tokens, node;
    options == null && (options = {});
    if (!options.explicit && types.length === 1 && types[0].type === 'String') {
      return string;
    }
    tokens = reject(not$, string.split(tokenRegex));
    node = consumeTopLevel(tokens, types, options);
    if (!node) {
      throw new Error("Error parsing '" + string + "'.");
    }
    return node;
  };
  function not$(x){ return !x; }
}).call(this);


levn

author: George Zahariev <z@georgezahariev.com>

description: Light ECMAScript (JavaScript) Value Notation - human written, concise, typed, flexible

keywords: levn light ecmascript value notation json typed human concise typed flexible

files: lib README.md LICENSE

test: make test


code:
export declare type LilconfigResult = null | {
    filepath: string;
    config: any;
    isEmpty?: boolean;
};
interface OptionsBase {
    stopDir?: string;
    searchPlaces?: string[];
    ignoreEmptySearchPlaces?: boolean;
    packageProp?: string | string[];
}
export declare type Transform = TransformSync | ((result: LilconfigResult) => Promise<LilconfigResult>);
export declare type TransformSync = (result: LilconfigResult) => LilconfigResult;
declare type LoaderResult = any;
export declare type LoaderSync = (filepath: string, content: string) => LoaderResult;
export declare type Loader = LoaderSync | ((filepath: string, content: string) => Promise<LoaderResult>);
export declare type Loaders = Record<string, Loader>;
export declare type LoadersSync = Record<string, LoaderSync>;
export interface Options extends OptionsBase {
    loaders?: Loaders;
    transform?: Transform;
}
export interface OptionsSync extends OptionsBase {
    loaders?: LoadersSync;
    transform?: TransformSync;
}
export declare const defaultLoaders: LoadersSync;
declare type AsyncSearcher = {
    search(searchFrom?: string): Promise<LilconfigResult>;
    load(filepath: string): Promise<LilconfigResult>;
};
export declare function lilconfig(name: string, options?: Partial<Options>): AsyncSearcher;
declare type SyncSearcher = {
    search(searchFrom?: string): LilconfigResult;
    load(filepath: string): LilconfigResult;
};
export declare function lilconfigSync(name: string, options?: OptionsSync): SyncSearcher;
export {};


code:
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.lilconfigSync = exports.lilconfig = exports.defaultLoaders = void 0;
const path = require("path");
const fs = require("fs");
const os = require("os");
const fsReadFileAsync = fs.promises.readFile;
function getDefaultSearchPlaces(name) {
    return [
        'package.json',
        `.${name}rc.json`,
        `.${name}rc.js`,
        `.${name}rc.cjs`,
        `.config/${name}rc`,
        `.config/${name}rc.json`,
        `.config/${name}rc.js`,
        `.config/${name}rc.cjs`,
        `${name}.config.js`,
        `${name}.config.cjs`,
    ];
}
function getSearchPaths(startDir, stopDir) {
    return startDir
        .split(path.sep)
        .reduceRight((acc, _, ind, arr) => {
        const currentPath = arr.slice(0, ind + 1).join(path.sep);
        if (!acc.passedStopDir)
            acc.searchPlaces.push(currentPath || path.sep);
        if (currentPath === stopDir)
            acc.passedStopDir = true;
        return acc;
    }, { searchPlaces: [], passedStopDir: false }).searchPlaces;
}
exports.defaultLoaders = Object.freeze({
    '.js': require,
    '.json': require,
    '.cjs': require,
    noExt(_, content) {
        return JSON.parse(content);
    },
});
function getExtDesc(ext) {
    return ext === 'noExt' ? 'files without extensions' : `extension "${ext}"`;
}
function getOptions(name, options = {}) {
    const conf = {
        stopDir: os.homedir(),
        searchPlaces: getDefaultSearchPlaces(name),
        ignoreEmptySearchPlaces: true,
        transform: (x) => x,
        packageProp: [name],
        ...options,
        loaders: { ...exports.defaultLoaders, ...options.loaders },
    };
    conf.searchPlaces.forEach(place => {
        const key = path.extname(place) || 'noExt';
        const loader = conf.loaders[key];
        if (!loader) {
            throw new Error(`No loader specified for ${getExtDesc(key)}, so searchPlaces item "${place}" is invalid`);
        }
        if (typeof loader !== 'function') {
            throw new Error(`loader for ${getExtDesc(key)} is not a function (type provided: "${typeof loader}"), so searchPlaces item "${place}" is invalid`);
        }
    });
    return conf;
}
function getPackageProp(props, obj) {
    if (typeof props === 'string' && props in obj)
        return obj[props];
    return ((Array.isArray(props) ? props : props.split('.')).reduce((acc, prop) => (acc === undefined ? acc : acc[prop]), obj) || null);
}
function getSearchItems(searchPlaces, searchPaths) {
    return searchPaths.reduce((acc, searchPath) => {
        searchPlaces.forEach(sp => acc.push({
            searchPlace: sp,
            filepath: path.join(searchPath, sp),
            loaderKey: path.extname(sp) || 'noExt',
        }));
        return acc;
    }, []);
}
function validateFilePath(filepath) {
    if (!filepath)
        throw new Error('load must pass a non-empty string');
}
function validateLoader(loader, ext) {
    if (!loader)
        throw new Error(`No loader specified for extension "${ext}"`);
    if (typeof loader !== 'function')
        throw new Error('loader is not a function');
}
function lilconfig(name, options) {
    const { ignoreEmptySearchPlaces, loaders, packageProp, searchPlaces, stopDir, transform, } = getOptions(name, options);
    return {
        async search(searchFrom = process.cwd()) {
            const searchPaths = getSearchPaths(searchFrom, stopDir);
            const result = {
                config: null,
                filepath: '',
            };
            const searchItems = getSearchItems(searchPlaces, searchPaths);
            for (const { searchPlace, filepath, loaderKey } of searchItems) {
                try {
                    await fs.promises.access(filepath);
                }
                catch (_a) {
                    continue;
                }
                const content = String(await fsReadFileAsync(filepath));
                const loader = loaders[loaderKey];
                if (searchPlace === 'package.json') {
                    const pkg = await loader(filepath, content);
                    const maybeConfig = getPackageProp(packageProp, pkg);
                    if (maybeConfig != null) {
                        result.config = maybeConfig;
                        result.filepath = filepath;
                        break;
                    }
                    continue;
                }
                const isEmpty = content.trim() === '';
                if (isEmpty && ignoreEmptySearchPlaces)
                    continue;
                if (isEmpty) {
                    result.isEmpty = true;
                    result.config = undefined;
                }
                else {
                    validateLoader(loader, loaderKey);
                    result.config = await loader(filepath, content);
                }
                result.filepath = filepath;
                break;
            }
            if (result.filepath === '' && result.config === null)
                return transform(null);
            return transform(result);
        },
        async load(filepath) {
            validateFilePath(filepath);
            const absPath = path.resolve(process.cwd(), filepath);
            const { base, ext } = path.parse(absPath);
            const loaderKey = ext || 'noExt';
            const loader = loaders[loaderKey];
            validateLoader(loader, loaderKey);
            const content = String(await fsReadFileAsync(absPath));
            if (base === 'package.json') {
                const pkg = await loader(absPath, content);
                return transform({
                    config: getPackageProp(packageProp, pkg),
                    filepath: absPath,
                });
            }
            const result = {
                config: null,
                filepath: absPath,
            };
            const isEmpty = content.trim() === '';
            if (isEmpty && ignoreEmptySearchPlaces)
                return transform({
                    config: undefined,
                    filepath: absPath,
                    isEmpty: true,
                });
            result.config = isEmpty
                ? undefined
                : await loader(absPath, content);
            return transform(isEmpty ? { ...result, isEmpty, config: undefined } : result);
        },
    };
}
exports.lilconfig = lilconfig;
function lilconfigSync(name, options) {
    const { ignoreEmptySearchPlaces, loaders, packageProp, searchPlaces, stopDir, transform, } = getOptions(name, options);
    return {
        search(searchFrom = process.cwd()) {
            const searchPaths = getSearchPaths(searchFrom, stopDir);
            const result = {
                config: null,
                filepath: '',
            };
            const searchItems = getSearchItems(searchPlaces, searchPaths);
            for (const { searchPlace, filepath, loaderKey } of searchItems) {
                try {
                    fs.accessSync(filepath);
                }
                catch (_a) {
                    continue;
                }
                const loader = loaders[loaderKey];
                const content = String(fs.readFileSync(filepath));
                if (searchPlace === 'package.json') {
                    const pkg = loader(filepath, content);
                    const maybeConfig = getPackageProp(packageProp, pkg);
                    if (maybeConfig != null) {
                        result.config = maybeConfig;
                        result.filepath = filepath;
                        break;
                    }
                    continue;
                }
                const isEmpty = content.trim() === '';
                if (isEmpty && ignoreEmptySearchPlaces)
                    continue;
                if (isEmpty) {
                    result.isEmpty = true;
                    result.config = undefined;
                }
                else {
                    validateLoader(loader, loaderKey);
                    result.config = loader(filepath, content);
                }
                result.filepath = filepath;
                break;
            }
            if (result.filepath === '' && result.config === null)
                return transform(null);
            return transform(result);
        },
        load(filepath) {
            validateFilePath(filepath);
            const absPath = path.resolve(process.cwd(), filepath);
            const { base, ext } = path.parse(absPath);
            const loaderKey = ext || 'noExt';
            const loader = loaders[loaderKey];
            validateLoader(loader, loaderKey);
            const content = String(fs.readFileSync(absPath));
            if (base === 'package.json') {
                const pkg = loader(absPath, content);
                return transform({
                    config: getPackageProp(packageProp, pkg),
                    filepath: absPath,
                });
            }
            const result = {
                config: null,
                filepath: absPath,
            };
            const isEmpty = content.trim() === '';
            if (isEmpty && ignoreEmptySearchPlaces)
                return transform({
                    filepath: absPath,
                    config: undefined,
                    isEmpty: true,
                });
            result.config = isEmpty ? undefined : loader(absPath, content);
            return transform(isEmpty ? { ...result, isEmpty, config: undefined } : result);
        },
    };
}
exports.lilconfigSync = lilconfigSync;


lilconfig

description: A zero-dependency alternative to cosmiconfig

prebuild: npm run clean

build: tsc --declaration

postbuild: du -h ./dist/*

clean: rm -rf ./dist

test: jest --coverage

lint: eslint ./src/*.ts

keywords: cosmiconfig config configuration search


code:
# Lilconfig ⚙
[![npm version](https://badge.fury.io/js/lilconfig.svg)](https://badge.fury.io/js/lilconfig)
[![install size](https://packagephobia.now.sh/badge?p=lilconfig)](https://packagephobia.now.sh/result?p=lilconfig)
[![Coverage Status](https://coveralls.io/repos/github/antonk52/lilconfig/badge.svg)](https://coveralls.io/github/antonk52/lilconfig)

A zero-dependency alternative to [cosmiconfig](https://www.npmjs.com/package/cosmiconfig) with the same API.

## Installation

```sh
npm install lilconfig
```

## Usage

```js
import {lilconfig, lilconfigSync} from 'lilconfig';

// all keys are optional
const options = {
    stopDir: '/Users/you/some/dir',
    searchPlaces: ['package.json', 'myapp.conf.js'],
    ignoreEmptySearchPlaces: false
}

lilconfig(
    'myapp',
    options // optional
).search() // Promise<LilconfigResult>

lilconfigSync(
    'myapp',
    options // optional
).load(pathToConfig) // LilconfigResult

/**
 * LilconfigResult
 * {
 *   config: any; // your config
 *   filepath: string;
 * }
 */
```

## Difference to `cosmiconfig`
Lilconfig does not intend to be 100% compatible with `cosmiconfig` but tries to mimic it where possible. The key differences are:
- **no** support for yaml files out of the box(`lilconfig` attempts to parse files with no extension as JSON instead of YAML). You can still add the support for YAML files by providing a loader, see an [example](#yaml-loader) below.
- **no** cache

### Options difference between the two.

|cosmiconfig option      | lilconfig |
|------------------------|-----------|
|cache                   | ❌        |
|loaders                 | ✅        |
|ignoreEmptySearchPlaces | ✅        |
|packageProp             | ✅        |
|searchPlaces            | ✅        |
|stopDir                 | ✅        |
|transform               | ✅        |

## Loaders examples

### Yaml loader

If you need the YAML support you can provide your own loader

```js
import {lilconfig} from 'lilconfig';
import yaml from 'yaml';

function loadYaml(filepath, content) {
    return yaml.parse(content);
}

const options = {
    loaders: {
        '.yaml': loadYaml,
        '.yml': loadYaml,
        // loader for files with no extension
        noExt: loadYaml
    }
};

lilconfig('myapp', options)
    .search()
    .then(result => {
        result // {config, filepath}
    });
```

### ESM loader

Lilconfig v2 does not support ESM modules out of the box. However, you can support it with a custom a loader. Note that this will only work with the async `lilconfig` function and won't work with the sync `lilconfigSync`.

```js
import {lilconfig} from 'lilconfig';

const loadEsm = filepath => import(filepath);

lilconfig('myapp', {
    loaders: {
        '.js': loadEsm,
        '.mjs': loadEsm,
    }
})
    .search()
    .then(result => {
        result // {config, filepath}

        result.config.default // if config uses `export default`
    });
```

## Version correlation

- lilconig v1 → cosmiconfig v6
- lilconig v2 → cosmiconfig v7


code:
# lines-and-columns

Maps lines and columns to character offsets and back. This is useful for parsers
and other text processors that deal in character ranges but process text with
meaningful lines and columns.

## Install

```
$ npm install [--save] lines-and-columns
```

## Usage

```js
import { LinesAndColumns } from 'lines-and-columns'

const lines = new LinesAndColumns(
  `table {
  border: 0
}`
)

lines.locationForIndex(9)
// { line: 1, column: 1 }

lines.indexForLocation({ line: 1, column: 2 })
// 10
```

## License

MIT


code:
export declare type SourceLocation = {
    line: number;
    column: number;
};
export declare class LinesAndColumns {
    private string;
    private offsets;
    constructor(string: string);
    locationForIndex(index: number): SourceLocation | null;
    indexForLocation(location: SourceLocation): number | null;
    private lengthOfLine;
}
export default LinesAndColumns;


code:
"use strict";
exports.__esModule = true;
exports.LinesAndColumns = void 0;
var LF = '\n';
var CR = '\r';
var LinesAndColumns = /** @class */ (function () {
    function LinesAndColumns(string) {
        this.string = string;
        var offsets = [0];
        for (var offset = 0; offset < string.length;) {
            switch (string[offset]) {
                case LF:
                    offset += LF.length;
                    offsets.push(offset);
                    break;
                case CR:
                    offset += CR.length;
                    if (string[offset] === LF) {
                        offset += LF.length;
                    }
                    offsets.push(offset);
                    break;
                default:
                    offset++;
                    break;
            }
        }
        this.offsets = offsets;
    }
    LinesAndColumns.prototype.locationForIndex = function (index) {
        if (index < 0 || index > this.string.length) {
            return null;
        }
        var line = 0;
        var offsets = this.offsets;
        while (offsets[line + 1] <= index) {
            line++;
        }
        var column = index - offsets[line];
        return { line: line, column: column };
    };
    LinesAndColumns.prototype.indexForLocation = function (location) {
        var line = location.line, column = location.column;
        if (line < 0 || line >= this.offsets.length) {
            return null;
        }
        if (column < 0 || column > this.lengthOfLine(line)) {
            return null;
        }
        return this.offsets[line] + column;
    };
    LinesAndColumns.prototype.lengthOfLine = function (line) {
        var offset = this.offsets[line];
        var nextOffset = line === this.offsets.length - 1
            ? this.string.length
            : this.offsets[line + 1];
        return nextOffset - offset;
    };
    return LinesAndColumns;
}());
exports.LinesAndColumns = LinesAndColumns;
exports["default"] = LinesAndColumns;


lines-and-columns

description: Maps lines and columns to character offsets and back.

keywords: lines columns parser

author: Brian Donovan <brian@donovans.cc>

build:watch: tsc --build tsconfig.build.json --watch

lint: eslint .

lint:fix: eslint . --fix

test: is-ci test:coverage test:watch

test:coverage: jest --coverage

test:watch: jest --watch