nuclide-commons
Advanced tools
Comparing version 0.1.0 to 0.1.1
@@ -1,35 +0,1 @@ | ||
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { | ||
value: true | ||
}); | ||
exports.arrayRemove = arrayRemove; | ||
exports.arrayEqual = arrayEqual; | ||
exports.arrayCompact = arrayCompact; | ||
exports.arrayFlatten = arrayFlatten; | ||
exports.arrayUnique = arrayUnique; | ||
exports.arrayFindLastIndex = arrayFindLastIndex; | ||
exports.mapUnion = mapUnion; | ||
exports.mapFilter = mapFilter; | ||
exports.mapTransform = mapTransform; | ||
exports.mapEqual = mapEqual; | ||
exports.mapGetWithDefault = mapGetWithDefault; | ||
exports.areSetsEqual = areSetsEqual; | ||
exports.every = every; | ||
exports.setIntersect = setIntersect; | ||
exports.setUnion = setUnion; | ||
exports.setDifference = setDifference; | ||
exports.isEmpty = isEmpty; | ||
exports.keyMirror = keyMirror; | ||
exports.collect = collect; | ||
exports.objectEntries = objectEntries; | ||
exports.objectFromMap = objectFromMap; | ||
exports.concatIterators = concatIterators; | ||
exports.someOfIterable = someOfIterable; | ||
exports.findInIterable = findInIterable; | ||
exports.filterIterable = filterIterable; | ||
exports.mapIterable = mapIterable; | ||
exports.firstOfIterable = firstOfIterable; | ||
exports.iterableIsEmpty = iterableIsEmpty; | ||
exports.iterableContains = iterableContains; | ||
/** | ||
@@ -42,7 +8,7 @@ * Copyright (c) 2015-present, Facebook, Inc. | ||
* | ||
* | ||
* @flow | ||
* @format | ||
*/ | ||
function arrayRemove(array, element) { | ||
export function arrayRemove<T>(array: Array<T>, element: T): void { | ||
const index = array.indexOf(element); | ||
@@ -54,7 +20,11 @@ if (index >= 0) { | ||
function arrayEqual(array1, array2, equalComparator) { | ||
export function arrayEqual<T>( | ||
array1: Array<T>, | ||
array2: Array<T>, | ||
equalComparator?: (a: T, b: T) => boolean, | ||
): boolean { | ||
if (array1.length !== array2.length) { | ||
return false; | ||
} | ||
const equalFunction = equalComparator || ((a, b) => a === b); | ||
const equalFunction = equalComparator || ((a: T, b: T) => a === b); | ||
return array1.every((item1, i) => equalFunction(item1, array2[i])); | ||
@@ -67,3 +37,3 @@ } | ||
*/ | ||
function arrayCompact(array) { | ||
export function arrayCompact<T>(array: Array<?T>): Array<T> { | ||
const result = []; | ||
@@ -81,3 +51,3 @@ for (const elem of array) { | ||
*/ | ||
function arrayFlatten(array) { | ||
export function arrayFlatten<T>(array: Array<Array<T>>): Array<T> { | ||
const result = []; | ||
@@ -95,3 +65,3 @@ for (const subArray of array) { | ||
*/ | ||
function arrayUnique(array) { | ||
export function arrayUnique<T>(array: Array<T>): Array<T> { | ||
return Array.from(new Set(array)); | ||
@@ -104,3 +74,7 @@ } | ||
*/ | ||
function arrayFindLastIndex(array, predicate, thisArg) { | ||
export function arrayFindLastIndex<T>( | ||
array: Array<T>, | ||
predicate: (elem: T, index: number, array: Array<T>) => boolean, | ||
thisArg?: any, | ||
): number { | ||
for (let i = array.length - 1; i >= 0; i--) { | ||
@@ -118,3 +92,3 @@ if (predicate.call(thisArg, array[i], i, array)) { | ||
*/ | ||
function mapUnion(...maps) { | ||
export function mapUnion<T, X>(...maps: Array<Map<T, X>>): Map<T, X> { | ||
const unionMap = new Map(); | ||
@@ -129,3 +103,6 @@ for (const map of maps) { | ||
function mapFilter(map, selector) { | ||
export function mapFilter<T, X>( | ||
map: Map<T, X>, | ||
selector: (key: T, value: X) => boolean, | ||
): Map<T, X> { | ||
const selected = new Map(); | ||
@@ -140,3 +117,6 @@ for (const [key, value] of map) { | ||
function mapTransform(src, transform) { | ||
export function mapTransform<T, V1, V2>( | ||
src: Map<T, V1>, | ||
transform: (value: V1, key: T) => V2, | ||
): Map<T, V2> { | ||
const result = new Map(); | ||
@@ -149,9 +129,13 @@ for (const [key, value] of src) { | ||
function mapEqual(map1, map2, equalComparator) { | ||
export function mapEqual<T, X>( | ||
map1: Map<T, X>, | ||
map2: Map<T, X>, | ||
equalComparator?: (val1: X, val2: X, key1?: T, key2?: T) => boolean, | ||
) { | ||
if (map1.size !== map2.size) { | ||
return false; | ||
} | ||
const equalFunction = equalComparator || ((a, b) => a === b); | ||
const equalFunction = equalComparator || ((a: X, b: X) => a === b); | ||
for (const [key1, value1] of map1) { | ||
if (!map2.has(key1) || !equalFunction(value1, map2.get(key1))) { | ||
if (!map2.has(key1) || !equalFunction(value1, (map2.get(key1): any))) { | ||
return false; | ||
@@ -163,3 +147,7 @@ } | ||
function mapGetWithDefault(map, key, default_) { | ||
export function mapGetWithDefault<K, V>( | ||
map: Map<K, V>, | ||
key: K, | ||
default_: V, | ||
): V { | ||
if (map.has(key)) { | ||
@@ -169,3 +157,3 @@ // Cast through `any` since map.get's return is a maybe type. We can't just get the value and | ||
// just checked that the map has the key. | ||
return map.get(key); | ||
return (map.get(key): any); | ||
} else { | ||
@@ -176,3 +164,3 @@ return default_; | ||
function areSetsEqual(a, b) { | ||
export function areSetsEqual<T>(a: Set<T>, b: Set<T>): boolean { | ||
return a.size === b.size && every(a, element => b.has(element)); | ||
@@ -182,3 +170,6 @@ } | ||
// Array.every but for any iterable. | ||
function every(values, predicate) { | ||
export function every<T>( | ||
values: Iterable<T>, | ||
predicate: (element: T) => boolean, | ||
): boolean { | ||
for (const element of values) { | ||
@@ -192,7 +183,7 @@ if (!predicate(element)) { | ||
function setIntersect(a, b) { | ||
export function setIntersect<T>(a: Set<T>, b: Set<T>): Set<T> { | ||
return new Set(Array.from(a).filter(e => b.has(e))); | ||
} | ||
function setUnion(a, b) { | ||
export function setUnion<T>(a: Set<T>, b: Set<T>): Set<T> { | ||
// Avoids the extra Array allocations that `new Set([...a, ...b])` would incur. Some quick tests | ||
@@ -207,3 +198,7 @@ // indicate it would be about 60% slower. | ||
function setDifference(a, b, hash_) { | ||
export function setDifference<T>( | ||
a: Set<T>, | ||
b: Set<T>, | ||
hash_?: (v: T) => any, | ||
): Set<T> { | ||
if (a.size === 0) { | ||
@@ -228,3 +223,3 @@ return new Set(); | ||
*/ | ||
function isEmpty(obj) { | ||
export function isEmpty(obj: Object): boolean { | ||
for (const key in obj) { | ||
@@ -242,3 +237,3 @@ return false; | ||
*/ | ||
function keyMirror(obj) { | ||
export function keyMirror<T: Object>(obj: T): {[key: $Enum<T>]: $Enum<T>} { | ||
const ret = {}; | ||
@@ -255,3 +250,3 @@ Object.keys(obj).forEach(key => { | ||
*/ | ||
function collect(pairs) { | ||
export function collect<K, V>(pairs: Array<[K, V]>): Map<K, Array<V>> { | ||
const result = new Map(); | ||
@@ -270,4 +265,13 @@ for (const pair of pairs) { | ||
class MultiMap { | ||
export class MultiMap<K, V> { | ||
// Invariant: no empty sets. They should be removed instead. | ||
_map: Map<K, Set<V>>; | ||
// TODO may be worth defining a getter but no setter, to mimic Map. But please just behave and | ||
// don't mutate this from outside this class. | ||
// | ||
// Invariant: equal to the sum of the sizes of all the sets contained in this._map | ||
/* The total number of key-value bindings contained */ | ||
size: number; | ||
constructor() { | ||
@@ -282,10 +286,3 @@ this._map = new Map(); | ||
*/ | ||
// TODO may be worth defining a getter but no setter, to mimic Map. But please just behave and | ||
// don't mutate this from outside this class. | ||
// | ||
// Invariant: equal to the sum of the sizes of all the sets contained in this._map | ||
/* The total number of key-value bindings contained */ | ||
get(key) { | ||
get(key: K): Set<V> { | ||
const set = this._map.get(key); | ||
@@ -302,3 +299,3 @@ if (set == null) { | ||
*/ | ||
add(key, value) { | ||
add(key: K, value: V): MultiMap<K, V> { | ||
let set = this._map.get(key); | ||
@@ -319,3 +316,3 @@ if (set == null) { | ||
*/ | ||
set(key, values) { | ||
set(key: K, values: Iterable<V>): void { | ||
this.deleteAll(key); | ||
@@ -332,3 +329,3 @@ const newSet = new Set(values); | ||
*/ | ||
delete(key, value) { | ||
delete(key: K, value: V): boolean { | ||
const set = this.get(key); | ||
@@ -348,3 +345,3 @@ const didRemove = set.delete(value); | ||
*/ | ||
deleteAll(key) { | ||
deleteAll(key: K): boolean { | ||
const set = this.get(key); | ||
@@ -355,3 +352,3 @@ this.size -= set.size; | ||
clear() { | ||
clear(): void { | ||
this._map.clear(); | ||
@@ -361,11 +358,11 @@ this.size = 0; | ||
has(key, value) { | ||
has(key: K, value: V): boolean { | ||
return this.get(key).has(value); | ||
} | ||
hasAny(key) { | ||
hasAny(key: K): boolean { | ||
return this._map.has(key); | ||
} | ||
*values() { | ||
*values(): Iterable<V> { | ||
for (const set of this._map.values()) { | ||
@@ -376,9 +373,10 @@ yield* set; | ||
forEach(callback) { | ||
this._map.forEach((values, key) => values.forEach(value => callback(value, key, this))); | ||
forEach(callback: (value: V, key: K, obj: MultiMap<K, V>) => void): void { | ||
this._map.forEach((values, key) => | ||
values.forEach(value => callback(value, key, this)), | ||
); | ||
} | ||
} | ||
exports.MultiMap = MultiMap; | ||
function objectEntries(obj) { | ||
export function objectEntries<T>(obj: {[key: string]: T}): Array<[string, T]> { | ||
if (obj == null) { | ||
@@ -389,3 +387,6 @@ throw new TypeError(); | ||
for (const key in obj) { | ||
if (obj.hasOwnProperty(key) && Object.prototype.propertyIsEnumerable.call(obj, key)) { | ||
if ( | ||
obj.hasOwnProperty(key) && | ||
Object.prototype.propertyIsEnumerable.call(obj, key) | ||
) { | ||
entries.push([key, obj[key]]); | ||
@@ -397,3 +398,3 @@ } | ||
function objectFromMap(map) { | ||
export function objectFromMap<T>(map: Map<string, T>): {[key: string]: T} { | ||
const obj = {}; | ||
@@ -406,3 +407,5 @@ map.forEach((v, k) => { | ||
function* concatIterators(...iterators) { | ||
export function* concatIterators<T>( | ||
...iterators: Array<Iterable<T>> | ||
): Iterator<T> { | ||
for (const iterator of iterators) { | ||
@@ -415,3 +418,6 @@ for (const element of iterator) { | ||
function someOfIterable(iterable, predicate) { | ||
export function someOfIterable<T>( | ||
iterable: Iterable<T>, | ||
predicate: (element: T) => boolean, | ||
): boolean { | ||
for (const element of iterable) { | ||
@@ -425,3 +431,6 @@ if (predicate(element)) { | ||
function findInIterable(iterable, predicate) { | ||
export function findInIterable<T>( | ||
iterable: Iterable<T>, | ||
predicate: (element: T) => boolean, | ||
): ?T { | ||
for (const element of iterable) { | ||
@@ -435,3 +444,6 @@ if (predicate(element)) { | ||
function* filterIterable(iterable, predicate) { | ||
export function* filterIterable<T>( | ||
iterable: Iterable<T>, | ||
predicate: (element: T) => boolean, | ||
): Iterable<T> { | ||
for (const element of iterable) { | ||
@@ -444,3 +456,6 @@ if (predicate(element)) { | ||
function* mapIterable(iterable, projectorFn) { | ||
export function* mapIterable<T, M>( | ||
iterable: Iterable<T>, | ||
projectorFn: (element: T) => M, | ||
): Iterable<M> { | ||
for (const element of iterable) { | ||
@@ -451,7 +466,7 @@ yield projectorFn(element); | ||
function firstOfIterable(iterable) { | ||
export function firstOfIterable<T>(iterable: Iterable<T>): ?T { | ||
return findInIterable(iterable, () => true); | ||
} | ||
function iterableIsEmpty(iterable) { | ||
export function iterableIsEmpty<T>(iterable: Iterable<T>): boolean { | ||
// eslint-disable-next-line no-unused-vars | ||
@@ -464,4 +479,6 @@ for (const element of iterable) { | ||
function iterableContains(iterable, value) { | ||
return !iterableIsEmpty(filterIterable(iterable, element => element === value)); | ||
} | ||
export function iterableContains<T>(iterable: Iterable<T>, value: T): boolean { | ||
return !iterableIsEmpty( | ||
filterIterable(iterable, element => element === value), | ||
); | ||
} |
@@ -1,16 +0,35 @@ | ||
'use strict'; | ||
/** | ||
* Copyright (c) 2015-present, Facebook, Inc. | ||
* All rights reserved. | ||
* | ||
* This source code is licensed under the license found in the LICENSE file in | ||
* the root directory of this source tree. | ||
* | ||
* @flow | ||
* @format | ||
*/ | ||
Object.defineProperty(exports, "__esModule", { | ||
value: true | ||
}); | ||
exports.default = debounce; | ||
function debounce(func, wait, immediate = false) { | ||
import invariant from 'assert'; | ||
export default function debounce< | ||
T, | ||
TArgs: Array<T>, | ||
TReturn, | ||
TFunc: (...TArgs) => TReturn, // eslint-disable-line space-before-function-paren | ||
>( | ||
func: TFunc, | ||
wait: number, | ||
immediate?: boolean = false, | ||
): { | ||
(...TArgs): TReturn | void, | ||
dispose(): void, | ||
} { | ||
// Taken from: https://github.com/jashkenas/underscore/blob/b10b2e6d72/underscore.js#L815. | ||
let timeout; | ||
let args; | ||
let context; | ||
let timeout: ?number; | ||
let args: ?TArgs; | ||
let context: any; | ||
let timestamp = 0; | ||
let result; | ||
let result: TReturn | void; | ||
const later = function () { | ||
const later = function() { | ||
const last = Date.now() - timestamp; | ||
@@ -23,6 +42,3 @@ | ||
if (!immediate) { | ||
if (!(args != null)) { | ||
throw new Error('Invariant violation: "args != null"'); | ||
} | ||
invariant(args != null); | ||
result = func.apply(context, args); | ||
@@ -36,3 +52,3 @@ if (!timeout) { | ||
const debounced = function (...args_) { | ||
const debounced = function(...args_: TArgs): TReturn | void { | ||
context = this; | ||
@@ -61,11 +77,2 @@ args = args_; | ||
return debounced; | ||
} /** | ||
* Copyright (c) 2015-present, Facebook, Inc. | ||
* All rights reserved. | ||
* | ||
* This source code is licensed under the license found in the LICENSE file in | ||
* the root directory of this source tree. | ||
* | ||
* | ||
* @format | ||
*/ | ||
} |
50
event.js
@@ -1,23 +0,2 @@ | ||
'use strict'; | ||
Object.defineProperty(exports, "__esModule", { | ||
value: true | ||
}); | ||
exports.attachEvent = attachEvent; | ||
exports.observableFromSubscribeFunction = observableFromSubscribeFunction; | ||
var _eventKit; | ||
function _load_eventKit() { | ||
return _eventKit = require('event-kit'); | ||
} | ||
var _rxjsBundlesRxMinJs = require('rxjs/bundles/Rx.min.js'); | ||
/** | ||
* Add an event listener an return a disposable for removing it. Note that this function assumes | ||
* node EventEmitter semantics: namely, that adding the same combination of eventName and callback | ||
* adds a second listener. | ||
*/ | ||
/** | ||
* Copyright (c) 2015-present, Facebook, Inc. | ||
@@ -29,9 +8,21 @@ * All rights reserved. | ||
* | ||
* | ||
* @flow | ||
* @format | ||
*/ | ||
function attachEvent(emitter, eventName, callback) { | ||
import {Disposable} from 'event-kit'; | ||
import {Observable} from 'rxjs'; | ||
/** | ||
* Add an event listener an return a disposable for removing it. Note that this function assumes | ||
* node EventEmitter semantics: namely, that adding the same combination of eventName and callback | ||
* adds a second listener. | ||
*/ | ||
export function attachEvent( | ||
emitter: events$EventEmitter, | ||
eventName: string, | ||
callback: Function, | ||
): Disposable { | ||
emitter.addListener(eventName, callback); | ||
return new (_eventKit || _load_eventKit()).Disposable(() => { | ||
return new Disposable(() => { | ||
emitter.removeListener(eventName, callback); | ||
@@ -41,4 +32,9 @@ }); | ||
function observableFromSubscribeFunction(fn) { | ||
return _rxjsBundlesRxMinJs.Observable.create(observer => { | ||
type SubscribeCallback<T> = (item: T) => any; | ||
type SubscribeFunction<T> = (callback: SubscribeCallback<T>) => IDisposable; | ||
export function observableFromSubscribeFunction<T>( | ||
fn: SubscribeFunction<T>, | ||
): Observable<T> { | ||
return Observable.create(observer => { | ||
const disposable = fn(observer.next.bind(observer)); | ||
@@ -49,2 +45,2 @@ return () => { | ||
}); | ||
} | ||
} |
@@ -1,42 +0,49 @@ | ||
'use strict'; | ||
/** | ||
* Copyright (c) 2015-present, Facebook, Inc. | ||
* All rights reserved. | ||
* | ||
* This source code is licensed under the license found in the LICENSE file in | ||
* the root directory of this source tree. | ||
* | ||
* @flow | ||
* @format | ||
*/ | ||
Object.defineProperty(exports, "__esModule", { | ||
value: true | ||
}); | ||
exports.__TEST__ = undefined; | ||
// NuclideUri's are either a local file path, or a URI | ||
// of the form nuclide://<host><path> | ||
// | ||
// This package creates, queries and decomposes NuclideUris. | ||
var _path = _interopRequireDefault(require('path')); | ||
export type NuclideUri = string; | ||
var _url = _interopRequireDefault(require('url')); | ||
type ParsedUrl = { | ||
hostname: ?string, | ||
path: string, | ||
}; | ||
var _os = _interopRequireDefault(require('os')); | ||
type ParsedRemoteUrl = { | ||
hostname: string, | ||
path: string, | ||
}; | ||
var _string; | ||
type ParsedPath = { | ||
root: string, | ||
dir: string, | ||
base: string, | ||
ext: string, | ||
name: string, | ||
}; | ||
function _load_string() { | ||
return _string = require('./string'); | ||
} | ||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } | ||
import invariant from 'assert'; | ||
// eslint-disable-next-line nuclide-internal/prefer-nuclide-uri | ||
const REMOTE_PATH_URI_PREFIX = 'nuclide://'; /** | ||
* Copyright (c) 2015-present, Facebook, Inc. | ||
* All rights reserved. | ||
* | ||
* This source code is licensed under the license found in the LICENSE file in | ||
* the root directory of this source tree. | ||
* | ||
* | ||
* @format | ||
*/ | ||
import pathModule from 'path'; | ||
// NuclideUri's are either a local file path, or a URI | ||
// of the form nuclide://<host><path> | ||
// | ||
// This package creates, queries and decomposes NuclideUris. | ||
import url from 'url'; | ||
import os from 'os'; | ||
import {maybeToString} from './string'; | ||
const REMOTE_PATH_URI_PREFIX = 'nuclide://'; | ||
const URI_PREFIX_REGEX = /^[A-Za-z0-9_-]+:\/\/.*/; | ||
function isRemote(uri) { | ||
function isRemote(uri: NuclideUri): boolean { | ||
return uri.startsWith(REMOTE_PATH_URI_PREFIX); | ||
@@ -48,3 +55,3 @@ } | ||
// and are destroyed during Nuclide startup. | ||
function isBrokenDeserializedUri(uri) { | ||
function isBrokenDeserializedUri(uri: ?NuclideUri): boolean { | ||
return uri != null && uri.match(/nuclide:[\\/][^/]/) != null; | ||
@@ -54,19 +61,19 @@ } | ||
// Atom often puts its URIs in places where we'd expect to see Nuclide URIs (or plain paths) | ||
function isAtomUri(uri) { | ||
function isAtomUri(uri: NuclideUri): boolean { | ||
return uri.startsWith('atom://'); | ||
} | ||
function isUri(uri) { | ||
function isUri(uri: string): boolean { | ||
return URI_PREFIX_REGEX.test(uri); | ||
} | ||
function isLocal(uri) { | ||
function isLocal(uri: NuclideUri): boolean { | ||
return !isRemote(uri) && !isUri(uri) && !isAtomUri(uri); | ||
} | ||
function createRemoteUri(hostname, remotePath) { | ||
if (!(remotePath != null && remotePath !== '')) { | ||
throw new Error('NuclideUri must include a path.'); | ||
} | ||
function createRemoteUri(hostname: string, remotePath: string): string { | ||
invariant( | ||
remotePath != null && remotePath !== '', | ||
'NuclideUri must include a path.', | ||
); | ||
return `nuclide://${hostname}${remotePath}`; | ||
@@ -84,3 +91,3 @@ } | ||
*/ | ||
function parse(uri) { | ||
function parse(uri: NuclideUri): ParsedUrl { | ||
if (uri.startsWith(REMOTE_PATH_URI_PREFIX)) { | ||
@@ -90,24 +97,26 @@ const hostAndPath = uri.substr(REMOTE_PATH_URI_PREFIX.length); | ||
if (!(hostSep !== -1)) { | ||
throw new Error(`Remote URIs must contain a hostname and a path. Failed to parse ${uri}`); | ||
} | ||
invariant( | ||
hostSep !== -1, | ||
`Remote URIs must contain a hostname and a path. Failed to parse ${uri}`, | ||
); | ||
const hostname = hostAndPath.substr(0, hostSep); | ||
invariant( | ||
hostname !== '', | ||
`Remote URIs must contain a hostname. Failed to parse ${uri}`, | ||
); | ||
if (!(hostname !== '')) { | ||
throw new Error(`Remote URIs must contain a hostname. Failed to parse ${uri}`); | ||
} | ||
const path = hostAndPath.substr(hostSep); | ||
return { hostname, path }; | ||
return {hostname, path}; | ||
} | ||
if (!(uri.indexOf('://') === -1)) { | ||
throw new Error('Nuclide URI must be either local file names or URLs starting with nuclide://'); | ||
} | ||
invariant( | ||
uri.indexOf('://') === -1, | ||
'Nuclide URI must be either local file names or URLs starting with nuclide://', | ||
); | ||
return { hostname: null, path: uri }; | ||
return {hostname: null, path: uri}; | ||
} | ||
function parseRemoteUri(remoteUri) { | ||
function parseRemoteUri(remoteUri: NuclideUri): ParsedRemoteUrl { | ||
if (!isRemote(remoteUri)) { | ||
@@ -117,26 +126,25 @@ throw new Error('Expected remote uri. Got ' + remoteUri); | ||
const parsedUri = parse(remoteUri); | ||
invariant( | ||
parsedUri.hostname, | ||
`Remote Nuclide URIs must contain hostnames, '${maybeToString(parsedUri.hostname)}' found ` + | ||
`while parsing '${remoteUri}'`, | ||
); | ||
if (!parsedUri.hostname) { | ||
throw new Error(`Remote Nuclide URIs must contain hostnames, '${(0, (_string || _load_string()).maybeToString)(parsedUri.hostname)}' found ` + `while parsing '${remoteUri}'`); | ||
} | ||
// Explicitly copying object properties appeases Flow's "maybe" type handling. Using the `...` | ||
// operator causes null/undefined errors, and `Object.assign` bypasses type checking. | ||
return { | ||
hostname: parsedUri.hostname, | ||
path: parsedUri.path | ||
path: parsedUri.path, | ||
}; | ||
} | ||
function getPath(uri) { | ||
function getPath(uri: NuclideUri): string { | ||
return parse(uri).path; | ||
} | ||
function getHostname(remoteUri) { | ||
function getHostname(remoteUri: NuclideUri): string { | ||
return parseRemoteUri(remoteUri).hostname; | ||
} | ||
function getHostnameOpt(remoteUri) { | ||
function getHostnameOpt(remoteUri: ?NuclideUri): ?string { | ||
if (remoteUri == null || !isRemote(remoteUri)) { | ||
@@ -149,9 +157,12 @@ return null; | ||
function join(uri, ...relativePath) { | ||
function join(uri: NuclideUri, ...relativePath: Array<string>): NuclideUri { | ||
_testForAtomUri(uri); | ||
const uriPathModule = _pathModuleFor(uri); | ||
if (isRemote(uri)) { | ||
const { hostname, path } = parseRemoteUri(uri); | ||
const {hostname, path} = parseRemoteUri(uri); | ||
relativePath.splice(0, 0, path); | ||
return createRemoteUri(hostname, uriPathModule.join.apply(null, relativePath)); | ||
return createRemoteUri( | ||
hostname, | ||
uriPathModule.join.apply(null, relativePath), | ||
); | ||
} else { | ||
@@ -163,7 +174,7 @@ relativePath.splice(0, 0, uri); | ||
function normalize(uri) { | ||
function normalize(uri: NuclideUri): NuclideUri { | ||
_testForAtomUri(uri); | ||
const uriPathModule = _pathModuleFor(uri); | ||
if (isRemote(uri)) { | ||
const { hostname, path } = parseRemoteUri(uri); | ||
const {hostname, path} = parseRemoteUri(uri); | ||
return createRemoteUri(hostname, uriPathModule.normalize(path)); | ||
@@ -175,7 +186,7 @@ } else { | ||
function normalizeDir(uri) { | ||
function normalizeDir(uri: NuclideUri): NuclideUri { | ||
return ensureTrailingSeparator(normalize(uri)); | ||
} | ||
function getParent(uri) { | ||
function getParent(uri: NuclideUri): NuclideUri { | ||
// TODO: Is this different than dirname? | ||
@@ -185,8 +196,13 @@ return normalize(join(uri, '..')); | ||
function relative(uri, other) { | ||
function relative(uri: NuclideUri, other: NuclideUri): string { | ||
_testForAtomUri(uri); | ||
const uriPathModule = _pathModuleFor(uri); | ||
const remote = isRemote(uri); | ||
if (remote !== isRemote(other) || remote && getHostname(uri) !== getHostname(other)) { | ||
throw new Error(`Cannot relative urls on different hosts: ${uri} and ${other}`); | ||
if ( | ||
remote !== isRemote(other) || | ||
(remote && getHostname(uri) !== getHostname(other)) | ||
) { | ||
throw new Error( | ||
`Cannot relative urls on different hosts: ${uri} and ${other}`, | ||
); | ||
} | ||
@@ -200,3 +216,3 @@ if (remote) { | ||
function basename(uri, ext = '') { | ||
function basename(uri: NuclideUri, ext: string = ''): string { | ||
_testForAtomUri(uri); | ||
@@ -207,7 +223,7 @@ const uriPathModule = _pathModuleFor(uri); | ||
function dirname(uri) { | ||
function dirname(uri: NuclideUri): NuclideUri { | ||
_testForAtomUri(uri); | ||
const uriPathModule = _pathModuleFor(uri); | ||
if (isRemote(uri)) { | ||
const { hostname, path } = parseRemoteUri(uri); | ||
const {hostname, path} = parseRemoteUri(uri); | ||
return createRemoteUri(hostname, uriPathModule.dirname(path)); | ||
@@ -219,3 +235,3 @@ } else { | ||
function extname(uri) { | ||
function extname(uri: NuclideUri): string { | ||
_testForAtomUri(uri); | ||
@@ -226,3 +242,3 @@ const uriPathModule = _pathModuleFor(uri); | ||
function stripExtension(uri) { | ||
function stripExtension(uri: NuclideUri): NuclideUri { | ||
_testForAtomUri(uri); | ||
@@ -237,7 +253,7 @@ const ext = extname(uri); | ||
function _isWindowsPath(path) { | ||
return _pathModuleFor(path) === _path.default.win32; | ||
function _isWindowsPath(path: string): boolean { | ||
return _pathModuleFor(path) === pathModule.win32; | ||
} | ||
function _getWindowsPathFromWindowsFileUri(uri) { | ||
function _getWindowsPathFromWindowsFileUri(uri: string): ?string { | ||
const prefix = 'file://'; | ||
@@ -258,3 +274,3 @@ if (!uri.startsWith(prefix)) { | ||
*/ | ||
function uriToNuclideUri(uri) { | ||
function uriToNuclideUri(uri: string): ?string { | ||
const windowsPathFromUri = _getWindowsPathFromWindowsFileUri(uri); | ||
@@ -269,3 +285,3 @@ if (windowsPathFromUri) { | ||
const urlParts = _url.default.parse(_escapeSpecialCharacters(uri), false); | ||
const urlParts = url.parse(_escapeSpecialCharacters(uri), false); | ||
if (urlParts.protocol === 'file:' && urlParts.path) { | ||
@@ -284,3 +300,3 @@ // only handle real files for now. | ||
*/ | ||
function nuclideUriToUri(uri) { | ||
function nuclideUriToUri(uri: NuclideUri): string { | ||
_testForAtomUri(uri); | ||
@@ -297,3 +313,3 @@ if (isRemote(uri)) { | ||
*/ | ||
function contains(parent, child) { | ||
function contains(parent: NuclideUri, child: NuclideUri): boolean { | ||
_testForAtomUri(parent); | ||
@@ -344,3 +360,3 @@ _testForAtomUri(child); | ||
*/ | ||
function collapse(paths) { | ||
function collapse(paths: Array<NuclideUri>): Array<NuclideUri> { | ||
return paths.filter(p => !paths.some(fp => contains(fp, p) && fp !== p)); | ||
@@ -353,6 +369,6 @@ } | ||
// Returns null if the formatter won't shorten the hostname. | ||
export type HostnameFormatter = (uri: NuclideUri) => ?string; | ||
// Registers a host formatter for nuclideUriToDisplayString | ||
function registerHostnameFormatter(formatter) { | ||
function registerHostnameFormatter(formatter: HostnameFormatter): IDisposable { | ||
hostFormatters.push(formatter); | ||
@@ -365,3 +381,3 @@ return { | ||
} | ||
} | ||
}, | ||
}; | ||
@@ -374,3 +390,3 @@ } | ||
*/ | ||
function nuclideUriToDisplayString(uri) { | ||
function nuclideUriToDisplayString(uri: NuclideUri): string { | ||
_testForAtomUri(uri); | ||
@@ -392,3 +408,3 @@ if (isRemote(uri)) { | ||
function ensureTrailingSeparator(uri) { | ||
function ensureTrailingSeparator(uri: NuclideUri): NuclideUri { | ||
_testForAtomUri(uri); | ||
@@ -403,3 +419,3 @@ const uriPathModule = _pathModuleFor(uri); | ||
function trimTrailingSeparator(uri) { | ||
function trimTrailingSeparator(uri: NuclideUri): NuclideUri { | ||
_testForAtomUri(uri); | ||
@@ -416,3 +432,3 @@ const uriPathModule = _pathModuleFor(uri); | ||
function endsWithSeparator(uri) { | ||
function endsWithSeparator(uri: NuclideUri): boolean { | ||
_testForAtomUri(uri); | ||
@@ -423,3 +439,3 @@ const uriPathModule = _pathModuleFor(uri); | ||
function isAbsolute(uri) { | ||
function isAbsolute(uri: NuclideUri): boolean { | ||
_testForAtomUri(uri); | ||
@@ -434,7 +450,7 @@ if (isRemote(uri)) { | ||
function resolve(uri, ...paths) { | ||
function resolve(uri: NuclideUri, ...paths: Array<string>): NuclideUri { | ||
_testForAtomUri(uri); | ||
const uriPathModule = _pathModuleFor(uri); | ||
if (isRemote(uri)) { | ||
const { hostname, path } = parseRemoteUri(uri); | ||
const {hostname, path} = parseRemoteUri(uri); | ||
paths.splice(0, 0, path); | ||
@@ -448,3 +464,3 @@ return createRemoteUri(hostname, uriPathModule.resolve.apply(null, paths)); | ||
function expandHomeDir(uri) { | ||
function expandHomeDir(uri: NuclideUri): NuclideUri { | ||
_testForAtomUri(uri); | ||
@@ -460,10 +476,8 @@ | ||
// on Windows, so asking for any case is expected to work. | ||
const { HOME, UserProfile } = process.env; | ||
const {HOME, UserProfile} = process.env; | ||
const homePath = _os.default.platform() === 'win32' ? UserProfile : HOME; | ||
const isWindows = !isRemote(uri) && os.platform() === 'win32'; | ||
const homePath = isWindows ? UserProfile : HOME; | ||
invariant(homePath != null); | ||
if (!(homePath != null)) { | ||
throw new Error('Invariant violation: "homePath != null"'); | ||
} | ||
if (uri === '~') { | ||
@@ -474,7 +488,7 @@ return homePath; | ||
// Uris like ~abc should not be expanded | ||
if (!uri.startsWith('~/')) { | ||
if (!uri.startsWith('~/') && (!isWindows || !uri.startsWith('~\\'))) { | ||
return uri; | ||
} | ||
return _path.default.resolve(homePath, uri.replace('~', '.')); | ||
return pathModule.resolve(homePath, uri.replace('~', '.')); | ||
} | ||
@@ -488,7 +502,7 @@ | ||
*/ | ||
function splitPathList(paths) { | ||
if (!(paths.indexOf(REMOTE_PATH_URI_PREFIX) < 0)) { | ||
throw new Error('Splitting remote URIs is not supported'); | ||
} | ||
function splitPathList(paths: string): Array<NuclideUri> { | ||
invariant( | ||
paths.indexOf(REMOTE_PATH_URI_PREFIX) < 0, | ||
'Splitting remote URIs is not supported', | ||
); | ||
const uriPathModule = _pathModuleFor(paths); | ||
@@ -505,3 +519,3 @@ | ||
*/ | ||
function joinPathList(paths) { | ||
function joinPathList(paths: Array<NuclideUri>): string { | ||
if (paths.length === 0) { | ||
@@ -511,5 +525,6 @@ return ''; | ||
if (!paths.every(path => !isRemote(path))) { | ||
throw new Error('Joining of remote URIs is not supported'); | ||
} | ||
invariant( | ||
paths.every(path => !isRemote(path)), | ||
'Joining of remote URIs is not supported', | ||
); | ||
@@ -524,14 +539,12 @@ const uriPathModule = _pathModuleFor(paths[0]); | ||
*/ | ||
function ensureLocalPrefix(uri) { | ||
function ensureLocalPrefix(uri: NuclideUri): NuclideUri { | ||
_testForAtomUri(uri); | ||
const uriPathModule = _pathModuleFor(uri); | ||
if (!!isRemote(uri)) { | ||
throw new Error('Local prefix can not be added to a remote path'); | ||
} | ||
invariant(!isRemote(uri), 'Local prefix can not be added to a remote path'); | ||
invariant( | ||
!isAbsolute(uri), | ||
'Local prefix can not be added to an absolute path', | ||
); | ||
if (!!isAbsolute(uri)) { | ||
throw new Error('Local prefix can not be added to an absolute path'); | ||
} | ||
const localPrefix = `.${uriPathModule.sep}`; | ||
@@ -545,3 +558,3 @@ if (uri.startsWith(localPrefix)) { | ||
function isRoot(uri) { | ||
function isRoot(uri: NuclideUri): boolean { | ||
_testForAtomUri(uri); | ||
@@ -551,3 +564,3 @@ return dirname(uri) === uri; | ||
function parsePath(uri) { | ||
function parsePath(uri: NuclideUri): ParsedPath { | ||
_testForAtomUri(uri); | ||
@@ -558,7 +571,7 @@ const uriPathModule = _pathModuleFor(uri); | ||
function pathSeparatorFor(uri) { | ||
function pathSeparatorFor(uri: NuclideUri): string { | ||
return _pathModuleFor(uri).sep; | ||
} | ||
function split(uri) { | ||
function split(uri: NuclideUri): Array<string> { | ||
const parts = []; | ||
@@ -582,17 +595,20 @@ let current = uri; | ||
function _pathModuleFor(uri) { | ||
if (uri.startsWith(_path.default.posix.sep)) { | ||
return _path.default.posix; | ||
function _pathModuleFor(uri: NuclideUri): typeof pathModule { | ||
if (uri.startsWith(pathModule.posix.sep)) { | ||
return pathModule.posix; | ||
} | ||
if (uri.indexOf('://') > -1) { | ||
return _path.default.posix; | ||
return pathModule.posix; | ||
} | ||
if (uri[1] === ':' && uri[2] === _path.default.win32.sep) { | ||
return _path.default.win32; | ||
if (uri[1] === ':' && uri[2] === pathModule.win32.sep) { | ||
return pathModule.win32; | ||
} | ||
if (uri.split(_path.default.win32.sep).length > uri.split(_path.default.posix.sep).length) { | ||
return _path.default.win32; | ||
if ( | ||
uri.split(pathModule.win32.sep).length > | ||
uri.split(pathModule.posix.sep).length | ||
) { | ||
return pathModule.win32; | ||
} else { | ||
return _path.default.posix; | ||
return pathModule.posix; | ||
} | ||
@@ -606,7 +622,7 @@ } | ||
*/ | ||
function _escapeSpecialCharacters(uri) { | ||
function _escapeSpecialCharacters(uri: NuclideUri): NuclideUri { | ||
return uri.replace(/%/g, '%25').replace(/\\/g, '%5C'); | ||
} | ||
function _testForAtomUri(uri) { | ||
function _testForAtomUri(uri: ?NuclideUri): void { | ||
if (uri != null && isAtomUri(uri)) { | ||
@@ -621,30 +637,20 @@ throw new Error(`Path operation invoked on Atom URI ${uri}`); | ||
// is ignored. | ||
function validate(uri, mustBeRemote) { | ||
function validate(uri: NuclideUri, mustBeRemote?: boolean): void { | ||
// Be a little extra paranoid to catch places where the type system may be weak. | ||
if (!(uri != null)) { | ||
throw new Error('Unexpected null NuclideUri'); | ||
} | ||
invariant(uri != null, 'Unexpected null NuclideUri'); | ||
invariant( | ||
typeof uri === 'string', | ||
`Unexpected NuclideUri type: ${String(uri)}`, | ||
); | ||
if (!(typeof uri === 'string')) { | ||
throw new Error(`Unexpected NuclideUri type: ${String(uri)}`); | ||
} | ||
if (isRemote(uri)) { | ||
parse(uri); | ||
if (!(mustBeRemote !== false)) { | ||
throw new Error('Expected remote NuclideUri'); | ||
} | ||
invariant(mustBeRemote !== false, 'Expected remote NuclideUri'); | ||
} else { | ||
if (!(uri !== '')) { | ||
throw new Error('NuclideUri must contain a non-empty path'); | ||
} | ||
if (!(mustBeRemote !== true)) { | ||
throw new Error('Expected local NuclideUri'); | ||
} | ||
invariant(uri !== '', 'NuclideUri must contain a non-empty path'); | ||
invariant(mustBeRemote !== true, 'Expected local NuclideUri'); | ||
} | ||
} | ||
exports.default = { | ||
export default { | ||
basename, | ||
@@ -688,6 +694,7 @@ dirname, | ||
pathSeparatorFor, | ||
NUCLIDE_URI_TYPE_NAME | ||
NUCLIDE_URI_TYPE_NAME, | ||
}; | ||
const __TEST__ = exports.__TEST__ = { | ||
_pathModuleFor | ||
}; | ||
export const __TEST__ = { | ||
_pathModuleFor, | ||
}; |
@@ -1,35 +0,19 @@ | ||
'use strict'; | ||
/** | ||
* Copyright (c) 2015-present, Facebook, Inc. | ||
* All rights reserved. | ||
* | ||
* This source code is licensed under the license found in the LICENSE file in | ||
* the root directory of this source tree. | ||
* | ||
* @flow | ||
* @format | ||
*/ | ||
Object.defineProperty(exports, "__esModule", { | ||
value: true | ||
}); | ||
exports.nextAnimationFrame = exports.nextTick = undefined; | ||
exports.splitStream = splitStream; | ||
exports.bufferUntil = bufferUntil; | ||
exports.cacheWhileSubscribed = cacheWhileSubscribed; | ||
exports.diffSets = diffSets; | ||
exports.reconcileSetDiffs = reconcileSetDiffs; | ||
exports.reconcileSets = reconcileSets; | ||
exports.toggle = toggle; | ||
exports.compact = compact; | ||
exports.takeWhileInclusive = takeWhileInclusive; | ||
exports.concatLatest = concatLatest; | ||
exports.throttle = throttle; | ||
/* global requestAnimationFrame, cancelAnimationFrame */ | ||
var _UniversalDisposable; | ||
import UniversalDisposable from './UniversalDisposable'; | ||
import invariant from 'assert'; | ||
import {setDifference} from './collection'; | ||
import {Observable, ReplaySubject} from 'rxjs'; | ||
function _load_UniversalDisposable() { | ||
return _UniversalDisposable = _interopRequireDefault(require('./UniversalDisposable')); | ||
} | ||
var _collection; | ||
function _load_collection() { | ||
return _collection = require('./collection'); | ||
} | ||
var _rxjsBundlesRxMinJs = require('rxjs/bundles/Rx.min.js'); | ||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } | ||
/** | ||
@@ -41,5 +25,5 @@ * Splits a stream of strings on newlines. | ||
*/ | ||
function splitStream(input) { | ||
return _rxjsBundlesRxMinJs.Observable.create(observer => { | ||
let current = ''; | ||
export function splitStream(input: Observable<string>): Observable<string> { | ||
return Observable.create(observer => { | ||
let current: string = ''; | ||
@@ -53,13 +37,17 @@ function onEnd() { | ||
return input.subscribe(value => { | ||
const lines = (current + value).split('\n'); | ||
current = lines.pop(); | ||
lines.forEach(line => observer.next(line + '\n')); | ||
}, error => { | ||
onEnd(); | ||
observer.error(error); | ||
}, () => { | ||
onEnd(); | ||
observer.complete(); | ||
}); | ||
return input.subscribe( | ||
value => { | ||
const lines = (current + value).split('\n'); | ||
current = lines.pop(); | ||
lines.forEach(line => observer.next(line + '\n')); | ||
}, | ||
error => { | ||
onEnd(); | ||
observer.error(error); | ||
}, | ||
() => { | ||
onEnd(); | ||
observer.complete(); | ||
}, | ||
); | ||
}); | ||
@@ -77,17 +65,7 @@ } | ||
*/ | ||
/** | ||
* Copyright (c) 2015-present, Facebook, Inc. | ||
* All rights reserved. | ||
* | ||
* This source code is licensed under the license found in the LICENSE file in | ||
* the root directory of this source tree. | ||
* | ||
* | ||
* @format | ||
*/ | ||
/* global requestAnimationFrame, cancelAnimationFrame */ | ||
function bufferUntil(stream, condition) { | ||
return _rxjsBundlesRxMinJs.Observable.create(observer => { | ||
export function bufferUntil<T>( | ||
stream: Observable<T>, | ||
condition: (item: T, buffer: Array<T>) => boolean, | ||
): Observable<Array<T>> { | ||
return Observable.create(observer => { | ||
let buffer = null; | ||
@@ -100,17 +78,21 @@ const flush = () => { | ||
}; | ||
return stream.subscribe(x => { | ||
if (buffer == null) { | ||
buffer = []; | ||
} | ||
buffer.push(x); | ||
if (condition(x, buffer)) { | ||
return stream.subscribe( | ||
x => { | ||
if (buffer == null) { | ||
buffer = []; | ||
} | ||
buffer.push(x); | ||
if (condition(x, buffer)) { | ||
flush(); | ||
} | ||
}, | ||
err => { | ||
flush(); | ||
} | ||
}, err => { | ||
flush(); | ||
observer.error(err); | ||
}, () => { | ||
flush(); | ||
observer.complete(); | ||
}); | ||
observer.error(err); | ||
}, | ||
() => { | ||
flush(); | ||
observer.complete(); | ||
}, | ||
); | ||
}); | ||
@@ -127,6 +109,11 @@ } | ||
*/ | ||
function cacheWhileSubscribed(input) { | ||
return input.multicast(() => new _rxjsBundlesRxMinJs.ReplaySubject(1)).refCount(); | ||
export function cacheWhileSubscribed<T>(input: Observable<T>): Observable<T> { | ||
return input.multicast(() => new ReplaySubject(1)).refCount(); | ||
} | ||
type Diff<T> = { | ||
added: Set<T>, | ||
removed: Set<T>, | ||
}; | ||
/** | ||
@@ -136,8 +123,16 @@ * Given a stream of sets, return a stream of diffs. | ||
*/ | ||
function diffSets(sets, hash) { | ||
return _rxjsBundlesRxMinJs.Observable.concat(_rxjsBundlesRxMinJs.Observable.of(new Set()), // Always start with no items with an empty set | ||
sets).pairwise().map(([previous, next]) => ({ | ||
added: (0, (_collection || _load_collection()).setDifference)(next, previous, hash), | ||
removed: (0, (_collection || _load_collection()).setDifference)(previous, next, hash) | ||
})).filter(diff => diff.added.size > 0 || diff.removed.size > 0); | ||
export function diffSets<T>( | ||
sets: Observable<Set<T>>, | ||
hash?: (v: T) => any, | ||
): Observable<Diff<T>> { | ||
return Observable.concat( | ||
Observable.of(new Set()), // Always start with no items with an empty set | ||
sets, | ||
) | ||
.pairwise() | ||
.map(([previous, next]) => ({ | ||
added: setDifference(next, previous, hash), | ||
removed: setDifference(previous, next, hash), | ||
})) | ||
.filter(diff => diff.added.size > 0 || diff.removed.size > 0); | ||
} | ||
@@ -149,3 +144,7 @@ | ||
*/ | ||
function reconcileSetDiffs(diffs, addAction, hash_) { | ||
export function reconcileSetDiffs<T>( | ||
diffs: Observable<Diff<T>>, | ||
addAction: (addedItem: T) => IDisposable, | ||
hash_?: (v: T) => any, | ||
): IDisposable { | ||
const hash = hash_ || (x => x); | ||
@@ -155,7 +154,3 @@ const itemsToDisposables = new Map(); | ||
const disposable = itemsToDisposables.get(hash(item)); | ||
if (!(disposable != null)) { | ||
throw new Error('Invariant violation: "disposable != null"'); | ||
} | ||
invariant(disposable != null); | ||
disposable.dispose(); | ||
@@ -171,11 +166,14 @@ itemsToDisposables.delete(item); | ||
return new (_UniversalDisposable || _load_UniversalDisposable()).default(diffs.subscribe(diff => { | ||
// For every item that got added, perform the add action. | ||
diff.added.forEach(item => { | ||
itemsToDisposables.set(hash(item), addAction(item)); | ||
}); | ||
return new UniversalDisposable( | ||
diffs.subscribe(diff => { | ||
// For every item that got added, perform the add action. | ||
diff.added.forEach(item => { | ||
itemsToDisposables.set(hash(item), addAction(item)); | ||
}); | ||
// "Undo" the add action for each item that got removed. | ||
diff.removed.forEach(disposeItem); | ||
}), disposeAll); | ||
// "Undo" the add action for each item that got removed. | ||
diff.removed.forEach(disposeItem); | ||
}), | ||
disposeAll, | ||
); | ||
} | ||
@@ -211,3 +209,7 @@ | ||
*/ | ||
function reconcileSets(sets, addAction, hash) { | ||
export function reconcileSets<T>( | ||
sets: Observable<Set<T>>, | ||
addAction: (addedItem: T) => IDisposable, | ||
hash?: (v: T) => any, | ||
): IDisposable { | ||
const diffs = diffSets(sets, hash); | ||
@@ -217,9 +219,14 @@ return reconcileSetDiffs(diffs, addAction, hash); | ||
function toggle(source, toggler) { | ||
return toggler.distinctUntilChanged().switchMap(enabled => enabled ? source : _rxjsBundlesRxMinJs.Observable.empty()); | ||
export function toggle<T>( | ||
source: Observable<T>, | ||
toggler: Observable<boolean>, | ||
): Observable<T> { | ||
return toggler | ||
.distinctUntilChanged() | ||
.switchMap(enabled => (enabled ? source : Observable.empty())); | ||
} | ||
function compact(source) { | ||
export function compact<T>(source: Observable<?T>): Observable<T> { | ||
// Flow does not understand the semantics of `filter` | ||
return source.filter(x => x != null); | ||
return (source.filter(x => x != null): any); | ||
} | ||
@@ -230,13 +237,22 @@ | ||
*/ | ||
function takeWhileInclusive(source, predicate) { | ||
return _rxjsBundlesRxMinJs.Observable.create(observer => source.subscribe(x => { | ||
observer.next(x); | ||
if (!predicate(x)) { | ||
observer.complete(); | ||
} | ||
}, err => { | ||
observer.error(err); | ||
}, () => { | ||
observer.complete(); | ||
})); | ||
export function takeWhileInclusive<T>( | ||
source: Observable<T>, | ||
predicate: (value: T) => boolean, | ||
): Observable<T> { | ||
return Observable.create(observer => | ||
source.subscribe( | ||
x => { | ||
observer.next(x); | ||
if (!predicate(x)) { | ||
observer.complete(); | ||
} | ||
}, | ||
err => { | ||
observer.error(err); | ||
}, | ||
() => { | ||
observer.complete(); | ||
}, | ||
), | ||
); | ||
} | ||
@@ -246,15 +262,36 @@ | ||
// Observables who have not emitted a value yet are treated as empty. | ||
function concatLatest(...observables) { | ||
export function concatLatest<T>( | ||
...observables: Array<Observable<Array<T>>> | ||
): Observable<Array<T>> { | ||
// First, tag all input observables with their index. | ||
const tagged = observables.map((observable, index) => observable.map(list => [list, index])); | ||
return _rxjsBundlesRxMinJs.Observable.merge(...tagged).scan((accumulator, [list, index]) => { | ||
accumulator[index] = list; | ||
return accumulator; | ||
}, observables.map(x => [])).map(accumulator => [].concat(...accumulator)); | ||
// Flow errors with ambiguity without the explicit annotation. | ||
const tagged: Array< | ||
Observable<[Array<T>, number]>, | ||
> = observables.map((observable, index) => | ||
observable.map(list => [list, index]), | ||
); | ||
return Observable.merge(...tagged) | ||
.scan((accumulator, [list, index]) => { | ||
accumulator[index] = list; | ||
return accumulator; | ||
}, observables.map(x => [])) | ||
.map(accumulator => [].concat(...accumulator)); | ||
} | ||
type ThrottleOptions = { | ||
// Should the first element be emitted immeditately? Defaults to true. | ||
leading?: boolean, | ||
}; | ||
/** | ||
* A more sensible alternative to RxJS's throttle/audit/sample operators. | ||
*/ | ||
function throttle(source, duration, options_) { | ||
export function throttle<T>( | ||
source: Observable<T>, | ||
duration: | ||
| number | ||
| Observable<any> | ||
| ((value: T) => Observable<any> | Promise<any>), | ||
options_: ?ThrottleOptions, | ||
): Observable<T> { | ||
const options = options_ || {}; | ||
@@ -279,10 +316,16 @@ const leading = options.leading !== false; | ||
return _rxjsBundlesRxMinJs.Observable.create(observer => { | ||
return Observable.create(observer => { | ||
const connectableSource = source.publish(); | ||
const throttled = _rxjsBundlesRxMinJs.Observable.merge(connectableSource.take(1), audit(connectableSource.skip(1))); | ||
return new (_UniversalDisposable || _load_UniversalDisposable()).default(throttled.subscribe(observer), connectableSource.connect()); | ||
const throttled = Observable.merge( | ||
connectableSource.take(1), | ||
audit(connectableSource.skip(1)), | ||
); | ||
return new UniversalDisposable( | ||
throttled.subscribe(observer), | ||
connectableSource.connect(), | ||
); | ||
}); | ||
} | ||
const nextTick = exports.nextTick = _rxjsBundlesRxMinJs.Observable.create(observer => { | ||
export const nextTick = Observable.create(observer => { | ||
process.nextTick(() => { | ||
@@ -294,3 +337,3 @@ observer.next(); | ||
const nextAnimationFrame = exports.nextAnimationFrame = _rxjsBundlesRxMinJs.Observable.create(observer => { | ||
export const nextAnimationFrame = Observable.create(observer => { | ||
if (typeof requestAnimationFrame === 'undefined') { | ||
@@ -306,2 +349,2 @@ throw new Error('This util can only be used in Atom'); | ||
}; | ||
}); | ||
}); |
{ | ||
"name": "nuclide-commons", | ||
"version": "0.1.0", | ||
"version": "0.1.1", | ||
"description": "Common Nuclide node modules.", | ||
@@ -9,3 +9,3 @@ "license": "SEE LICENSE IN LICENSE", | ||
"scripts": { | ||
"prepublishOnly": "../../scripts/release-transpile.js --overwrite .", | ||
"prepublishOnly": "../../scripts/modules-prepublish.sh", | ||
"test": "node ../../pkg/nuclide-jasmine/bin/jasmine-node-transpiled spec" | ||
@@ -16,7 +16,12 @@ }, | ||
"event-kit": "2.2.0", | ||
"fs-plus": "2.9.3", | ||
"glob": "7.1.1", | ||
"idx": "1.2.0", | ||
"lru-cache": "4.0.2", | ||
"mkdirp": "0.5.1", | ||
"rimraf": "2.5.4", | ||
"rxjs": "5.3.1", | ||
"shell-quote": "1.6.1" | ||
}, | ||
"devDependencies": { | ||
"shell-quote": "1.6.1", | ||
"temp": "0.8.3" | ||
} | ||
} |
764
promise.js
@@ -1,252 +0,24 @@ | ||
'use strict'; | ||
Object.defineProperty(exports, "__esModule", { | ||
value: true | ||
}); | ||
exports.asyncSome = exports.asyncObjFilter = exports.asyncFilter = exports.Deferred = exports.retryLimit = exports.triggerAfterWait = exports.RequestSerializer = undefined; | ||
var _asyncToGenerator = _interopRequireDefault(require('async-to-generator')); | ||
/** | ||
* Executes a provided callback only if a promise takes longer than | ||
* `milliSeconds` milliseconds to resolve. | ||
* Copyright (c) 2015-present, Facebook, Inc. | ||
* All rights reserved. | ||
* | ||
* @param `promise` the promise to wait on. | ||
* @param `milliSeconds` max amount of time that `promise` can take to resolve | ||
* before timeoutFn is fired. | ||
* @param `timeoutFn` the function to execute when a promise takes longer than | ||
* `milliSeconds` ms to resolve. | ||
* @param `cleanupFn` the cleanup function to execute after the promise resolves. | ||
* This source code is licensed under the license found in the LICENSE file in | ||
* the root directory of this source tree. | ||
* | ||
* @flow | ||
* @format | ||
*/ | ||
let triggerAfterWait = exports.triggerAfterWait = (() => { | ||
var _ref = (0, _asyncToGenerator.default)(function* (promise, milliSeconds, timeoutFn, cleanupFn) { | ||
const timeout = setTimeout(timeoutFn, milliSeconds); | ||
try { | ||
return yield promise; | ||
} finally { | ||
clearTimeout(timeout); | ||
if (cleanupFn) { | ||
cleanupFn(); | ||
} | ||
} | ||
}); | ||
return function triggerAfterWait(_x, _x2, _x3, _x4) { | ||
return _ref.apply(this, arguments); | ||
}; | ||
})(); | ||
import invariant from 'assert'; | ||
/** | ||
* Returns a Promise that resolves to the same value as the given promise, or rejects if it takes | ||
* longer than `milliseconds` milliseconds | ||
*/ | ||
/** | ||
* Call an async function repeatedly with a maximum number of trials limit, | ||
* until a valid result that's defined by a validation function. | ||
* A failed call can result from an async thrown exception, or invalid result. | ||
* | ||
* @param `retryFunction` the async logic that's wanted to be retried. | ||
* @param `validationFunction` the validation function that decides whether a response is valid. | ||
* @param `maximumTries` the number of times the `retryFunction` can fail to get a valid | ||
* response before the `retryLimit` is terminated reporting an error. | ||
* @param `retryIntervalMs` optional, the number of milliseconds to wait between trials, if wanted. | ||
* | ||
* If an exception is encountered on the last trial, the exception is thrown. | ||
* If no valid response is found, an exception is thrown. | ||
*/ | ||
let retryLimit = exports.retryLimit = (() => { | ||
var _ref2 = (0, _asyncToGenerator.default)(function* (retryFunction, validationFunction, maximumTries, retryIntervalMs = 0) { | ||
let result = null; | ||
let tries = 0; | ||
let lastError = null; | ||
while (tries === 0 || tries < maximumTries) { | ||
try { | ||
// eslint-disable-next-line no-await-in-loop | ||
result = yield retryFunction(); | ||
lastError = null; | ||
if (validationFunction(result)) { | ||
return result; | ||
} | ||
} catch (error) { | ||
lastError = error; | ||
result = null; | ||
} | ||
if (++tries < maximumTries && retryIntervalMs !== 0) { | ||
// eslint-disable-next-line no-await-in-loop | ||
yield sleep(retryIntervalMs); | ||
} | ||
type RunReturn<T> = | ||
| { | ||
status: 'success', | ||
result: T, | ||
} | ||
if (lastError != null) { | ||
throw lastError; | ||
} else if (tries === maximumTries) { | ||
throw new Error('No valid response found!'); | ||
} else { | ||
return result; | ||
} | ||
}); | ||
| { | ||
status: 'outdated', | ||
}; | ||
return function retryLimit(_x5, _x6, _x7) { | ||
return _ref2.apply(this, arguments); | ||
}; | ||
})(); | ||
/** | ||
* Limits async function execution parallelism to only one at a time. | ||
* Hence, if a call is already running, it will wait for it to finish, | ||
* then start the next async execution, but if called again while not finished, | ||
* it will return the scheduled execution promise. | ||
* | ||
* Sample Usage: | ||
* ``` | ||
* let i = 1; | ||
* const oneExecAtATime = oneParallelAsyncCall(() => { | ||
* return next Promise((resolve, reject) => { | ||
* setTimeout(200, () => resolve(i++)); | ||
* }); | ||
* }); | ||
* | ||
* const result1Promise = oneExecAtATime(); // Start an async, and resolve to 1 in 200 ms. | ||
* const result2Promise = oneExecAtATime(); // Schedule the next async, and resolve to 2 in 400 ms. | ||
* const result3Promise = oneExecAtATime(); // Reuse scheduled promise and resolve to 2 in 400 ms. | ||
* ``` | ||
*/ | ||
/** | ||
* `filter` Promise utility that allows filtering an array with an async Promise function. | ||
* It's an alternative to `Array.prototype.filter` that accepts an async function. | ||
* You can optionally configure a limit to set the maximum number of async operations at a time. | ||
* | ||
* Previously, with the `Promise.all` primitive, we can't set the parallelism limit and we have to | ||
* `filter`, so, we replace the old `filter` code: | ||
* var existingFilePaths = []; | ||
* await Promise.all(filePaths.map(async (filePath) => { | ||
* if (await fsPromise.exists(filePath)) { | ||
* existingFilePaths.push(filePath); | ||
* } | ||
* })); | ||
* with limit 5 parallel filesystem operations at a time: | ||
* var existingFilePaths = await asyncFilter(filePaths, fsPromise.exists, 5); | ||
* | ||
* @param array the array of items for `filter`ing. | ||
* @param filterFunction the async `filter` function that returns a Promise that resolves to a | ||
* boolean. | ||
* @param limit the configurable number of parallel async operations. | ||
*/ | ||
let asyncFilter = exports.asyncFilter = (() => { | ||
var _ref5 = (0, _asyncToGenerator.default)(function* (array, filterFunction, limit) { | ||
const filteredList = []; | ||
yield asyncLimit(array, limit || array.length, (() => { | ||
var _ref6 = (0, _asyncToGenerator.default)(function* (item) { | ||
if (yield filterFunction(item)) { | ||
filteredList.push(item); | ||
} | ||
}); | ||
return function (_x12) { | ||
return _ref6.apply(this, arguments); | ||
}; | ||
})()); | ||
return filteredList; | ||
}); | ||
return function asyncFilter(_x9, _x10, _x11) { | ||
return _ref5.apply(this, arguments); | ||
}; | ||
})(); | ||
let asyncObjFilter = exports.asyncObjFilter = (() => { | ||
var _ref7 = (0, _asyncToGenerator.default)(function* (obj, filterFunction, limit) { | ||
const keys = Object.keys(obj); | ||
const filteredObj = {}; | ||
yield asyncLimit(keys, limit || keys.length, (() => { | ||
var _ref8 = (0, _asyncToGenerator.default)(function* (key) { | ||
const item = obj[key]; | ||
if (yield filterFunction(item, key)) { | ||
filteredObj[key] = item; | ||
} | ||
}); | ||
return function (_x16) { | ||
return _ref8.apply(this, arguments); | ||
}; | ||
})()); | ||
return filteredObj; | ||
}); | ||
return function asyncObjFilter(_x13, _x14, _x15) { | ||
return _ref7.apply(this, arguments); | ||
}; | ||
})(); | ||
/** | ||
* `some` Promise utility that allows `some` an array with an async Promise some function. | ||
* It's an alternative to `Array.prototype.some` that accepts an async some function. | ||
* You can optionally configure a limit to set the maximum number of async operations at a time. | ||
* | ||
* Previously, with the Promise.all primitive, we can't set the parallelism limit and we have to | ||
* `some`, so, we replace the old `some` code: | ||
* var someFileExist = false; | ||
* await Promise.all(filePaths.map(async (filePath) => { | ||
* if (await fsPromise.exists(filePath)) { | ||
* someFileExist = true; | ||
* } | ||
* })); | ||
* with limit 5 parallel filesystem operations at a time: | ||
* var someFileExist = await asyncSome(filePaths, fsPromise.exists, 5); | ||
* | ||
* @param array the array of items for `some`ing. | ||
* @param someFunction the async `some` function that returns a Promise that resolves to a | ||
* boolean. | ||
* @param limit the configurable number of parallel async operations. | ||
*/ | ||
let asyncSome = exports.asyncSome = (() => { | ||
var _ref9 = (0, _asyncToGenerator.default)(function* (array, someFunction, limit) { | ||
let resolved = false; | ||
yield asyncLimit(array, limit || array.length, (() => { | ||
var _ref10 = (0, _asyncToGenerator.default)(function* (item) { | ||
if (resolved) { | ||
// We don't need to call the someFunction anymore or wait any longer. | ||
return; | ||
} | ||
if (yield someFunction(item)) { | ||
resolved = true; | ||
} | ||
}); | ||
return function (_x20) { | ||
return _ref10.apply(this, arguments); | ||
}; | ||
})()); | ||
return resolved; | ||
}); | ||
return function asyncSome(_x17, _x18, _x19) { | ||
return _ref9.apply(this, arguments); | ||
}; | ||
})(); | ||
/** | ||
* Check if an object is Promise by testing if it has a `then` function property. | ||
*/ | ||
exports.sleep = sleep; | ||
exports.nextTick = nextTick; | ||
exports.timeoutPromise = timeoutPromise; | ||
exports.serializeAsyncCall = serializeAsyncCall; | ||
exports.asyncFind = asyncFind; | ||
exports.denodeify = denodeify; | ||
exports.asyncLimit = asyncLimit; | ||
exports.isPromise = isPromise; | ||
exports.lastly = lastly; | ||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } | ||
/** | ||
* Allows a caller to ensure that the results it receives from consecutive | ||
@@ -276,15 +48,8 @@ * promise resolutions are never outdated. Usage: | ||
*/ | ||
/** | ||
* Copyright (c) 2015-present, Facebook, Inc. | ||
* All rights reserved. | ||
* | ||
* This source code is licensed under the license found in the LICENSE file in | ||
* the root directory of this source tree. | ||
* | ||
* | ||
* @format | ||
*/ | ||
export class RequestSerializer<T> { | ||
_lastDispatchedOp: number; | ||
_lastFinishedOp: number; | ||
_latestPromise: Promise<T>; | ||
_waitResolve: Function; | ||
class RequestSerializer { | ||
constructor() { | ||
@@ -298,23 +63,19 @@ this._lastDispatchedOp = 0; | ||
run(promise) { | ||
var _this = this; | ||
return (0, _asyncToGenerator.default)(function* () { | ||
const thisOp = _this._lastDispatchedOp + 1; | ||
_this._lastDispatchedOp = thisOp; | ||
_this._latestPromise = promise; | ||
_this._waitResolve(); | ||
const result = yield promise; | ||
if (_this._lastFinishedOp < thisOp) { | ||
_this._lastFinishedOp = thisOp; | ||
return { | ||
status: 'success', | ||
result | ||
}; | ||
} else { | ||
return { | ||
status: 'outdated' | ||
}; | ||
} | ||
})(); | ||
async run(promise: Promise<T>): Promise<RunReturn<T>> { | ||
const thisOp = this._lastDispatchedOp + 1; | ||
this._lastDispatchedOp = thisOp; | ||
this._latestPromise = promise; | ||
this._waitResolve(); | ||
const result = await promise; | ||
if (this._lastFinishedOp < thisOp) { | ||
this._lastFinishedOp = thisOp; | ||
return { | ||
status: 'success', | ||
result, | ||
}; | ||
} else { | ||
return { | ||
status: 'outdated', | ||
}; | ||
} | ||
} | ||
@@ -326,22 +87,18 @@ | ||
*/ | ||
waitForLatestResult() { | ||
var _this2 = this; | ||
return (0, _asyncToGenerator.default)(function* () { | ||
let lastPromise = null; | ||
let result = null; | ||
while (lastPromise !== _this2._latestPromise) { | ||
lastPromise = _this2._latestPromise; | ||
// Wait for the current last know promise to resolve, or a next run have started. | ||
// eslint-disable-next-line no-await-in-loop | ||
result = yield new Promise(function (resolve, reject) { | ||
_this2._waitResolve = resolve; | ||
_this2._latestPromise.then(resolve); | ||
}); | ||
} | ||
return result; | ||
})(); | ||
async waitForLatestResult(): Promise<T> { | ||
let lastPromise = null; | ||
let result: any = null; | ||
while (lastPromise !== this._latestPromise) { | ||
lastPromise = this._latestPromise; | ||
// Wait for the current last know promise to resolve, or a next run have started. | ||
// eslint-disable-next-line no-await-in-loop | ||
result = await new Promise((resolve, reject) => { | ||
this._waitResolve = resolve; | ||
this._latestPromise.then(resolve); | ||
}); | ||
} | ||
return (result: T); | ||
} | ||
isRunInProgress() { | ||
isRunInProgress(): boolean { | ||
return this._lastDispatchedOp > this._lastFinishedOp; | ||
@@ -351,9 +108,8 @@ } | ||
exports.RequestSerializer = RequestSerializer; /* | ||
* Returns a promise that will resolve after `milliSeconds` milli seconds. | ||
* this can be used to pause execution asynchronously. | ||
* e.g. await sleep(1000), pauses the async flow execution for 1 second. | ||
*/ | ||
function sleep(milliSeconds) { | ||
/* | ||
* Returns a promise that will resolve after `milliSeconds` milli seconds. | ||
* this can be used to pause execution asynchronously. | ||
* e.g. await sleep(1000), pauses the async flow execution for 1 second. | ||
*/ | ||
export function sleep(milliSeconds: number): Promise<void> { | ||
return new Promise(resolve => { | ||
@@ -364,7 +120,44 @@ setTimeout(resolve, milliSeconds); | ||
function nextTick() { | ||
export function nextTick(): Promise<void> { | ||
return new Promise(resolve => { | ||
process.nextTick(resolve); | ||
}); | ||
}function timeoutPromise(promise, milliseconds) { | ||
} | ||
/** | ||
* Executes a provided callback only if a promise takes longer than | ||
* `milliSeconds` milliseconds to resolve. | ||
* | ||
* @param `promise` the promise to wait on. | ||
* @param `milliSeconds` max amount of time that `promise` can take to resolve | ||
* before timeoutFn is fired. | ||
* @param `timeoutFn` the function to execute when a promise takes longer than | ||
* `milliSeconds` ms to resolve. | ||
* @param `cleanupFn` the cleanup function to execute after the promise resolves. | ||
*/ | ||
export async function triggerAfterWait<T>( | ||
promise: Promise<T>, | ||
milliSeconds: number, | ||
timeoutFn: () => void, | ||
cleanupFn?: () => void, | ||
): Promise<T> { | ||
const timeout = setTimeout(timeoutFn, milliSeconds); | ||
try { | ||
return await promise; | ||
} finally { | ||
clearTimeout(timeout); | ||
if (cleanupFn) { | ||
cleanupFn(); | ||
} | ||
} | ||
} | ||
/** | ||
* Returns a Promise that resolves to the same value as the given promise, or rejects if it takes | ||
* longer than `milliseconds` milliseconds | ||
*/ | ||
export function timeoutPromise<T>( | ||
promise: Promise<T>, | ||
milliseconds: number, | ||
): Promise<T> { | ||
return new Promise((resolve, reject) => { | ||
@@ -375,15 +168,91 @@ let timeout = setTimeout(() => { | ||
}, milliseconds); | ||
promise.then(value => { | ||
if (timeout != null) { | ||
clearTimeout(timeout); | ||
promise | ||
.then(value => { | ||
if (timeout != null) { | ||
clearTimeout(timeout); | ||
} | ||
resolve(value); | ||
}) | ||
.catch(value => { | ||
if (timeout != null) { | ||
clearTimeout(timeout); | ||
} | ||
reject(value); | ||
}); | ||
}); | ||
} | ||
/** | ||
* Call an async function repeatedly with a maximum number of trials limit, | ||
* until a valid result that's defined by a validation function. | ||
* A failed call can result from an async thrown exception, or invalid result. | ||
* | ||
* @param `retryFunction` the async logic that's wanted to be retried. | ||
* @param `validationFunction` the validation function that decides whether a response is valid. | ||
* @param `maximumTries` the number of times the `retryFunction` can fail to get a valid | ||
* response before the `retryLimit` is terminated reporting an error. | ||
* @param `retryIntervalMs` optional, the number of milliseconds to wait between trials, if wanted. | ||
* | ||
* If an exception is encountered on the last trial, the exception is thrown. | ||
* If no valid response is found, an exception is thrown. | ||
*/ | ||
export async function retryLimit<T>( | ||
retryFunction: () => Promise<T>, | ||
validationFunction: (result: T) => boolean, | ||
maximumTries: number, | ||
retryIntervalMs?: number = 0, | ||
): Promise<T> { | ||
let result = null; | ||
let tries = 0; | ||
let lastError = null; | ||
while (tries === 0 || tries < maximumTries) { | ||
try { | ||
// eslint-disable-next-line no-await-in-loop | ||
result = await retryFunction(); | ||
lastError = null; | ||
if (validationFunction(result)) { | ||
return result; | ||
} | ||
resolve(value); | ||
}).catch(value => { | ||
if (timeout != null) { | ||
clearTimeout(timeout); | ||
} | ||
reject(value); | ||
}); | ||
}); | ||
}function serializeAsyncCall(asyncFun) { | ||
} catch (error) { | ||
lastError = error; | ||
result = null; | ||
} | ||
if (++tries < maximumTries && retryIntervalMs !== 0) { | ||
// eslint-disable-next-line no-await-in-loop | ||
await sleep(retryIntervalMs); | ||
} | ||
} | ||
if (lastError != null) { | ||
throw lastError; | ||
} else if (tries === maximumTries) { | ||
throw new Error('No valid response found!'); | ||
} else { | ||
return ((result: any): T); | ||
} | ||
} | ||
/** | ||
* Limits async function execution parallelism to only one at a time. | ||
* Hence, if a call is already running, it will wait for it to finish, | ||
* then start the next async execution, but if called again while not finished, | ||
* it will return the scheduled execution promise. | ||
* | ||
* Sample Usage: | ||
* ``` | ||
* let i = 1; | ||
* const oneExecAtATime = oneParallelAsyncCall(() => { | ||
* return next Promise((resolve, reject) => { | ||
* setTimeout(200, () => resolve(i++)); | ||
* }); | ||
* }); | ||
* | ||
* const result1Promise = oneExecAtATime(); // Start an async, and resolve to 1 in 200 ms. | ||
* const result2Promise = oneExecAtATime(); // Schedule the next async, and resolve to 2 in 400 ms. | ||
* const result3Promise = oneExecAtATime(); // Reuse scheduled promise and resolve to 2 in 400 ms. | ||
* ``` | ||
*/ | ||
export function serializeAsyncCall<T>( | ||
asyncFun: () => Promise<T>, | ||
): () => Promise<T> { | ||
let scheduledCall = null; | ||
@@ -393,3 +262,6 @@ let pendingCall = null; | ||
const resultPromise = asyncFun(); | ||
pendingCall = resultPromise.then(() => pendingCall = null, () => pendingCall = null); | ||
pendingCall = resultPromise.then( | ||
() => (pendingCall = null), | ||
() => (pendingCall = null), | ||
); | ||
return resultPromise; | ||
@@ -403,6 +275,3 @@ }; | ||
if (scheduledCall == null) { | ||
if (!pendingCall) { | ||
throw new Error('pendingCall must not be null!'); | ||
} | ||
invariant(pendingCall, 'pendingCall must not be null!'); | ||
scheduledCall = pendingCall.then(callNext, callNext); | ||
@@ -428,3 +297,6 @@ } | ||
*/ | ||
class Deferred { | ||
export class Deferred<T> { | ||
promise: Promise<T>; | ||
resolve: (value: T) => void; | ||
reject: (error: Error) => void; | ||
@@ -439,22 +311,25 @@ constructor() { | ||
exports.Deferred = Deferred; /** | ||
* Returns a value derived asynchronously from an element in the items array. | ||
* The test function is applied sequentially to each element in items until | ||
* one returns a Promise that resolves to a non-null value. When this happens, | ||
* the Promise returned by this method will resolve to that non-null value. If | ||
* no such Promise is produced, then the Promise returned by this function | ||
* will resolve to null. | ||
* | ||
* @param items Array of elements that will be passed to test, one at a time. | ||
* @param test Will be called with each item and must return either: | ||
* (1) A "thenable" (i.e, a Promise or promise-like object) that resolves | ||
* to a derived value (that will be returned) or null. | ||
* (2) null. | ||
* In both cases where null is returned, test will be applied to the next | ||
* item in the array. | ||
* @param thisArg Receiver that will be used when test is called. | ||
* @return Promise that resolves to an asynchronously derived value or null. | ||
*/ | ||
function asyncFind(items_, test, thisArg) { | ||
/** | ||
* Returns a value derived asynchronously from an element in the items array. | ||
* The test function is applied sequentially to each element in items until | ||
* one returns a Promise that resolves to a non-null value. When this happens, | ||
* the Promise returned by this method will resolve to that non-null value. If | ||
* no such Promise is produced, then the Promise returned by this function | ||
* will resolve to null. | ||
* | ||
* @param items Array of elements that will be passed to test, one at a time. | ||
* @param test Will be called with each item and must return either: | ||
* (1) A "thenable" (i.e, a Promise or promise-like object) that resolves | ||
* to a derived value (that will be returned) or null. | ||
* (2) null. | ||
* In both cases where null is returned, test will be applied to the next | ||
* item in the array. | ||
* @param thisArg Receiver that will be used when test is called. | ||
* @return Promise that resolves to an asynchronously derived value or null. | ||
*/ | ||
export function asyncFind<T, U>( | ||
items_: Array<T>, | ||
test: (t: T) => ?Promise<?U>, | ||
thisArg?: mixed, | ||
): Promise<?U> { | ||
let items = items_; | ||
@@ -467,23 +342,17 @@ return new Promise((resolve, reject) => { | ||
const next = (() => { | ||
var _ref3 = (0, _asyncToGenerator.default)(function* (index) { | ||
if (index === numItems) { | ||
resolve(null); | ||
return; | ||
} | ||
const next = async function(index) { | ||
if (index === numItems) { | ||
resolve(null); | ||
return; | ||
} | ||
const item = items[index]; | ||
const result = yield test.call(thisArg, item); | ||
if (result !== null) { | ||
resolve(result); | ||
} else { | ||
next(index + 1); | ||
} | ||
}); | ||
const item = items[index]; | ||
const result = await test.call(thisArg, item); | ||
if (result !== null) { | ||
resolve(result); | ||
} else { | ||
next(index + 1); | ||
} | ||
}; | ||
return function next(_x8) { | ||
return _ref3.apply(this, arguments); | ||
}; | ||
})(); | ||
next(0); | ||
@@ -493,4 +362,6 @@ }); | ||
function denodeify(f) { | ||
return function (...args) { | ||
export function denodeify( | ||
f: (...args: Array<any>) => any, | ||
): (...args: Array<any>) => Promise<any> { | ||
return function(...args: Array<any>) { | ||
return new Promise((resolve, reject) => { | ||
@@ -525,4 +396,8 @@ function callback(error, result) { | ||
*/ | ||
function asyncLimit(array, limit, mappingFunction) { | ||
const result = new Array(array.length); | ||
export function asyncLimit<T, V>( | ||
array: Array<T>, | ||
limit: number, | ||
mappingFunction: (item: T) => Promise<V>, | ||
): Promise<Array<V>> { | ||
const result: Array<V> = new Array(array.length); | ||
let parallelPromises = 0; | ||
@@ -534,26 +409,20 @@ let index = 0; | ||
return new Promise((resolve, reject) => { | ||
const runPromise = (() => { | ||
var _ref4 = (0, _asyncToGenerator.default)(function* () { | ||
if (index === array.length) { | ||
if (parallelPromises === 0) { | ||
resolve(result); | ||
} | ||
return; | ||
const runPromise = async () => { | ||
if (index === array.length) { | ||
if (parallelPromises === 0) { | ||
resolve(result); | ||
} | ||
++parallelPromises; | ||
const i = index++; | ||
try { | ||
result[i] = yield mappingFunction(array[i]); | ||
} catch (e) { | ||
reject(e); | ||
} | ||
--parallelPromises; | ||
runPromise(); | ||
}); | ||
return; | ||
} | ||
++parallelPromises; | ||
const i = index++; | ||
try { | ||
result[i] = await mappingFunction(array[i]); | ||
} catch (e) { | ||
reject(e); | ||
} | ||
--parallelPromises; | ||
runPromise(); | ||
}; | ||
return function runPromise() { | ||
return _ref4.apply(this, arguments); | ||
}; | ||
})(); | ||
while (parallelLimit--) { | ||
@@ -563,16 +432,121 @@ runPromise(); | ||
}); | ||
}function isPromise(object) { | ||
return Boolean(object) && typeof object === 'object' && typeof object.then === 'function'; | ||
} | ||
/** | ||
* `filter` Promise utility that allows filtering an array with an async Promise function. | ||
* It's an alternative to `Array.prototype.filter` that accepts an async function. | ||
* You can optionally configure a limit to set the maximum number of async operations at a time. | ||
* | ||
* Previously, with the `Promise.all` primitive, we can't set the parallelism limit and we have to | ||
* `filter`, so, we replace the old `filter` code: | ||
* var existingFilePaths = []; | ||
* await Promise.all(filePaths.map(async (filePath) => { | ||
* if (await fsPromise.exists(filePath)) { | ||
* existingFilePaths.push(filePath); | ||
* } | ||
* })); | ||
* with limit 5 parallel filesystem operations at a time: | ||
* var existingFilePaths = await asyncFilter(filePaths, fsPromise.exists, 5); | ||
* | ||
* @param array the array of items for `filter`ing. | ||
* @param filterFunction the async `filter` function that returns a Promise that resolves to a | ||
* boolean. | ||
* @param limit the configurable number of parallel async operations. | ||
*/ | ||
export async function asyncFilter<T>( | ||
array: Array<T>, | ||
filterFunction: (item: T) => Promise<boolean>, | ||
limit?: number, | ||
): Promise<Array<T>> { | ||
const filteredList = []; | ||
await asyncLimit(array, limit || array.length, async (item: T) => { | ||
if (await filterFunction(item)) { | ||
filteredList.push(item); | ||
} | ||
}); | ||
return filteredList; | ||
} | ||
export async function asyncObjFilter<T>( | ||
obj: {[key: string]: T}, | ||
filterFunction: (item: T, key: string) => Promise<boolean>, | ||
limit?: number, | ||
): Promise<{[key: string]: T}> { | ||
const keys = Object.keys(obj); | ||
const filteredObj = {}; | ||
await asyncLimit(keys, limit || keys.length, async (key: string) => { | ||
const item = obj[key]; | ||
if (await filterFunction(item, key)) { | ||
filteredObj[key] = item; | ||
} | ||
}); | ||
return filteredObj; | ||
} | ||
/** | ||
* `some` Promise utility that allows `some` an array with an async Promise some function. | ||
* It's an alternative to `Array.prototype.some` that accepts an async some function. | ||
* You can optionally configure a limit to set the maximum number of async operations at a time. | ||
* | ||
* Previously, with the Promise.all primitive, we can't set the parallelism limit and we have to | ||
* `some`, so, we replace the old `some` code: | ||
* var someFileExist = false; | ||
* await Promise.all(filePaths.map(async (filePath) => { | ||
* if (await fsPromise.exists(filePath)) { | ||
* someFileExist = true; | ||
* } | ||
* })); | ||
* with limit 5 parallel filesystem operations at a time: | ||
* var someFileExist = await asyncSome(filePaths, fsPromise.exists, 5); | ||
* | ||
* @param array the array of items for `some`ing. | ||
* @param someFunction the async `some` function that returns a Promise that resolves to a | ||
* boolean. | ||
* @param limit the configurable number of parallel async operations. | ||
*/ | ||
export async function asyncSome<T>( | ||
array: Array<T>, | ||
someFunction: (item: T) => Promise<boolean>, | ||
limit?: number, | ||
): Promise<boolean> { | ||
let resolved = false; | ||
await asyncLimit(array, limit || array.length, async (item: T) => { | ||
if (resolved) { | ||
// We don't need to call the someFunction anymore or wait any longer. | ||
return; | ||
} | ||
if (await someFunction(item)) { | ||
resolved = true; | ||
} | ||
}); | ||
return resolved; | ||
} | ||
/** | ||
* Check if an object is Promise by testing if it has a `then` function property. | ||
*/ | ||
export function isPromise(object: any): boolean { | ||
return ( | ||
Boolean(object) && | ||
typeof object === 'object' && | ||
typeof object.then === 'function' | ||
); | ||
} | ||
/** | ||
* We can't name a function 'finally', so use lastly instead. | ||
* fn() will be executed (and completed) after the provided promise resolves/rejects. | ||
*/ | ||
function lastly(promise, fn) { | ||
return promise.then(ret => { | ||
return Promise.resolve(fn()).then(() => ret); | ||
}, err => { | ||
return Promise.resolve(fn()).then(() => Promise.reject(err)); | ||
}); | ||
} | ||
export function lastly<T>( | ||
promise: Promise<T>, | ||
fn: () => Promise<mixed> | mixed, | ||
): Promise<T> { | ||
return promise.then( | ||
ret => { | ||
return Promise.resolve(fn()).then(() => ret); | ||
}, | ||
err => { | ||
return Promise.resolve(fn()).then(() => Promise.reject(err)); | ||
}, | ||
); | ||
} |
34
range.js
@@ -1,8 +0,1 @@ | ||
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { | ||
value: true | ||
}); | ||
exports.wordAtPositionFromBuffer = wordAtPositionFromBuffer; | ||
exports.matchRegexEndingAt = matchRegexEndingAt; | ||
/** | ||
@@ -15,8 +8,12 @@ * Copyright (c) 2015-present, Facebook, Inc. | ||
* | ||
* | ||
* @flow | ||
* @format | ||
*/ | ||
function wordAtPositionFromBuffer(buffer, position, wordRegex) { | ||
const { row, column } = position; | ||
export function wordAtPositionFromBuffer( | ||
buffer: atom$TextBuffer | simpleTextBuffer$TextBuffer, | ||
position: atom$PointObject, | ||
wordRegex: RegExp, | ||
): ?{wordMatch: Array<string>, range: atom$Range} { | ||
const {row, column} = position; | ||
const rowRange = buffer.rangeForRow(row); | ||
@@ -26,4 +23,7 @@ let matchData; | ||
buffer.scanInRange(wordRegex, rowRange, data => { | ||
const { range } = data; | ||
if (range.start.isLessThanOrEqual(position) && range.end.isGreaterThan(position)) { | ||
const {range} = data; | ||
if ( | ||
range.start.isLessThanOrEqual(position) && | ||
range.end.isGreaterThan(position) | ||
) { | ||
matchData = data; | ||
@@ -39,3 +39,3 @@ } | ||
wordMatch: matchData.match, | ||
range: matchData.range | ||
range: matchData.range, | ||
}; | ||
@@ -50,6 +50,10 @@ } else { | ||
// Useful for autocomplete. | ||
function matchRegexEndingAt(buffer, endPosition, regex) { | ||
export function matchRegexEndingAt( | ||
buffer: atom$TextBuffer | simpleTextBuffer$TextBuffer, | ||
endPosition: atom$PointObject, | ||
regex: RegExp, | ||
): ?string { | ||
const line = buffer.getTextInRange([[endPosition.row, 0], endPosition]); | ||
const match = regex.exec(line); | ||
return match == null ? null : match[0]; | ||
} | ||
} |
127
string.js
@@ -1,25 +0,1 @@ | ||
'use strict'; | ||
Object.defineProperty(exports, "__esModule", { | ||
value: true | ||
}); | ||
exports.URL_REGEX = undefined; | ||
exports.stringifyError = stringifyError; | ||
exports.maybeToString = maybeToString; | ||
exports.relativeDate = relativeDate; | ||
exports.countOccurrences = countOccurrences; | ||
exports.shellParse = shellParse; | ||
exports.removeCommonPrefix = removeCommonPrefix; | ||
exports.removeCommonSuffix = removeCommonSuffix; | ||
exports.shorten = shorten; | ||
exports.splitOnce = splitOnce; | ||
exports.indent = indent; | ||
exports.pluralize = pluralize; | ||
var _shellQuote; | ||
function _load_shellQuote() { | ||
return _shellQuote = require('shell-quote'); | ||
} | ||
/** | ||
@@ -32,7 +8,10 @@ * Copyright (c) 2015-present, Facebook, Inc. | ||
* | ||
* | ||
* @flow | ||
* @format | ||
*/ | ||
function stringifyError(error) { | ||
import invariant from 'assert'; | ||
import {parse} from 'shell-quote'; | ||
export function stringifyError(error: Error): string { | ||
return `name: ${error.name}, message: ${error.message}, stack: ${error.stack}.`; | ||
@@ -43,3 +22,3 @@ } | ||
// make it explicit. | ||
function maybeToString(str) { | ||
export function maybeToString(str: ?string): string { | ||
// We don't want to encourage the use of this function directly because it coerces anything to a | ||
@@ -63,7 +42,39 @@ // string. We get stricter typechecking by using maybeToString, so it should generally be | ||
const shortFormats = [[0.7 * MINUTE, 'now'], [1.5 * MINUTE, '1m'], [60 * MINUTE, 'm', MINUTE], [1.5 * HOUR, '1h'], [DAY, 'h', HOUR], [2 * DAY, '1d'], [7 * DAY, 'd', DAY], [1.5 * WEEK, '1w'], [MONTH, 'w', WEEK], [1.5 * MONTH, '1mo'], [YEAR, 'mo', MONTH], [1.5 * YEAR, '1y'], [Number.MAX_VALUE, 'y', YEAR]]; | ||
const shortFormats = [ | ||
[0.7 * MINUTE, 'now'], | ||
[1.5 * MINUTE, '1m'], | ||
[60 * MINUTE, 'm', MINUTE], | ||
[1.5 * HOUR, '1h'], | ||
[DAY, 'h', HOUR], | ||
[2 * DAY, '1d'], | ||
[7 * DAY, 'd', DAY], | ||
[1.5 * WEEK, '1w'], | ||
[MONTH, 'w', WEEK], | ||
[1.5 * MONTH, '1mo'], | ||
[YEAR, 'mo', MONTH], | ||
[1.5 * YEAR, '1y'], | ||
[Number.MAX_VALUE, 'y', YEAR], | ||
]; | ||
const longFormats = [[0.7 * MINUTE, 'just now'], [1.5 * MINUTE, 'a minute ago'], [60 * MINUTE, 'minutes ago', MINUTE], [1.5 * HOUR, 'an hour ago'], [DAY, 'hours ago', HOUR], [2 * DAY, 'yesterday'], [7 * DAY, 'days ago', DAY], [1.5 * WEEK, 'a week ago'], [MONTH, 'weeks ago', WEEK], [1.5 * MONTH, 'a month ago'], [YEAR, 'months ago', MONTH], [1.5 * YEAR, 'a year ago'], [Number.MAX_VALUE, 'years ago', YEAR]]; | ||
const longFormats = [ | ||
[0.7 * MINUTE, 'just now'], | ||
[1.5 * MINUTE, 'a minute ago'], | ||
[60 * MINUTE, 'minutes ago', MINUTE], | ||
[1.5 * HOUR, 'an hour ago'], | ||
[DAY, 'hours ago', HOUR], | ||
[2 * DAY, 'yesterday'], | ||
[7 * DAY, 'days ago', DAY], | ||
[1.5 * WEEK, 'a week ago'], | ||
[MONTH, 'weeks ago', WEEK], | ||
[1.5 * MONTH, 'a month ago'], | ||
[YEAR, 'months ago', MONTH], | ||
[1.5 * YEAR, 'a year ago'], | ||
[Number.MAX_VALUE, 'years ago', YEAR], | ||
]; | ||
function relativeDate(input_, reference_, useShortVariant = false) { | ||
export function relativeDate( | ||
input_: number | Date, | ||
reference_?: number | Date, | ||
useShortVariant?: boolean = false, | ||
): string { | ||
let input = input_; | ||
@@ -86,3 +97,7 @@ let reference = reference_; | ||
if (typeof remainder === 'number') { | ||
return Math.round(delta / remainder) + (useShortVariant ? '' : ' ') + relativeFormat; | ||
return ( | ||
Math.round(delta / remainder) + | ||
(useShortVariant ? '' : ' ') + | ||
relativeFormat | ||
); | ||
} else { | ||
@@ -101,6 +116,4 @@ return relativeFormat; | ||
*/ | ||
function countOccurrences(haystack, char) { | ||
if (!(char.length === 1)) { | ||
throw new Error('char must be a string of length 1'); | ||
} | ||
export function countOccurrences(haystack: string, char: string) { | ||
invariant(char.length === 1, 'char must be a string of length 1'); | ||
@@ -121,7 +134,9 @@ let count = 0; | ||
*/ | ||
function shellParse(str, env) { | ||
const result = (0, (_shellQuote || _load_shellQuote()).parse)(str, env); | ||
export function shellParse(str: string, env?: Object): Array<string> { | ||
const result = parse(str, env); | ||
for (let i = 0; i < result.length; i++) { | ||
if (typeof result[i] !== 'string') { | ||
throw new Error(`Unexpected operator "${result[i].op}" provided to shellParse`); | ||
throw new Error( | ||
`Unexpected operator "${result[i].op}" provided to shellParse`, | ||
); | ||
} | ||
@@ -132,3 +147,3 @@ } | ||
function removeCommonPrefix(a, b) { | ||
export function removeCommonPrefix(a: string, b: string): [string, string] { | ||
let i = 0; | ||
@@ -141,5 +156,9 @@ while (a[i] === b[i] && i < a.length && i < b.length) { | ||
function removeCommonSuffix(a, b) { | ||
export function removeCommonSuffix(a: string, b: string): [string, string] { | ||
let i = 0; | ||
while (a[a.length - 1 - i] === b[b.length - 1 - i] && i < a.length && i < b.length) { | ||
while ( | ||
a[a.length - 1 - i] === b[b.length - 1 - i] && | ||
i < a.length && | ||
i < b.length | ||
) { | ||
i++; | ||
@@ -150,4 +169,10 @@ } | ||
function shorten(str, maxLength, suffix) { | ||
return str.length < maxLength ? str : str.slice(0, maxLength) + (suffix || ''); | ||
export function shorten( | ||
str: string, | ||
maxLength: number, | ||
suffix?: string, | ||
): string { | ||
return str.length < maxLength | ||
? str | ||
: str.slice(0, maxLength) + (suffix || ''); | ||
} | ||
@@ -158,5 +183,7 @@ | ||
*/ | ||
function splitOnce(str, separator) { | ||
export function splitOnce(str: string, separator: string): [string, ?string] { | ||
const index = str.indexOf(separator); | ||
return index === -1 ? [str, null] : [str.slice(0, index), str.slice(index + separator.length)]; | ||
return index === -1 | ||
? [str, null] | ||
: [str.slice(0, index), str.slice(index + separator.length)]; | ||
} | ||
@@ -167,7 +194,11 @@ | ||
*/ | ||
function indent(str, level = 2, char = ' ') { | ||
export function indent( | ||
str: string, | ||
level: number = 2, | ||
char: string = ' ', | ||
): string { | ||
return str.replace(/^([^\n])/gm, char.repeat(level) + '$1'); | ||
} | ||
function pluralize(noun, count) { | ||
export function pluralize(noun: string, count: number) { | ||
return count === 1 ? noun : noun + 's'; | ||
@@ -183,2 +214,2 @@ } | ||
// eslint-disable-next-line max-len | ||
const URL_REGEX = exports.URL_REGEX = /(https?:\/\/(?:www\.)?[-\w@:%.+~#=]{2,256}\.[a-z]{2,6}\b[-\w@:%+.~#?&/=!]*|www\.[-\w@:%.+~#=]{2,256}\.[a-z]{2,6}\b[-\w@:%+.~#?&/=!]*)/; | ||
export const URL_REGEX = /(https?:\/\/(?:www\.)?[-\w@:%.+~#=]{2,256}\.[a-z]{2,6}\b[-\w@:%+.~#?&/=!]*|www\.[-\w@:%.+~#=]{2,256}\.[a-z]{2,6}\b[-\w@:%+.~#?&/=!]*)/; |
@@ -1,8 +0,14 @@ | ||
'use strict'; | ||
/** | ||
* Copyright (c) 2015-present, Facebook, Inc. | ||
* All rights reserved. | ||
* | ||
* This source code is licensed under the license found in the LICENSE file in | ||
* the root directory of this source tree. | ||
* | ||
* @flow | ||
* @format | ||
*/ | ||
Object.defineProperty(exports, "__esModule", { | ||
value: true | ||
}); | ||
export type AnyTeardown = (() => mixed) | rxjs$ISubscription | IDisposable; | ||
/** | ||
@@ -12,5 +18,7 @@ * Like a CompositeDisposable, but in addition to Disposable instances it can | ||
*/ | ||
class UniversalDisposable { | ||
export default class UniversalDisposable { | ||
disposed: boolean; | ||
teardowns: Set<AnyTeardown>; | ||
constructor(...teardowns) { | ||
constructor(...teardowns: Array<AnyTeardown>) { | ||
this.teardowns = new Set(); | ||
@@ -23,3 +31,3 @@ this.disposed = false; | ||
add(...teardowns) { | ||
add(...teardowns: Array<AnyTeardown>): void { | ||
if (this.disposed) { | ||
@@ -34,3 +42,3 @@ throw new Error('Cannot add to an already disposed UniversalDisposable!'); | ||
remove(teardown) { | ||
remove(teardown: AnyTeardown): void { | ||
if (!this.disposed) { | ||
@@ -41,3 +49,3 @@ this.teardowns.delete(teardown); | ||
dispose() { | ||
dispose(): void { | ||
if (!this.disposed) { | ||
@@ -54,11 +62,11 @@ this.disposed = true; | ||
}); | ||
this.teardowns = null; | ||
this.teardowns = (null: any); | ||
} | ||
} | ||
unsubscribe() { | ||
unsubscribe(): void { | ||
this.dispose(); | ||
} | ||
clear() { | ||
clear(): void { | ||
if (!this.disposed) { | ||
@@ -70,18 +78,13 @@ this.teardowns.clear(); | ||
exports.default = UniversalDisposable; /** | ||
* Copyright (c) 2015-present, Facebook, Inc. | ||
* All rights reserved. | ||
* | ||
* This source code is licensed under the license found in the LICENSE file in | ||
* the root directory of this source tree. | ||
* | ||
* | ||
* @format | ||
*/ | ||
function assertTeardown(teardown) { | ||
if (typeof teardown.dispose === 'function' || typeof teardown.unsubscribe === 'function' || typeof teardown === 'function') { | ||
function assertTeardown(teardown: AnyTeardown): void { | ||
if ( | ||
typeof teardown.dispose === 'function' || | ||
typeof teardown.unsubscribe === 'function' || | ||
typeof teardown === 'function' | ||
) { | ||
return; | ||
} | ||
throw new TypeError('Arguments to UniversalDisposable.add must be disposable'); | ||
} | ||
throw new TypeError( | ||
'Arguments to UniversalDisposable.add must be disposable', | ||
); | ||
} |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Shell access
Supply chain riskThis module accesses the system shell. Accessing the system shell increases the risk of executing arbitrary code.
Found 1 instance in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 2 instances in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
132072
27
4211
11
6
2
+ Addedfs-plus@2.9.3
+ Addedglob@7.1.1
+ Addedidx@1.2.0
+ Addedlru-cache@4.0.2
+ Addedmkdirp@0.5.1
+ Addedrimraf@2.5.4
+ Addedtemp@0.8.3
+ Addedasync@0.2.10(transitive)
+ Addedbalanced-match@1.0.2(transitive)
+ Addedbrace-expansion@1.1.11(transitive)
+ Addedconcat-map@0.0.1(transitive)
+ Addedfs-plus@2.9.3(transitive)
+ Addedfs.realpath@1.0.0(transitive)
+ Addedglob@7.1.1(transitive)
+ Addedidx@1.2.0(transitive)
+ Addedinflight@1.0.6(transitive)
+ Addedinherits@2.0.4(transitive)
+ Addedlru-cache@4.0.2(transitive)
+ Addedminimatch@3.1.2(transitive)
+ Addedminimist@0.0.8(transitive)
+ Addedmkdirp@0.3.50.5.1(transitive)
+ Addedonce@1.4.0(transitive)
+ Addedos-tmpdir@1.0.2(transitive)
+ Addedpath-is-absolute@1.0.1(transitive)
+ Addedpseudomap@1.0.2(transitive)
+ Addedrimraf@2.2.82.5.4(transitive)
+ Addedtemp@0.8.3(transitive)
+ Addedunderscore@1.13.7(transitive)
+ Addedunderscore-plus@1.7.0(transitive)
+ Addedwrappy@1.0.2(transitive)
+ Addedyallist@2.1.2(transitive)