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.4.2 to 0.4.3

examples/dependent-indy.js

49

doc/main/contracts.md

@@ -169,2 +169,51 @@ % Contracts.js Documentation

### Dependent Contracts
You can also write a function contract who's result depends on the
value of its arguments.
```js
@ (x: Pos) -> res: Num | res <= x
function square_root(x) { return Math.sqrt(x); }
```
Name each argument and result with the notation `<name>: <contract>`
and then each name can be referred to in the dependency guard
following the `|`. The guard is an expression the must evaluate to a
boolean. If the guard evaluates to `true` the dependent function
contract will pass otherwise it fails.
If you need more than a single boolean expression you can wrap it in
curlies:
```js
@ (x: Pos) -> res: Num | {
var fromlib = Math.sqrt(x);
return res <= x && fromlib === res;
}
function square_root(x) { return Math.sqrt(x); }
```
Note that guards in a dependent contract could potentially violate
a contract on one of the arguments:
```js
@ (f: (Num) -> Num) -> res: Num | f("foo") > 10
function foo(f) { return f(24) }
```
In a case like this, the contract itself will be blamed:
<pre style="color:red">
expected: Num
given: 'foo'
in: the 1st argument of
the 1st argument of
(f: (Num) -> Num) -> res: Num | f (foo) > 10
function foo guarded at line: 2
blaming: the contract of foo
</pre>
If you are familiar with contract research, this is the [indy](http://www.ccs.neu.edu/racket/pubs/popl11-dfff.pdf) semantics.
## Object Contracts

@@ -171,0 +220,0 @@

@@ -30,2 +30,12 @@ // returns the log array

},
{
id: 4,
file: "dependent.js",
title: "Dependent Contracts"
},
{
id: 4,
file: "dependent-indy.js",
title: "Dependent Contracts with Indy Blame"
}
];

@@ -32,0 +42,0 @@ var contractModulePromise = Ember.$.ajax("macros/index.js", {

65

macros/disabled.js

@@ -55,2 +55,5 @@ var _c;

};
BlameObj.prototype.setNeg = function (neg) {
return Blame.clone(this, { neg: neg });
};
function assert(cond, msg) {

@@ -122,4 +125,8 @@ if (!cond) {

function fun(dom, rng, options) {
var domName = '(' + dom.join(', ') + ')';
var contractName = domName + ' -> ' + rng;
var domStr = dom.map(function (d, idx) {
return options && options.namesStr ? options.namesStr[idx] + ': ' + d : d;
}).join(', ');
var domName = '(' + domStr + ')';
var rngStr = options && options.namesStr ? options.namesStr[options.namesStr.length - 1] + ': ' + rng : rng;
var contractName = domName + ' -> ' + rngStr + (options && options.dependencyStr ? ' | ' + options.dependencyStr : '');
var c = new Contract(contractName, 'fun', function (blame) {

@@ -133,2 +140,3 @@ return function (f) {

var checkedArgs = [];
var depArgs = [];
for (var i = 0; i < dom.length; i++) {

@@ -138,4 +146,9 @@ if (dom[i].type === 'optional' && args[i] === undefined) {

} else {
var domProj = dom[i].proj(blame.swap().addLocation('the ' + addTh(i + 1) + ' argument of'));
var location = 'the ' + addTh(i + 1) + ' argument of';
var domProj = dom[i].proj(blame.swap().addLocation(location));
checkedArgs.push(domProj(args[i]));
if (options && options.dependency) {
var depProj = dom[i].proj(blame.swap().setNeg('the contract of ' + blame.name).addLocation(location));
depArgs.push(depProj(args[i]));
}
}

@@ -147,3 +160,10 @@ }

var rngProj = rng.proj(blame.addLocation('the return of'));
return rngProj(rawResult);
var rngResult = rngProj(rawResult);
if (options && options.dependency && typeof options.dependency === 'function') {
var depResult = options.dependency.apply(this, depArgs.concat(rngResult));
if (!depResult) {
raiseBlame(blame.addExpected(options.dependencyStr).addGiven(false).addLocation('the return dependency of'));
}
}
return rngResult;
}

@@ -348,2 +368,21 @@ // only use expensive proxies when needed (to distinguish between apply and construct)

macro stringify {
case {_ ($toks ...) } => {
var toks = #{$toks ...}[0].token.inner;
function traverse(stx) {
return stx.map(function(s) {
if (s.token.inner) {
return s.token.value[0] + traverse(s.token.inner) + s.token.value[1];
}
return s.token.value;
}).join(" ");
}
var toksStr = traverse(toks);
letstx $str = [makeValue(toksStr, #{here})];
return #{$str}
}
}
macro base_contract {

@@ -354,2 +393,20 @@ rule { $name } => { _c.$name }

macro function_contract {
rule { ($dom:named_contract (,) ...) -> $range:named_contract | { $guard ... } } => {
_c.fun([$dom$contract (,) ...], $range$contract, {
dependency: function($dom$name (,) ..., $range$name) {
$guard ...
},
namesStr: [$(stringify (($dom$name))) (,) ..., stringify (($range$name))],
dependencyStr: stringify (($guard ...))
})
}
rule { ($dom:named_contract (,) ...) -> $range:named_contract | $guard:expr } => {
_c.fun([$dom$contract (,) ...], $range$contract, {
dependency: function($dom$name (,) ..., $range$name) {
return $guard;
},
namesStr: [$(stringify (($dom$name))) (,) ..., stringify (($range$name))],
dependencyStr: stringify ($guard)
})
}
rule { ($dom:any_contract (,) ...) -> $range:any_contract } => {

@@ -356,0 +413,0 @@ _c.fun([$dom (,) ...], $range)

@@ -55,2 +55,5 @@ var _c;

};
BlameObj.prototype.setNeg = function (neg) {
return Blame.clone(this, { neg: neg });
};
function assert(cond, msg) {

@@ -122,4 +125,8 @@ if (!cond) {

function fun(dom, rng, options) {
var domName = '(' + dom.join(', ') + ')';
var contractName = domName + ' -> ' + rng;
var domStr = dom.map(function (d, idx) {
return options && options.namesStr ? options.namesStr[idx] + ': ' + d : d;
}).join(', ');
var domName = '(' + domStr + ')';
var rngStr = options && options.namesStr ? options.namesStr[options.namesStr.length - 1] + ': ' + rng : rng;
var contractName = domName + ' -> ' + rngStr + (options && options.dependencyStr ? ' | ' + options.dependencyStr : '');
var c = new Contract(contractName, 'fun', function (blame) {

@@ -133,2 +140,3 @@ return function (f) {

var checkedArgs = [];
var depArgs = [];
for (var i = 0; i < dom.length; i++) {

@@ -138,4 +146,9 @@ if (dom[i].type === 'optional' && args[i] === undefined) {

} else {
var domProj = dom[i].proj(blame.swap().addLocation('the ' + addTh(i + 1) + ' argument of'));
var location = 'the ' + addTh(i + 1) + ' argument of';
var domProj = dom[i].proj(blame.swap().addLocation(location));
checkedArgs.push(domProj(args[i]));
if (options && options.dependency) {
var depProj = dom[i].proj(blame.swap().setNeg('the contract of ' + blame.name).addLocation(location));
depArgs.push(depProj(args[i]));
}
}

@@ -147,3 +160,10 @@ }

var rngProj = rng.proj(blame.addLocation('the return of'));
return rngProj(rawResult);
var rngResult = rngProj(rawResult);
if (options && options.dependency && typeof options.dependency === 'function') {
var depResult = options.dependency.apply(this, depArgs.concat(rngResult));
if (!depResult) {
raiseBlame(blame.addExpected(options.dependencyStr).addGiven(false).addLocation('the return dependency of'));
}
}
return rngResult;
}

@@ -348,2 +368,21 @@ // only use expensive proxies when needed (to distinguish between apply and construct)

macro stringify {
case {_ ($toks ...) } => {
var toks = #{$toks ...}[0].token.inner;
function traverse(stx) {
return stx.map(function(s) {
if (s.token.inner) {
return s.token.value[0] + traverse(s.token.inner) + s.token.value[1];
}
return s.token.value;
}).join(" ");
}
var toksStr = traverse(toks);
letstx $str = [makeValue(toksStr, #{here})];
return #{$str}
}
}
macro base_contract {

@@ -353,3 +392,25 @@ rule { $name } => { _c.$name }

macroclass named_contract {
rule { $name $[:] $contract:any_contract }
}
macro function_contract {
rule { ($dom:named_contract (,) ...) -> $range:named_contract | { $guard ... } } => {
_c.fun([$dom$contract (,) ...], $range$contract, {
dependency: function($dom$name (,) ..., $range$name) {
$guard ...
},
namesStr: [$(stringify (($dom$name))) (,) ..., stringify (($range$name))],
dependencyStr: stringify (($guard ...))
})
}
rule { ($dom:named_contract (,) ...) -> $range:named_contract | $guard:expr } => {
_c.fun([$dom$contract (,) ...], $range$contract, {
dependency: function($dom$name (,) ..., $range$name) {
return $guard;
},
namesStr: [$(stringify (($dom$name))) (,) ..., stringify (($range$name))],
dependencyStr: stringify ($guard)
})
}
rule { ($dom:any_contract (,) ...) -> $range:any_contract } => {

@@ -406,2 +467,3 @@ _c.fun([$dom (,) ...], $range)

macro non_or_contract {

@@ -408,0 +470,0 @@ rule { $contract:function_contract } => { $contract }

2

package.json

@@ -10,3 +10,3 @@ {

"author": "Tim Disney",
"version": "0.4.2",
"version": "0.4.3",
"licenses": [

@@ -13,0 +13,0 @@ {

@@ -63,3 +63,9 @@ (function() {

BlameObj.prototype.setNeg = function(neg) {
return Blame.clone(this, {
neg: neg
});
};
function assert(cond, msg) {

@@ -134,6 +140,12 @@ if(!cond) {

function fun(dom, rng, options) {
var domStr = dom.map(function (d, idx) {
return options && options.namesStr ? options.namesStr[idx] + ": " + d : d;
}).join(", ");
var domName = "(" + domStr + ")";
var domName = "(" + dom.join(", ") + ")";
var contractName = domName + " -> " + rng;
var rngStr = options && options.namesStr ? options.namesStr[options.namesStr.length - 1] + ": " + rng : rng;
var contractName = domName + " -> " + rngStr +
(options && options.dependencyStr ? " | " + options.dependencyStr : "");
var c = new Contract(contractName, "fun", function(blame) {

@@ -151,3 +163,3 @@ return function(f) {

var checkedArgs = [];
var depArgs = [];
for (var i = 0; i < dom.length; i++) {

@@ -157,8 +169,14 @@ if (dom[i].type === "optional" && args[i] === undefined) {

} else {
var location = "the " + addTh(i+1) + " argument of";
var domProj = dom[i].proj(blame.swap()
.addLocation("the " +
addTh(i+1) +
" argument of"));
.addLocation(location));
checkedArgs.push(domProj(args[i]));
if (options && options.dependency) {
var depProj = dom[i].proj(blame.swap()
.setNeg("the contract of " + blame.name)
.addLocation(location));
depArgs.push(depProj(args[i]));
}
}

@@ -172,3 +190,12 @@ }

var rngProj = rng.proj(blame.addLocation("the return of"));
return rngProj(rawResult);
var rngResult = rngProj(rawResult);
if (options && options.dependency && typeof options.dependency === "function") {
var depResult = options.dependency.apply(this, depArgs.concat(rngResult));
if (!depResult) {
raiseBlame(blame.addExpected(options.dependencyStr)
.addGiven(false)
.addLocation("the return dependency of"));
}
}
return rngResult;
}

@@ -175,0 +202,0 @@

@@ -12,2 +12,21 @@ var _c;

macro stringify {
case {_ ($toks ...) } => {
var toks = #{$toks ...}[0].token.inner;
function traverse(stx) {
return stx.map(function(s) {
if (s.token.inner) {
return s.token.value[0] + traverse(s.token.inner) + s.token.value[1];
}
return s.token.value;
}).join(" ");
}
var toksStr = traverse(toks);
letstx $str = [makeValue(toksStr, #{here})];
return #{$str}
}
}
macro base_contract {

@@ -18,2 +37,20 @@ rule { $name } => { _c.$name }

macro function_contract {
rule { ($dom:named_contract (,) ...) -> $range:named_contract | { $guard ... } } => {
_c.fun([$dom$contract (,) ...], $range$contract, {
dependency: function($dom$name (,) ..., $range$name) {
$guard ...
},
namesStr: [$(stringify (($dom$name))) (,) ..., stringify (($range$name))],
dependencyStr: stringify (($guard ...))
})
}
rule { ($dom:named_contract (,) ...) -> $range:named_contract | $guard:expr } => {
_c.fun([$dom$contract (,) ...], $range$contract, {
dependency: function($dom$name (,) ..., $range$name) {
return $guard;
},
namesStr: [$(stringify (($dom$name))) (,) ..., stringify (($range$name))],
dependencyStr: stringify ($guard)
})
}
rule { ($dom:any_contract (,) ...) -> $range:any_contract } => {

@@ -20,0 +57,0 @@ _c.fun([$dom (,) ...], $range)

@@ -12,2 +12,21 @@ var _c;

macro stringify {
case {_ ($toks ...) } => {
var toks = #{$toks ...}[0].token.inner;
function traverse(stx) {
return stx.map(function(s) {
if (s.token.inner) {
return s.token.value[0] + traverse(s.token.inner) + s.token.value[1];
}
return s.token.value;
}).join(" ");
}
var toksStr = traverse(toks);
letstx $str = [makeValue(toksStr, #{here})];
return #{$str}
}
}
macro base_contract {

@@ -17,3 +36,25 @@ rule { $name } => { _c.$name }

macroclass named_contract {
rule { $name $[:] $contract:any_contract }
}
macro function_contract {
rule { ($dom:named_contract (,) ...) -> $range:named_contract | { $guard ... } } => {
_c.fun([$dom$contract (,) ...], $range$contract, {
dependency: function($dom$name (,) ..., $range$name) {
$guard ...
},
namesStr: [$(stringify (($dom$name))) (,) ..., stringify (($range$name))],
dependencyStr: stringify (($guard ...))
})
}
rule { ($dom:named_contract (,) ...) -> $range:named_contract | $guard:expr } => {
_c.fun([$dom$contract (,) ...], $range$contract, {
dependency: function($dom$name (,) ..., $range$name) {
return $guard;
},
namesStr: [$(stringify (($dom$name))) (,) ..., stringify (($range$name))],
dependencyStr: stringify ($guard)
})
}
rule { ($dom:any_contract (,) ...) -> $range:any_contract } => {

@@ -70,2 +111,3 @@ _c.fun([$dom (,) ...], $range)

macro non_or_contract {

@@ -72,0 +114,0 @@ rule { $contract:function_contract } => { $contract }

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

var should = require("should");
var should = require("should"), assert = require("assert");
import @ from "contracts.js";

@@ -10,2 +10,3 @@

$body ...
assert.fail("no exception", "exception", "Should have blamed: " + $expectedMsg);
} catch (b) {

@@ -31,3 +32,3 @@ (b.message).should.equal($expectedMsg);

(Num) -> Num
function numId guarded at line: 21
function numId guarded at line: 22
blaming: (calling context for numId)

@@ -48,3 +49,3 @@ `

(Num) -> Num
function numId guarded at line: 37
function numId guarded at line: 38
blaming: function numId

@@ -65,3 +66,3 @@ `

(Num, Str) -> Num
function f guarded at line: 53
function f guarded at line: 54
blaming: (calling context for f)

@@ -93,3 +94,3 @@ `

(Num, opt Str) -> Num
function f guarded at line: 78
function f guarded at line: 79
blaming: (calling context for f)

@@ -110,3 +111,3 @@ `

((Num) -> Num) -> Num
function f guarded at line: 96
function f guarded at line: 97
blaming: (calling context for f)

@@ -132,3 +133,3 @@ `

((Num) -> Num) -> Num
function numApp guarded at line: 112
function numApp guarded at line: 113
blaming: (calling context for numApp)

@@ -152,3 +153,3 @@ `

((Num) -> Num) -> Num
function bad guarded at line: 133
function bad guarded at line: 134
blaming: function bad

@@ -170,3 +171,3 @@ `

({age: Num}) -> Num
function f guarded at line: 152
function f guarded at line: 153
blaming: (calling context for f)

@@ -191,3 +192,3 @@ `

({g: (Num) -> Num}) -> Num
function f guarded at line: 169
function f guarded at line: 170
blaming: (calling context for f)

@@ -208,3 +209,3 @@ `

({s: Str}) -> Str
function f guarded at line: 189
function f guarded at line: 190
blaming: (calling context for f)

@@ -233,3 +234,3 @@ `

({foo: opt Str}) -> Str
function f guarded at line: 212
function f guarded at line: 213
blaming: (calling context for f)

@@ -254,3 +255,3 @@ `

(Num) -> !{age: Num}
function makePerson guarded at line: 229
function makePerson guarded at line: 230
blaming: (calling context for makePerson)

@@ -275,3 +276,3 @@ `

(!{age: Num}) -> Num
function f guarded at line: 249
function f guarded at line: 250
blaming: function f

@@ -293,3 +294,3 @@ `

([Str]) -> Num
function f guarded at line: 269
function f guarded at line: 270
blaming: (calling context for f)

@@ -311,3 +312,3 @@ `

([Str, Num]) -> Num
function f guarded at line: 286
function f guarded at line: 287
blaming: (calling context for f)

@@ -330,3 +331,3 @@ `

(Num) -> ![Num]
function makeArr guarded at line: 303
function makeArr guarded at line: 304
blaming: (calling context for makeArr)

@@ -348,3 +349,3 @@ `

([....Num]) -> Num
function f guarded at line: 321
function f guarded at line: 322
blaming: (calling context for f)

@@ -385,3 +386,3 @@ `

(![....Num]) -> Num
function f guarded at line: 354
function f guarded at line: 355
blaming: function f

@@ -404,3 +405,3 @@ `

({o: {name: Str}}) -> Str
function f guarded at line: 374
function f guarded at line: 375
blaming: (calling context for f)

@@ -430,3 +431,3 @@ `

({name: Str}, [....{loc: Num}]) -> Str
function calcAverageLoc guarded at line: 392
function calcAverageLoc guarded at line: 393
blaming: (calling context for calcAverageLoc)

@@ -451,3 +452,3 @@ `

((Num) -> Num) -> Num
function f guarded at line: 419
function f guarded at line: 420
blaming: (calling context for f)

@@ -471,7 +472,42 @@ `

(Str or Num) -> Str
function foo guarded at line: 438
function foo guarded at line: 439
blaming: (calling context for foo)
`
});
it("should work for dependent contracts", function() {
@ (x: Pos) -> res: Num | res <= x
function bad_square_root(x) { return x * x; }
blame of {
bad_square_root(100)
} should be `bad_square_root: contract violation
expected: res <= x
given: false
in: the return dependency of
(x: Pos) -> res: Num | res <= x
function bad_square_root guarded at line: 457
blaming: function bad_square_root
`
});
it("should blame the contract if the dependency breaks a domain contract", function() {
@ (f: (Num) -> Num) -> res: Num | { return f("foo") > 10 }
function foo(f) { return f(24) }
blame of {
foo(function(x) {
return x;
});
} should be `foo: contract violation
expected: Num
given: 'foo'
in: the 1st argument of
the 1st argument of
(f: (Num) -> Num) -> res: Num | return f (foo) > 10
function foo guarded at line: 473
blaming: the contract of foo
`
})
});

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