Contractual

Unobtrusive, backwards compatible syntactic sugar for Design by contract in JavaScript.

What?

Design by contract is a very powerful technique for writing robust software, it can be thought of as a formal but convenient method for specifying assertions.

Instead of the developer documenting their assumptions in comments, or worse, not documenting them at all, DbyC gives them a way to express their assumptions in a convenient syntax, and have those assumptions validated at runtime.

Contractual is a transpiler, that takes Contractual JavaScript and turns it into JavaScript which enforces the contracts.

In Contractual, there are two types of contract, preconditions and postconditions.

Preconditions are evaluated before the main function body, they are typically used to validate arguments to the function, or the state of the system.

Postconditions are evaluated after the main function body completes, they are typically used to validate the return value of the function, or any side effects that the function caused.

Neither preconditions nor postconditions themselves may have side-effects, for instance it is not possible to increment a variable, or assign a new value from within a contract.

Why?

Because Design by contract leads to better software which is easier to maintain.

JavaScript gives developers many opportunities to shoot themselves in the foot, and this is a way to help keep their toes intact.

DbyC can enforce an even greater level of safety than even the most stringent type system.

How it works

Contractual abuses two quirks of the JavaScript language to implement a convenient backwards compatible syntax.

  1. Results of expressions do not have to be used.

    This means that the following code is valid:

    function myfun (a) {
      a > 10;
    }
    

    In this example, when myfun() is called the JavaScript engine will evaluate the a > 10 expression but silently discard the result.

  2. Labels can appear anywhere in a function body, and they also do not have to be used.

    This means that the following code is valid:

    function myotherfun (a) {
      foo:
      return a * a;
    }
    

    In this example, when myotherfun() is called, the JavaScript engine will simply ignore the foo label (but not the label body!) and behave as if it doesn't exist.



Contractual combines these quirks to offer a simple syntax for specifying preconditions and postconditions.

function divide (a, b) {
  pre:
    typeof a === 'number';
    typeof b === 'number';
    b !== 0, 'May not divide by zero';
  main:
    return a / b;
  post:
    __result < a;
}

alert(divide(10, 0));

This is normal, valid JavaScript. If you execute it without compiling it with Contractual, it will still behave just as normal, but the contracts will not be enforced.

In default mode, Contractual will compile the above code into:

var OBLIGATIONS = require('obligations');
function divide(a, b) {
    OBLIGATIONS.precondition(typeof a === 'number');
    OBLIGATIONS.precondition(typeof b === 'number');
    OBLIGATIONS.precondition(b !== 0, 'May not divide by zero');
    var __result;
    __result = a / b;
    OBLIGATIONS.postcondition(__result < a);
    return __result;
}
alert(divide(10, 0));

Now the alert() call in the above code will result in a PreconditionError.

PreconditionError: May not divide by zero
Try it

Download / Install

Install Contractual from npm:

npm install -g contractual

You may also download the source from github.

If you download the source from github, don't forget to install the dependencies after extracting the archive: npm install

Usage

It's possible to use Contractual programatically, but most functionality is exposed via a command line interface.

> contractual --help
contractual - Syntactic sugar for Design by contract in JavaScript.

Usage: contractual [OPTIONS] [FILES]

Options:
  --output, -o   The directory to write compiled files to.                             [default: "./out"]
  --libname, -l  The name of the identifier for the obligations library                [default: "OBLIGATIONS"]
  --global, -g   Whether a global identifier should be used for the obligations lib.   [default: false]
  --require, -r  The obligations library to require, if `global` is not specified.     [default: "obligations"]
  --version, -v  Show the version information.
  --help, -h     Show this help screen.

Compile a directory

Compile all the Contractual JavaScript files in the src directory to the lib directory:

> contractual -o ./lib ./src

Use a global identifier

If you're targetting the browser, you might prefer to use a global reference to the obligations library, rather than requiring it separately at the top of each file. Using the global flag instructs Contractual to omit the generated require statements.

> contractual -g -o ./lib ./src

Using a different obligations library

Contractual uses the tiny obligations library by default. If you'd like to use a different library, you can specify its name using the require flag.

> contractual --require=mylib -o ./lib ./src

Changing the name of the obligations identifier

By default Contractual accesses the obligations library under the name OBLIGATIONS, which is pretty ugly but likely to be unique in a code base. If you'd like to use a different identifier, use the libname flag.

> contractual --libname=contracts -o ./lib ./src

The above will generate preconditions that look like contracts.precondition(...) rather than OBLIGATIONS.precondition(...) etc.

MIT Licensed

Contractual is licensed under the MIT license, it's free for any use, even commercial, see the full license.