-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathindex.js
113 lines (94 loc) · 2.42 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
const assert = require('assert')
const contains = (list, elt) => !!~list.indexOf(elt)
function cc () {
let fn = null
let sealed = false
const validate = () => {
assert(!sealed, 'This contract is sealed')
}
const configuration = {
pure: false,
nothrow: false,
throws: [assert.AssertionError],
pre: [],
post: []
}
configuration.toJSON = function () {
return {
pure: configuration.pure,
nothrow: configuration.nothrow,
throws: configuration.throws.map(x => x.name),
pre: configuration.pre.map(f => f.toString()),
post: configuration.post.map(f => f.toString())
}
}
const configurationOptions = {
pre: registerPreCondition,
post: registerPostCondition,
throws: registerError,
nothrow: setNothrow,
pure: setPure,
seal: seal
}
function registerError (e) {
validate()
configuration.throws.push(e)
return configurationOptions
}
function setNothrow () {
validate()
configuration.nothrow = true
return configurationOptions
}
function setPure () {
validate()
configuration.pure = true
return configurationOptions
}
function registerPreCondition (condition) {
validate()
configuration.pre.push(condition)
return configurationOptions
}
function registerPostCondition (condition) {
validate()
configuration.post.push(condition)
return configurationOptions
}
function seal (impl) {
validate()
sealed = true
fn = impl
return wrapper
}
function wrapper (...args) {
for (let i = 0; i < configuration.pre.length; ++i) {
const cond = configuration.pre[i]
const failMsg =
`The arguments must satisfy ${cond.toString()}`
assert(cond.apply(this, args), failMsg)
}
let result = null
try {
result = fn.apply(this, args)
} catch (e) {
if (!configuration.nothrow) {
const etype = e.constructor
assert(
contains(configuration.throws, etype),
`Not a registered error [${etype.name}]`)
throw e
}
}
for (let i = 0; i < configuration.post.length; ++i) {
const cond = configuration.post[i]
const failMsg =
`The return value must satisfy ${cond.toString()}`
assert(cond(result, args), failMsg)
}
return result
}
wrapper.getContractInfo = () => configuration.toJSON()
return configurationOptions
}
module.exports = cc