Skip to content

Commit

Permalink
reordered std-additions
Browse files Browse the repository at this point in the history
  • Loading branch information
rsms committed Apr 22, 2010
1 parent 155277b commit 7e61c36
Show file tree
Hide file tree
Showing 6 changed files with 202 additions and 95 deletions.
3 changes: 0 additions & 3 deletions client/lib/std-additions/array.js

This file was deleted.

1 change: 1 addition & 0 deletions client/lib/std-additions/array.js
1 change: 1 addition & 0 deletions client/lib/std-additions/object.js
81 changes: 81 additions & 0 deletions oui/std-additions/array.js
@@ -0,0 +1,81 @@
// NOTE: this file is used by both the server and client library, thus it need
// to work in web browsers.

if (typeof Array.isArray !== 'function') {
Array.isArray = function(obj) { return toString.call(obj) === "[object Array]"; };
}

/**
* Return the first true return value from fun which is called for each value.
* fun is called on this and receives a single argument (current value).
*/
Array.prototype.find = function (fun) {
for (var i = 0, r; i < this.length; i++)
if ((r = fun.call(this, this[i]))) return r;
};

/** Return a (possibly new) array which only contains unique values. */
Array.prototype.unique = function() {
var i, tag, m = {};
for (i=0; (tag = this[i]); ++i) m[tag] = true;
m = Object.keys(m);
return (m.length === this.length) ? this : m;
};

/**
* Difference between this and other array.
*
* Returns a new array with values (or indices if returnIndices) which are not
* at the same place.
*
* Example 1:
*
* oldTags = ['computer', 'car'];
* newTags = ['car', 'computer', '80s'];
* oldTags.diff(newTags) --> ['80s']
*
* Example 2:
*
* A = [1, 2, 3, 4, 5]
* B = [1, 2, 6, 4, 5, 6, 7, 8]
* B.diff(A) => [3] // values
* B.diff(A, true) => [2] // indices
* A.diff(B) => [8, 7, 6, 6] // values
* A.diff(B, true) => [7, 6, 5, 2] // indices
*/
Array.prototype.diff = function (other, returnIndices) {
var d = [], e = -1, h, i, j, k;
for(i = other.length, k = this.length; i--;){
for(j = k; j && (h = other[i] !== this[--j]);){}
// The comparator here will be optimized away by V8
if (h) (d[++e] = returnIndices ? i : other[i]);
}
return d;
};

/**
* Return a new array which contains the intersection of this and any other
* array passed as an argument.
*/
Array.prototype.intersect = function() {
var retArr = [], k1, arr, i, k;
arr1keys:
for (k1=0,L=this.length; k1<L; ++k1) {
arrs:
for (i=0; i < arguments.length; ++i) {
arr = arguments[i];
for (k=0,L=arr.length; k<L; ++k) {
if (arr[k] === this[k1]) {
if (i === arguments.length-1)
retArr[k1] = this[k1];
// If the innermost loop always leads at least once to an equal value,
// continue the loop until done
continue arrs;
}
}
// If it got here, it wasn't found in at least one array, try next value.
continue arr1keys;
}
}
return retArr;
};
94 changes: 4 additions & 90 deletions oui/std-additions/index.js
@@ -1,7 +1,7 @@
var sys = require('sys'), var sys = require('sys'),
path = require('path'), path = require('path'),
fs = require('fs'), fs = require('fs'),
util = require('./util'); util = require('../util');


// ------------------------------------------------------------------------- // -------------------------------------------------------------------------
// GLOBAL // GLOBAL
Expand Down Expand Up @@ -29,99 +29,13 @@ GLOBAL.mixin = function(target) {
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// Object // Object


// Define a frozen constant on <obj>. require('./object');
// - obj.name += 3 will fail
// - obj.name = other will fail
// - delete obj.name will fail
// However, only simple types (strings, numbers, language constants) will be
// truly immutable. Complex types (arrays, objects) will still be mutable.
Object.defineConstant = function (obj, name, value, enumerable, deep) {
Object.defineProperty(obj, name, {
value: value,
writable: false,
enumerable: enumerable !== undefined ? (!!enumerable) : true,
configurable: false
});
}


//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// Array // Array


/** require('./array');
* Return the first true return value from fun which is called for each value.
* fun is called on this and receives a single argument (current value).
*/
Array.prototype.find = function (fun) {
for (var i = 0, r; i < this.length; i++)
if (r = fun.call(this, this[i])) return r;
};

/** Return a (possibly new) array which only contains unique values. */
Array.prototype.unique = function() {
const x = 1;
var i, tag, m = {};
for (i=0; (tag = this[i]); ++i) m[tag] = x;
m = Object.keys(m);
return (m.length === this.length) ? this : m;
}

/**
* Difference between this and other array.
*
* Returns a new array with values (or indices if returnIndices) which are not
* at the same place.
*
* Example 1:
*
* oldTags = ['computer', 'car'];
* newTags = ['car', 'computer', '80s'];
* oldTags.diff(newTags) --> ['80s']
*
* Example 2:
*
* A = [1, 2, 3, 4, 5]
* B = [1, 2, 6, 4, 5, 6, 7, 8]
* B.diff(A) => [3] // values
* B.diff(A, true) => [2] // indices
* A.diff(B) => [8, 7, 6, 6] // values
* A.diff(B, true) => [7, 6, 5, 2] // indices
*/
Array.prototype.diff = function (other, returnIndices) {
var d = [], e = -1, h, i, j, k;
for(i = other.length, k = this.length; i--;){
for(j = k; j && (h = other[i] !== this[--j]););
// The comparator here will be optimized away by V8
h && (d[++e] = returnIndices ? i : other[i]);
}
return d;
}

/**
* Return a new array which contains the intersection of this and any other
* array passed as an argument.
*/
Array.prototype.intersect = function() {
var retArr = [], k1, arr, i, k;
arr1keys:
for (k1=0,L=this.length; k1<L; ++k1) {
arrs:
for (i=0; i < arguments.length; ++i) {
arr = arguments[i];
for (k=0,L=arr.length; k<L; ++k) {
if (arr[k] === this[k1]) {
if (i === arguments.length-1)
retArr[k1] = this[k1];
// If the innermost loop always leads at least once to an equal value,
// continue the loop until done
continue arrs;
}
}
// If it got here, it wasn't found in at least one array, try next value.
continue arr1keys;
}
}
return retArr;
}


//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// String // String
Expand Down
41 changes: 39 additions & 2 deletions oui/std-additions/object.js
@@ -1,3 +1,30 @@
// NOTE: this file is used by both the server and client library, thus it need
// to work in web browsers.

// Define a frozen constant on <obj>.
// - obj.name += 3 will fail
// - obj.name = other will fail
// - delete obj.name will fail
// However, only simple types (strings, numbers, language constants) will be
// truly immutable. Complex types (arrays, objects) will still be mutable.
if (typeof Object.defineConstant !== 'function') {
if (typeof Object.defineProperty === 'function') {
Object.defineConstant = function (obj, name, value, enumerable, deep) {
Object.defineProperty(obj, name, {
value: value,
writable: false,
enumerable: enumerable !== undefined ? (!!enumerable) : true,
configurable: false
});
};
} else {
// better than nothing I guess...
Object.defineConstant = function (obj, name, value, enumerable, deep) {
obj[name] = value;
};
}
}

if (typeof Object.keys !== 'function') { if (typeof Object.keys !== 'function') {
Object.keys = function(obj){ Object.keys = function(obj){
var keys = []; var keys = [];
Expand Down Expand Up @@ -184,8 +211,18 @@ if (typeof Object.merge3 !== 'function') {
} }


if (k in o) { if (k in o) {
if (!Object.deepEquals(v, ov)) if (!Object.deepEquals(v, ov)) {
updatedInA[k] = v; if (typeof v === 'object' && !Array.isArray(v)) {
if (Object.keys(v).length === 0) {
if (Object.keys(r[k]).length === 0)
updatedInA[k] = v;
} else {
updatedInA[k] = v;
}
} else {
updatedInA[k] = v;
}
}
} else { } else {
newInA[k] = v; newInA[k] = v;
} }
Expand Down
76 changes: 76 additions & 0 deletions oui/util.js
Expand Up @@ -168,3 +168,79 @@ CallQueue.prototype.performNext = function() {
this.autostart = false; this.autostart = false;
} }
} }

// -----------------------------------------------------------------------------
// Input sanitation

exports.urlRegExp = /\b(([\w-]+:\/\/?|www[.])[^\s()<>]+(?:\([\w\d]+\)|([^[:punct:]\s]|\/)))/;
exports.emailRegExp = /^[^@]+@[^@]+\.[^@]+$/;

exports.sanitizeInput = function (params, dst, accepts) {
var k, e, type, def, value, ok, dstbuf = {};
for (k in accepts) { def = accepts[k];
// not set?
if (!(k in params) || (value = params[k]) === undefined) {
// required and missing?
if (def.required) {
return ((e = new Error('missing parameter "'+k+'"'))
&& (e.statusCode = 400) && e);
}
// it's optional, so lets simply skip it
continue;
}
// retrieve value
value = params[k];
type = typeof value;
// check type
if (def.type) {
if (def.type === 'array') {
ok = Array.isArray(value);
} else if (def.type === 'url') {
ok = String(value).match(exports.urlRegExp);
} else if (def.type === 'email') {
ok = String(value).match(exports.emailRegExp);
} else if (def.type.substr(0,3) === 'int') {
if ((ok = (type === 'number')))
value = Math.round(value);
} else if ((ok = (def.type === type)) && (def.type === 'number')) {
ok = !isNaN(value);
}
if (!ok) {
return ((e = new Error('bad type of parameter "'+k+'" -- expected '+def.type))
&& (e.statusCode = 400) && e);
}
}
// trim strings
if (type === 'string') {
value = value.trim();
}
// empty string?
if (def.empty !== undefined && !def.empty && type !== 'number') {
ok = true;
if (type === 'string') {
ok = (value.length !== 0);
} else if (type === 'object') {
ok = (Array.isArray(value) ? value.length : Object.keys(value).length) !== 0;
}
if (!ok) {
return ((e = new Error('empty parameter "'+k+'"'))
&& (e.statusCode = 400) && e);
}
}
// check regexp match
if (def.match && !String(value).match(def.match)) {
return ((e = new Error('bad format of argument "'+k+'" -- expected '+def.match))
&& (e.statusCode = 400) && e);
}
// post-filter
if (typeof def.filter === 'function') {
value = def.filter(value);
}
// accepted
dstbuf[k] = value;
}
// all ok -- apply dstbuf to dst
for (k in dstbuf) dst[k] = dstbuf[k];
// return a false value to indicate there was no error
return null;
}

0 comments on commit 7e61c36

Please sign in to comment.