UNPKG

@uirouter/core

Version:

UI-Router Core: Framework agnostic, State-based routing for JavaScript Single Page Apps

78 lines 618 kB
{ "version": 3, "file": "ui-router-core.js", "sources": [ "@uirouter/core/common/hof.ts", "@uirouter/core/common/predicates.ts", "@uirouter/core/common/coreservices.ts", "@uirouter/core/common/common.ts", "@uirouter/core/common/glob.ts", "@uirouter/core/common/queue.ts", "@uirouter/core/transition/rejectFactory.ts", "@uirouter/core/common/strings.ts", "@uirouter/core/common/safeConsole.ts", "@uirouter/core/common/trace.ts", "@uirouter/core/params/paramType.ts", "@uirouter/core/params/param.ts", "@uirouter/core/params/paramTypes.ts", "@uirouter/core/params/stateParams.ts", "@uirouter/core/path/pathNode.ts", "@uirouter/core/state/targetState.ts", "@uirouter/core/path/pathUtils.ts", "@uirouter/core/resolve/interface.ts", "@uirouter/core/resolve/resolvable.ts", "@uirouter/core/resolve/resolveContext.ts", "@uirouter/core/state/stateBuilder.ts", "@uirouter/core/state/stateObject.ts", "@uirouter/core/state/stateMatcher.ts", "@uirouter/core/state/stateQueueManager.ts", "@uirouter/core/state/stateRegistry.ts", "@uirouter/core/transition/interface.ts", "@uirouter/core/transition/transitionHook.ts", "@uirouter/core/transition/hookRegistry.ts", "@uirouter/core/transition/hookBuilder.ts", "@uirouter/core/transition/transition.ts", "@uirouter/core/url/urlMatcher.ts", "@uirouter/core/url/urlMatcherFactory.ts", "@uirouter/core/url/urlRule.ts", "@uirouter/core/url/urlRouter.ts", "@uirouter/core/view/view.ts", "@uirouter/core/globals.ts", "@uirouter/core/url/urlRules.ts", "@uirouter/core/url/urlConfig.ts", "@uirouter/core/url/urlService.ts", "@uirouter/core/router.ts", "@uirouter/core/hooks/coreResolvables.ts", "@uirouter/core/hooks/redirectTo.ts", "@uirouter/core/hooks/onEnterExitRetain.ts", "@uirouter/core/hooks/resolve.ts", "@uirouter/core/hooks/views.ts", "@uirouter/core/hooks/updateGlobals.ts", "@uirouter/core/hooks/url.ts", "@uirouter/core/hooks/lazyLoad.ts", "@uirouter/core/transition/transitionEventType.ts", "@uirouter/core/hooks/ignoredTransition.ts", "@uirouter/core/hooks/invalidTransition.ts", "@uirouter/core/transition/transitionService.ts", "@uirouter/core/state/stateService.ts", "@uirouter/core/vanilla/q.ts", "@uirouter/core/vanilla/injector.ts", "@uirouter/core/vanilla/utils.ts", "@uirouter/core/vanilla/baseLocationService.ts", "@uirouter/core/vanilla/hashLocationService.ts", "@uirouter/core/vanilla/memoryLocationService.ts", "@uirouter/core/vanilla/pushStateLocationService.ts", "@uirouter/core/vanilla/memoryLocationConfig.ts", "@uirouter/core/vanilla/browserLocationConfig.ts", "@uirouter/core/vanilla/plugins.ts", "@uirouter/core/interface.ts" ], "sourcesContent": [ "/**\n * Higher order functions\n *\n * These utility functions are exported, but are subject to change without notice.\n *\n * @packageDocumentation\n */\n\nimport { Predicate } from './common';\n/**\n * Returns a new function for [Partial Application](https://en.wikipedia.org/wiki/Partial_application) of the original function.\n *\n * Given a function with N parameters, returns a new function that supports partial application.\n * The new function accepts anywhere from 1 to N parameters. When that function is called with M parameters,\n * where M is less than N, it returns a new function that accepts the remaining parameters. It continues to\n * accept more parameters until all N parameters have been supplied.\n *\n *\n * This contrived example uses a partially applied function as an predicate, which returns true\n * if an object is found in both arrays.\n * @example\n * ```\n * // returns true if an object is in both of the two arrays\n * function inBoth(array1, array2, object) {\n * return array1.indexOf(object) !== -1 &&\n * array2.indexOf(object) !== 1;\n * }\n * let obj1, obj2, obj3, obj4, obj5, obj6, obj7\n * let foos = [obj1, obj3]\n * let bars = [obj3, obj4, obj5]\n *\n * // A curried \"copy\" of inBoth\n * let curriedInBoth = curry(inBoth);\n * // Partially apply both the array1 and array2\n * let inFoosAndBars = curriedInBoth(foos, bars);\n *\n * // Supply the final argument; since all arguments are\n * // supplied, the original inBoth function is then called.\n * let obj1InBoth = inFoosAndBars(obj1); // false\n *\n * // Use the inFoosAndBars as a predicate.\n * // Filter, on each iteration, supplies the final argument\n * let allObjs = [ obj1, obj2, obj3, obj4, obj5, obj6, obj7 ];\n * let foundInBoth = allObjs.filter(inFoosAndBars); // [ obj3 ]\n *\n * ```\n *\n * @param fn\n * @returns {*|function(): (*|any)}\n */\nexport function curry(fn: Function): Function {\n return function curried() {\n if (arguments.length >= fn.length) {\n return fn.apply(this, arguments);\n }\n const args = Array.prototype.slice.call(arguments);\n return curried.bind(this, ...args);\n };\n}\n\n/**\n * Given a varargs list of functions, returns a function that composes the argument functions, right-to-left\n * given: f(x), g(x), h(x)\n * let composed = compose(f,g,h)\n * then, composed is: f(g(h(x)))\n */\nexport function compose() {\n const args = arguments;\n const start = args.length - 1;\n return function () {\n let i = start,\n result = args[start].apply(this, arguments);\n while (i--) result = args[i].call(this, result);\n return result;\n };\n}\n\n/**\n * Given a varargs list of functions, returns a function that is composes the argument functions, left-to-right\n * given: f(x), g(x), h(x)\n * let piped = pipe(f,g,h);\n * then, piped is: h(g(f(x)))\n */\nexport function pipe(...funcs: Function[]): (obj: any) => any {\n return compose.apply(null, [].slice.call(arguments).reverse());\n}\n\n/**\n * Given a property name, returns a function that returns that property from an object\n * let obj = { foo: 1, name: \"blarg\" };\n * let getName = prop(\"name\");\n * getName(obj) === \"blarg\"\n */\nexport const prop = (name: string) => (obj: any) => obj && obj[name];\n\n/**\n * Given a property name and a value, returns a function that returns a boolean based on whether\n * the passed object has a property that matches the value\n * let obj = { foo: 1, name: \"blarg\" };\n * let getName = propEq(\"name\", \"blarg\");\n * getName(obj) === true\n */\nexport const propEq = curry((name: string, _val: any, obj: any) => obj && obj[name] === _val);\n\n/**\n * Given a dotted property name, returns a function that returns a nested property from an object, or undefined\n * let obj = { id: 1, nestedObj: { foo: 1, name: \"blarg\" }, };\n * let getName = prop(\"nestedObj.name\");\n * getName(obj) === \"blarg\"\n * let propNotFound = prop(\"this.property.doesnt.exist\");\n * propNotFound(obj) === undefined\n */\nexport const parse = (name: string) => pipe.apply(null, name.split('.').map(prop));\n\n/**\n * Given a function that returns a truthy or falsey value, returns a\n * function that returns the opposite (falsey or truthy) value given the same inputs\n */\nexport const not: (fn: Predicate<any>) => Predicate<any> = (fn: Predicate<any>) => (...args: any[]) =>\n !fn.apply(null, args);\n\n/**\n * Given two functions that return truthy or falsey values, returns a function that returns truthy\n * if both functions return truthy for the given arguments\n */\nexport function and(fn1: Predicate<any>, fn2: Predicate<any>): Predicate<any> {\n return (...args: any[]) => fn1.apply(null, args) && fn2.apply(null, args);\n}\n\n/**\n * Given two functions that return truthy or falsey values, returns a function that returns truthy\n * if at least one of the functions returns truthy for the given arguments\n */\nexport function or(fn1: Predicate<any>, fn2: Predicate<any>): Predicate<any> {\n return (...args: any[]) => fn1.apply(null, args) || fn2.apply(null, args);\n}\n\n/**\n * Check if all the elements of an array match a predicate function\n *\n * @param fn1 a predicate function `fn1`\n * @returns a function which takes an array and returns true if `fn1` is true for all elements of the array\n */\nexport const all = (fn1: Predicate<any>) => (arr: any[]) => arr.reduce((b, x) => b && !!fn1(x), true) as boolean;\n\n// tslint:disable-next-line:variable-name\nexport const any = (fn1: Predicate<any>) => (arr: any[]) => arr.reduce((b, x) => b || !!fn1(x), false) as boolean;\n\n/** Given a class, returns a Predicate function that returns true if the object is of that class */\nexport const is = <T>(ctor: { new (...args): T }) => (obj: any): obj is T =>\n (obj != null && obj.constructor === ctor) || obj instanceof ctor;\n\n/** Given a value, returns a Predicate function that returns true if another value is === equal to the original value */\nexport const eq: (comp: any) => Predicate<any> = (value: any) => (other: any) => value === other;\n\n/** Given a value, returns a function which returns the value */\nexport const val = <T>(v: T) => () => v;\n\nexport function invoke(fnName: string): Function;\nexport function invoke(fnName: string, args: any[]): Function;\nexport function invoke(fnName: string, args?: any[]): Function {\n return (obj: any) => obj[fnName].apply(obj, args);\n}\n\n/**\n * Sorta like Pattern Matching (a functional programming conditional construct)\n *\n * See http://c2.com/cgi/wiki?PatternMatching\n *\n * This is a conditional construct which allows a series of predicates and output functions\n * to be checked and then applied. Each predicate receives the input. If the predicate\n * returns truthy, then its matching output function (mapping function) is provided with\n * the input and, then the result is returned.\n *\n * Each combination (2-tuple) of predicate + output function should be placed in an array\n * of size 2: [ predicate, mapFn ]\n *\n * These 2-tuples should be put in an outer array.\n *\n * @example\n * ```\n *\n * // Here's a 2-tuple where the first element is the isString predicate\n * // and the second element is a function that returns a description of the input\n * let firstTuple = [ angular.isString, (input) => `Heres your string ${input}` ];\n *\n * // Second tuple: predicate \"isNumber\", mapfn returns a description\n * let secondTuple = [ angular.isNumber, (input) => `(${input}) That's a number!` ];\n *\n * let third = [ (input) => input === null, (input) => `Oh, null...` ];\n *\n * let fourth = [ (input) => input === undefined, (input) => `notdefined` ];\n *\n * let descriptionOf = pattern([ firstTuple, secondTuple, third, fourth ]);\n *\n * console.log(descriptionOf(undefined)); // 'notdefined'\n * console.log(descriptionOf(55)); // '(55) That's a number!'\n * console.log(descriptionOf(\"foo\")); // 'Here's your string foo'\n * ```\n *\n * @param struct A 2D array. Each element of the array should be an array, a 2-tuple,\n * with a Predicate and a mapping/output function\n * @returns {function(any): *}\n */\nexport function pattern(struct: Function[][]): Function {\n return function (x: any) {\n for (let i = 0; i < struct.length; i++) {\n if (struct[i][0](x)) return struct[i][1](x);\n }\n };\n}\n", "/**\n * Predicates\n *\n * These predicates return true/false based on the input.\n * Although these functions are exported, they are subject to change without notice.\n *\n * @packageDocumentation\n */\nimport { and, not, pipe, prop, or } from './hof';\nimport { Predicate } from './common'; // has or is using\nimport { StateObject } from '../state/stateObject';\n\nconst toStr = Object.prototype.toString;\nconst tis = (t: string) => (x: any) => typeof x === t;\nexport const isUndefined = tis('undefined');\nexport const isDefined = not(isUndefined);\nexport const isNull = (o: any) => o === null;\nexport const isNullOrUndefined = or(isNull, isUndefined);\nexport const isFunction: (x: any) => x is Function = <any>tis('function');\nexport const isNumber: (x: any) => x is number = <any>tis('number');\nexport const isString = <(x: any) => x is string>tis('string');\nexport const isObject = (x: any) => x !== null && typeof x === 'object';\nexport const isArray = Array.isArray;\nexport const isDate: (x: any) => x is Date = <any>((x: any) => toStr.call(x) === '[object Date]');\nexport const isRegExp: (x: any) => x is RegExp = <any>((x: any) => toStr.call(x) === '[object RegExp]');\n\n/**\n * Predicate which checks if a value is injectable\n *\n * A value is \"injectable\" if it is a function, or if it is an ng1 array-notation-style array\n * where all the elements in the array are Strings, except the last one, which is a Function\n */\nexport function isInjectable(val: any) {\n if (isArray(val) && val.length) {\n const head = val.slice(0, -1),\n tail = val.slice(-1);\n return !(head.filter(not(isString)).length || tail.filter(not(isFunction)).length);\n }\n return isFunction(val);\n}\n\n/**\n * Predicate which checks if a value looks like a Promise\n *\n * It is probably a Promise if it's an object, and it has a `then` property which is a Function\n */\nexport const isPromise = <(x: any) => x is Promise<any>>and(isObject, pipe(prop('then'), isFunction));\n", "/**\n * This module is a stub for core services such as Dependency Injection or Browser Location.\n * Core services may be implemented by a specific framework, such as ng1 or ng2, or be pure javascript.\n *\n * @packageDocumentation\n */\nimport { IInjectable, Obj } from './common';\nimport { Disposable } from '../interface';\nimport { UrlConfig, UrlService } from '../url';\n\nconst noImpl = (fnname: string) => () => {\n throw new Error(`No implementation for ${fnname}. The framework specific code did not implement this method.`);\n};\n\nexport const makeStub = <T>(service: string, methods: (keyof T)[]): T =>\n methods.reduce((acc, key) => ((acc[key] = noImpl(`${service}.${key}()`) as any), acc), {} as T);\n\nconst services: CoreServices = {\n $q: undefined,\n $injector: undefined,\n};\n\nexport interface $QLikeDeferred {\n resolve: (val?: any) => void;\n reject: (reason?: any) => void;\n promise: Promise<any>;\n}\n\nexport interface $QLike {\n when<T>(value?: T | PromiseLike<T>): Promise<T>;\n reject<T>(reason: any): Promise<T>;\n defer(): $QLikeDeferred;\n all(promises: { [key: string]: Promise<any> }): Promise<any>;\n all(promises: Promise<any>[]): Promise<any[]>;\n}\n\nexport interface $InjectorLike {\n strictDi?: boolean;\n get(token: any): any;\n get<T>(token: any): T;\n has(token: any): boolean;\n invoke(fn: IInjectable, context?: any, locals?: Obj): any;\n annotate(fn: IInjectable, strictDi?: boolean): any[];\n}\n\nexport interface CoreServices {\n $q: $QLike;\n $injector: $InjectorLike;\n}\n\n/**\n * Handles low level URL read/write\n *\n * This service handles low level reads and updates of the URL and listens for url changes.\n * Implementors should pass these through to the underlying URL mechanism.\n * The underlying URL mechanism might be browser APIs, framework APIs, or some 3rd party URL management library.\n *\n * UI-Router Core includes three basic implementations:\n *\n * - [[PushStateLocationService]]\n * - [[HashLocationService]]\n * - [[MemoryLocationService]]\n */\nexport interface LocationServices extends Disposable {\n /** See: [[UrlService.url]] */ url: UrlService['url'];\n /** See: [[UrlService.path]] */ path: UrlService['path'];\n /** See: [[UrlService.search]] */ search: UrlService['search'];\n /** See: [[UrlService.hash]] */ hash: UrlService['hash'];\n /** See: [[UrlService.onChange]] */ onChange: UrlService['onChange'];\n}\n\n/**\n * Returns low level URL configuration and metadata\n *\n * This service returns information about the location configuration.\n * This service is primarily used when building URLs (e.g., for `hrefs`)\n *\n * Implementors should pass these through to the underlying URL APIs.\n * The underlying URL mechanism might be browser APIs, framework APIs, or some 3rd party URL management library.\n *\n * UI-Router Core includes two basic implementations:\n *\n * - [[BrowserLocationConfig]]\n * - [[MemoryLocationConfig]]\n */\nexport interface LocationConfig extends Disposable {\n /** See: [[UrlConfig.port]] */ port: UrlConfig['port'];\n /** See: [[UrlConfig.protocol]] */ protocol: UrlConfig['protocol'];\n /** See: [[UrlConfig.host]] */ host: UrlConfig['host'];\n /** See: [[UrlConfig.baseHref]] */ baseHref: UrlConfig['baseHref'];\n /** See: [[UrlConfig.html5Mode]] */ html5Mode: UrlConfig['html5Mode'];\n /** See: [[UrlConfig.hashPrefix]] */ hashPrefix: UrlConfig['hashPrefix'];\n}\n\nexport { services };\n", "/**\n * Random utility functions used in the UI-Router code\n *\n * These functions are exported, but are subject to change without notice.\n *\n * @packageDocumentation\n * @preferred\n */\nimport { isFunction, isString, isArray, isRegExp, isDate } from './predicates';\nimport { all, any, prop, curry, not } from './hof';\nimport { services } from './coreservices';\nimport { StateObject } from '../state/stateObject';\n\ndeclare const global;\nexport const root: any =\n (typeof self === 'object' && self.self === self && self) ||\n (typeof global === 'object' && global.global === global && global) ||\n this;\nconst angular = root.angular || {};\n\nexport const fromJson = angular.fromJson || JSON.parse.bind(JSON);\nexport const toJson = angular.toJson || JSON.stringify.bind(JSON);\nexport const forEach = angular.forEach || _forEach;\nexport const extend = Object.assign || _extend;\nexport const equals = angular.equals || _equals;\nexport function identity(x: any) {\n return x;\n}\nexport function noop(): any {}\n\nexport type Mapper<X, T> = (x: X, key?: string | number) => T;\nexport interface TypedMap<T> {\n [key: string]: T;\n}\nexport type Predicate<X> = (x?: X) => boolean;\nexport type PredicateBinary<X, Y> = (x?: X, y?: Y) => boolean;\n/**\n * An ng1-style injectable\n *\n * This could be a (non-minified) function such as:\n * ```js\n * function injectableFunction(SomeDependency) {\n *\n * }\n * ```\n *\n * or an explicitly annotated function (minify safe)\n * ```js\n * injectableFunction.$inject = [ 'SomeDependency' ];\n * function injectableFunction(SomeDependency) {\n *\n * }\n * ```\n *\n * or an array style annotated function (minify safe)\n * ```js\n * ['SomeDependency', function injectableFunction(SomeDependency) {\n *\n * }];\n * ```\n */\nexport type IInjectable = Function | any[];\n\nexport interface Obj extends Object {\n [key: string]: any;\n}\n\n/**\n * Builds proxy functions on the `to` object which pass through to the `from` object.\n *\n * For each key in `fnNames`, creates a proxy function on the `to` object.\n * The proxy function calls the real function on the `from` object.\n *\n *\n * #### Example:\n * This example creates an new class instance whose functions are prebound to the new'd object.\n * ```js\n * class Foo {\n * constructor(data) {\n * // Binds all functions from Foo.prototype to 'this',\n * // then copies them to 'this'\n * bindFunctions(Foo.prototype, this, this);\n * this.data = data;\n * }\n *\n * log() {\n * console.log(this.data);\n * }\n * }\n *\n * let myFoo = new Foo([1,2,3]);\n * var logit = myFoo.log;\n * logit(); // logs [1, 2, 3] from the myFoo 'this' instance\n * ```\n *\n * #### Example:\n * This example creates a bound version of a service function, and copies it to another object\n * ```\n *\n * var SomeService = {\n * this.data = [3, 4, 5];\n * this.log = function() {\n * console.log(this.data);\n * }\n * }\n *\n * // Constructor fn\n * function OtherThing() {\n * // Binds all functions from SomeService to SomeService,\n * // then copies them to 'this'\n * bindFunctions(SomeService, this, SomeService);\n * }\n *\n * let myOtherThing = new OtherThing();\n * myOtherThing.log(); // logs [3, 4, 5] from SomeService's 'this'\n * ```\n *\n * @param source A function that returns the source object which contains the original functions to be bound\n * @param target A function that returns the target object which will receive the bound functions\n * @param bind A function that returns the object which the functions will be bound to\n * @param fnNames The function names which will be bound (Defaults to all the functions found on the 'from' object)\n * @param latebind If true, the binding of the function is delayed until the first time it's invoked\n */\nexport function createProxyFunctions(\n source: Function,\n target: Obj,\n bind: Function,\n fnNames?: string[],\n latebind = false\n): Obj {\n const bindFunction = (fnName) => source()[fnName].bind(bind());\n\n const makeLateRebindFn = (fnName) =>\n function lateRebindFunction() {\n target[fnName] = bindFunction(fnName);\n return target[fnName].apply(null, arguments);\n };\n\n fnNames = fnNames || Object.keys(source());\n\n return fnNames.reduce((acc, name) => {\n acc[name] = latebind ? makeLateRebindFn(name) : bindFunction(name);\n return acc;\n }, target);\n}\n\n/**\n * prototypal inheritance helper.\n * Creates a new object which has `parent` object as its prototype, and then copies the properties from `extra` onto it\n */\nexport const inherit = (parent: Obj, extra?: Obj) => extend(Object.create(parent), extra);\n\n/** Given an array, returns true if the object is found in the array, (using indexOf) */\nexport const inArray: typeof _inArray = curry(_inArray) as any;\nexport function _inArray(array: any[], obj: any): boolean;\nexport function _inArray(array: any[]): (obj: any) => boolean;\nexport function _inArray(array, obj?): any {\n return array.indexOf(obj) !== -1;\n}\n\n/**\n * Given an array, and an item, if the item is found in the array, it removes it (in-place).\n * The same array is returned\n */\nexport const removeFrom: typeof _removeFrom = curry(_removeFrom) as any;\nexport function _removeFrom<T>(array: T[], obj: T): T[];\nexport function _removeFrom<T>(array: T[]): (obj: T) => T[];\nexport function _removeFrom(array, obj?) {\n const idx = array.indexOf(obj);\n if (idx >= 0) array.splice(idx, 1);\n return array;\n}\n\n/** pushes a values to an array and returns the value */\nexport const pushTo: typeof _pushTo = curry(_pushTo) as any;\nexport function _pushTo<T>(arr: T[], val: T): T;\nexport function _pushTo<T>(arr: T[]): (val: T) => T;\nexport function _pushTo(arr, val?): any {\n return arr.push(val), val;\n}\n\n/** Given an array of (deregistration) functions, calls all functions and removes each one from the source array */\nexport const deregAll = (functions: Function[]) =>\n functions.slice().forEach((fn) => {\n typeof fn === 'function' && fn();\n removeFrom(functions, fn);\n });\n/**\n * Applies a set of defaults to an options object. The options object is filtered\n * to only those properties of the objects in the defaultsList.\n * Earlier objects in the defaultsList take precedence when applying defaults.\n */\nexport function defaults(opts, ...defaultsList: Obj[]) {\n const defaultVals = extend({}, ...defaultsList.reverse());\n return extend(defaultVals, pick(opts || {}, Object.keys(defaultVals)));\n}\n\n/** Reduce function that merges each element of the list into a single object, using extend */\nexport const mergeR = (memo: Obj, item: Obj) => extend(memo, item);\n\n/**\n * Finds the common ancestor path between two states.\n *\n * @param {Object} first The first state.\n * @param {Object} second The second state.\n * @return {Array} Returns an array of state names in descending order, not including the root.\n */\nexport function ancestors(first: StateObject, second: StateObject) {\n const path: StateObject[] = [];\n\n // tslint:disable-next-line:forin\n for (const n in first.path) {\n if (first.path[n] !== second.path[n]) break;\n path.push(first.path[n]);\n }\n return path;\n}\n\n/**\n * Return a copy of the object only containing the whitelisted properties.\n *\n * #### Example:\n * ```\n * var foo = { a: 1, b: 2, c: 3 };\n * var ab = pick(foo, ['a', 'b']); // { a: 1, b: 2 }\n * ```\n * @param obj the source object\n * @param propNames an Array of strings, which are the whitelisted property names\n */\nexport function pick(obj: Obj, propNames: string[]): Obj {\n const objCopy = {};\n for (const _prop in obj) {\n if (propNames.indexOf(_prop) !== -1) {\n objCopy[_prop] = obj[_prop];\n }\n }\n return objCopy;\n}\n\n/**\n * Return a copy of the object omitting the blacklisted properties.\n *\n * @example\n * ```\n *\n * var foo = { a: 1, b: 2, c: 3 };\n * var ab = omit(foo, ['a', 'b']); // { c: 3 }\n * ```\n * @param obj the source object\n * @param propNames an Array of strings, which are the blacklisted property names\n */\nexport function omit(obj: Obj, propNames: string[]): Obj {\n return Object.keys(obj)\n .filter(not(inArray(propNames)))\n .reduce((acc, key) => ((acc[key] = obj[key]), acc), {});\n}\n\n/** Given an array of objects, maps each element to a named property of the element. */\nexport function pluck<T>(collection: Obj[], propName: string): T[];\n/** Given an object, maps each property of the object to a named property of the property. */\nexport function pluck(collection: { [key: string]: any }, propName: string): { [key: string]: any };\n/**\n * Maps an array, or object to a property (by name)\n */\nexport function pluck(collection: any, propName: string): any {\n return map(collection, <Mapper<any, string>>prop(propName));\n}\n\n/** Given an array of objects, returns a new array containing only the elements which passed the callback predicate */\nexport function filter<T>(collection: T[], callback: (t: T, key?: number) => boolean): T[];\n/** Given an object, returns a new object with only those properties that passed the callback predicate */\nexport function filter<T>(collection: TypedMap<T>, callback: (t: T, key?: string) => boolean): TypedMap<T>;\n/** Filters an Array or an Object's properties based on a predicate */\nexport function filter<T>(collection: any, callback: Function): T {\n const arr = isArray(collection),\n result: any = arr ? [] : {};\n const accept = arr ? (x) => result.push(x) : (x, key) => (result[key] = x);\n forEach(collection, function (item, i) {\n if (callback(item, i)) accept(item, i);\n });\n return <T>result;\n}\n\n/** Given an object, return the first property of that object which passed the callback predicate */\nexport function find<T>(collection: TypedMap<T>, callback: Predicate<T>): T;\n/** Given an array of objects, returns the first object which passed the callback predicate */\nexport function find<T>(collection: T[], callback: Predicate<T>): T;\n/** Finds an object from an array, or a property of an object, that matches a predicate */\nexport function find(collection: any, callback: any) {\n let result;\n\n forEach(collection, function (item, i) {\n if (result) return;\n if (callback(item, i)) result = item;\n });\n\n return result;\n}\n\n/** Given an object, returns a new object, where each property is transformed by the callback function */\nexport let mapObj: <T, U>(\n collection: { [key: string]: T },\n callback: Mapper<T, U>,\n target?: typeof collection\n) => { [key: string]: U } = map;\n/** Given an array, returns a new array, where each element is transformed by the callback function */\nexport function map<T, U>(collection: T[], callback: Mapper<T, U>, target?: typeof collection): U[];\nexport function map<T, U>(\n collection: { [key: string]: T },\n callback: Mapper<T, U>,\n target?: typeof collection\n): { [key: string]: U };\n/** Maps an array or object properties using a callback function */\nexport function map(collection: any, callback: any, target: typeof collection): any {\n target = target || (isArray(collection) ? [] : {});\n forEach(collection, (item, i) => (target[i] = callback(item, i)));\n return target;\n}\n\n/**\n * Given an object, return its enumerable property values\n *\n * @example\n * ```\n *\n * let foo = { a: 1, b: 2, c: 3 }\n * let vals = values(foo); // [ 1, 2, 3 ]\n * ```\n */\nexport const values: <T>(obj: TypedMap<T>) => T[] = (obj: Obj) => Object.keys(obj).map((key) => obj[key]);\n\n/**\n * Reduce function that returns true if all of the values are truthy.\n *\n * @example\n * ```\n *\n * let vals = [ 1, true, {}, \"hello world\"];\n * vals.reduce(allTrueR, true); // true\n *\n * vals.push(0);\n * vals.reduce(allTrueR, true); // false\n * ```\n */\nexport const allTrueR = (memo: boolean, elem: any) => memo && elem;\n\n/**\n * Reduce function that returns true if any of the values are truthy.\n *\n * * @example\n * ```\n *\n * let vals = [ 0, null, undefined ];\n * vals.reduce(anyTrueR, true); // false\n *\n * vals.push(\"hello world\");\n * vals.reduce(anyTrueR, true); // true\n * ```\n */\nexport const anyTrueR = (memo: boolean, elem: any) => memo || elem;\n\n/**\n * Reduce function which un-nests a single level of arrays\n * @example\n * ```\n *\n * let input = [ [ \"a\", \"b\" ], [ \"c\", \"d\" ], [ [ \"double\", \"nested\" ] ] ];\n * input.reduce(unnestR, []) // [ \"a\", \"b\", \"c\", \"d\", [ \"double, \"nested\" ] ]\n * ```\n */\nexport const unnestR = (memo: any[], elem: any[]) => memo.concat(elem);\n\n/**\n * Reduce function which recursively un-nests all arrays\n *\n * @example\n * ```\n *\n * let input = [ [ \"a\", \"b\" ], [ \"c\", \"d\" ], [ [ \"double\", \"nested\" ] ] ];\n * input.reduce(unnestR, []) // [ \"a\", \"b\", \"c\", \"d\", \"double, \"nested\" ]\n * ```\n */\nexport const flattenR = (memo: any[], elem: any) =>\n isArray(elem) ? memo.concat(elem.reduce(flattenR, [])) : pushR(memo, elem);\n\n/**\n * Reduce function that pushes an object to an array, then returns the array.\n * Mostly just for [[flattenR]] and [[uniqR]]\n */\nexport function pushR(arr: any[], obj: any) {\n arr.push(obj);\n return arr;\n}\n\n/** Reduce function that filters out duplicates */\nexport const uniqR = <T>(acc: T[], token: T): T[] => (inArray(acc, token) ? acc : pushR(acc, token));\n\n/**\n * Return a new array with a single level of arrays unnested.\n *\n * @example\n * ```\n *\n * let input = [ [ \"a\", \"b\" ], [ \"c\", \"d\" ], [ [ \"double\", \"nested\" ] ] ];\n * unnest(input) // [ \"a\", \"b\", \"c\", \"d\", [ \"double, \"nested\" ] ]\n * ```\n */\nexport const unnest = (arr: any[]) => arr.reduce(unnestR, []);\n/**\n * Return a completely flattened version of an array.\n *\n * @example\n * ```\n *\n * let input = [ [ \"a\", \"b\" ], [ \"c\", \"d\" ], [ [ \"double\", \"nested\" ] ] ];\n * flatten(input) // [ \"a\", \"b\", \"c\", \"d\", \"double, \"nested\" ]\n * ```\n */\nexport const flatten = (arr: any[]) => arr.reduce(flattenR, []);\n\n/**\n * Given a .filter Predicate, builds a .filter Predicate which throws an error if any elements do not pass.\n * @example\n * ```\n *\n * let isNumber = (obj) => typeof(obj) === 'number';\n * let allNumbers = [ 1, 2, 3, 4, 5 ];\n * allNumbers.filter(assertPredicate(isNumber)); //OK\n *\n * let oneString = [ 1, 2, 3, 4, \"5\" ];\n * oneString.filter(assertPredicate(isNumber, \"Not all numbers\")); // throws Error(\"\"Not all numbers\"\");\n * ```\n */\nexport const assertPredicate: <T>(predicate: Predicate<T>, errMsg: string | Function) => Predicate<T> = assertFn;\n/**\n * Given a .map function, builds a .map function which throws an error if any mapped elements do not pass a truthyness test.\n * @example\n * ```\n *\n * var data = { foo: 1, bar: 2 };\n *\n * let keys = [ 'foo', 'bar' ]\n * let values = keys.map(assertMap(key => data[key], \"Key not found\"));\n * // values is [1, 2]\n *\n * let keys = [ 'foo', 'bar', 'baz' ]\n * let values = keys.map(assertMap(key => data[key], \"Key not found\"));\n * // throws Error(\"Key not found\")\n * ```\n */\nexport const assertMap: <T, U>(mapFn: (t: T) => U, errMsg: string | Function) => (t: T) => U = assertFn;\nexport function assertFn(predicateOrMap: Function, errMsg: string | Function = 'assert failure'): any {\n return (obj) => {\n const result = predicateOrMap(obj);\n if (!result) {\n throw new Error(isFunction(errMsg) ? (<Function>errMsg)(obj) : errMsg);\n }\n return result;\n };\n}\n\n/**\n * Like _.pairs: Given an object, returns an array of key/value pairs\n *\n * @example\n * ```\n *\n * pairs({ foo: \"FOO\", bar: \"BAR }) // [ [ \"foo\", \"FOO\" ], [ \"bar\": \"BAR\" ] ]\n * ```\n */\nexport const pairs = (obj: Obj) => Object.keys(obj).map((key) => [key, obj[key]]);\n\n/**\n * Given two or more parallel arrays, returns an array of tuples where\n * each tuple is composed of [ a[i], b[i], ... z[i] ]\n *\n * @example\n * ```\n *\n * let foo = [ 0, 2, 4, 6 ];\n * let bar = [ 1, 3, 5, 7 ];\n * let baz = [ 10, 30, 50, 70 ];\n * arrayTuples(foo, bar); // [ [0, 1], [2, 3], [4, 5], [6, 7] ]\n * arrayTuples(foo, bar, baz); // [ [0, 1, 10], [2, 3, 30], [4, 5, 50], [6, 7, 70] ]\n * ```\n */\nexport function arrayTuples(...args: any[]): any[] {\n if (args.length === 0) return [];\n const maxArrayLen = args.reduce((min, arr) => Math.min(arr.length, min), 9007199254740991); // aka 2^53 − 1 aka Number.MAX_SAFE_INTEGER\n const result = [];\n\n for (let i = 0; i < maxArrayLen; i++) {\n // This is a hot function\n // Unroll when there are 1-4 arguments\n switch (args.length) {\n case 1:\n result.push([args[0][i]]);\n break;\n case 2:\n result.push([args[0][i], args[1][i]]);\n break;\n case 3:\n result.push([args[0][i], args[1][i], args[2][i]]);\n break;\n case 4:\n result.push([args[0][i], args[1][i], args[2][i], args[3][i]]);\n break;\n default:\n result.push(args.map((array) => array[i]));\n break;\n }\n }\n\n return result;\n}\n\n/**\n * Reduce function which builds an object from an array of [key, value] pairs.\n *\n * Each iteration sets the key/val pair on the memo object, then returns the memo for the next iteration.\n *\n * Each keyValueTuple should be an array with values [ key: string, value: any ]\n *\n * @example\n * ```\n *\n * var pairs = [ [\"fookey\", \"fooval\"], [\"barkey\", \"barval\"] ]\n *\n * var pairsToObj = pairs.reduce((memo, pair) => applyPairs(memo, pair), {})\n * // pairsToObj == { fookey: \"fooval\", barkey: \"barval\" }\n *\n * // Or, more simply:\n * var pairsToObj = pairs.reduce(applyPairs, {})\n * // pairsToObj == { fookey: \"fooval\", barkey: \"barval\" }\n * ```\n */\nexport function applyPairs(memo: TypedMap<any>, keyValTuple: any[]) {\n let key: string, value: any;\n if (isArray(keyValTuple)) [key, value] = keyValTuple;\n if (!isString(key)) throw new Error('invalid parameters to applyPairs');\n memo[key] = value;\n return memo;\n}\n\n/** Get the last element of an array */\nexport function tail<T>(arr: T[]): T {\n return (arr.length && arr[arr.length - 1]) || undefined;\n}\n\n/**\n * shallow copy from src to dest\n */\nexport function copy(src: Obj, dest?: Obj) {\n if (dest) Object.keys(dest).forEach((key) => delete dest[key]);\n if (!dest) dest = {};\n return extend(dest, src);\n}\n\n/** Naive forEach implementation works with Objects or Arrays */\nfunction _forEach(obj: any[] | any, cb: (el, idx?) => void, _this: Obj) {\n if (isArray(obj)) return obj.forEach(cb, _this);\n Object.keys(obj).forEach((key) => cb(obj[key], key));\n}\n\n/** Like Object.assign() */\nexport function _extend(toObj: Obj, ...fromObjs: Obj[]): any;\nexport function _extend(toObj: Obj): any {\n for (let i = 1; i < arguments.length; i++) {\n const obj = arguments[i];\n if (!obj) continue;\n const keys = Object.keys(obj);\n\n for (let j = 0; j < keys.length; j++) {\n toObj[keys[j]] = obj[keys[j]];\n }\n }\n\n return toObj;\n}\n\nfunction _equals(o1: any, o2: any): boolean {\n if (o1 === o2) return true;\n if (o1 === null || o2 === null) return false;\n if (o1 !== o1 && o2 !== o2) return true; // NaN === NaN\n const t1 = typeof o1,\n t2 = typeof o2;\n if (t1 !== t2 || t1 !== 'object') return false;\n\n const tup = [o1, o2];\n if (all(isArray)(tup)) return _arraysEq(o1, o2);\n if (all(isDate)(tup)) return o1.getTime() === o2.getTime();\n if (all(isRegExp)(tup)) return o1.toString() === o2.toString();\n if (all(isFunction)(tup)) return true; // meh\n\n const predicates = [isFunction, isArray, isDate, isRegExp];\n if (predicates.map(any).reduce((b, fn) => b || !!fn(tup), false)) return false;\n\n const keys: { [i: string]: boolean } = {};\n // tslint:disable-next-line:forin\n for (const key in o1) {\n if (!_equals(o1[key], o2[key])) return false;\n keys[key] = true;\n }\n for (const key in o2) {\n if (!keys[key]) return false;\n }\n\n return true;\n}\n\nfunction _arraysEq(a1: any[], a2: any[]) {\n if (a1.length !== a2.length) return false;\n return arrayTuples(a1, a2).reduce((b, t) => b && _equals(t[0], t[1]), true);\n}\n\n// issue #2676\nexport const silenceUncaughtInPromise = (promise: Promise<any>) => promise.catch((e) => 0) && promise;\nexport const silentRejection = (error: any) => silenceUncaughtInPromise(services.$q.reject(error));\n", "/**\n * Matches state names using glob-like pattern strings.\n *\n * Globs can be used in specific APIs including:\n *\n * - [[StateService.is]]\n * - [[StateService.includes]]\n * - The first argument to Hook Registration functions like [[TransitionService.onStart]]\n * - [[HookMatchCriteria]] and [[HookMatchCriterion]]\n *\n * A `Glob` string is a pattern which matches state names.\n * Nested state names are split into segments (separated by a dot) when processing.\n * The state named `foo.bar.baz` is split into three segments ['foo', 'bar', 'baz']\n *\n * Globs work according to the following rules:\n *\n * ### Exact match:\n *\n * The glob `'A.B'` matches the state named exactly `'A.B'`.\n *\n * | Glob |Matches states named|Does not match state named|\n * |:------------|:--------------------|:---------------------|\n * | `'A'` | `'A'` | `'B'` , `'A.C'` |\n * | `'A.B'` | `'A.B'` | `'A'` , `'A.B.C'` |\n * | `'foo'` | `'foo'` | `'FOO'` , `'foo.bar'`|\n *\n * ### Single star (`*`)\n *\n * A single star (`*`) is a wildcard that matches exactly one segment.\n *\n * | Glob |Matches states named |Does not match state named |\n * |:------------|:---------------------|:--------------------------|\n * | `'*'` | `'A'` , `'Z'` | `'A.B'` , `'Z.Y.X'` |\n * | `'A.*'` | `'A.B'` , `'A.C'` | `'A'` , `'A.B.C'` |\n * | `'A.*.*'` | `'A.B.C'` , `'A.X.Y'`| `'A'`, `'A.B'` , `'Z.Y.X'`|\n *\n * ### Double star (`**`)\n *\n * A double star (`'**'`) is a wildcard that matches *zero or more segments*\n *\n * | Glob |Matches states named |Does not match state named |\n * |:------------|:----------------------------------------------|:----------------------------------|\n * | `'**'` | `'A'` , `'A.B'`, `'Z.Y.X'` | (matches all states) |\n * | `'A.**'` | `'A'` , `'A.B'` , `'A.C.X'` | `'Z.Y.X'` |\n * | `'**.X'` | `'X'` , `'A.X'` , `'Z.Y.X'` | `'A'` , `'A.login.Z'` |\n * | `'A.**.X'` | `'A.X'` , `'A.B.X'` , `'A.B.C.X'` | `'A'` , `'A.B.C'` |\n *\n * @packageDocumentation\n */\nexport class Glob {\n text: string;\n glob: Array<string>;\n regexp: RegExp;\n\n /** Returns true if the string has glob-like characters in it */\n static is(text: string) {\n return !!/[!,*]+/.exec(text);\n }\n\n /** Returns a glob from the string, or null if the string isn't Glob-like */\n static fromString(text: string) {\n return Glob.is(text) ? new Glob(text) : null;\n }\n\n constructor(text: string) {\n this.text = text;\n this.glob = text.split('.');\n\n const regexpString = this.text\n .split('.')\n .map((seg) => {\n if (seg === '**') return '(?:|(?:\\\\.[^.]*)*)';\n if (seg === '*') return '\\\\.[^.]*';\n return '\\\\.' + seg;\n })\n .join('');\n\n this.regexp = new RegExp('^' + regexpString + '$');\n }\n\n matches(name: string) {\n return this.regexp.test('.' + name);\n }\n}\n", "import { pushTo } from './common';\n\nexport class Queue<T> {\n private _evictListeners: ((item: T) => void)[] = [];\n public onEvict = pushTo(this._evictListeners);\n\n constructor(private _items: T[] = [], private _limit: number = null) {}\n\n enqueue(item: T) {\n const items = this._items;\n items.push(item);\n if (this._limit && items.length > this._limit) this.evict();\n return item;\n }\n\n evict(): T {\n const item: T = this._items.shift();\n this._evictListeners.forEach((fn) => fn(item));\n return item;\n }\n\n dequeue(): T {\n if (this.size()) return this._items.splice(0, 1)[0];\n }\n\n clear(): Array<T> {\n const current = this._items;\n this._items = [];\n return current;\n }\n\n size(): number {\n return this._items.length;\n }\n\n remove(item: T) {\n const idx = this._items.indexOf(item);\n return idx > -1 && this._items.splice(idx, 1)[0];\n }\n\n peekTail(): T {\n return this._items[this._items.length - 1];\n }\n\n peekHead(): T {\n if (this.size()) return this._items[0];\n }\n}\n", "'use strict';\nimport { extend, silentRejection } from '../common/common';\nimport { stringify } from '../common/strings';\nimport { is } from '../common/hof';\n\n/** An enum for Transition Rejection reasons */\nenum RejectType {\n /**\n * A new transition superseded this one.\n *\n * While this transition was running, a new transition started.\n * This transition is cancelled because it was superseded by new transition.\n */\n SUPERSEDED = 2,\n\n /**\n * The transition was aborted\n *\n * The transition was aborted by a hook which returned `false`\n */\n ABORTED = 3,\n\n /**\n * The transition was invalid\n *\n * The transition was never started because it was invalid\n */\n INVALID = 4,\n\n /**\n * The transition was ignored\n *\n * The transition was ignored because it would have no effect.\n *\n * Either:\n *\n * - The transition is targeting the current state and parameter values\n * - The transition is targeting the same state and parameter values as the currently running transition.\n */\n IGNORED = 5,\n\n /**\n * The transition errored.\n *\n * This generally means a hook threw an error or returned a rejected promise\n */\n ERROR = 6,\n}\n\nexport { RejectType };\n\n/** @internal */\nlet id = 0;\n\nexport class Rejection {\n /** @internal */\n $id = id++;\n /**\n * The type of the rejection.\n *\n * This value is an number representing the type of transition rejection.\n * If using Typescript, this is a Typescript enum.\n *\n * - [[RejectType.SUPERSEDED]] (`2`)\n * - [[RejectType.ABORTED]] (`3`)\n * - [[RejectType.INVALID]] (`4`)\n * - [[RejectType.IGNORED]] (`5`)\n * - [[RejectType.ERROR]] (`6`)\n *\n */\n type: RejectType;\n\n /**\n * A message describing the rejection\n */\n message: string;\n\n /**\n * A detail object\n *\n * This value varies based on the mechanism for rejecting the transition.\n * For example, if an error was thrown from a hook, the `detail` will be the `Error` object.\n * If a hook returned a rejected promise, the `detail` will be the rejected value.\n */\n detail: any;\n\n /**\n * Indicates if the transition was redirected.\n *\n * When a transition is redirected, the rejection [[type]] will be [[RejectType.SUPERSEDED]] and this flag will be true.\n */\n redirected: boolean;\n\n /** Returns true if the obj is a rejected promise created from the `asPromise` factory */\n static isRejectionPromise(obj: any): boolean {\n return obj && typeof obj.then === 'function' && is(Rejection)(obj._transitionRejection);\n }\n\n /** Returns a Rejection due to transition superseded */\n static superseded(detail?: any, options?: any): Rejection {\n const message = 'The transition has been superseded by a different transition';\n const rejection = new Rejection(RejectType.SUPERSEDED, message, detail);\n if (options && options.redirected) {\n rejection.redirected = true;\n }\n return rejection;\n }\n\n /** Returns a Rejection due to redirected transition */\n static redirected(detail?: any): Rejection {\n return Rejection.superseded(detail, { redirected: true });\n }\n\n /** Returns a Rejection due to invalid transition */\n static invalid(detail?: any): Rejection {\n const message = 'This transition is invalid';\n return new Rejection(RejectType.INVALID, message, detail);\n }\n\n /** Returns a Rejection due to ignored transition */\n static ignored(detail?: any): Rejection {\n const message = 'The transition was ignored';\n return new Rejection(RejectType.IGNORED, message, detail);\n }\n\n /** Returns a Rejection due to aborted transition */\n static aborted(detail?: any): Rejection {\n const message = 'The transition has been aborted';\n return new Rejection(RejectType.ABORTED, message, detail);\n }\n\n /** Returns a Rejection due to aborted transition */\n static errored(detail?: any): Rejection {\n const message = 'The transition errored';\n return new Rejection(RejectType.ERROR, message, detail);\n }\n\n /**\n * Returns a Rejection\n *\n * Normalizes a value as a Rejection.\n * If the value is already a Rejection, returns it.\n * Otherwise, wraps and returns the value as a Rejection (Rejection type: ERROR).\n *\n * @returns `detail` if it is already a `Rejection`, else returns an ERROR Rejection.\n */\n static normalize(detail?: Rejection | Error | any): Rejection {\n return is(Rejection)(detail) ? detail : Rejection.errored(detail);\n }\n\n constructor(type: number, message?: string, detail?: any) {\n this.type = type;\n this.message = message;\n this.detail = detail;\n }\n\n toString() {\n const detailString = (d: any) => (d && d.toString !== Object.prototype.toString ? d.toString() : stringify(d));\n const detail = detailString(this.detail);\n const { $id, type, message } = this;\n return `Transition Rejection($id: ${$id} type: ${type}, message: ${message}, detail: ${detail})`;\n }\n\n toPromise(): Promise<any> {\n return extend(silentRejection(this), { _transitionRejection: this });\n }\n}\n", "/**\n * Functions that manipulate strings\n *\n * Although these functions are exported, they are subject to change without notice.\n *\n * @packageDocumentation\n */\n\nimport { isArray, isFunction, isInjectable, isNull, isObject, isPromise, isString, isUndefined } from './predicates';\nimport { Rejection } from '../transition/rejectFactory';\nimport { identity, IInjectable, pushR, tail } from './common';\nimport { pattern, val } from './hof';\n\n/**\n * Returns a string shortened to a maximum length\n *\n * If the string is already less than the `max` length, return the string.\n * Else return the string, shortened to `max - 3` and append three dots (\"...\").\n *\n * @param max the maximum length of the string to return\n * @param str the input string\n */\nexport function maxLength(max: number, str: string) {\n if (str.length <= max) return str;\n return str.substr(0, max - 3) + '...';\n}\n\n/**\n * Returns a string, with spaces added to the end, up to a desired str length\n *\n * If the string is already longer than the desired length, return the string.\n * Else returns the string, with extra spaces on the end, such that it reaches `length` characters.\n *\n * @param length the desired length of the string to return\n * @param str the input string\n */\nexport function padString(length: number, str: string) {\n while (str.length < length) str += ' ';\n return str;\n}\n\nexport function kebobString(camelCase: string) {\n return camelCase\n .replace(/^([A-Z])/, ($1) => $1.toLowerCase()) // replace first char\n .replace(/([A-Z])/g, ($1) => '-' + $1.toLowerCase()); // replace rest\n}\n\nexport function functionToString(fn: Function) {\n const fnStr = fnToString(fn);\n const namedFunctionMatch = fnStr.match(/^(function [^ ]+\\([^)]*\\))/);\n const toStr = namedFunctionMatch ? namedFunctionMatch[1] : fnStr;\n\n const fnName = fn['name'] || '';\n if (fnName && toStr.match(/function \\(/)) {\n return 'function ' + fnName + toStr.substr(9);\n }\n return toStr;\n}\n\nexport function fnToString(fn: IInjectable) {\n const _fn = isArray(fn) ? fn.slice(-1)[0] : fn;\n return (_fn && _fn.toString()) || 'undefined';\n}\n\nexport function stringify(o: any) {\n const seen: any[] = [];\n\n const isRejection = Rejection.isRejectionPromise;\n const hasToString = (obj: any) =>\n isObject(obj) && !isArray(obj) && obj.constructor !== Object && isFunction(obj.toString);\n\n const stringifyPattern = pattern([\n [isUndefined, val('undefined')],\n [isNull, val('null')],\n [isPromise, val('[Promise]')],\n [isRejection, (x: any) => x._transitionRejection.toString()],\n [hasToString, (x: object) => x.toString()],\n [isInjectable, functionToString],\n [val(true), identity],\n ]) as (val: any) => string;\n\n function format(value: any) {\n if (isObject(value)) {\n if (seen.indexOf(value) !== -1) return '[circular ref]';\n seen.push(value);\n }\n return stringifyPattern(value);\n }\n\n if (isUndefined(o)) {\n // Workaround for IE & Edge Spec incompatibility where replacer function would not be called when JSON.stringify\n // is given `undefined` as value. To work around that, we simply detect `undefined` and bail out early by\n // manually stringifying it.\n return format(o);\n }\n\n return JSON.stringify(o, (key, value) => format(value)).replace(/\\\\\"/g, '\"');\n}\n\n/** Returns a function that splits a string on