Skip to content

Instantly share code, notes, and snippets.

@sammich
Created April 20, 2016 06:31
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save sammich/b192f9f5980813c8ed120d3cab0490ae to your computer and use it in GitHub Desktop.
Save sammich/b192f9f5980813c8ed120d3cab0490ae to your computer and use it in GitHub Desktop.
Sssssh...this is still a work in progress, and Sam hasn't decided if he should release it yet.
var _ = (function () {
return {
// array
filter: array_filter
, last: array_last
, map: array_map
, pop: array_pop
, push: array_push
, unshift: array_unshift
// string
, format: string_format
// utilities
, __typeof: __typeof
, __isTw: __isTw
, __isTWList: __isTWList
};
// ARRAYS
/**
* @typedef {Object} TWList
* @property {Number} listLength number of resident elements
* @method removeIndex
*/
/**
* Iterates over each element in the input list and returns a new list with elements based on the return of the
* callback function: returning a truthy value adds the element into the output array
*
* Aims to be functionally similar (if not identical) to Array.prototype.map
*
* @param {Array|TWList} arr Target collection to iterate over
* @param {Function} callback This function is called for each element in the input list. See map() spec for more
* details
* @returns {Object} last object in the array or undefined for zero-length arr
*/
function array_filter(arr, callback /*, thisArg*/ ) {
if (!__isListOrArray(arr)) {
throw new Error('_.filter requires a JS array or TW List as it\'s first argument');
}
if (typeof callback !== 'function') {
throw new TypeError();
}
var res, i, val, t, len;
var thisArg = arguments.length >= 3 ? arguments[2] : void 0;
if (__isTWList(arr)) {
// bpm list
t = arr;
len = arr.listLength;
var type = __typeof(arr);
res = new tw.object.listOf[type];
for (i = 0; i < len; i++) {
if (t[i] !== null) {
val = t[i];
if (callback.call(thisArg, val, i, t)) {
res[res.listLength] = (val);
}
}
}
} else if (arr instanceof Array) {
// regular JS array
t = arr;
len = t.length >>> 0;
res = [];
for (i = 0; i < len; i++) {
if (i in t) {
val = t[i];
if (callback.call(thisArg, val, i, t)) {
res.push(val);
}
}
}
}
return res;
}
/**
* Iterates over each element in the input list and returns a new list with elements returned for each call
* of the callback function.
*
* Aims to be functionally similar (if not identical) to Array.prototype.map
*
* @param {Array|TWList} arr Target collection to iterate over
* @param {Function} callback This function is called for each element in the input list. See map() spec for more
* details
* @returns {Object} last object in the array or undefined for zero-length arr
*/
function array_map(arr, callback /*, thisArg*/) {
if (!__isListOrArray(arr)) {
throw new Error('_.map requires a JS array or TW List as it\'s first argument');
}
if (typeof callback !== 'function') {
throw new TypeError(callback + ' is not a function');
}
var res, len, i, val;
var thisArg = arguments.length >= 3 ? arguments[2] : void 0;
// quack quack?
if (__isTWList(arr)) {
// bpm list
t = arr;
len = arr.listLength;
var type = __typeof(arr);
res = new tw.object.listOf[type];
for (i = 0; i < len; i++) {
if (t[i] !== null) {
val = t[i];
res[res.listLength] = callback.call(thisArg, val, i, t);
}
}
} else if (arr instanceof Array) {
var _arr = Object(arr);
len = _arr.length >>> 0;
res = new Array(len);
i = 0;
while (i < len) {
var mappedValue;
if (i in _arr) {
val = _arr[i];
mappedValue = callback.call(thisArg, val, i, _arr);
res[i] = mappedValue;
}
i++;
}
}
return res;
}
/**
* Removes and returns last item in list
*
* Aims to be functionally similar (if not identical) to Array.prototype.pop
*
* @param {Array|TWList} arr Target collection to remove item from
* @returns {Object} last object in the array or undefined for zero-length arr
*/
function array_pop(arr) {
if (!__isListOrArray(arr)) {
throw new TypeError('_.pop() requires a JS array or TW List as it\'s only argument');
}
if (__isTWList(arr)) {
var len = arr.listLength;
if (len === 0) {
return;
} else {
var res = arr[len - 1];
arr.removeIndex(len - 1);
return res;
}
} else if (arr instanceof Array) {
return arr.pop();
}
}
/**
* Adds elements to the end of the input list.
*
* Aims to be functionally similar (if not identical) to Array.prototype.push
*
* @param {Array|TWList} arr Target collection to add element to
* @param {Object} element Object (or primitive) to be added to arr. Behaviour undefined if element is not passed in
* @returns {Number} Length of modified array (note note for param element)
*/
function array_push(arr /*, element1, element2 ... */) {
if (!__isListOrArray(arr)) {
throw new TypeError('_.push requires a JS array or TW List as it\'s first argument');
}
var args = Array.prototype.slice.call(arguments, 1);
if (__isTWList(arr)) {
for (var i = 0, x = args.length; i < x; i++) {
arr[arr.listLength] = args[i];
}
return arr.listLength;
} else if (arr instanceof Array) {
return Array.prototype.push.apply(arr, args);
}
}
/**
* Adds elements to the front of the input list
*
* Aims to be functionally similar (if not identical) to Array.prototype.unshift
*
* @param {Array|TWList} arr Target collection to add element to
* @param {Object} element Object (or primitive) to be added to arr. Behaviour undefined if element is not passed in
* @returns {Number} Length of modified array (note note for param element)
*/
function array_unshift(arr /*, element1, element2 ... */) {
if (!__isListOrArray(arr)) {
throw new TypeError('_.unshift requires a JS array or TW List as it\'s first argument');
}
var args = Array.prototype.slice.call(arguments, 1);
if (__isTWList(arr)) {
for (var i = 0, x = args.length; i < x; i++) {
arr.insertIntoList(i, args[i]); // push into array same order as input arg
}
return arr.listLength;
} else if (arr instanceof Array) {
return Array.prototype.unshift.apply(arr, args);
}
}
/**
* Returns retrieves the last element in `arr` list or array
*
* Aims to be functionally similar (if not identical) to Array.prototype.last
*
* @param {Array|TWList} arr Target collection
* @returns {*} Returns the item at position `arr.length - 1` in `arr`
*/
function array_last(arr) {
if (!__isListOrArray(arr)) {
throw new Error('_.last requires a JS array or TW List as it\'s first argument');
}
if (__isTWList(arr)) {
return arr.listLength ? arr[arr.listLength - 1] : null;
} else if (arr instanceof Array) {
return arr.length ? arr[arr.length - 1] : null;
}
}
// STRINGS
/**
* Takes a string with the delimiter {n}, and replaces it with values passed in as arguments
*
* @example
* _.format('{0}, {1}', 'Hello', 'World') === 'Hello, World'
*
* @param {String} str The string to be modified
* @returns {String} the formatted string
*/
function string_format(str) {
if (!__isString(str)) {
throw new Error('_.format requires a string as the first argument');
}
var args = Array.prototype.slice.call(arguments, 1);
return str.replace(/{(\d+)}/g, function(match, number) {
return typeof args[number] != 'undefined' ? args[number] : match;
});
}
// UTILITIES
/**
* Test if `value` is a string. It's naive. Consider upgrading to lodash's isString implementation
*
* @param {*} value Test subject
* @returns {boolean} Returns `true` if `value` is indeed a string, else `false`
* @private
*/
function __isString(value) {
return typeof value === 'string';
}
/**
* Test if `value` is not `null` or `undefined`
*
* @param {*} value Test subject
* @returns {boolean} Returns `true` if `value` is neither `undefined` nor `null`
* @private
*/
function __unset(value) {
return value === undefined || value === null;
}
/**
* Simple wrapper for typeof that also works on Teamworks objects
*
* @param {*} value Test subject
* @returns {String} The Business Object name of the Teamworks object or the JS typeof value
*/
function __typeof(value) {
if (value == null || value == undefined) {
return typeof value;
} else if (__isTw(value)) {
return value.toXML().getAttribute('type').replace('[]', '');
}
return typeof value;
}
/**
* Determines if the subject is 'listy'
*
* @param {*} value Test subject
* @returns {boolean} Returns `true` if `value` is a Teamworks List of JS Array, `false` otherwise
* @private
*/
function __isListOrArray(value) {
return __isTWList(value) || value instanceof Array;
}
/**
* Naive/shallow test for if the subject is a Teamworks Object
*
* @param {*} value Test subject
* @returns {boolean} Returns `true` if `value` is a Teamworks type, `false` otherwise
*/
function __isTw(value) {
return value ? ('toXML' in value) : false;
}
/**
* Shallow test for if the subject is a Teamworks List object
*
* @param {*} value Test subject
* @returns {boolean} Returns `true` if `value` is a Teamworks list, `false` otherwise
* @private
*/
function __isTWList(value) {
return value ? (__isTw(value) && ('listLength' in value)) : false;
}
function isObjectLike(value) {
return !!value && typeof value == 'object';
}
})();
@sammich
Copy link
Author

sammich commented Nov 22, 2018

Needs unit tests
Detect null objects like TWDate

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment