UNPKG

breeze-client

Version:

Breeze data management for JavaScript clients

1 lines 1.05 MB
{"version":3,"file":"breeze-client.mjs","sources":["../../src/enum.ts","../../src/core.ts","../../src/assert-param.ts","../../src/event.ts","../../src/config.ts","../../src/data-service.ts","../../src/validate.ts","../../src/data-type.ts","../../src/entity-state.ts","../../src/entity-action.ts","../../src/entity-key.ts","../../src/query-options.ts","../../src/predicate.ts","../../src/entity-query.ts","../../src/entity-aspect.ts","../../src/naming-convention.ts","../../src/csdl-metadata-parser.ts","../../src/local-query-comparison-options.ts","../../src/default-property-interceptor.ts","../../src/entity-metadata.ts","../../src/abstract-data-service-adapter.ts","../../src/validation-options.ts","../../src/save-options.ts","../../src/key-generator.ts","../../src/entity-group.ts","../../src/mapping-context.ts","../../src/unattached-children-map.ts","../../src/entity-manager.ts","../../src/interface-registry.ts","../../src/observable-array.ts","../../src/relation-array.ts","../../src/complex-array.ts","../../src/primitive-array.ts","../../src/breeze.ts","../../breeze-client.ts"],"sourcesContent":["/*\r\n * Copyright 2012-2023 IdeaBlade, Inc. All Rights Reserved. \r\n * Use, reproduction, distribution, and modification of this code is subject to the terms and \r\n * conditions of the IdeaBlade Breeze license, available at http://www.breezejs.com/license\r\n *\r\n * Author: Jay Traband\r\n */\r\n\r\n/**\r\nBase class for all Breeze enumerations, such as EntityState, DataType, FetchStrategy, MergeStrategy etc.\r\nA Breeze Enum is a namespaced set of constant values. Each Enum consists of a group of related constants, called 'symbols'.\r\nUnlike enums in some other environments, each 'symbol' can have both methods and properties.\r\n> class DayOfWeek extends BreezeEnum {\r\n> dayIndex: number;\r\n> isWeekend?: boolean;\r\n> nextDay() {\r\n> let nextIndex = (this.dayIndex + 1) % 7;\r\n> return DayOfWeek.getSymbols()[nextIndex];\r\n> }\r\n>\r\n> static Monday = new DayOfWeek( { dayIndex: 0});\r\n> static Tuesday = new DayOfWeek( { dayIndex: 1 });\r\n> static Wednesday = new DayOfWeek( { dayIndex: 2 });\r\n> static Thursday = new DayOfWeek( { dayIndex: 3 });\r\n> static Friday = new DayOfWeek( { dayIndex: 4 });\r\n> static Saturday = new DayOfWeek( { dayIndex: 5, isWeekend: true });\r\n> static Sunday = new DayOfWeek( { dayIndex: 6, isWeekend: true });\r\n> }\r\n>\r\n> describe(\"DayOfWeek\", () => {\r\n> test(\"should support full enum capabilities\", function() {\r\n> // // custom methods\r\n> let dowSymbols = DayOfWeek.getSymbols();\r\n> expect(dowSymbols.length).toBe(7);\r\n> expect(DayOfWeek.Monday.nextDay()).toBe(DayOfWeek.Tuesday);\r\n> expect(DayOfWeek.Sunday.nextDay()).toBe(DayOfWeek.Monday);\r\n> // // custom properties\r\n> expect(DayOfWeek.Tuesday.isWeekend).toBe(undefined);\r\n> expect(DayOfWeek.Saturday.isWeekend).toBe(true);\r\n> // // Standard enum capabilities\r\n> expect(DayOfWeek.Thursday instanceof DayOfWeek).toBe(true);\r\n> expect(BreezeEnum.isSymbol(DayOfWeek.Wednesday)).toBe(true);\r\n> expect(DayOfWeek.contains(DayOfWeek.Thursday)).toBe(true);\r\n> expect(DayOfWeek.Friday.toString()).toBe(\"Friday\");\r\n> });\r\n> });\r\nNote that we have Error['x'] = ... in some places in the code to prevent Terser from optimizing out some important calls.\r\n@dynamic\r\n*/\r\nexport class BreezeEnum {\r\n // // TODO: think about CompositeEnum (flags impl).\r\n /** The name of this symbol */\r\n declare name: string;\r\n /** Type of the enum; set in prototype of each enum */\r\n declare _$typeName: string;\r\n /** @hidden @internal */\r\n static _resolvedNamesAndSymbols: { name: string, symbol: BreezeEnum }[];\r\n\r\n /** */\r\n constructor(propertiesObj?: Object) {\r\n if (propertiesObj) {\r\n Object.keys(propertiesObj).forEach((key) => this[key] = propertiesObj[key]);\r\n }\r\n }\r\n\r\n /**\r\n Returns all of the symbols contained within this Enum.\r\n > let symbols = DayOfWeek.getSymbols();\r\n @return All of the symbols contained within this Enum.\r\n **/\r\n static getSymbols() {\r\n return this.resolveSymbols().map(ks => ks.symbol);\r\n }\r\n\r\n /**\r\n Returns the names of all of the symbols contained within this Enum.\r\n > let symbols = DayOfWeek.getNames();\r\n @return All of the names of the symbols contained within this Enum.\r\n **/\r\n static getNames() {\r\n return this.resolveSymbols().map(ks => ks.name);\r\n }\r\n\r\n /**\r\n Returns an Enum symbol given its name.\r\n > let dayOfWeek = DayOfWeek.from(\"Thursday\");\r\n > // nowdayOfWeek === DayOfWeek.Thursday\r\n @param name - Name for which an enum symbol should be returned.\r\n @return The symbol that matches the name or 'undefined' if not found.\r\n **/\r\n static fromName(name: string) {\r\n return this[name];\r\n }\r\n\r\n /**\r\n Seals this enum so that no more symbols may be added to it. This should only be called after all symbols\r\n have already been added to the Enum. This method also sets the 'name' property on each of the symbols.\r\n > DayOfWeek.resolveSymbols();\r\n **/\r\n static resolveSymbols() {\r\n if (this._resolvedNamesAndSymbols) return this._resolvedNamesAndSymbols;\r\n let result: {name: string, symbol: BreezeEnum }[] = [];\r\n\r\n for (let key in this) {\r\n if (this.hasOwnProperty(key)) {\r\n let symb = this[key];\r\n if (symb instanceof BreezeEnum) {\r\n result.push( { name: key, symbol: symb });\r\n this[key] = symb;\r\n symb.name = key;\r\n }\r\n }\r\n }\r\n this._resolvedNamesAndSymbols = result;\r\n return result;\r\n }\r\n\r\n /**\r\n Returns whether an Enum contains a specified symbol.\r\n > let symbol = DayOfWeek.Friday;\r\n > if (DayOfWeek.contains(symbol)) {\r\n > // do something\r\n > }\r\n @param sym - Object or symbol to test.\r\n @return Whether this Enum contains the specified symbol.\r\n **/\r\n static contains(sym: BreezeEnum) {\r\n if (!(sym instanceof BreezeEnum)) {\r\n return false;\r\n }\r\n\r\n return this[sym.name] != null;\r\n }\r\n\r\n\r\n // /**\r\n // Checks if an object is an Enum 'symbol'. Use the 'contains' method instead of this one \r\n // if you want to test for a specific Enum. \r\n // > if (Enum.isSymbol(DayOfWeek.Wednesday)) {\r\n // > // do something ...\r\n // > };\r\n // **/\r\n // static isSymbol(obj: any) {\r\n // return obj instanceof BreezeEnum;\r\n // };\r\n\r\n /** Returns the string name of this Enum */\r\n toString() {\r\n return this.name;\r\n }\r\n\r\n /** Return enum name and symbol name */\r\n toJSON() {\r\n return {\r\n _$typeName: this['_$typeName'] || (this.constructor as any).name,\r\n name: this.name\r\n };\r\n }\r\n\r\n}\r\n\r\n\r\n","/** See if this comment will make it into .d.ts */\r\nimport { BreezeEnum } from './enum';\r\ndeclare var global: any;\r\ndeclare var window: any;\r\n\r\nexport interface ErrorCallback {\r\n (error: Error): void;\r\n}\r\n\r\nexport interface Callback {\r\n (data: any): void;\r\n}\r\n\r\n// type Predicate = (i: any) => boolean;\r\ntype Predicate<T> = (i: T) => boolean;\r\n\r\nlet hasOwnProperty: (obj: Object, key: string) => boolean = uncurry(Object.prototype.hasOwnProperty);\r\nlet arraySlice: (ar: any[], start?: number, end?: number) => any[] = uncurry(Array.prototype.slice);\r\nlet isES5Supported: boolean = function () {\r\n try {\r\n return !!(Object.getPrototypeOf && Object.defineProperty({}, 'x', {}));\r\n } catch (e) {\r\n return false;\r\n }\r\n} ();\r\n\r\n// iterate over object\r\nfunction objectForEach(obj: Object, kvFn: (key: string, val: any) => any) {\r\n for (let key in obj) {\r\n if (hasOwnProperty(obj, key)) {\r\n kvFn(key, obj[key]);\r\n }\r\n }\r\n}\r\n\r\nfunction objectMap(obj: Object, kvFn?: (key: string, val: any) => any): any[] {\r\n let results: any[] = [];\r\n for (let key in obj) {\r\n if (hasOwnProperty(obj, key)) {\r\n let result = kvFn ? kvFn(key, obj[key]) : obj[key];\r\n if (result !== undefined) {\r\n results.push(result);\r\n }\r\n }\r\n }\r\n return results;\r\n}\r\n\r\nfunction objectFirst(obj: Object, kvPredicate: (key: string, val: any) => boolean): { key: string, value: any } | null {\r\n for (let key in obj) {\r\n if (hasOwnProperty(obj, key)) {\r\n let value = obj[key];\r\n if (kvPredicate(key, value)) {\r\n return { key: key, value: value };\r\n }\r\n }\r\n }\r\n return null;\r\n}\r\n\r\nfunction arrayFlatMap<T, U>(arr: T[], mapFn: (arg: T) => U[]) {\r\n return Array.prototype.concat.apply([], arr.map(mapFn)) as U[];\r\n}\r\n\r\nfunction isSettable(obj: Object, propertyName: string): boolean {\r\n let pd = getPropDescriptor(obj, propertyName);\r\n if (pd == null) return true;\r\n return !!(pd.writable || pd.set);\r\n}\r\n\r\nfunction getPropDescriptor(obj: Object, propertyName: string): PropertyDescriptor | undefined {\r\n if (!isES5Supported) return undefined;\r\n\r\n if (obj.hasOwnProperty(propertyName)) {\r\n return Object.getOwnPropertyDescriptor(obj, propertyName);\r\n } else {\r\n let nextObj = Object.getPrototypeOf(obj);\r\n if (nextObj == null) return undefined;\r\n return getPropDescriptor(nextObj, propertyName);\r\n }\r\n}\r\n\r\n// Functional extensions\r\n\r\n/** can be used like: persons.filter(propEq(\"firstName\", \"John\")) */\r\nfunction propEq(propertyName: string, value: any): (obj: Object) => boolean {\r\n return function (obj: any) {\r\n return obj[propertyName] === value;\r\n };\r\n}\r\n\r\n/** can be used like: persons.filter(propEq(\"firstName\", \"FirstName\", \"John\")) */\r\nfunction propsEq(property1Name: string, property2Name: string, value: any): (obj: Object) => boolean {\r\n return function (obj: any) {\r\n return obj[property1Name] === value || obj[property2Name] === value;\r\n };\r\n}\r\n\r\n/** can be used like persons.map(pluck(\"firstName\")) */\r\nfunction pluck(propertyName: any): (obj: Object) => any {\r\n return function (obj: any) {\r\n return obj[propertyName];\r\n };\r\n}\r\n\r\n// end functional extensions\r\n\r\n/** Return an array of property values from source */\r\nfunction getOwnPropertyValues(source: Object): any[] {\r\n let result: any[] = [];\r\n for (let name in source) {\r\n if (hasOwnProperty(source, name)) {\r\n result.push(source[name]);\r\n }\r\n }\r\n return result;\r\n}\r\n\r\n/** Copy properties from source to target. Returns target. */\r\nfunction extend(target: Object, source: Object, propNames?: string[]): Object {\r\n if (!source) return target;\r\n if (propNames) {\r\n propNames.forEach(function (propName) {\r\n target[propName] = source[propName];\r\n });\r\n } else {\r\n for (let propName in source) {\r\n if (hasOwnProperty(source, propName)) {\r\n target[propName] = source[propName];\r\n }\r\n }\r\n }\r\n return target;\r\n}\r\n\r\n/** Copy properties from defaults iff undefined on target. Returns target. */\r\nfunction updateWithDefaults(target: Object, defaults: Object): any {\r\n for (let name in defaults) {\r\n if (target[name] === undefined) {\r\n target[name] = defaults[name];\r\n }\r\n }\r\n return target;\r\n}\r\n\r\n/** Set ctor.defaultInstance to an instance of ctor with properties from target.\r\n We want to insure that the object returned by ctor.defaultInstance is always immutable\r\n Use 'target' as the primary template for the ctor.defaultInstance;\r\n Use current 'ctor.defaultInstance' as the template for any missing properties\r\n creates a new instance for ctor.defaultInstance\r\n returns target unchanged */\r\nfunction setAsDefault(target: Object, ctor: { new (...args: any[]): any, defaultInstance?: any }): any {\r\n ctor.defaultInstance = updateWithDefaults(new ctor(target), ctor.defaultInstance);\r\n return target;\r\n}\r\n\r\n/**\r\n 'source' is an object that will be transformed into another\r\n 'template' is a map where the\r\n keys: are the keys to return\r\n if a key contains ','s then the key is treated as a delimited string with first of the\r\n keys being the key to return and the others all valid aliases for this key\r\n 'values' are either\r\n 1) the 'default' value of the key\r\n 2) a function that takes in the source value and should return the value to set\r\n The value from the source is then set on the target,\r\n after first passing thru the fn, if provided, UNLESS:\r\n 1) it is the default value\r\n 2) it is undefined ( nulls WILL be set)\r\n 'target' is optional\r\n - if it exists then properties of the target will be set ( overwritten if the exist)\r\n - if it does not exist then a new object will be created as filled.\r\n 'target is returned.\r\n*/\r\nfunction toJson(source: Object, template: Object, target: Object = {}): Object {\r\n\r\n for (let key in template) {\r\n let aliases = key.split(\",\");\r\n let defaultValue = template[key];\r\n // using some as a forEach with a 'break'\r\n aliases.some(function (propName) {\r\n if (!(propName in source)) return false;\r\n let value = source[propName];\r\n // there is a functional property defined with this alias ( not what we want to replace).\r\n if (typeof value === 'function') return false;\r\n // '==' is deliberate here - idea is that null or undefined values will never get serialized\r\n // if default value is set to null.\r\n // tslint:disable-next-line\r\n if (value == defaultValue) return true;\r\n if (Array.isArray(value) && value.length === 0) return true;\r\n if (typeof (defaultValue) === \"function\") {\r\n value = defaultValue(value);\r\n } else if (typeof (value) === \"object\") {\r\n if (value && value instanceof BreezeEnum) {\r\n value = value.name;\r\n }\r\n }\r\n if (value === undefined) return true;\r\n target[aliases[0]] = value;\r\n return true;\r\n });\r\n }\r\n return target;\r\n}\r\n\r\n/** Replacer function for toJSONSafe, when serializing entities. Excludes entityAspect and other internal properties. */\r\nfunction toJSONSafeReplacer(prop: string, val: any) {\r\n if (prop === \"entityAspect\" || prop === \"complexAspect\" || prop === \"entityType\" || prop === \"complexType\"\r\n || prop === \"getProperty\" || prop === \"setProperty\"\r\n || prop === \"constructor\" || prop.charAt(0) === '_' || prop.charAt(0) === '$') return;\r\n return val;\r\n}\r\n\r\n/** Safely perform toJSON logic on objects with cycles. */\r\nfunction toJSONSafe(obj: any, replacer?: (prop: string, value: any) => any): any {\r\n if (obj !== Object(obj)) return obj; // primitive value\r\n if (obj._$visited) return undefined;\r\n if (obj.toJSON) {\r\n let newObj = obj.toJSON();\r\n if (newObj !== Object(newObj)) return newObj; // primitive value\r\n if (newObj !== obj) return toJSONSafe(newObj, replacer);\r\n // toJSON returned the object unchanged.\r\n obj = newObj;\r\n }\r\n obj._$visited = true;\r\n let result: any;\r\n if (obj instanceof Array) {\r\n result = obj.map(function (o: any) {\r\n return toJSONSafe(o, replacer);\r\n });\r\n } else if (typeof (obj) === \"function\") {\r\n result = undefined;\r\n } else {\r\n result = {};\r\n for (let prop in obj) {\r\n if (prop === \"_$visited\") continue;\r\n let val = obj[prop];\r\n if (replacer) {\r\n val = replacer(prop, val);\r\n if (val === undefined) continue;\r\n }\r\n val = toJSONSafe(val, replacer);\r\n if (val === undefined) continue;\r\n result[prop] = val;\r\n }\r\n }\r\n delete obj._$visited;\r\n return result;\r\n}\r\n\r\n/** Resolves the values of a list of properties by checking each property in multiple sources until a value is found. */\r\nfunction resolveProperties(sources: Object[], propertyNames: string[]): any {\r\n let r = {};\r\n let length = sources.length;\r\n propertyNames.forEach(function (pn) {\r\n for (let i = 0; i < length; i++) {\r\n let src = sources[i];\r\n if (src) {\r\n let val = src[pn];\r\n if (val !== undefined) {\r\n r[pn] = val;\r\n break;\r\n }\r\n }\r\n }\r\n });\r\n return r;\r\n}\r\n\r\n\r\n// array functions\r\n\r\nfunction toArray(item: any): any[] {\r\n if (item == null) {\r\n return [];\r\n } else if (Array.isArray(item)) {\r\n return item;\r\n } else {\r\n return [item];\r\n }\r\n}\r\n\r\n/** a version of Array.map that doesn't require an array, i.e. works on arrays and scalars. */\r\n// function map<T, U>(items: T | T[], fn: (v: T, ix?: number) => U, includeNull?: boolean): U | U[] {\r\n function map<T>(items: T | T[], fn: (v: T, ix?: number) => any, includeNull?: boolean): any | any[] {\r\n // whether to return nulls in array of results; default = true;\r\n includeNull = includeNull == null ? true : includeNull;\r\n if (items == null) return items;\r\n // let result: U[];\r\n if (Array.isArray(items)) {\r\n let result: any[] = [];\r\n items.forEach(function (v: any, ix: number) {\r\n let r = fn(v, ix);\r\n if (r != null || includeNull) {\r\n result[ix] = r;\r\n }\r\n });\r\n return result;\r\n } else {\r\n let result = fn(items);\r\n return result;\r\n }\r\n\r\n}\r\n\r\n/** Return first element matching predicate */\r\nfunction arrayFirst<T>(array: T[], predicate: Predicate<any>): T;\r\nfunction arrayFirst<T>(array: T[], predicate: Predicate<T>) {\r\n for (let i = 0, j = array.length; i < j; i++) {\r\n if (predicate(array[i])) {\r\n return array[i];\r\n }\r\n }\r\n return null;\r\n}\r\n\r\n/** Return index of first element matching predicate */\r\nfunction arrayIndexOf<T>(array: T[], predicate: Predicate<any>): number;\r\nfunction arrayIndexOf<T>(array: T[], predicate: Predicate<T>): number {\r\n for (let i = 0, j = array.length; i < j; i++) {\r\n if (predicate(array[i])) return i;\r\n }\r\n return -1;\r\n}\r\n\r\n/** Add item if not already in array */\r\nfunction arrayAddItemUnique<T>(array: T[], item: T) {\r\n let ix = array.indexOf(item);\r\n if (ix === -1) array.push(item);\r\n}\r\n\r\n/** Remove items from the array\r\n * @param array\r\n * @param predicateOrItem - item to remove, or function to determine matching item\r\n * @param shouldRemoveMultiple - true to keep removing after first match, false otherwise\r\n */\r\nfunction arrayRemoveItem<T>(array: T[], predicateOrItem: T | Predicate<T> , shouldRemoveMultiple?: boolean) {\r\n let predicate = (isFunction(predicateOrItem) ? predicateOrItem : undefined) as Predicate<T>;\r\n let lastIx = array.length - 1;\r\n let removed = false;\r\n for (let i = lastIx; i >= 0; i--) {\r\n if (predicate ? predicate(array[i]) : (array[i] === predicateOrItem)) {\r\n array.splice(i, 1);\r\n removed = true;\r\n if (!shouldRemoveMultiple) {\r\n return true;\r\n }\r\n }\r\n }\r\n return removed;\r\n}\r\n\r\n/** Combine array elements using the callback. Returns array with length == min(a1.length, a2.length) */\r\nfunction arrayZip(a1: any[], a2: any[], callback: (x1: any, x2: any) => any): any[] {\r\n let result: any[] = [];\r\n let n = Math.min(a1.length, a2.length);\r\n for (let i = 0; i < n; ++i) {\r\n result.push(callback(a1[i], a2[i]));\r\n }\r\n return result;\r\n}\r\n\r\n//function arrayDistinct(array) {\r\n// array = array || [];\r\n// let result = [];\r\n// for (let i = 0, j = array.length; i < j; i++) {\r\n// if (result.indexOf(array[i]) < 0)\r\n// result.push(array[i]);\r\n// }\r\n// return result;\r\n//}\r\n\r\n// Not yet needed\r\n//// much faster but only works on array items with a toString method that\r\n//// returns distinct string for distinct objects. So this is safe for arrays with primitive\r\n//// types but not for arrays with object types, unless toString() has been implemented.\r\n//function arrayDistinctUnsafe(array) {\r\n// let o = {}, i, l = array.length, r = [];\r\n// for (i = 0; i < l; i += 1) {\r\n// let v = array[i];\r\n// o[v] = v;\r\n// }\r\n// for (i in o) r.push(o[i]);\r\n// return r;\r\n//}\r\n\r\nfunction arrayEquals(a1: any[], a2: any[], equalsFn?: (x1: any, x2: any) => boolean): boolean {\r\n //Check if the arrays are undefined/null\r\n if (!a1 || !a2) return false;\r\n\r\n if (a1.length !== a2.length) return false;\r\n\r\n //go thru all the vars\r\n for (let i = 0; i < a1.length; i++) {\r\n //if the let is an array, we need to make a recursive check\r\n //otherwise we'll just compare the values\r\n if (Array.isArray(a1[i])) {\r\n if (!arrayEquals(a1[i], a2[i])) return false;\r\n } else {\r\n if (equalsFn) {\r\n if (!equalsFn(a1[i], a2[i])) return false;\r\n } else {\r\n if (a1[i] !== a2[i]) return false;\r\n }\r\n }\r\n }\r\n return true;\r\n}\r\n\r\n// end of array functions\r\n\r\n/** Returns an array for a source and a prop, and creates the prop if needed. */\r\nfunction getArray(source: Object, propName: string): any[] {\r\n let arr = source[propName];\r\n if (!arr) {\r\n arr = [];\r\n source[propName] = arr;\r\n }\r\n return arr;\r\n}\r\n\r\n/** Calls requireLibCore on semicolon-separated libNames */\r\nfunction requireLib(libNames: string, errMessage?: string) {\r\n let arrNames = libNames.split(\";\");\r\n for (let i = 0, j = arrNames.length; i < j; i++) {\r\n let lib = requireLibCore(arrNames[i]);\r\n if (lib) return lib;\r\n }\r\n if (errMessage) {\r\n throw new Error(\"Unable to initialize \" + libNames + \". \" + errMessage);\r\n }\r\n}\r\n\r\n\r\n\r\n/** Returns the 'libName' module if loaded or else returns undefined */\r\nfunction requireLibCore(libName: string) {\r\n let win = window || (global ? global.window : undefined);\r\n if (!win) return; // Must run in a browser. Todo: add commonjs support\r\n\r\n // get library from browser globals if we can\r\n let lib = win[libName];\r\n if (lib) return lib;\r\n\r\n // if require exists, maybe require can get it.\r\n // This method is synchronous so it can't load modules with AMD.\r\n // It can only obtain modules from require that have already been loaded.\r\n // Developer should bootstrap such that the breeze module\r\n // loads after all other libraries that breeze should find with this method\r\n // See documentation\r\n let r = win.require;\r\n if (r) { // if require exists\r\n if (r.defined) { // require.defined is not standard and may not exist\r\n // require.defined returns true if module has been loaded\r\n return r.defined(libName) ? r(libName) : undefined;\r\n } else {\r\n // require.defined does not exist so we have to call require('libName') directly.\r\n // The require('libName') overload is synchronous and does not load modules.\r\n // It throws an exception if the module isn't already loaded.\r\n try {\r\n return r(libName);\r\n } catch (e) {\r\n // require('libName') threw because module not loaded\r\n return;\r\n }\r\n }\r\n }\r\n}\r\n\r\n/** Execute fn while obj has tempValue for property */\r\nfunction using(obj: Object, property: string, tempValue: any, fn: () => any) {\r\n if (!obj) {\r\n return fn();\r\n }\r\n let originalValue = obj[property];\r\n if (tempValue === originalValue) {\r\n return fn();\r\n }\r\n obj[property] = tempValue;\r\n try {\r\n return fn();\r\n } finally {\r\n if (originalValue === undefined) {\r\n delete obj[property];\r\n } else {\r\n obj[property] = originalValue;\r\n }\r\n }\r\n}\r\n\r\n/** Call state = startFn(), call fn(), call endFn(state) */\r\nfunction wrapExecution(startFn: () => any, endFn: (state: any) => any, fn: () => any) {\r\n let state: any;\r\n try {\r\n state = startFn();\r\n return fn();\r\n } catch (e) {\r\n if (typeof (state) === 'object') {\r\n state.error = e;\r\n }\r\n throw e;\r\n } finally {\r\n endFn(state);\r\n }\r\n}\r\n\r\n/** Remember & return the value of fn() when it was called with its current args */\r\nfunction memoize(fn: any): any {\r\n return function () {\r\n let args = arraySlice(<any>arguments),\r\n hash = \"\",\r\n i = args.length,\r\n currentArg: any = null;\r\n while (i--) {\r\n currentArg = args[i];\r\n hash += (currentArg === Object(currentArg)) ? JSON.stringify(currentArg) : currentArg;\r\n fn.memoize || (fn.memoize = {});\r\n }\r\n return (hash in fn.memoize) ?\r\n fn.memoize[hash] :\r\n fn.memoize[hash] = fn.apply(this, args);\r\n };\r\n}\r\n\r\nconst uuidrex = /[xy]/g;\r\nfunction getUuid(): string {\r\n return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(uuidrex, function (c) {\r\n // tslint:disable-next-line\r\n let r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8);\r\n return v.toString(16);\r\n });\r\n}\r\n\r\nconst durationrex = /^P((\\d+Y)?(\\d+M)?(\\d+D)?)?(T(\\d+H)?(\\d+M)?(\\d+S)?)?$/;\r\nconst lettersrex = /[A-Za-z]+/g;\r\nfunction durationToSeconds(duration: string) {\r\n // basic algorithm from https://github.com/nezasa/iso8601-js-period\r\n if (typeof duration !== \"string\") throw new Error(\"Invalid ISO8601 duration '\" + duration + \"'\");\r\n\r\n // regex splits as follows - grp0, grp1, y, m, d, grp2, h, m, s\r\n // 0 1 2 3 4 5 6 7 8\r\n let struct = durationrex.exec(duration);\r\n if (!struct) throw new Error(\"Invalid ISO8601 duration '\" + duration + \"'\");\r\n\r\n let ymdhmsIndexes = [2, 3, 4, 6, 7, 8]; // -> grp1,y,m,d,grp2,h,m,s\r\n let factors = [31104000, // year (360*24*60*60)\r\n 2592000, // month (30*24*60*60)\r\n 86400, // day (24*60*60)\r\n 3600, // hour (60*60)\r\n 60, // minute (60)\r\n 1]; // second (1)\r\n\r\n let seconds = 0;\r\n for (let i = 0; i < 6; i++) {\r\n let digit = struct[ymdhmsIndexes[i]];\r\n // remove letters, replace by 0 if not defined\r\n digit = <any>(digit ? +digit.replace(lettersrex, '') : 0);\r\n seconds += <any>digit * factors[i];\r\n }\r\n return seconds;\r\n\r\n}\r\n\r\n// is functions\r\n\r\nfunction noop() {\r\n // does nothing\r\n}\r\n\r\nfunction identity(x: any): any {\r\n return x;\r\n}\r\n\r\nfunction classof(o: any) {\r\n if (o === null) {\r\n return \"null\";\r\n }\r\n if (o === undefined) {\r\n return \"undefined\";\r\n }\r\n return Object.prototype.toString.call(o).slice(8, -1).toLowerCase();\r\n}\r\n\r\nfunction isDate(o: any) {\r\n return classof(o) === \"date\" && !isNaN(o.getTime());\r\n}\r\n\r\nconst isdaterex = /^((\\d{4}-[01]\\d-[0-3]\\dT[0-2]\\d:[0-5]\\d:[0-5]\\d\\.\\d+([+-][0-2]\\d:[0-5]\\d|Z))|(\\d{4}-[01]\\d-[0-3]\\dT[0-2]\\d:[0-5]\\d:[0-5]\\d([+-][0-2]\\d:[0-5]\\d|Z))|(\\d{4}-[01]\\d-[0-3]\\dT[0-2]\\d:[0-5]\\d([+-][0-2]\\d:[0-5]\\d|Z)))$/;\r\nfunction isDateString(s: string) {\r\n // let rx = /^(\\d{4}|[+\\-]\\d{6})(?:-(\\d{2})(?:-(\\d{2}))?)?(?:T(\\d{2}):(\\d{2})(?::(\\d{2})(?:\\.(\\d{3}))?)?(?:(Z)|([+\\-])(\\d{2})(?::(\\d{2}))?)?)?$/;\r\n return (typeof s === \"string\") && isdaterex.test(s);\r\n}\r\n\r\nfunction isFunction(o: any) {\r\n return classof(o) === \"function\";\r\n}\r\n\r\n// function isString(o: any) {\r\n// return (typeof o === \"string\");\r\n// }\r\n\r\n// function isObject(o: any) {\r\n// return (typeof o === \"object\");\r\n// }\r\n\r\nconst isguidrex = /^[a-fA-F\\d]{8}-(?:[a-fA-F\\d]{4}-){3}[a-fA-F\\d]{12}$/;\r\nfunction isGuid(value: any) {\r\n return (typeof value === \"string\") && isguidrex.test(value);\r\n}\r\n\r\nconst isdurationrex = /^(-|)?P[T]?[\\d\\.,\\-]+[YMDTHS]/;\r\nfunction isDuration(value: any) {\r\n return (typeof value === \"string\") && isdurationrex.test(value);\r\n}\r\n\r\nfunction isEmpty(obj: any) {\r\n if (obj === null || obj === undefined) {\r\n return true;\r\n }\r\n for (let key in obj) {\r\n if (hasOwnProperty(obj, key)) {\r\n return false;\r\n }\r\n }\r\n return true;\r\n}\r\n\r\nfunction isNumeric(n: any) {\r\n return !isNaN(parseFloat(n)) && isFinite(n);\r\n}\r\n\r\n\r\n\r\n// end of is Functions\r\n\r\n// string functions\r\n\r\nfunction stringStartsWith(str: string, prefix: string) {\r\n // returns true for empty string or null prefix\r\n if ((!str)) return false;\r\n if (prefix === \"\" || prefix == null) return true;\r\n return str.indexOf(prefix, 0) === 0;\r\n}\r\n\r\nfunction stringEndsWith(str: string, suffix: string) {\r\n // returns true for empty string or null suffix\r\n if ((!str)) return false;\r\n if (suffix === \"\" || suffix == null) return true;\r\n return str.indexOf(suffix, str.length - suffix.length) !== -1;\r\n}\r\n\r\n// Based on fragment from Dean Edwards' Base 2 library\r\n/** format(\"a %1 and a %2\", \"cat\", \"dog\") -> \"a cat and a dog\" */\r\nfunction formatString(str: string, ...params: any[]) {\r\n let args = arguments;\r\n let pattern = RegExp(\"%([1-\" + (arguments.length - 1) + \"])\", \"g\");\r\n return str.replace(pattern, function (match, index) {\r\n return args[index];\r\n });\r\n}\r\n\r\n// See http://stackoverflow.com/questions/7225407/convert-camelcasetext-to-camel-case-text\r\n/** Change text to title case with spaces, e.g. 'myPropertyName12' to 'My Property Name 12' */\r\nconst camelEdges = /([A-Z](?=[A-Z][a-z])|[^A-Z](?=[A-Z])|[a-zA-Z](?=[^a-zA-Z]))/g;\r\nfunction titleCaseSpace(text: string) {\r\n text = text.replace(camelEdges, '$1 ');\r\n text = text.charAt(0).toUpperCase() + text.slice(1);\r\n return text;\r\n}\r\n\r\n// end of string functions\r\n\r\n// See Mark Miller’s explanation of what this does.\r\n// http://wiki.ecmascript.org/doku.php?id=conventions:safe_meta_programming\r\nfunction uncurry(f: any) {\r\n let call = Function.call;\r\n return function () {\r\n return call.apply(f, arguments);\r\n };\r\n}\r\n\r\n// shims\r\n\r\nif (!Object.create) {\r\n Object.create = function (parent: any) {\r\n let F = <any>function () {\r\n };\r\n F.prototype = parent;\r\n return new F();\r\n };\r\n}\r\n\r\n// strings for error messages\r\n\r\nconst strings = {\r\n \"TO_TYPE\": \"Add 'EntityQuery.toType()' to your query, or call 'MetadataStore.setEntityTypeForResourceName()' to register an EntityType for this resourceName.\"\r\n}\r\n\r\n// // not all methods above are exported\r\nexport const core = {\r\n isES5Supported: isES5Supported,\r\n hasOwnProperty: hasOwnProperty,\r\n getOwnPropertyValues: getOwnPropertyValues,\r\n getPropertyDescriptor: getPropDescriptor,\r\n objectForEach: objectForEach,\r\n objectFirst: objectFirst,\r\n objectMap: objectMap, // TODO: replace this with something strongly typed.\r\n extend: extend,\r\n propEq: propEq,\r\n propsEq: propsEq,\r\n pluck: pluck,\r\n map: map,\r\n resolveProperties: resolveProperties,\r\n setAsDefault: setAsDefault,\r\n updateWithDefaults: updateWithDefaults,\r\n getArray: getArray,\r\n toArray: toArray,\r\n arrayEquals: arrayEquals,\r\n arraySlice: arraySlice,\r\n arrayFirst: arrayFirst,\r\n arrayIndexOf: arrayIndexOf,\r\n arrayRemoveItem: arrayRemoveItem,\r\n arrayZip: arrayZip,\r\n arrayAddItemUnique: arrayAddItemUnique,\r\n arrayFlatMap: arrayFlatMap,\r\n\r\n requireLib: requireLib,\r\n using: using,\r\n wrapExecution: wrapExecution,\r\n\r\n memoize: memoize,\r\n getUuid: getUuid,\r\n durationToSeconds: durationToSeconds,\r\n\r\n isSettable: isSettable,\r\n\r\n isDate: isDate,\r\n isDateString: isDateString,\r\n isGuid: isGuid,\r\n isDuration: isDuration,\r\n isFunction: isFunction,\r\n isEmpty: isEmpty,\r\n isNumeric: isNumeric,\r\n\r\n identity: identity,\r\n noop: noop,\r\n\r\n stringStartsWith: stringStartsWith,\r\n stringEndsWith: stringEndsWith,\r\n formatString: formatString,\r\n titleCase: titleCaseSpace,\r\n\r\n toJson: toJson,\r\n toJSONSafe: toJSONSafe,\r\n toJSONSafeReplacer: toJSONSafeReplacer,\r\n\r\n strings: strings\r\n};\r\n\r\nexport interface ErrorCallback {\r\n (error: any): void;\r\n}\r\n\r\n\r\n// Unused\r\n/*\r\n// returns true for booleans, numbers, strings and dates\r\n// false for null, and non-date objects, functions, and arrays\r\nfunction isPrimitive(obj: any) {\r\n if (obj == null) return false;\r\n // true for numbers, strings, booleans and null, false for objects\r\n if (obj != Object(obj)) return true;\r\n return isDate(obj);\r\n}\r\n\r\n*/","import { BreezeEnum } from './enum';\r\nimport { core } from './core';\r\n\r\n/** @hidden @internal */\r\nexport interface IParamContext {\r\n typeName?: string;\r\n type?: Function;\r\n prevContext?: IParamContext;\r\n msg?: string | ((context: IParamContext, v: any) => string);\r\n mustNotBeEmpty?: boolean;\r\n enumType?: BreezeEnum;\r\n propertyName?: string;\r\n allowNull?: boolean;\r\n fn?(context: IParamContext, v: any): boolean;\r\n}\r\n\r\n/** @hidden @internal */\r\nexport interface IConfigParam {\r\n config: any;\r\n params: Param[];\r\n whereParam: (propName: string) => Param;\r\n}\r\n\r\n/** @hidden @internal */\r\nexport class Param {\r\n // The %1 parameter\r\n // is required\r\n // must be a %2\r\n // must be an instance of %2\r\n // must be an instance of the %2 enumeration\r\n // must have a %2 property\r\n // must be an array where each element\r\n // is optional or\r\n\r\n v: any;\r\n name: string;\r\n defaultValue: any;\r\n parent: IConfigParam;\r\n /** @hidden @internal */\r\n _context: IParamContext;\r\n /** @hidden @internal */\r\n _contexts: IParamContext[];\r\n\r\n constructor(v: any, name: string) {\r\n this.v = v;\r\n this.name = name;\r\n this._contexts = [<any>null];\r\n }\r\n\r\n isObject(): Param {\r\n return this.isTypeOf('object');\r\n }\r\n\r\n isBoolean(): Param {\r\n return this.isTypeOf('boolean');\r\n }\r\n\r\n isString(): Param {\r\n return this.isTypeOf('string');\r\n }\r\n\r\n isNumber(): Param {\r\n return this.isTypeOf('number');\r\n }\r\n\r\n isFunction(): Param {\r\n return this.isTypeOf('function');\r\n }\r\n\r\n isNonEmptyString(): Param {\r\n return addContext(this, {\r\n fn: isNonEmptyString,\r\n msg: \"must be a nonEmpty string\"\r\n });\r\n }\r\n\r\n\r\n isTypeOf(typeName: string): Param {\r\n return addContext(this, {\r\n fn: isTypeOf,\r\n typeName: typeName,\r\n msg: \"must be a '\" + typeName + \"'\"\r\n });\r\n }\r\n\r\n\r\n isInstanceOf(type: Function, typeName?: string): Param {\r\n typeName = typeName || type.prototype._$typeName;\r\n return addContext(this, {\r\n fn: isInstanceOf,\r\n type: type,\r\n typeName: typeName,\r\n msg: \"must be an instance of '\" + typeName + \"'\"\r\n });\r\n }\r\n\r\n\r\n hasProperty(propertyName: string): Param {\r\n return addContext(this, {\r\n fn: hasProperty,\r\n propertyName: propertyName,\r\n msg: \"must have a '\" + propertyName + \"' property\"\r\n });\r\n }\r\n\r\n\r\n isEnumOf(enumType: any): Param {\r\n return addContext(this, {\r\n fn: isEnumOf,\r\n enumType: enumType,\r\n msg: \"must be an instance of the '\" + (enumType.name || 'unknown') + \"' enumeration\"\r\n });\r\n }\r\n\r\n isRequired(allowNull: boolean = false): Param {\r\n return addContext(this, {\r\n fn: isRequired,\r\n allowNull: allowNull,\r\n msg: \"is required\"\r\n });\r\n }\r\n\r\n isOptional(): Param {\r\n let context = {\r\n fn: isOptional,\r\n prevContext: <any>null,\r\n msg: isOptionalMessage\r\n };\r\n return addContext(this, context);\r\n }\r\n\r\n isNonEmptyArray(): Param {\r\n return this.isArray(true);\r\n }\r\n\r\n isArray(mustNotBeEmpty?: boolean): Param {\r\n let context = {\r\n fn: isArray,\r\n mustNotBeEmpty: mustNotBeEmpty,\r\n prevContext: <any>null,\r\n msg: isArrayMessage\r\n };\r\n return addContext(this, context);\r\n }\r\n\r\n or() {\r\n this._contexts.push(<any>null);\r\n this._context = <any>null;\r\n return this;\r\n }\r\n\r\n check(defaultValue?: any) {\r\n let ok = exec(this);\r\n if (ok === undefined) return;\r\n if (!ok) {\r\n throw new Error(this.getMessage());\r\n }\r\n\r\n if (this.v !== undefined) {\r\n return this.v;\r\n } else {\r\n return defaultValue;\r\n }\r\n }\r\n\r\n /** @hidden @internal */\r\n // called from outside this file.\r\n _addContext(context: IParamContext) {\r\n return addContext(this, context);\r\n }\r\n\r\n getMessage() {\r\n let that = this;\r\n let message = this._contexts.map(function (context) {\r\n return getMessage(context, that.v);\r\n }).join(\", or it \");\r\n return core.formatString(this.MESSAGE_PREFIX, this.name) + \" \" + message;\r\n }\r\n\r\n withDefault(defaultValue: any) {\r\n this.defaultValue = defaultValue;\r\n return this;\r\n }\r\n\r\n whereParam(propName: string) {\r\n return this.parent.whereParam(propName);\r\n }\r\n\r\n applyAll(instance: any, checkOnly: boolean = false) {\r\n let parentTypeName = instance._$typeName;\r\n let allowUnknownProperty = (parentTypeName && this.parent.config._$typeName === parentTypeName);\r\n\r\n let clone = core.extend({}, this.parent.config);\r\n this.parent.params.forEach(function (p) {\r\n if (!allowUnknownProperty) delete clone[p.name];\r\n try {\r\n p.check();\r\n } catch (e) {\r\n throwConfigError(instance, e.message);\r\n }\r\n (!checkOnly) && p._applyOne(instance);\r\n });\r\n // should be no properties left in the clone\r\n if (!allowUnknownProperty) {\r\n for (let key in clone) {\r\n // allow props with an undefined value\r\n if (clone[key] !== undefined) {\r\n throwConfigError(instance, core.formatString(\"Unknown property: '%1'.\", key));\r\n }\r\n }\r\n }\r\n }\r\n\r\n /** @hidden @internal */\r\n _applyOne = function (this: Param, instance: any) {\r\n if (this.v !== undefined) {\r\n instance[this.name] = this.v;\r\n } else {\r\n if (this.defaultValue !== undefined) {\r\n instance[this.name] = this.defaultValue;\r\n }\r\n }\r\n };\r\n\r\n MESSAGE_PREFIX = \"The '%1' parameter \";\r\n\r\n}\r\n\r\n/** @hidden @internal */\r\nexport let assertParam = function (v: any, name: string) {\r\n return new Param(v, name);\r\n};\r\n\r\nfunction isTypeOf(context: IParamContext, v: any) {\r\n if (v == null) return false;\r\n if (typeof (v) === context.typeName) return true;\r\n return false;\r\n}\r\n\r\nfunction isNonEmptyString(context: IParamContext, v: any) {\r\n if (v == null) return false;\r\n return (typeof (v) === 'string') && v.length > 0;\r\n}\r\n\r\nfunction isInstanceOf(context: IParamContext, v: any) {\r\n if (v == null || context.type == null) return false;\r\n return (v instanceof context.type);\r\n}\r\n\r\nfunction isEnumOf(context: IParamContext, v: any) {\r\n if (v == null || context.enumType == null ) return false;\r\n return (context.enumType as any).contains(v);\r\n}\r\n\r\nfunction hasProperty(context: IParamContext, v: any) {\r\n if (v == null || context.propertyName == null) return false;\r\n return (v[context.propertyName] !== undefined);\r\n}\r\n\r\nfunction isRequired(context: IParamContext, v: any) {\r\n if (context.allowNull) {\r\n return v !== undefined;\r\n } else {\r\n return v != null;\r\n }\r\n}\r\n\r\nfunction isOptional(context: IParamContext, v: any) {\r\n if (v == null) return true;\r\n let prevContext = context.prevContext;\r\n if (prevContext && prevContext.fn) {\r\n return prevContext.fn(prevContext, v);\r\n } else {\r\n return true;\r\n }\r\n}\r\n\r\nfunction isOptionalMessage(context: IParamContext, v: any) {\r\n let prevContext = context.prevContext;\r\n let element = prevContext ? \" or it \" + getMessage(prevContext, v) : \"\";\r\n return \"is optional\" + element;\r\n}\r\n\r\nfunction isArray(context: IParamContext, v: any) {\r\n if (!Array.isArray(v)) {\r\n return false;\r\n }\r\n if (context.mustNotBeEmpty) {\r\n if (v.length === 0) return false;\r\n }\r\n // allow standalone is array call.\r\n let prevContext = context.prevContext;\r\n if (!prevContext) return true;\r\n\r\n let pc = <any>prevContext;\r\n return v.every(function (v1: any) {\r\n return pc.fn && pc.fn(pc, v1);\r\n });\r\n}\r\n\r\nfunction isArrayMessage(context: IParamContext, v: any) {\r\n let arrayDescr = context.mustNotBeEmpty ? \"a nonEmpty array\" : \"an array\";\r\n let prevContext = context.prevContext;\r\n let element = prevContext ? \" where each element \" + getMessage(prevContext, v) : \"\";\r\n return \" must be \" + arrayDescr + element;\r\n}\r\n\r\nfunction getMessage(context: IParamContext, v: any) {\r\n let msg = context.msg;\r\n if (typeof (msg) === \"function\") {\r\n msg = (<any>msg)(context, v);\r\n }\r\n return msg;\r\n}\r\n\r\nfunction addContext(that: Param, context: IParamContext) {\r\n if (that._context) {\r\n let curContext = that._context;\r\n\r\n while (curContext.prevContext != null) {\r\n curContext = curContext.prevContext;\r\n }\r\n\r\n if (curContext.prevContext === null) {\r\n curContext.prevContext = context;\r\n // just update the prevContext but don't change the curContext.\r\n return that;\r\n } else if (context.prevContext == null) {\r\n context.prevContext = that._context;\r\n } else {\r\n throw new Error(\"Illegal construction - use 'or' to combine checks\");\r\n }\r\n }\r\n return setContext(that, context);\r\n}\r\n\r\nfunction setContext(that: Param, context: IParamContext) {\r\n that._contexts[that._contexts.length - 1] = context;\r\n that._context = context;\r\n return that;\r\n}\r\n\r\n\r\nfunction exec(self: Param) {\r\n // clear off last one if null\r\n let contexts = self._contexts;\r\n if (contexts[contexts.length - 1] == null) {\r\n contexts.pop();\r\n }\r\n if (contexts.length === 0) {\r\n return undefined;\r\n }\r\n return contexts.some(function (context: IParamContext) {\r\n return context.fn ? context.fn(context, self.v) : false;\r\n });\r\n}\r\n\r\nfunction throwConfigError(instance: any, message: string) {\r\n throw new Error(core.formatString(\"Error configuring an instance of '%1'. %2\", (instance && instance._$typeName) || \"object\", message));\r\n}\r\n\r\nclass ConfigParam {\r\n config: any;\r\n params: Param[];\r\n constructor(config: Object) {\r\n if (typeof (config) !== \"object\") {\r\n throw new Error(\"Configuration parameter should be an object, instead it is a: \" + typeof (config));\r\n }\r\n this.config = config;\r\n this.params = [];\r\n }\r\n\r\n whereParam(propName: string) {\r\n let param = new Param(this.config[propName], propName);\r\n param.parent = this;\r\n this.params.push(param);\r\n return param;\r\n }\r\n}\r\n\r\n/** @hidden @internal */\r\nexport let assertConfig = function (config: Object) {\r\n return new ConfigParam(config) as IConfigParam;\r\n};\r\n\r\n\r\n// Param is exposed so that additional 'is' methods can be added to the prototype.\r\n(core as any).Param = Param;\r\n(core as any).assertParam = assertParam;\r\n(core as any).assertConfig = assertConfig;\r\n","import { core } from './core';\r\nimport { assertParam } from './assert-param';\r\n\r\nfunction publishCore<T>(that: BreezeEvent<T>, data: T, errorCallback?: (e: Error) => any) {\r\n let subscribers = that._subscribers;\r\n if (!subscribers) return true;\r\n // subscribers from outer scope.\r\n subscribers.forEach(function (s) {\r\n try {\r\n s.callback(data);\r\n } catch (e) {\r\n e.context = \"unable to publish on topic: \" + that.name;\r\n if (errorCallback) {\r\n errorCallback(e);\r\n } else if (that._defaultErrorCallback) {\r\n that._defaultErrorCallback(e);\r\n } else {\r\n fallbackErrorHandler(e);\r\n }\r\n }\r\n });\r\n}\r\n\r\nfunction fallbackErrorHandler(e: Error) {\r\n // TODO: maybe log this\r\n // for now do nothing;\r\n}\r\n\r\n\r\n/** @hidden @internal */\r\nexport interface Subscription {\r\n unsubKey: number;\r\n callback: (data: any) => any;\r\n}\r\n\r\n/**\r\nClass to support basic event publication and subscription semantics.\r\n@dynamic\r\n**/\r\nexport class BreezeEvent<T> {\r\n /** @hidden @internal */\r\n static __eventNameMap = {};\r\n /** @hidden @internal */\r\n static __nextUnsubKey = 1;\r\n /** The name of this Event */\r\n name: string;\r\n /** The object doing the publication. i.e. the object to which this event is attached. */\r\n publisher: Object;\r\n\r\n /** @hidden @internal */\r\n _subscribers: Subscription[];\r\n /** @hidden @internal */\r\n _defaultErrorCallback: (e: Error) => any;\r\n\r\n\r\n /**\r\n Constructor for an Event\r\n > salaryEvent = new BreezeEvent(\"salaryEvent\", person);\r\n @param name - The name of the event.\r\n @param publisher - The object that will be doing the publication. i.e. the object to which this event is attached.\r\n @param defaultErrorCallback - Function to call when an error occurs during subscription execution. \r\n If omitted then subscriber notification failures will be ignored.\r\n **/\r\n constructor(name: string, publisher: Object, defaultErrorCallback?: (e: Error) => any) {\r\n assertParam(name, \"eventName\").isNonEmptyString().check();\r\n assertParam(publisher, \"publisher\").isObject().check();\r\n\r\n this.name = name;\r\n // register the name\r\n BreezeEvent.__eventNameMap[name] = true;\r\n this.publisher = publisher;\r\n if (defaultErrorCallback) {\r\n this._defaultErrorCallback = defaultErrorCallback;\r\n }\r\n }\r\n\r\n /**\r\n Publish data for this event.\r\n > // Assume 'salaryEvent' is previously constructed Event\r\n > salaryEvent.publish( { eventType: \"payRaise\", amount: 100 });\r\n\r\n This event can also be published asychronously\r\n > salaryEvent.publish( { eventType: \"payRaise\", amount: 100 }, true);\r\n\r\n And we can add a handler in case the subscriber 'mishandles' the event.\r\n > salaryEvent.publish( { eventType: \"payRaise\", amount: 100 }, true, function(error) {\r\n > // do something with the 'error' object\r\n > });\r\n @param data - Data to publish\r\n @param publishAsync - (default=false) Whether to publish asynchonously or not.\r\n @param errorCallback - Function to be called for any errors that occur during publication. If omitted,\r\n errors will be eaten.\r\n @return false if event is disabled; true otherwise.\r\n **/\r\n publish(data: T, publishAsync: boolean = false, errorCallback?: (e: Error) => any) {\r\n\r\n if (!BreezeEvent._isEnabled(this.name, this.publisher)) return false;\r\n\r\n if (publishAsync === true) {\r\n setTimeout(publishCore, 0, this, data, errorC