yllr
v1.1.0
Published
Minimal, extensible runtime assertion library.
Downloads
14
Maintainers
Readme
yllr
Minimal runtime assertion library.
Goal
This library aims to be small. The current release comes in around 1.75KB in its minified form. It has just enough functionality (i.e. syntactic sugar) to make it easy to add and manage runtime assertions in your code base.
The goal is not to replace static code analysis provided by transpilers such as TypeScript. Rather, it's to make it easy to help developers properly use a library you've built. If an API calls for a number as a parameter and you don't want to write extra code to make it work with anything else that might get thrown at it, this little library is for you!
Installation
npm install yllr
bower install yllr
// html file
<script src="yllr.js"></script>
The library will detect and register itself into AMD and CommonJS environments before adding itself to the global namespace (i.e. window
). Under AMD, it defines itself as the yllr
module. As a global, it defines a new yllr
property.
Use In Code
This library provides a single yllr.check()
function which throws an error if the condition isn't met.
Many existing assertion libraries provide extra specialized assertion functions to check for strict equality (yllr.check(a === b)
), loose equality (yllr.check(a == b)
), types (yllr.check(_.isPlainObject(a))
, where _
is typically underscore or lodash), etc.
Those specialized functions would unnecessarily bloat this library since a project usually already has an existing, consistent way of checking a condition.
With that in mind, instead of having code like this throughout your code base...
function add(left, right) {
if (typeof left !== 'number') {
throw new MyAssertion('left must be a number: ' + left);
}
if (typeof right !== 'number') {
throw new MyAssertion('right must be a number: ' + right);
}
return left + right;
};
(note, in the code above, if left
were an empty string, the resulting error.message
would be 'left must be a number: '
-- not very helpful!)
...you can now use yllr.check()
, which looks much nicer and is easily identified as an assertion (and allows to you instantly turn them all on/off with yllr.config.enableChecks()
):
function add(left, right) {
yllr.check(typeof left === 'number', 'left must be a number: {0}', left);
yllr.check(typeof right === 'number', 'right must be a number: {0}', right);
return left + right;
};
Note now with the token feature, if left
were an empty string, the resulting error.message
would be 'left must be a number: <empty>'
, which is immediately more helpful! No other special values are generated, however, since JavaScript provides adequate string representations of other built-in types:
null.toString() === 'null'
undefined.toString() === 'undefined'
NaN.toString() === 'NaN'
false.toString() === 'false'
true.toString() === 'true'
Finally, the condition
parameter can optionally be a function that returns a truthy or falsy value. By using a function, it ensures that any potentially expensive condition evaluation code is only executed if yllr
checks are enabled (see API docs on enabling/disabling checks).
Contextual Checks
The yllr.make(context)
creates a contextual yllr
object which has the same interface as the global yllr
object (exception for yllr.config
and yllr.make
), the difference being that errors thrown from this object's check()
method get an additional context string when they're created. The yllr.YllrError
object has a context
property that is set to this value, and the constructor of any custom error type will also get this context as a parameter.
The main advantage of a contextual yllr
object's check()
method over the generic yllr.check()
is the context. Each browser deals with uncaught errors and logged errors in different ways, and error stacks, especially resulting from an asynchronous call (e.g. promise resolutions) are often meaningless. This simple context string, if set judiciously, can greatly simplify debugging by providing a crucial hint about the source of the failed check.
When converting a yllr.YllrError
instance to a string, the output looks like this:
- With context:
YllrError: <context>: <message>
- Without context:
YllrError: <message>
Configuration
Assertion Type
By default, the error thrown is an instance of yllr.YllrError
which extends from the JavaScript Error
type. In case your code base wants all errors throw to stem from the same base error type used throughout, the error type yllr
generates can be customized:
var MyError = function(message, tokens) {
...
};
yllr.config.setErrorType(MyError);
yllr.check(false) // throws a new instance of `MyError`
yllr.config.setErrorType(); // resets to throwing new `yllr.YllrError` instances
Enable Checks
By default, checks are enabled, which means any yllr.check()
call with a falsy condition will assert. All checks can be enabled or disabled with a single call:
yllr.config.enableChecks(false); // disable checks
yllr.config.enableChecks(); // enable checks
Documentation
Refer to the generated API Documentation.
Customization
Custom check can easily be added to an instance of yllr
for your project's specific needs. Let's say you want to make it easy to check the type of variable, parameter, property, etc. You might want to add a checkType()
method to yllr
as well as any contextual yllr
objects that might get created:
// somewhere in your project's bootstrap sequence...
(function() {
// @param {*|Function} condition Condition to check.
// @param {String} name Name of property, variable, parameter being checked.
// @param {(String|Array.<String>)} types Expected type, or list of expected types.
// @param {*} value Value that was checked.
var checkType = function(condition, name, types, value) {
types = (Object.prototype.toString.call(types) !== '[object Array]') ?
[types] : types;
this.check(condition, '{0}: expected {1}, got {2}', name, types.join(' or '),
value);
};
yllr.checkType = checkType; // add to global yllr
(function(yllrMake) {
yllr.make = function(context) {
var ctxYllr = yllrMake.call(this, context);
ctxYllr.checkType = checkType; // add to contextual yllr
return ctxYllr;
};
})(yllr.make);
})();
var foo = 1;
yllr.checkType(typeof foo === 'string', 'foo', 'string', foo);
// throws YllrError with message 'foo: expected string, got 1'
function bar(param) {
yllr.checkType(function() {
var isArray = (Object.prototype.toString.call(param) !== '[object Array]');
return !param || (typeof param === 'string') || isArray;
}, 'param', ['falsy', 'string', 'array[string]'], param);
// ...
};
bar(2);
// throws YllrError with message
// 'param: expected falsy or string or array[string], got 2'
History
1.1.0
- Updated all dependencies to their latest versions. No functionality changes.
1.0.0
Enhancements
yllr.make()
now accepts any non-undefined
value as a context.- Contextual
yllr
object now has acontext():string
method that returns the specified context. - New
yllr.onFail()
handler (also on contextualyllr
objects) allows failed check behavior to be customized (e.g. to result in a failed assertion in NodeJS which produces a nice stack trace). - New
yllr.tokenize()
is used to defer token substitution in tokenized messages so that custom failure handlers don't have to worry about having to understand how to substitute tokens in messages.
Bug Fixes
- Only the first occurrence of a token would be replaced with its associated value. All occurrences are now replaced with its value.
Breaking Changes
- When instantiating a new error resulting from a failed check, the error constructor is no longer called with tokens. The expected signature is now
function(message:String, context:*)
andmessage
contains substituted token values.
Other Changes
- Updated all package dependencies to comply with npm3 peer dependency changes.
- Added
karma:globaldebug
grunt target for debugging unit tests in the global deployment scenario.
0.0.5
- New
yllr.make(context)
makes new contextualyllr
objects. - New
yllr.config.noConflict()
method. - Updated default error name to be
'YllrError'
instead of'yllrError'
, which is more in line with standard JavaScript error names like'Error'
,'TypeError'
,'SyntaxError'
, etc. - Updated all package dependencies.
0.0.4
yllr.check()
'scondition
parameter can now optionally be a function which evaluates to the condition result. This ensures that condition checking code is only executed IIF checks are enabled.
0.0.3
- Added
yllr.config.checksEnabled()
to complimentyllr.config.enableChecks()
. - Added support for the rest parameter of
yllr.check()
as alternate substitution tokens (to using an array with tokens). This makes the function more similar to some common string formatting methods in NodeJS (e.g.debug('foo %s', 'bar'); // foo bar
using the handy debug library). - Updated grunt-jsdoc-to-markdown dependency which uses the latest (1.1.1 at this time) jsdoc-to-markdown library. This adds support for the
@see
tag which is useful.
0.0.2
Added API Documentation.
0.0.1
Initial release.