You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

175 lines
4.4 KiB

8 years ago
/**
* @license
* Copyright 2016 Google Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
var Validate = exports;
function InvalidValueError(message) {
this.message = message;
this.name = 'InvalidValueError';
Error.captureStackTrace(this, InvalidValueError);
}
InvalidValueError.prototype = Object.create(Error.prototype);
InvalidValueError.prototype.constructor = InvalidValueError;
InvalidValueError.prepend = function(message, error) {
if (error instanceof InvalidValueError) {
return new InvalidValueError(message + ': ' + error.message);
}
return error;
};
Validate.InvalidValueError = InvalidValueError;
Validate.acceptAll = function(value) {
return value;
};
Validate.optional = function(validator) {
return function(value) {
return (value == undefined) ? value : validator(value);
};
};
Validate.that = function(predicate, message) {
return function(value) {
if (predicate(value)) return value;
throw new InvalidValueError(message);
};
};
Validate.number = Validate.that(function(value) {
return typeof value === 'number';
}, 'not a number');
Validate.string = Validate.that(function(value) {
return typeof value === 'string';
}, 'not a string');
Validate.object = function(propertyValidators) {
return function(object) {
var result = {};
if (!object || typeof object !== 'object') {
throw new InvalidValueError('not an Object');
}
// Validate all properties.
for (key in propertyValidators) {
var validator = propertyValidators[key];
try {
var valid = validator(object[key]);
} catch (error) {
if (key in object) {
throw InvalidValueError.prepend('in property "' + key + '"', error);
} else {
throw new InvalidValueError('missing property "' + key + '"');
}
}
if (valid !== undefined) {
result[key] = valid;
}
}
// Check for unexpected properties.
for (var key in object) {
if (!propertyValidators[key]) {
throw new InvalidValueError('unexpected property "' + key + '"');
}
}
return result;
};
};
Validate.array = function(validator) {
return function(array) {
var result = [];
if (Object.prototype.toString.call(array) !== '[object Array]') {
throw new InvalidValueError('not an Array');
}
for (var i = 0; i < array.length; ++i) {
try {
result[i] = validator(array[i]);
} catch (error) {
throw InvalidValueError.prepend('at index ' + i, error);
}
}
return result;
};
};
Validate.oneOf = function(names) {
var myObject = {};
var quotedNames = [];
names.forEach(function(name) {
myObject[name] = true;
quotedNames.push('"' + name + '"');
});
return function(value) {
if (myObject[value]) return value;
throw new InvalidValueError('not one of ' + quotedNames.join(', '));
};
};
Validate.mutuallyExclusiveProperties = function(names) {
return function(value) {
if (!value) return value;
var present = [];
names.forEach(function(name) {
if (name in value) {
present.push('"' + name + '"');
}
});
if (present.length > 1) {
throw new InvalidValueError(
'cannot specify properties '
+ present.slice(0, -1).join(', ')
+ ' and '
+ present.slice(-1)
+ ' together');
}
return value;
};
};
Validate.compose = function(validators) {
return function(value) {
validators.forEach(function(validate) {
value = validate(value);
});
return value;
};
};
Validate.boolean = Validate.compose([
Validate.that(function(value) {
return typeof value === 'boolean';
}, 'not a boolean'),
function(value) {
// In each API, boolean fields default to false, and the presence of
// a querystring value indicates true, so we omit the value if
// explicitly set to false.
return value ? value : undefined;
}
]);