-
Notifications
You must be signed in to change notification settings - Fork 478
/
wrapper.ts
executable file
·169 lines (138 loc) · 5.25 KB
/
wrapper.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
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
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
import MemoryStream from 'memorystream';
import { https } from 'follow-redirects';
import { formatFatalError } from './formatters';
import { isNil } from './common/helpers';
import setupBindings from './bindings';
import translate from './translate';
const Module = module.constructor as any;
function wrapper (soljson) {
const {
coreBindings,
compileBindings,
methodFlags
} = setupBindings(soljson);
return {
version: coreBindings.version,
semver: coreBindings.versionToSemver,
license: coreBindings.license,
lowlevel: {
compileSingle: compileBindings.compileJson,
compileMulti: compileBindings.compileJsonMulti,
compileCallback: compileBindings.compileJsonCallback,
compileStandard: compileBindings.compileStandard
},
features: {
legacySingleInput: methodFlags.compileJsonStandardSupported,
multipleInputs: methodFlags.compileJsonMultiSupported || methodFlags.compileJsonStandardSupported,
importCallback: methodFlags.compileJsonCallbackSuppported || methodFlags.compileJsonStandardSupported,
nativeStandardJSON: methodFlags.compileJsonStandardSupported
},
compile: compileStandardWrapper.bind(this, compileBindings),
// Loads the compiler of the given version from the github repository
// instead of from the local filesystem.
loadRemoteVersion,
// Use this if you want to add wrapper functions around the pure module.
setupMethods: wrapper
};
}
function loadRemoteVersion (versionString, callback) {
const memoryStream = new MemoryStream(null, { readable: false });
const url = `https://binaries.soliditylang.org/bin/soljson-${versionString}.js`;
https.get(url, response => {
if (response.statusCode !== 200) {
callback(new Error(`Error retrieving binary: ${response.statusMessage}`));
} else {
response.pipe(memoryStream);
response.on('end', () => {
// Based on the require-from-string package.
const soljson = new Module();
soljson._compile(memoryStream.toString(), `soljson-${versionString}.js`);
if (module.parent && module.parent.children) {
// Make sure the module is plugged into the hierarchy correctly to have parent
// properly garbage collected.
module.parent.children.splice(module.parent.children.indexOf(soljson), 1);
}
callback(null, wrapper(soljson.exports));
});
}
}).on('error', function (error) {
callback(error);
});
}
// Expects a Standard JSON I/O but supports old compilers
function compileStandardWrapper (compile, inputRaw, readCallback) {
if (!isNil(compile.compileStandard)) {
return compile.compileStandard(inputRaw, readCallback);
}
let input: { language: string, sources: any[], settings: any };
try {
input = JSON.parse(inputRaw);
} catch (e) {
return formatFatalError(`Invalid JSON supplied: ${e.message}`);
}
if (input.language !== 'Solidity') {
return formatFatalError('Only "Solidity" is supported as a language.');
}
// NOTE: this is deliberately `== null`
if (isNil(input.sources) || input.sources.length === 0) {
return formatFatalError('No input sources specified.');
}
const sources = translateSources(input);
const optimize = isOptimizerEnabled(input);
const libraries = librariesSupplied(input);
if (isNil(sources) || Object.keys(sources).length === 0) {
return formatFatalError('Failed to process sources.');
}
// Try to wrap around old versions
if (!isNil(compile.compileJsonCallback)) {
const inputJson = JSON.stringify({ sources: sources });
const output = compile.compileJsonCallback(inputJson, optimize, readCallback);
return translateOutput(output, libraries);
}
if (!isNil(compile.compileJsonMulti)) {
const output = compile.compileJsonMulti(JSON.stringify({ sources: sources }), optimize);
return translateOutput(output, libraries);
}
// Try our luck with an ancient compiler
if (!isNil(compile.compileJson)) {
if (Object.keys(sources).length > 1) {
return formatFatalError('Multiple sources provided, but compiler only supports single input.');
}
const input = sources[Object.keys(sources)[0]];
const output = compile.compileJson(input, optimize);
return translateOutput(output, libraries);
}
return formatFatalError('Compiler does not support any known interface.');
}
function isOptimizerEnabled (input) {
return input.settings && input.settings.optimizer && input.settings.optimizer.enabled;
}
function translateSources (input) {
const sources = {};
for (const source in input.sources) {
if (input.sources[source].content !== null) {
sources[source] = input.sources[source].content;
} else {
// force failure
return null;
}
}
return sources;
}
function librariesSupplied (input) {
if (!isNil(input.settings)) return input.settings.libraries;
}
function translateOutput (outputRaw, libraries) {
let parsedOutput;
try {
parsedOutput = JSON.parse(outputRaw);
} catch (e) {
return formatFatalError(`Compiler returned invalid JSON: ${e.message}`);
}
const output = translate.translateJsonCompilerOutput(parsedOutput, libraries);
if (isNil(output)) {
return formatFatalError('Failed to process output.');
}
return JSON.stringify(output);
}
export = wrapper;