import {isJsObject, global, isPresent, isBlank, isArray} from 'angular2/src/core/facade/lang'; export var List = global.Array; export var Map = global.Map; export var Set = global.Set; export var StringMap = global.Object; // Safari and Internet Explorer do not support the iterable parameter to the // Map constructor. We work around that by manually adding the items. var createMapFromPairs: {(pairs: List): Map} = (function() { try { if (new Map([[1, 2]]).size === 1) { return function createMapFromPairs(pairs: List): Map { return new Map(pairs); }; } } catch (e) { } return function createMapAndPopulateFromPairs(pairs: List): Map { var map = new Map(); for (var i = 0; i < pairs.length; i++) { var pair = pairs[i]; map.set(pair[0], pair[1]); } return map; }; })(); var createMapFromMap: {(m: Map): Map} = (function() { try { if (new Map(new Map())) { return function createMapFromMap(m: Map): Map { return new Map(m); }; } } catch (e) { } return function createMapAndPopulateFromMap(m: Map): Map { var map = new Map(); m.forEach((v, k) => { map.set(k, v); }); return map; }; })(); var _clearValues: {(m: Map)} = (function() { if (((new Map()).keys()).next) { return function _clearValues(m: Map) { var keyIterator = m.keys(); var k; while (!((k = (keyIterator).next()).done)) { m.set(k.value, null); } }; } else { return function _clearValuesWithForeEach(m: Map) { m.forEach((v, k) => { m.set(k, null); }); }; } })(); // Safari doesn't implement MapIterator.next(), which is used is Traceur's polyfill of Array.from // TODO(mlaval): remove the work around once we have a working polyfill of Array.from var _arrayFromMap: {(m: Map, getValues: boolean): List} = (function() { try { if (((new Map()).values()).next) { return function createArrayFromMap(m: Map, getValues: boolean): List { return getValues ? (Array).from(m.values()) : (Array).from(m.keys()); }; } } catch (e) { } return function createArrayFromMapWithForeach(m: Map, getValues: boolean): List { var res = ListWrapper.createFixedSize(m.size), i = 0; m.forEach((v, k) => { ListWrapper.set(res, i, getValues ? v : k); i++; }); return res; }; })(); export class MapWrapper { static clone(m: Map): Map { return createMapFromMap(m); } static createFromStringMap(stringMap: StringMap): Map { var result = new Map(); for (var prop in stringMap) { result.set(prop, stringMap[prop]); } return result; } static toStringMap(m: Map): StringMap { var r = {}; m.forEach((v, k) => r[k] = v); return r; } static createFromPairs(pairs: List): Map { return createMapFromPairs(pairs); } static forEach(m: Map, fn: /*(V, K) => void*/ Function) { m.forEach(fn); } static get(map: Map, key: K): V { return map.get(key); } static size(m: Map): number { return m.size; } static delete(m: Map, k: K) { m.delete(k); } static clearValues(m: Map) { _clearValues(m); } static iterable(m: T): T { return m; } static keys(m: Map): List { return _arrayFromMap(m, false); } static values(m: Map): List { return _arrayFromMap(m, true); } } /** * Wraps Javascript Objects */ export class StringMapWrapper { static create(): StringMap { // Note: We are not using Object.create(null) here due to // performance! // http://jsperf.com/ng2-object-create-null return {}; } static contains(map: StringMap, key: string): boolean { return map.hasOwnProperty(key); } static get(map: StringMap, key: string): V { return map.hasOwnProperty(key) ? map[key] : undefined; } static set(map: StringMap, key: string, value: V) { map[key] = value; } static keys(map: StringMap): List { return Object.keys(map); } static isEmpty(map: StringMap): boolean { for (var prop in map) { return false; } return true; } static delete (map: StringMap, key: string) { delete map[key]; } static forEach(map: StringMap, callback: /*(V, K) => void*/ Function) { for (var prop in map) { if (map.hasOwnProperty(prop)) { callback(map[prop], prop); } } } static merge(m1: StringMap, m2: StringMap): StringMap { var m = {}; for (var attr in m1) { if (m1.hasOwnProperty(attr)) { m[attr] = m1[attr]; } } for (var attr in m2) { if (m2.hasOwnProperty(attr)) { m[attr] = m2[attr]; } } return m; } static equals(m1: StringMap, m2: StringMap): boolean { var k1 = Object.keys(m1); var k2 = Object.keys(m2); if (k1.length != k2.length) { return false; } var key; for (var i = 0; i < k1.length; i++) { key = k1[i]; if (m1[key] !== m2[key]) { return false; } } return true; } } export interface Predicate { (value: T, index?: number, array?: T[]): boolean; } export class ListWrapper { // JS has no way to express a staticly fixed size list, but dart does so we // keep both methods. static createFixedSize(size: number): List { return new List(size); } static createGrowableSize(size: number): List { return new List(size); } static get(m: List, k: number): T { return m[k]; } static set(m: List, k: number, v: T) { m[k] = v; } static clone(array: List): T[] { return array.slice(0); } static map(array: List, fn: (T) => V): List { return array.map(fn); } static forEach(array: List, fn: (T) => void) { for (var i = 0; i < array.length; i++) { fn(array[i]); } } static forEachWithIndex(array: List, fn: (T, number) => void) { for (var i = 0; i < array.length; i++) { fn(array[i], i); } } static first(array: List): T { if (!array) return null; return array[0]; } static last(array: List): T { if (!array || array.length == 0) return null; return array[array.length - 1]; } static find(list: List, pred: Predicate): T { for (var i = 0; i < list.length; ++i) { if (pred(list[i])) return list[i]; } return null; } static indexOf(array: List, value: T, startIndex: number = 0): number { return array.indexOf(value, startIndex); } static reduce(list: List, fn: (accumValue: E, currentValue: T, currentIndex: number, array: T[]) => E, init: E): E { return list.reduce(fn, init); } static filter(array: List, pred: Predicate): T[] { return array.filter(pred); } static any(list: List, pred: Function): boolean { for (var i = 0; i < list.length; ++i) { if (pred(list[i])) return true; } return false; } static contains(list: List, el: T): boolean { return list.indexOf(el) !== -1; } static reversed(array: List): T[] { var a = ListWrapper.clone(array); return a.reverse(); } static concat(a: List, b: List): List { return a.concat(b); } static insert(list: List, index: number, value: T) { list.splice(index, 0, value); } static removeAt(list: List, index: number): T { var res = list[index]; list.splice(index, 1); return res; } static removeAll(list: List, items: List) { for (var i = 0; i < items.length; ++i) { var index = list.indexOf(items[i]); list.splice(index, 1); } } static removeLast(list: List): T { return list.pop(); } static remove(list: List, el: T): boolean { var index = list.indexOf(el); if (index > -1) { list.splice(index, 1); return true; } return false; } static clear(list: List) { list.splice(0, list.length); } static join(list: List, s: string): string { return list.join(s); } static isEmpty(list: List): boolean { return list.length == 0; } static fill(list: List, value: any, start: number = 0, end: number = null) { list.fill(value, start, end === null ? list.length : end); } static equals(a: List, b: List): boolean { if (a.length != b.length) return false; for (var i = 0; i < a.length; ++i) { if (a[i] !== b[i]) return false; } return true; } static slice(l: List, from: number = 0, to: number = null): List { return l.slice(from, to === null ? undefined : to); } static splice(l: List, from: number, length: number): List { return l.splice(from, length); } static sort(l: List, compareFn?: (a: T, b: T) => number) { if (isPresent(compareFn)) { l.sort(compareFn); } else { l.sort(); } } static toString(l: List): string { return l.toString(); } static toJSON(l: List): string { return JSON.stringify(l); } static maximum(list: List, predicate: (T) => number): T { if (list.length == 0) { return null; } var solution = null; var maxValue = -Infinity; for (var index = 0; index < list.length; index++) { var candidate = list[index]; if (isBlank(candidate)) { continue; } var candidateValue = predicate(candidate); if (candidateValue > maxValue) { solution = candidate; maxValue = candidateValue; } } return solution; } } export function isListLikeIterable(obj: any): boolean { if (!isJsObject(obj)) return false; return isArray(obj) || (!(obj instanceof Map) && // JS Map are iterables but return entries as [k, v] Symbol.iterator in obj); // JS Iterable have a Symbol.iterator prop } export function iterateListLike(obj: any, fn: Function) { if (isArray(obj)) { for (var i = 0; i < obj.length; i++) { fn(obj[i]); } } else { var iterator = obj[Symbol.iterator](); var item; while (!((item = iterator.next()).done)) { fn(item.value); } } } // Safari and Internet Explorer do not support the iterable parameter to the // Set constructor. We work around that by manually adding the items. var createSetFromList: {(lst: List): Set} = (function() { var test = new Set([1, 2, 3]); if (test.size === 3) { return function createSetFromList(lst: List): Set { return new Set(lst); }; } else { return function createSetAndPopulateFromList(lst: List): Set { var res = new Set(lst); if (res.size !== lst.length) { for (var i = 0; i < lst.length; i++) { res.add(lst[i]); } } return res; }; } })(); export class SetWrapper { static createFromList(lst: List): Set { return createSetFromList(lst); } static has(s: Set, key: T): boolean { return s.has(key); } static delete(m: Set, k: K) { m.delete(k); } }