class Sphere {
constructor (r) {
assert: r > 0;
this._radius = r;
}
setRadius (r) {
assert: this._radius > 0, {filter: 'jrambo'};
assert: r > 0;
this._radius = r;
}
}
Xplicit is a babel plugin that enables a simple assertion aproach for javascript. It was inspired by Charles Pick's use of javascript labeled statement in his babel-plugin-contracts.
Babel enables us to transform our assertion expressions, add some log information and probably the most important point, to strip code.
Asserting is a simplified aproach to design by contract, but strong enough to enable programmers to write consistent code. With this plugin, it is possible to write pre and post conditions and invariants, but the responsibility of writing them at the right place is left to the programmer.
You may be interested in some tips for javascript assertion.
Just like other babel plugins:
npm install --save-dev babel-plugin-xplicit
class Sphere {
constructor (r) {
assert: r > 0;
this._radius = r;
}
setRadius (r) {
assert: this._radius > 0, {filter: 'jrambo'};
assert: r > 0, {filter: 'jfive'};
this._radius = r;
}
}
This can be transpiled, depending on the options, to:
class Sphere {
constructor (r) {
console.assert(r > 0);
this._radius = r;
}
setRadius (r) {
console.assert(r > 0);
this._radius = r;
}
}
Just as other babel plugins, you can use your .babelrc to configure the plugin:
{
"presets": {...},
"env": {
"development": {
"plugins": [
["xplicit", {
"verbs": {
"assert": "myAssert"
},
"conditional": "_is_assert_active"
}]
]
},
"production": {
"plugins": [
["xplicit", {
"strip": true
}]
]
}
}
}
Then you can set the environment, for example, in you package.json:
{
"build": "babel ./src -d ./lib",
"dev": "BABEL_ENV=development npm run build",
"pub": "BABEL_ENV=production npm run build",
}
Probably one of the most important options is simply to strip all assertions in production environments.
{
"strip": true
}
This is the way you can customize the actual assertion function. It also allows you to specify the labels that you are going to use to assert. So you could use something like this:
{
"verbs": {
"assert": "console.assert",
"assert_log": "myAssertFunction"
}
}
Then you can use these labels to assert:
setRadius (r) {
assert: r > 0;
this._radius = r;
assert_log: this._radius > 0;
}
This would transpile to this:
setRadius (r) {
console.assert(r > 0);
this._radius = r;
myAssertFunction(this._radius > 0);
}
When assertions of one programmer affect other programmer (because they are continuously failing), we can filter them. This option strips all assertions except the ones we mark with an alias.
{
"filter": [
"jrambo"
]
}
Then, only asserts with 'jrambo' filter will survive:
setRadius (r) {
assert: r > 0;
this._radius = r;
assert: this._radius > 0, {filter: 'jrambo'};
}
This would transpile to this:
setRadius (r) {
this._radius = r;
console.assert(this._radius > 0);
}
It is also possible to activate assertions in runtime (if the strip option is not used) using a global activation variable:
{
"conditional": "_dbg_assert"
}
Then in the transpiled code, assertions will be checked only if the variable is evaluated as true:
setRadius (r) {
this._radius = r;
_dbg_assert && console.assert(this._radius > 0);
}
You should define and assign a value to it.
This option adds information about where the assert is located, adding an object indicating line and column of the assertion call:
{
"position": true
}
Once transpiled:
setRadius (r) {
this._radius = r;
console.assert(this._radius > 0, {line: 19, column: 4});
}
Licensed under the MIT license.