-
Notifications
You must be signed in to change notification settings - Fork 12
/
Copy pathpact-code.ts
87 lines (81 loc) · 3.07 KB
/
pact-code.ts
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
import * as Pact from "pact-lang-api";
// When we hit the Pact API we must send some Pact code. It can be awkward to
// represent Pact in JavaScript because the syntax is so different; we'll use
// this type to capture applying a function to arguments.
export interface PactCode {
cmd: string;
args: Array<PactCode | Pact.PactValue>;
}
export const isPactCode = (p: any): p is PactCode => p.cmd && Array.isArray(p.args);
export const isPactInt = (p: any): p is Pact.PactInt => p.int;
export const isPactDecimal = (p: any): p is Pact.PactDecimal => p.decimal;
export const isPactReference = (p: any): p is Pact.PactReference => p.ref;
export const isPactDate = (p: any): p is Pact.PactDate => p.timep;
// A helper function to format our representation of Pact code into a string
// that we can send off to Chainweb for evaluation.
export const formatPactCode = (code: PactCode | PactCode[]): string => {
const formatPactValue = (value: Pact.PactValue): string => {
if (typeof value === "boolean") {
return value.toString();
} else if (typeof value === "string") {
return `"${value}"`;
} else if (isPactInt(value)) {
return value.int;
} else if (isPactDecimal(value)) {
return value.decimal;
} else if (isPactReference(value)) {
return value.ref;
} else if (isPactDate(value)) {
return value.timep;
} else if (Array.isArray(value)) {
return `[ ${value.map(formatPactValue)} ]`;
} else {
for (const key in value) {
value[key] = formatPactValue(value[key]);
}
return JSON.stringify(value);
}
};
const format = (value: PactCode | Pact.PactValue): string => {
if (isPactCode(value)) {
return formatPactCode(value);
} else {
return formatPactValue(value);
}
};
if (isPactCode(code)) {
return `(${code.cmd} ${code.args.map(format).join(" ")})`;
} else {
return code.map(formatPactCode).join("\n");
}
};
// We'll validate that the provided input is parseable into a Pact decimal.
export const parsePactDecimal = (value: string): string | Pact.PactDecimal => {
const split = value.split(".");
const numbers = new RegExp("[0-9]+$");
if (split.length === 1) {
const parsed = parseFloat(split[0]);
if (!numbers.test(split[0])) {
return "Can only contain digits and a decimal point.";
} else if (isNaN(parsed) || parsed < 0) {
return "Invalid number.";
} else {
return { decimal: `${split[0]}.0` };
}
} else if (split.length === 2) {
if (!numbers.test(split[0]) || !numbers.test(split[1])) {
return "Can only contain digits and a decimal point.";
}
const parsedFirst = parseFloat(split[0]);
const parsedSecond = parseFloat(split[1]);
if (isNaN(parsedFirst) || parsedFirst < 0) {
return "Invalid number before the decimal place.";
} else if (isNaN(parsedSecond) || parsedSecond < 0) {
return "Invalid number after the decimal place.";
} else {
return { decimal: `${parsedFirst.toString()}.${parsedSecond.toString()}` };
}
} else {
return "Invalid number (more than one decimal point).";
}
};