typescript-map
Version:
ES6 Map Implemented in TypeScript
320 lines (319 loc) • 9.27 kB
JavaScript
"use strict";
var __spreadArrays = (this && this.__spreadArrays) || function () {
for (var s = 0, i = 0, il = arguments.length; i < il; i++) s += arguments[i].length;
for (var r = Array(s), k = 0, i = 0; i < il; i++)
for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++)
r[k] = a[j];
return r;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.TSMap = void 0;
var TSMap = /** @class */ (function () {
function TSMap(inputMap) {
var t = this;
t._keys = [];
t._values = [];
t.length = 0;
if (inputMap) {
inputMap.forEach(function (v, k) {
t.set(v[0], v[1]);
});
}
}
/**
* Convert a JSON object to a map.
*
* @param {*} jsonObject JSON object to convert
* @param {boolean} [convertObjs] convert nested objects to maps
* @returns {TSMap<K, V>}
* @memberof TSMap
*/
TSMap.prototype.fromJSON = function (jsonObject, convertObjs) {
var t = this;
var setProperty = function (value) {
if (value !== null && typeof value === 'object' && convertObjs)
return new TSMap().fromJSON(value, true);
if (Array.isArray(value) && convertObjs)
return value.map(function (v) { return setProperty(v); });
return value;
};
Object.keys(jsonObject).forEach(function (property) {
if (jsonObject.hasOwnProperty(property)) {
t.set(property, setProperty(jsonObject[property]));
}
});
return t;
};
/**
* Outputs the contents of the map to a JSON object
*
* @returns {{[key: string]: V}}
* @memberof TSMap
*/
TSMap.prototype.toJSON = function () {
var obj = {};
var t = this;
var getValue = function (value) {
if (value instanceof TSMap) {
return value.toJSON();
}
else if (Array.isArray(value)) {
return value.map(function (v) { return getValue(v); });
}
else {
return value;
}
};
t.keys().forEach(function (k) {
obj[String(k)] = getValue(t.get(k));
});
return obj;
};
/**
* Get an array of arrays respresenting the map, kind of like an export function.
*
* @returns {(Array<Array<K|V>>)}
*
* @memberOf TSMap
*/
TSMap.prototype.entries = function () {
var _this = this;
return [].slice.call(this.keys().map(function (k) { return [k, _this.get(k)]; }));
};
/**
* Get an array of keys in the map.
*
* @returns {Array<K>}
*
* @memberOf TSMap
*/
TSMap.prototype.keys = function () {
return [].slice.call(this._keys);
};
/**
* Get an array of the values in the map.
*
* @returns {Array<V>}
*
* @memberOf TSMap
*/
TSMap.prototype.values = function () {
return [].slice.call(this._values);
};
/**
* Check to see if an item in the map exists given it's key.
*
* @param {K} key
* @returns {Boolean}
*
* @memberOf TSMap
*/
TSMap.prototype.has = function (key) {
return this._keys.indexOf(key) > -1;
};
/**
* Get a specific item from the map given it's key.
*
* @param {K} key
* @returns {V}
*
* @memberOf TSMap
*/
TSMap.prototype.get = function (key) {
var i = this._keys.indexOf(key);
return i > -1 ? this._values[i] : undefined;
};
/**
* Safely retrieve a deeply nested property.
*
* @param {K[]} path
* @returns {V}
*
* @memberOf TSMap
*/
TSMap.prototype.deepGet = function (path) {
if (!path || !path.length)
return null;
var recursiveGet = function (obj, path) {
if (obj === undefined || obj === null)
return null;
if (!path.length)
return obj;
return recursiveGet(obj instanceof TSMap ? obj.get(path[0]) : obj[path[0]], path.slice(1));
};
return recursiveGet(this.get(path[0]), path.slice(1));
};
/**
* Set a specific item in the map given it's key, automatically adds new items as needed.
* Ovewrrites existing items
*
* @param {K} key
* @param {V} value
*
* @memberOf TSMap
*/
TSMap.prototype.set = function (key, value) {
var t = this;
// check if key exists and overwrite
var i = this._keys.indexOf(key);
if (i > -1) {
t._values[i] = value;
}
else {
t._keys.push(key);
t._values.push(value);
t.length = t._values.length;
}
return this;
};
/**
* Enters a value into the map forcing the keys to always be sorted.
* Stolen from https://machinesaredigging.com/2014/04/27/binary-insert-how-to-keep-an-array-sorted-as-you-insert-data-in-it/
* Best case speed is O(1), worse case is O(N).
*
* @param {K} key
* @param {V} value
* @param {number} [startVal]
* @param {number} [endVal]
* @returns {this}
* @memberof TSMap
*/
TSMap.prototype.sortedSet = function (key, value, startVal, endVal) {
var t = this;
var length = this._keys.length;
var start = startVal || 0;
var end = endVal !== undefined ? endVal : length - 1;
if (length == 0) {
t._keys.push(key);
t._values.push(value);
return t;
}
if (key == this._keys[start]) {
this._values[start] = value;
return this;
}
if (key == this._keys[end]) {
this._values[end] = value;
return this;
}
if (key > this._keys[end]) {
this._keys.splice(end + 1, 0, key);
this._values.splice(end + 1, 0, value);
return this;
}
if (key < this._keys[start]) {
this._values.splice(start, 0, value);
this._keys.splice(start, 0, key);
return this;
}
if (start >= end) {
return this;
}
var m = start + Math.floor((end - start) / 2);
if (key < this._keys[m]) {
return this.sortedSet(key, value, start, m - 1);
}
if (key > this._keys[m]) {
return this.sortedSet(key, value, m + 1, end);
}
return this;
};
/**
* Provide a number representing the number of items in the map
*
* @returns {number}
*
* @memberOf TSMap
*/
TSMap.prototype.size = function () {
return this.length;
};
/**
* Clear all the contents of the map
*
* @returns {TSMap<K,V>}
*
* @memberOf TSMap
*/
TSMap.prototype.clear = function () {
var t = this;
t._keys.length = t.length = t._values.length = 0;
return this;
};
/**
* Delete an item from the map given it's key
*
* @param {K} key
* @returns {Boolean}
*
* @memberOf TSMap
*/
TSMap.prototype.delete = function (key) {
var t = this;
var i = t._keys.indexOf(key);
if (i > -1) {
t._keys.splice(i, 1);
t._values.splice(i, 1);
t.length = t._keys.length;
return true;
}
return false;
};
/**
* Used to loop through the map.
*
* @param {(value:V,key?:K,index?:number) => void} callbackfn
*
* @memberOf TSMap
*/
TSMap.prototype.forEach = function (callbackfn) {
var _this = this;
this._keys.forEach(function (v, i) {
callbackfn(_this.get(v), v, i);
});
};
/**
* Returns an array containing the returned value of each item in the map.
*
* @param {(value:V,key?:K,index?:number) => any} callbackfn
* @returns {Array<any>}
*
* @memberOf TSMap
*/
TSMap.prototype.map = function (callbackfn) {
var _this = this;
return this.keys().map(function (itemKey, i) {
return callbackfn(_this.get(itemKey), itemKey, i);
});
};
/**
* Removes items based on a conditional function passed to filter.
* Mutates the map in place.
*
* @param {(value:V,key?:K,index?:number) => Boolean} callbackfn
* @returns {TSMap<K,V>}
*
* @memberOf TSMap
*/
TSMap.prototype.filter = function (callbackfn) {
var t = this;
__spreadArrays(t._keys).forEach(function (v, i) {
if (callbackfn(t.get(v), v, i) === false)
t.delete(v);
});
return this;
};
/**
* Creates a deep copy of the map, breaking all references to the old map and it's children.
* Uses JSON.parse so any functions will be stringified and lose their original purpose.
*
* @returns {TSMap<K,V>}
*
* @memberOf TSMap
*/
TSMap.prototype.clone = function () {
return new TSMap(this.entries());
};
return TSMap;
}());
exports.TSMap = TSMap;