UNPKG

paypal-checkout

Version:

PayPal Checkout components, for integrating checkout products.

381 lines (295 loc) 9.42 kB
/* @flow */ /* eslint max-lines: off */ import { ZalgoPromise } from 'zalgo-promise/src'; export { noop, once, uniqueID, isLocalStorageEnabled } from 'belter/src'; const moduleGlobal = {}; export function getGlobal() : Object { if (typeof window !== 'undefined') { return window; } if (typeof global !== 'undefined') { return global; } return moduleGlobal; } // eslint-disable-next-line flowtype/no-weak-types export function memoize<R>(method : (...args : $ReadOnlyArray<any>) => R, options : { time? : number } = {}) : ((...args : $ReadOnlyArray<any>) => R) { const cache : { [key : string] : { time : number, value : R } } = {}; // eslint-disable-next-line no-unused-vars, flowtype/no-weak-types return function memoizedFunction(...args : $ReadOnlyArray<any>) : R { let key : string; try { key = JSON.stringify(Array.prototype.slice.call(arguments)); } catch (err) { throw new Error(`Arguments not serializable -- can not be used to memoize`); } const time = options.time; if (cache[key] && time && (Date.now() - cache[key].time) < time) { delete cache[key]; } const glob = getGlobal(); if (glob.__CACHE_START_TIME__ && cache[key] && cache[key].time < glob.__CACHE_START_TIME__) { delete cache[key]; } if (cache[key]) { return cache[key].value; } cache[key] = { time: Date.now(), value: method.apply(this, arguments) }; return cache[key].value; }; } export function hashStr(str : string) : number { let hash = 0; for (let i = 0; i < str.length; i++) { hash += str[i].charCodeAt(0) * Math.pow((i % 10) + 1, 5); } return Math.floor(Math.pow(Math.sqrt(hash), 5)); } export function strHashStr(str : string) : string { let hash = ''; for (let i = 0; i < str.length; i++) { let total = (str[i].charCodeAt(0) * i); if (str[i + 1]) { total += (str[i + 1].charCodeAt(0) * (i - 1)); } hash += String.fromCharCode(97 + (Math.abs(total) % 26)); } return hash; } export function match(str : string, pattern : RegExp) : ?string { const regmatch = str.match(pattern); if (regmatch) { return regmatch[1]; } } export function safeJSON(item : mixed) : string { return JSON.stringify(item, (key, val) => { if (typeof val === 'function') { return `<${ typeof val }>`; } try { JSON.stringify(val); } catch (err) { return `<${ typeof val }>`; } return val; }); } type Listener = {| listen : (method : Function) => { cancel : () => void }, once : (method : Function) => void, trigger : (...args : $ReadOnlyArray<mixed>) => void |}; export function eventEmitter() : Listener { const listeners = []; return { listen(method : Function) : { cancel : () => void } { listeners.push(method); return { cancel() { listeners.splice(listeners.indexOf(method), 1); } }; }, once(method : Function) { const listener = this.listen(function onceListener() { method.apply(null, arguments); listener.cancel(); }); }, trigger(...args : $ReadOnlyArray<mixed>) { for (const listener of listeners) { listener(...args); } } }; } export function awaitKey<T: mixed>(obj : Object, key : string) : ZalgoPromise<T> { return new ZalgoPromise(resolve => { let value = obj[key]; if (value) { return resolve(value); } delete obj[key]; Object.defineProperty(obj, key, { configurable: true, set(item) { value = item; if (value) { resolve(value); } }, get() : mixed { return value; } }); }); } export function stringifyError(err : mixed, level : number = 1) : string { if (level >= 3) { return 'stringifyError stack overflow'; } try { if (!err) { return `<unknown error: ${ Object.prototype.toString.call(err) }>`; } if (typeof err === 'string') { return err; } if (err instanceof Error) { const stack = err && err.stack; const message = err && err.message; if (stack && message) { if (stack.indexOf(message) !== -1) { return stack; } else { return `${ message }\n${ stack }`; } } else if (stack) { return stack; } else if (message) { return message; } } if (typeof err.toString === 'function') { return err.toString(); } return Object.prototype.toString.call(err); } catch (newErr) { return `Error while stringifying error: ${ stringifyError(newErr, level + 1) }`; } } export function stringifyErrorMessage(err : mixed) : string { const defaultMessage = `<unknown error: ${ Object.prototype.toString.call(err) }>`; if (!err) { return defaultMessage; } if (err instanceof Error) { return err.message || defaultMessage; } if (typeof err.message === 'string') { return err.message || defaultMessage; } return defaultMessage; } export function stringify(item : mixed) : string { if (typeof item === 'string') { return item; } if (item && typeof item.toString === 'function') { return item.toString(); } return Object.prototype.toString.call(item); } export function domainMatches(hostname : string, domain : string) : boolean { hostname = hostname.split('://')[1]; const index = hostname.indexOf(domain); return (index !== -1 && hostname.slice(index) === domain); } export function patchMethod(obj : Object, name : string, handler : Function) { const original = obj[name]; obj[name] = function patchedMethod() : mixed { return handler({ context: this, args: Array.prototype.slice.call(arguments), original, callOriginal: () => original.apply(this, arguments) }); }; } export function isObject(obj : mixed) : boolean { return (typeof obj === 'object' && obj !== null); } export function extend<T : Object | Function>(obj : T, source : Object) : T { if (!source) { return obj; } if (Object.assign) { return Object.assign(obj, source); } for (const key in source) { if (source.hasOwnProperty(key)) { obj[key] = source[key]; } } return obj; } export function deepExtend<T : Object | Function > (obj : T, source : Object) : T { if (!source) { return obj; } for (const key in source) { if (source.hasOwnProperty(key)) { if (isObject(obj[key]) && isObject(source[key])) { deepExtend(obj[key], source[key]); } else { obj[key] = source[key]; } } } return obj; } export function hasValue<T : mixed>(obj : { [string] : T }, value : T) : boolean { for (const key in obj) { if (obj.hasOwnProperty(key) && obj[key] === value) { return true; } } return false; } export function contains<T>(arr : $ReadOnlyArray<T>, value : T) : boolean { return arr.indexOf(value) !== -1; } // eslint-disable-next-line flowtype/no-mutable-array export function sortBy<T>(arr : Array<T>, order : $ReadOnlyArray<T>) : Array<T> { return arr.sort((a : T, b : T) => { return order.indexOf(a) - order.indexOf(b); }); } export function reverseMap(obj : { [string] : string }) : { [string] : string } { const result = {}; for (const key in obj) { if (obj.hasOwnProperty(key)) { result[obj[key]] = key; } } return result; } // eslint-disable-next-line flowtype/no-mutable-array export function arrayRemove<T>(arr : Array<T>, item : T) { arr.splice(arr.indexOf(item), 1); } export function identity<T : mixed>(item : T) : T { return item; } export function values<T>(obj : { [string] : T }) : $ReadOnlyArray<T> { const result = []; for (const key in obj) { if (obj.hasOwnProperty(key)) { result.push(obj[key]); } } return result; } export function perc(pixels : number, percentage : number) : number { return Math.round((pixels * percentage) / 100); } export function min(...args : $ReadOnlyArray<number>) : number { return Math.min(...args); } export function max(...args : $ReadOnlyArray<number>) : number { return Math.max(...args); } export function regexMap<T>(str : string, regex : RegExp, handler : () => T) : $ReadOnlyArray<T> { const results = []; // $FlowFixMe str.replace(regex, function regexMapMatcher() { results.push(handler.apply(null, arguments)); }); return results; }