New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

contracts-js

Package Overview
Dependencies
Maintainers
1
Versions
12
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

contracts-js - npm Package Compare versions

Comparing version 0.3.4 to 0.4.0

.tern-port

493

lib/contracts.js

@@ -1,353 +0,18 @@

// Domain Public by Eric Wendelin http://eriwen.com/ (2008)
// Luke Smith http://lucassmith.name/ (2008)
// Loic Dachary <loic@dachary.org> (2008)
// Johan Euphrosine <proppy@aminche.com> (2008)
// Oyvind Sean Kinsey http://kinsey.no/blog (2010)
// Victor Homyakov <victor-homyakov@users.sourceforge.net> (2010)
function printStackTrace() { return [] }
/**
* Main function giving a function stack trace with a forced or passed in Error
*
* @cfg {Error} e The error to create a stacktrace from (optional)
* @cfg {Boolean} guess If we should try to resolve the names of anonymous functions
* @return {Array} of Strings with functions, lines, files, and arguments where possible
*/
function printStackTrace(options) {
options = options || {guess: true};
var ex = options.e || null, guess = !!options.guess;
var p = new printStackTrace.implementation(), result = p.run(ex);
return (guess) ? p.guessAnonymousFunctions(result) : result;
}
printStackTrace.implementation = function() {
};
printStackTrace.implementation.prototype = {
run: function(ex) {
ex = ex || this.createException();
// Do not use the stored mode: different exceptions in Chrome
// may or may not have arguments or stack
var mode = this.mode(ex);
// Use either the stored mode, or resolve it
//var mode = this._mode || this.mode(ex);
if (mode === 'other') {
return this.other(arguments.callee);
} else {
return this[mode](ex);
}
},
createException: function() {
try {
this.undef();
return null;
} catch (e) {
return e;
}
},
/**
* @return {String} mode of operation for the environment in question.
*/
mode: function(e) {
if (e['arguments'] && e.stack) {
return (this._mode = 'chrome');
} else if (e.message && typeof window !== 'undefined' && window.opera) {
return (this._mode = e.stacktrace ? 'opera10' : 'opera');
} else if (e.stack) {
return (this._mode = 'firefox');
}
return (this._mode = 'other');
},
/**
* Given a context, function name, and callback function, overwrite it so that it calls
* printStackTrace() first with a callback and then runs the rest of the body.
*
* @param {Object} context of execution (e.g. window)
* @param {String} functionName to instrument
* @param {Function} function to call with a stack trace on invocation
*/
instrumentFunction: function(context, functionName, callback) {
context = context || window;
var original = context[functionName];
context[functionName] = function instrumented() {
callback.call(this, printStackTrace().slice(4));
return context[functionName]._instrumented.apply(this, arguments);
};
context[functionName]._instrumented = original;
},
/**
* Given a context and function name of a function that has been
* instrumented, revert the function to it's original (non-instrumented)
* state.
*
* @param {Object} context of execution (e.g. window)
* @param {String} functionName to de-instrument
*/
deinstrumentFunction: function(context, functionName) {
if (context[functionName].constructor === Function &&
context[functionName]._instrumented &&
context[functionName]._instrumented.constructor === Function) {
context[functionName] = context[functionName]._instrumented;
}
},
/**
* Given an Error object, return a formatted Array based on Chrome's stack string.
*
* @param e - Error object to inspect
* @return Array<String> of function calls, files and line numbers
*/
chrome: function(e) {
var stack = (e.stack + '\n').replace(/^\S[^\(]+?[\n$]/gm, '').
replace(/^\s+at\s+/gm, '').
replace(/^([^\(]+?)([\n$])/gm, '{anonymous}()@$1$2').
replace(/^Object.<anonymous>\s*\(([^\)]+)\)/gm, '{anonymous}()@$1').split('\n');
stack.pop();
return stack;
},
/**
* Given an Error object, return a formatted Array based on Firefox's stack string.
*
* @param e - Error object to inspect
* @return Array<String> of function calls, files and line numbers
*/
firefox: function(e) {
return e.stack.replace(/(?:\n@:0)?\s+$/m, '').replace(/^\(/gm, '{anonymous}(').split('\n');
},
/**
* Given an Error object, return a formatted Array based on Opera 10's stacktrace string.
*
* @param e - Error object to inspect
* @return Array<String> of function calls, files and line numbers
*/
opera10: function(e) {
var stack = e.stacktrace;
var lines = stack.split('\n'), ANON = '{anonymous}', lineRE = /.*line (\d+), column (\d+) in ((<anonymous function\:?\s*(\S+))|([^\(]+)\([^\)]*\))(?: in )?(.*)\s*$/i, i, j, len;
for (i = 2, j = 0, len = lines.length; i < len - 2; i++) {
if (lineRE.test(lines[i])) {
var location = RegExp.$6 + ':' + RegExp.$1 + ':' + RegExp.$2;
var fnName = RegExp.$3;
fnName = fnName.replace(/<anonymous function\:?\s?(\S+)?>/g, ANON);
lines[j++] = fnName + '@' + location;
}
}
lines.splice(j, lines.length - j);
return lines;
},
// Opera 7.x-9.x only!
opera: function(e) {
var lines = e.message.split('\n'), ANON = '{anonymous}', lineRE = /Line\s+(\d+).*script\s+(http\S+)(?:.*in\s+function\s+(\S+))?/i, i, j, len;
for (i = 4, j = 0, len = lines.length; i < len; i += 2) {
//TODO: RegExp.exec() would probably be cleaner here
if (lineRE.test(lines[i])) {
lines[j++] = (RegExp.$3 ? RegExp.$3 + '()@' + RegExp.$2 + RegExp.$1 : ANON + '()@' + RegExp.$2 + ':' + RegExp.$1) + ' -- ' + lines[i + 1].replace(/^\s+/, '');
}
}
lines.splice(j, lines.length - j);
return lines;
},
// Safari, IE, and others
other: function(curr) {
var ANON = '{anonymous}', fnRE = /function\s*([\w\-$]+)?\s*\(/i, stack = [], fn, args, maxStackSize = 10;
while (curr && stack.length < maxStackSize) {
fn = fnRE.test(curr.toString()) ? RegExp.$1 || ANON : ANON;
args = Array.prototype.slice.call(curr['arguments'] || []);
stack[stack.length] = fn + '(' + this.stringifyArguments(args) + ')';
curr = curr.caller;
}
return stack;
},
/**
* Given arguments array as a String, subsituting type names for non-string types.
*
* @param {Arguments} object
* @return {Array} of Strings with stringified arguments
*/
stringifyArguments: function(args) {
var slice = Array.prototype.slice;
for (var i = 0; i < args.length; ++i) {
var arg = args[i];
if (arg === undefined) {
args[i] = 'undefined';
} else if (arg === null) {
args[i] = 'null';
} else if (arg.constructor) {
if (arg.constructor === Array) {
if (arg.length < 3) {
args[i] = '[' + this.stringifyArguments(arg) + ']';
} else {
args[i] = '[' + this.stringifyArguments(slice.call(arg, 0, 1)) + '...' + this.stringifyArguments(slice.call(arg, -1)) + ']';
}
} else if (arg.constructor === Object) {
args[i] = '#object';
} else if (arg.constructor === Function) {
args[i] = '#function';
} else if (arg.constructor === String) {
args[i] = '"' + arg + '"';
}
}
}
return args.join(',');
},
sourceCache: {},
/**
* @return the text from a given URL.
*/
ajax: function(url) {
var req = this.createXMLHTTPObject();
if (!req) {
return;
}
req.open('GET', url, false);
req.setRequestHeader('User-Agent', 'XMLHTTP/1.0');
req.send('');
return req.responseText;
},
/**
* Try XHR methods in order and store XHR factory.
*
* @return <Function> XHR function or equivalent
*/
createXMLHTTPObject: function() {
var xmlhttp, XMLHttpFactories = [
function() {
return new XMLHttpRequest();
}, function() {
return new ActiveXObject('Msxml2.XMLHTTP');
}, function() {
return new ActiveXObject('Msxml3.XMLHTTP');
}, function() {
return new ActiveXObject('Microsoft.XMLHTTP');
}
];
for (var i = 0; i < XMLHttpFactories.length; i++) {
try {
xmlhttp = XMLHttpFactories[i]();
// Use memoization to cache the factory
this.createXMLHTTPObject = XMLHttpFactories[i];
return xmlhttp;
} catch (e) {
}
}
},
/**
* Given a URL, check if it is in the same domain (so we can get the source
* via Ajax).
*
* @param url <String> source url
* @return False if we need a cross-domain request
*/
isSameDomain: function(url) {
return url.indexOf(location.hostname) !== -1;
},
/**
* Get source code from given URL if in the same domain.
*
* @param url <String> JS source URL
* @return <Array> Array of source code lines
*/
getSource: function(url) {
if (!(url in this.sourceCache)) {
this.sourceCache[url] = this.ajax(url).split('\n');
}
return this.sourceCache[url];
},
guessAnonymousFunctions: function(stack) {
for (var i = 0; i < stack.length; ++i) {
var reStack = /\{anonymous\}\(.*\)@(\w+:\/\/([\-\w\.]+)+(:\d+)?[^:]+):(\d+):?(\d+)?/;
var frame = stack[i], m = reStack.exec(frame);
if (m) {
var file = m[1], lineno = m[4], charno = m[7] || 0; //m[7] is character position in Chrome
if (file && this.isSameDomain(file) && lineno) {
var functionName = this.guessAnonymousFunction(file, lineno, charno);
stack[i] = frame.replace('{anonymous}', functionName);
}
}
}
return stack;
},
guessAnonymousFunction: function(url, lineNo, charNo) {
var ret;
try {
ret = this.findFunctionName(this.getSource(url), lineNo);
} catch (e) {
ret = 'getSource failed with url: ' + url + ', exception: ' + e.toString();
}
return ret;
},
findFunctionName: function(source, lineNo) {
// FIXME findFunctionName fails for compressed source
// (more than one function on the same line)
// TODO use captured args
// function {name}({args}) m[1]=name m[2]=args
var reFunctionDeclaration = /function\s+([^(]*?)\s*\(([^)]*)\)/;
// {name} = function ({args}) TODO args capture
// /['"]?([0-9A-Za-z_]+)['"]?\s*[:=]\s*function(?:[^(]*)/
var reFunctionExpression = /['"]?([0-9A-Za-z_]+)['"]?\s*[:=]\s*function\b/;
// {name} = eval()
var reFunctionEvaluation = /['"]?([0-9A-Za-z_]+)['"]?\s*[:=]\s*(?:eval|new Function)\b/;
// Walk backwards in the source lines until we find
// the line which matches one of the patterns above
var code = "", line, maxLines = 10, m;
for (var i = 0; i < maxLines; ++i) {
// FIXME lineNo is 1-based, source[] is 0-based
line = source[lineNo - i];
if (line) {
code = line + code;
m = reFunctionExpression.exec(code);
if (m && m[1]) {
return m[1];
}
m = reFunctionDeclaration.exec(code);
if (m && m[1]) {
//return m[1] + "(" + (m[2] || "") + ")";
return m[1];
}
m = reFunctionEvaluation.exec(code);
if (m && m[1]) {
return m[1];
}
}
}
return '(?)';
}
};
// Generated by CoffeeScript 1.6.2
(function() {
"use strict";
/*
contracts.coffee
http://disnetdev.com/contracts.coffee
Copyright 2011, Tim Disney
Released under the MIT License
*/
var Contract, ModuleName, Unproxy, Utils, and_, any, arr, blame, blameM, check, checkOptions, contract_orig_map, ctor, ctorSafe, enabled, findCallsite, fun, getModName, guard, idHandler, none, not_, object, opt, or_, root, self, show_parent_contracts, unproxy, ___, _blame,
__indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; },
__hasProp = {}.hasOwnProperty;
var Contract, ModuleName, Unproxy, Utils, and_,
any, arr, blame, blameM, check, checkOptions,
contract_orig_map, ctor, ctorSafe, enabled,
findCallsite, fun, getModName, guard, idHandler,
none, not_, object, opt, or_, root, self,
show_parent_contracts, unproxy, ___, _blame,
__indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; },
__hasProp = {}.hasOwnProperty;
root = {};
enabled = true;
enabled = typeof Proxy !== "undefined" && Proxy !== null ? true : false;

@@ -511,3 +176,3 @@ show_parent_contracts = true;

_blame = function(toblame, other, msg, parents) {
var callsite, err, m, ps, server, st;
var callsite, err, m, ps, server, sit, st;

@@ -672,7 +337,8 @@ ps = parents.slice(0);

// flat contracts
check = function(p, name) {
var c;
c = new Contract(name, "check", function(val, pos, neg, parentKs, stack) {
if (p(val, stack)) {
c = new Contract(name, "check", function(val, pos, neg, parentKs) {
if (p(val)) {
return val;

@@ -689,2 +355,3 @@ } else {

// function contracts
fun = function(dom, rng, options) {

@@ -694,11 +361,15 @@ var c, callOnly, calldom, callrng, cleanDom, contractName, domName, newOnly, newdom, newrng, optionsName;

cleanDom = function(dom) {
if (!Array.isArray(dom)) {
dom = [dom];
}
if (dom.some(function(d) {
var notContractInstance = dom.some(function(d) {
return !(d instanceof Contract);
})) {
});
if (notContractInstance) {
throw new Error("domain argument to the function contract is not a contract");
}
dom.reduce((function(prevWasOpt, curr) {
dom.reduce(function(prevWasOpt, curr) {
if (curr.ctype === "opt") {

@@ -713,5 +384,6 @@ return true;

}
}), false);
}, false);
return dom;
};
if (dom && dom.call && dom["new"]) {

@@ -730,27 +402,31 @@ calldom = cleanDom(dom.call[0]);

}
callOnly = options && options.callOnly;
newOnly = options && options.newOnly;
if (callOnly && newOnly) {
throw new Error("Cannot have a function be both newOnly and newSafe");
throw new Error("Cannot have a function be both newOnly");
}
if (newOnly && options["this"]) {
throw new Error("Illegal arguments: cannot have both newOnly and a contract on 'this'");
}
domName = "(" + calldom.join(",") + ")";
optionsName = (options["this"] ? "{this: " + options["this"].cname + "}" : "");
contractName = domName + " -> " + callrng.cname + " " + optionsName;
c = new Contract(contractName, "fun", function(f, pos, neg, parentKs, stack) {
var callHandler, handler, makeHandler, newHandler, p, parents, that;
c = new Contract(contractName, "fun", function(f, pos, neg, parentKs) {
var callHandler, handler, newHandler, p, parents, that;
handler = idHandler(f);
that = this;
parents = parentKs.slice(0);
if (typeof f !== "function") {
blame(pos, neg, this, f, parents);
}
parents.push(that);
/*
options:
isNew: Bool - make a constructor handler (to be called with new)
newSafe: Bool - make call handler that adds a call to new
/* options:
pre: ({} -> Bool) - function to check preconditions

@@ -760,21 +436,16 @@ post: ({} -> Bool) - function to check postconditions

*/
makeHandler = function(dom, rng, options) {
var functionHandler;
return functionHandler = function() {
function makeHandler(dom, rng, options, isNew) {
return function() {
var args, bf, boundArgs, checked, clean_rng, dep_args, i, max_i, res, thisc;
var rawArgs = isNew ? arguments[1] : arguments[2];
var receiver = isNew ? undefined : arguments[1];
args = [];
if (options && options.checkStack && !(options.checkStack(stack))) {
throw new Error("stack checking failed");
}
if (typeof options.pre === "function" && !options.pre(this)) {
if (typeof options.pre === "function" && !options.pre(receiver)) {
blame(neg, pos, "precondition: " + options.pre.toString(), "[failed precondition]", parents);
}
i = 0;
max_i = Math.max(dom != null ? dom.length : void 0, arguments.length);
max_i = Math.max(dom != null ? dom.length : void 0, rawArgs.length);
while (i < max_i) {
checked = dom[i] ? dom[i].check(arguments[i], neg, pos, parents, stack) : arguments[i];
if (i < arguments.length) {
checked = dom[i] ? dom[i].check(rawArgs[i], neg, pos, parents) : rawArgs[i];
if (i < rawArgs.length) {
args[i] = checked;

@@ -786,3 +457,3 @@ }

dep_args = Array.isArray(args) ? args : [args];
clean_rng = rng.call(this, args);
clean_rng = rng.call(receiver, args);
if (!(clean_rng instanceof Contract)) {

@@ -797,16 +468,16 @@ throw new Error("range argument to function contract is not a contract");

}
if (options.isNew || options.newSafe) {
if (isNew) {
boundArgs = [].concat.apply([null], args);
bf = f.bind.apply(f, boundArgs);
res = new bf();
res = clean_rng.check(res, pos, neg, parents, stack);
res = clean_rng.check(res, pos, neg, parents);
} else {
if (options["this"]) {
thisc = options["this"].check(this, neg, pos, parents, stack);
thisc = options["this"].check(receiver, neg, pos, parents);
} else {
thisc = this;
thisc = receiver;
}
res = clean_rng.check(f.apply(thisc, args), pos, neg, parents, stack);
res = clean_rng.check(f.apply(thisc, args), pos, neg, parents);
}
if (typeof options.post === "function" && !options.post(this)) {
if (typeof options.post === "function" && !options.post(receiver)) {
blame(neg, pos, "failed postcondition: " + options.post.toString(), "[failed postcondition]", parents);

@@ -816,23 +487,28 @@ }

};
};
}
if (newOnly) {
options.isNew = true;
callHandler = function() {
return blameM(neg, pos, "called newOnly function without new", parents);
};
newHandler = makeHandler(this.newdom, this.newrng, options);
newHandler = makeHandler(this.newdom, this.newrng, options, true);
} else if (callOnly) {
options.isNew = false;
newHandler = function() {
return blameM(neg, pos, "called callOnly function with a new", parents);
};
callHandler = makeHandler(this.calldom, this.callrng, options);
callHandler = makeHandler(this.calldom, this.callrng, options, false);
} else {
callHandler = makeHandler(this.calldom, this.callrng, options);
newHandler = makeHandler(this.newdom, this.newrng, options);
callHandler = makeHandler(this.calldom, this.callrng, options, false);
newHandler = makeHandler(this.newdom, this.newrng, options, true);
}
p = Proxy.createFunction(handler, callHandler, newHandler);
p = new Proxy(f, {
apply: callHandler,
construct: newHandler
});
unproxy.set(p, this);
return p;
});
c.calldom = calldom;

@@ -860,2 +536,3 @@ c.callrng = callrng;

};
return c;

@@ -873,11 +550,2 @@ };

ctorSafe = function(dom, rng, options) {
var opt;
opt = Utils.merge(options, {
newSafe: true
});
return fun(dom, rng, opt);
};
object = function(objContract, options, name) {

@@ -907,4 +575,5 @@ var c, objName, setSelfContracts;

};
c = new Contract(objName(objContract), "object", function(obj, pos, neg, parentKs) {
var contractDesc, e, handler, invariant, nonObject, objDesc, op, parents, prop, proto, that, value, _ref;
var contractDesc, e, handler, invariant, nonObject, objDesc, op, parents, prop, proto, that, value, _ref, _ref1;

@@ -937,3 +606,5 @@ handler = idHandler(obj);

}
for (prop in this.oc) {
_ref1 = this.oc;
for (prop in _ref1) {
if (!__hasProp.call(_ref1, prop)) continue;
contractDesc = this.oc[prop];

@@ -1083,9 +754,3 @@ if ((typeof obj === 'object') || (typeof obj === 'function')) {

} else {
proto = obj === null ? null : Object.getPrototypeOf(obj);
try {
op = new Proxy(obj, handler);
} catch (_error) {
e = _error;
op = Proxy.create(handler, proto);
}
op = new Proxy(obj, handler);
}

@@ -1095,2 +760,3 @@ unproxy.set(op, this);

});
c.oc = objContract;

@@ -1148,2 +814,3 @@ c.raw_options = options;

};
setSelfContracts(c, c);

@@ -1156,2 +823,3 @@ c.equals = function(other) {

};
return c;

@@ -1350,3 +1018,3 @@ };

filename = "unknown";
linenum = "-1";
linenum = "0";
}

@@ -1356,4 +1024,4 @@ return new ModuleName(filename, linenum, isServer);

guard = function(k, x, server, setup) {
var c, client, stack;
guard = function(k, x, server) {
var c, client;

@@ -1363,6 +1031,2 @@ if (!enabled) {

}
stack = [];
if (typeof setup === "function") {
setup(stack);
}
if (server == null) {

@@ -1375,3 +1039,3 @@ server = getModName(true);

server.linenum = "" + server.linenum + " (value)";
c = k.check(x, server, client, [], stack);
c = k.check(x, server, client, []);
contract_orig_map.set(c, {

@@ -1528,3 +1192,3 @@ originalValue: x,

};
return Proxy.create(handler);
return new Proxy(original, handler);
};

@@ -1592,2 +1256,3 @@

root.show_parent_contracts = function(b) {

@@ -1594,0 +1259,0 @@ return show_parent_contracts = b;

{
"name": "contracts-js",
"description": "A contract library for JavaScript",
"keywords": ["javascript", "contracts"],
"author": "Tim Disney",
"version": "0.3.4",
"licenses": [{
"type": "MIT",
"url": "https://raw.github.com/disnet/contracts.js/master/LICENSE"
}],
"engines": {
"node": ">=0.8.0"
"name": "contracts-js",
"description": "A contract library for JavaScript",
"keywords": [
"javascript",
"contracts"
],
"author": "Tim Disney",
"version": "0.4.0",
"licenses": [
{
"type": "MIT",
"url": "https://raw.github.com/disnet/contracts.js/master/LICENSE"
}
],
"scripts": {
"test": "node --harmony ./node_modules/.bin/grunt --stack",
"debug": "node-debug --harmony ./node_modules/.bin/grunt --stack"
},
"main": "./lib/contracts.js",
"directories" : {
"lib" : "./lib"
"engines": {
"node": ">=0.8.0"
},
"homepage": "http://disnetdev.com/contracts.js/",
"repository": {
"main": "./contracts.js",
"homepage": "http://disnetdev.com/contracts.js/",
"dependencies": {
"harmony-reflect": "~0.0.13",
"sweet.js": "^0.7.0"
},
"devDependencies": {
"es6-macros": "0.0.7",
"expect.js": "^0.3.1",
"grunt-cli": "0.1.x",
"grunt-contrib-copy": "0.4.x",
"grunt-contrib-jshint": "0.7.x",
"grunt-contrib-watch": "^0.6.1",
"grunt-mocha": "^0.4.11",
"grunt-mocha-test": "^0.11.0",
"grunt-sweet.js": "^0.1.4",
"grunt-template": "^0.2.3",
"harmony-reflect": "^1.0.0",
"mocha": "^1.20.1",
"sparkler": "^0.3.3",
"should": "^4.0.4"
},
"repository": {
"type": "git",

@@ -21,0 +47,0 @@ "url": "git://github.com/disnet/contracts.js.git"

@@ -1,136 +0,86 @@

Contracts.js
============
# Contracts.js
Contracts.js is a contract library for JavaScript that allows you to specify invariants between parts of your code and have them checked at runtime for violations.
Contracts.js is a contract library for JavaScript that allows you to
specify invariants between parts of your code and have them checked at
runtime for violations.
It is used in the CoffeeScript dialect [contracts.coffee](http://disnetdev.com/contracts.coffee/) but can also be used directly in normal JavaScript programs if you don't want to or can't use CoffeeScript.
For example, you can specify the that following function takes two
arguments, one that is an object with a string `name` field and the
other that is an array filled with objects that have a `loc` number
field, and returns a string.
This library is possible because of and requires [Proxies](https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Proxy) which is a new feature of JavaScript that is currently only implemented in Firefox 4+ and chrome/V8 with the experimental javascript flag enabled
(in about:flags or use the `--harmony` flag on the command line).
```js
import @ from "contracts.js"
Use
===
@ ({name: Str}, [...{loc: Num}]) -> Str
function calcAverageLoc(person, locArr) {
var sum = locArr.reduce(function (l1, l2) {
return l1.loc + l2.loc;
});
return "Average lines of code for " +
person.name + " was " +
sum / locArr.length;
}
To use include these files:
```
* src/stacktrace.js
* lib/contracts.js
If you call the function with a bad argument:
This adds a `Contracts` object to the global scope that has two properties `Contracts.contracts` (which contains some prebuilt contracts to use) and `Contracts.combinators` (which contains utility functions to build new contracts).
```js
var typoPerson = {nam: "Bob"};
calcAverageLoc(typoPerson, [{loc: 1000}, {loc: 789}, {loc: 9001}]);
```
We can now wrap a function in a contract like so:
you will get a helpful error message pin pointing what went wrong:
var C = contracts,
id = C.guard(
C.fun(C.Num, C.Num),
function(x) { return x; });
<pre style="color:red">
calcAverageLoc: contract violation
expected: Str
given: undefined
in: the name property of
the 1st argument of
({name: Str}, [....{loc: Num}]) -> Str
function calcAverageLoc guarded at line: 4
blaming: (calling context for calcAverageLoc)
</pre>
id("foo"); // contract violation!
# Installation
If you would like to load all of the combinators into the global scope, just run `contracts.autoload()`.
Uses [sweet.js](http://sweetjs.org) which you can install via npm:
More documentation and rational can be found at the sister project [contracts.coffee](http://disnetdev.com/contracts.coffee/).
```
npm install -g sweet.js
npm install contracts.js
```
Contracts.guard
===========================
# Using
Guards a value with a contract
At the top of your file you will need to use some special syntax to
import contracts.js:
Contracts.guard :: (Contract, Any, Str?, Str?) -> { use: () -> Any }
Contracts.guard(contract, value [, server[, client]])
```js
import @ from "contracts.js"
* _contract_ the contract to apply to the value
* _value_ value to be wrapped in a contract
* _server_ optional name of the server "module"
* _client_ optional name of the client "module"
// rest of your code goes here...
```
This looks like ES6 modules but it's not really and will work with
whatever module system you are using (if any). See
[here](http://disnetdev.com/contracts.js/doc/main/contracts.html#what-is-up-with-the-import) for details.
Contracts.check
===========================
Compile your JavaScript file with sweet.js using the contracts.js module:
Creates a contract that checks first-order values (i.e. not functions or objects).
```
sjs --module contracts.js -o output.js input.js
```
Contracts.check :: ((Any) -> Bool, Str) -> Contract
Contracts.check(predicate, name)
Then run your `output.js` file in any JavaScript environment. Some
features of contracts.js (eg. proxied objects and arrays) require ES6
features which not every JavaScript engine supports right now (any
recent version of Firefox is fine along with node.js/V8 with the
`--harmony` flag enabled).
* _predicate_ function that takes a value and return true if the contract should pass or false otherwise
* _name_ name of the contract. Displayed in contract violation messages.
# Documentation
This is used to build contracts that get applied to values via the `guard` function. The `guard` function handles calling the predicate supplied to `check` at the appropriate time.
An example of a contract to check for numbers:
Contracts.check(function(x) {
return typeof(x) === 'number';
}, 'Number')
Contracts.fun
=========================
Contracts.fun :: (Contract or [...Contract],
((Any) -> Contract) or Contract,
{
callOnly: Bool
newOnly: Bool
pre: (Any) -> Bool
post: (Any) -> Bool
this: {...}
}) -> Contract
Contracts.fun(domain, range, options)
* _domain_ Either a single contract or an array of contracts for each argument to the function
* _range_ Either a single contract for the function's result or a function that returns a contract.
* _options_ An options object:
* _callOnly_ Signal a contract violation if `new` is used with the function
* _newOnly_ Signal a contract violation if `new` is _not_ used with the function
* _pre_ A predicate to run _before_ the function is run
* _post_ A predicate to run _after_ the function is run
* _this_ An object contract to guard the `this` object
Dependent function contracts (where the result depends on the argument values) are handled by using a function as the `range`. When the function returns its argument values are first passed to the `range` function which should return a contract. This contract is then used to check the original function's result.
As a contrived example:
Contracts.fun(Str, function(x) {
if(x === 42) {
return Contracts.Num;
} else {
return Contracts.Str;
}
})
If the function contracted is called with `42` then its result must be a `Num` otherwise it must be a `Str`.
Note that arguments are potentially mutable (they might be one value at the beginning of the function and different when the function returns) so keep that in mind when using dependent contracts.
Contracts.object
============================
Contracts.object :: ({ ... },
{
extensible: Bool
sealed: Bool
frozen: Bool
invariant: (Any) -> Bool
}) -> Contract
Contracts.object(object, options)
* _object_ An object with properties mapping to contracts that should be present in the contracted object
* _options_ An objects object:
* _extensible_ Object should be extensible
* _sealed_ Object should be sealed
* _frozen_ Object should be frozen
* _invariant_ Predicate to run each time the contracted object changes
Object contracts are built with an object that maps properties to objects. Example:
Contracts.object({
foo: Str,
bar: Num
})
In this case the contracted object must have both the `foo` and `bar` properties (if missing, a contract violation is thrown at contract application time) and these properties must abide by their respective contracts (which are checked each time the property is changed).
Object invariants can be checked with the invariant option. Whenever any property is changed the invariant function is called with a reference to the object. If the invariant returns false a contract violation is thrown.
Contracts.js is documented [here](http://disnetdev.com/contracts.js/doc/main/contracts.html).

@@ -0,2 +1,5 @@

var contracts = window["contracts-js"];
contracts.autoload();
contracts.autoload();

@@ -3,0 +6,0 @@ function bt(msg, f) {

@@ -86,14 +86,14 @@ var contracts = window["contracts-js"];

test("dependent functions", function() {
var id = guard(
fun(Str, function(arg) { return check(function(r) { return arg === r; }, "id===id"); }),
function(x) { return x; });
// test("dependent functions", function() {
// var id = guard(
// fun(Str, function(arg) { return check(function(r) { return arg === r; }, "id===id"); }),
// function(x) { return x; });
ok(id("foo"), "id really is id");
// ok(id("foo"), "id really is id");
var not_id = guard(
fun(Str, function(arg) { return check(function(r) { return arg === r; }, "id===id"); }),
function(x) { return x + "foo"; });
raises(function() { not_id("foo"); }, "violates dependent contract");
});
// var not_id = guard(
// fun(Str, function(arg) { return check(function(r) { return arg === r; }, "id===id"); }),
// function(x) { return x + "foo"; });
// raises(function() { not_id("foo"); }, "violates dependent contract");
// });

@@ -139,8 +139,2 @@

raises(function() { new bad_ctor("foo"); } );
var safe_ctor = guard(
ctorSafe(Str, object({a: Str, b:Num})),
function(s) { this.a = s; this.b = 42; });
ok(new safe_ctor("foo"), "can call with new");
ok((new safe_ctor("foo")).a, "can call with new and get prop");
ok(safe_ctor("foo"), "can call without new");
});

@@ -288,3 +282,3 @@

raises(function() { fr.x = 55;}, "writing to frozen object");
raises(function() { delete fr.x;}, "deleting from frozen object");
// raises(function() { delete fr.x;}, "deleting from frozen object");

@@ -333,11 +327,11 @@ raises(function() { guard(

Object.defineProperty(o, "d", { value: 42, enumerable: true });
raises(function() { guard(
object({
a: {value: Num, writable: false},
b: {value: Str, writable: true},
c: {value: opt(Bool), configurable: false},
d: {value: Num, enumerable: false}
}),
o);
}, "all prop descriptors match the contract");
// raises(function() { guard(
// object({
// a: {value: Num, writable: false},
// b: {value: Str, writable: true},
// c: {value: opt(Bool), configurable: false},
// d: {value: Num, enumerable: false}
// }),
// o);
// }, "all prop descriptors match the contract");
});

@@ -417,21 +411,21 @@

var BC = Object.create(AC);
equals(BC.a(), "foo");
equals(BC.b, 42);
ok(BC.b = "foo", "since b is assigned to BC not proto there is not contract to stop it");
equals(BC.b, "foo");
// equals(BC.a(), "foo");
// equals(BC.b, 42);
// ok(BC.b = "foo", "since b is assigned to BC not proto there is not contract to stop it");
// equals(BC.b, "foo");
var BBadC = Object.create(ABadC);
raises(function() { BBadC.a(); }, "contract on prototype says number but gives string");
raises(function() { BBadC.b; }, "contract on proto still doesn't match value stored in b");
// var BBadC = Object.create(ABadC);
// raises(function() { BBadC.a(); }, "contract on prototype says number but gives string");
// raises(function() { BBadC.b; }, "contract on proto still doesn't match value stored in b");
var BGoodAttemptC = guard(
object({a: fun(any, Str), b: Num}),
BBadC);
raises(function() { BGoodAttemptC.a(); }, "contract on prototype still says there is a problem");
BBadC.a = function() { return "bar"; };
equals(BBadC.a(), "bar", "ok now we are shadowning bad contract");
// var BGoodAttemptC = guard(
// object({a: fun(any, Str), b: Num}),
// BBadC);
// raises(function() { BGoodAttemptC.a(); }, "contract on prototype still says there is a problem");
// BBadC.a = function() { return "bar"; };
// equals(BBadC.a(), "bar", "ok now we are shadowning bad contract");
var B_has_C_not_A = guard(object({a: fun(any, Str), b: Str}),
Object.create(A));
raises(function() { B_has_C_not_A.b; }, "blame even though contract is on object but prop is on proto");
// var B_has_C_not_A = guard(object({a: fun(any, Str), b: Str}),
// Object.create(A));
// raises(function() { B_has_C_not_A.b; }, "blame even though contract is on object but prop is on proto");
});

@@ -473,60 +467,2 @@

module("temporal contracts");
test("basic temporal contracts", function() {
var on = [true],
NumC = check(function(x, stack) {
if(stack[0][0]) { return typeof x === 'number'; }
else { return false; }
});
var incC = guard(
fun([NumC], NumC, {checkStack: function(stack) { return stack[0][0]; }}),
function(x) { return x + 1; },
false,
function(stack) { stack.push(on); });
same(incC(42), 43, "works when membrane is on");
on[0] = false;
raises(function() { incC(42); }, "membrane is off so fails");
});
test("temporal contracts can do dependency", function() {
var NumArg = check(function(x, stack) {
stack.push(x);
return typeof x === 'number';
}),
NumRng = check(function(x, stack) {
var arg = stack.pop();
return (typeof x === 'number') && (x > arg);
}),
incC = guard(
fun([NumArg], NumRng),
function(x) { return x + 1; }),
incBadC = guard(
fun([NumArg], NumRng),
function(x) { return x - 1; });
same(incC(42), 43, "abides by contract");
raises(function() { incBadC(42); }, "violates contract");
});
test("a basic temporal contract forbidding calling after return", function() {
var stolen_ref,
apply = guard(
fun([fun(any, Bool, {checkStack: function(stack) {
return stack.pop();
}}), any],
check(function(x, stack) {
stack.pop(); stack.push(false);
return typeof x === 'boolean';
})),
function(cmp, x) { stolen_ref = cmp; return cmp(x); },
false,
function(stack) { stack.push(true); });
same(apply(function(x) { return x > 0; }, 42), true);
raises(function() { stolen_ref(42); }, "attempted to call function after return");
});
test("can disable contract checking", function() {

@@ -533,0 +469,0 @@ contracts.enabled(false);

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc