solive-compiler-utils
Version:
Solidity Compiler helper tool
305 lines (295 loc) • 12 kB
JavaScript
import * as semver from 'semver';
const makeCompilerInput = (sources, opts) => {
const baseInput = {
language: 'Solidity',
sources,
settings: {
optimizer: {
enabled: opts.optimize === true || opts.optimize === 1,
runs: opts.runs > -1 ? opts.runs : 200,
},
libraries: opts.libraries,
outputSelection: {
'*': {
'': ['ast'],
'*': [
'abi',
'metadata',
'devdoc',
'userdoc',
'storageLayout',
'evm.legacyAssembly',
'evm.bytecode',
'evm.deployedBytecode',
'evm.methodIdentifiers',
'evm.gasEstimates',
'evm.assembly',
],
},
},
},
};
if (opts.evmVersion) {
if (opts.evmVersion.toLowerCase() === 'default') {
// eslint-disable-next-line no-param-reassign
opts.evmVersion = null;
}
else {
baseInput.settings.evmVersion = opts.evmVersion;
}
}
if (opts.language) {
baseInput.language = opts.language;
}
if (opts.language === 'Yul' && baseInput.settings.optimizer.enabled) {
if (!baseInput.settings.optimizer.details) {
baseInput.settings.optimizer.details = {};
}
baseInput.settings.optimizer.details.yul = true;
}
return baseInput;
};
var CompilerRetriggerMode;
(function (CompilerRetriggerMode) {
CompilerRetriggerMode[CompilerRetriggerMode["none"] = 0] = "none";
CompilerRetriggerMode[CompilerRetriggerMode["retrigger"] = 1] = "retrigger";
})(CompilerRetriggerMode || (CompilerRetriggerMode = {}));
const isFunctionDescription = (item) => item.stateMutability !== undefined;
const isEventDescription = (item) => item.type === 'event';
var MarkerSeverity;
(function (MarkerSeverity) {
MarkerSeverity[MarkerSeverity["Hint"] = 1] = "Hint";
MarkerSeverity[MarkerSeverity["Info"] = 2] = "Info";
MarkerSeverity[MarkerSeverity["Warning"] = 4] = "Warning";
MarkerSeverity[MarkerSeverity["Error"] = 8] = "Error";
})(MarkerSeverity || (MarkerSeverity = {}));
const baseURLBin = 'https://binaries.soliditylang.org/bin';
const baseURLWasm = 'https://binaries.soliditylang.org/wasm';
const pathToURL = {};
/**
* Retrieves the URL of the given compiler version
* @param version is the version of compiler with or without 'soljson-v' prefix and .js postfix
*/
// export function urlFromVersion(version: string) {
// let url;
// if (version === 'builtin') {
// let { location } = window.document;
// let path = location.pathname;
// if (!path.startsWith('/')) path = `/${path}`;
// location = `${location.protocol}//${location.host}${path}assets/js`;
// if (location.endsWith('index.html')) location = location.substring(0, location.length - 10);
// if (!location.endsWith('/')) location += '/';
// url = `${location}soljson.js`;
// } else {
// version = version.replace('.Emscripten.clang', '');
// if (!version.startsWith('soljson-v')) version = `soljson-v${version}`;
// if (!version.endsWith('.js')) version += '.js';
// url = `${(<any>pathToURL)[version]}/${version}`;
// }
// return url;
// }
/**
* Checks if the worker can be used to load a compiler.
* checks a compiler whitelist, browser support and OS.
*/
function canUseWorker(selectedVersion) {
if (selectedVersion.startsWith('http')) {
return browserSupportWorker();
}
const version = semver.coerce(selectedVersion);
if (!version) {
return browserSupportWorker();
}
const isNightly = selectedVersion.includes('nightly');
return (browserSupportWorker()
// All compiler versions (including nightlies) after 0.6.3 are wasm compiled
&& (semver.gt(version, '0.6.3')
// Only releases are wasm compiled starting with 0.3.6
|| (semver.gte(version, '0.3.6') && !isNightly)));
}
function browserSupportWorker() {
return document
? document.location.protocol !== 'file:' && Worker !== undefined
: false;
}
/******************************************************************************
Copyright (c) Microsoft Corporation.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
***************************************************************************** */
function __awaiter(thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
}
/**
* @dev Get contract obj of given contract name from last compilation result.
* @param contractName
* @param contracts 'contracts' object from last compilation result
*/
const getContract = (contractName, contracts) => {
for (const file in contracts) {
if (contracts[file][contractName]) {
return { object: contracts[file][contractName], file };
}
}
return null;
};
/**
* @dev call the given callback for all contracts from last compilation result, stop visiting when cb return true
* @param contracts - 'contracts' object from last compilation result
* @param cb - callback
*/
const visitContracts = (contracts, cb) => {
for (const file in contracts) {
for (const name in contracts[file]) {
const param = {
name,
object: contracts[file][name],
file,
};
if (cb(param))
return;
}
}
};
// ^ e.g:
// browser/gm.sol: Warning: Source file does
// not specify required compiler version! Consider adding "pragma solidity ^0.6.12
// https://github.com/OpenZeppelin/openzeppelin-contracts/blob/release-v3.2.0/contracts/introspection/IERC1820Registry.sol:3:1
// ParserError: Source file requires different compiler version
// (current compiler is 0.7.4+commit.3f05b770.Emscripten.clang)
// - note that nightly builds are considered to be strictly less than the released version
const getPositionDetails = (msg) => {
const result = {};
// To handle some compiler warning without location like SPDX license warning etc
if (!msg.includes(':'))
return { errLine: -1, errCol: -1, errFile: '' };
// eslint-disable-next-line no-param-reassign
if (msg.includes('-->'))
msg = msg.split('-->')[1].trim();
// extract line / column
let pos = msg.match(/^(.*?):([0-9]*?):([0-9]*?)?/);
result.errLine = pos ? parseInt(pos[2]) - 1 : -1;
result.errCol = pos ? parseInt(pos[3]) : -1;
// extract file
pos = msg.match(/^(https:.*?|http:.*?|.*?):/);
result.errFile = pos ? pos[1] : msg;
return result;
};
const createErrorMarker = (error, filePath, lineColumn) => ({
message: error.formattedMessage,
severity: error.severity === 'error'
? MarkerSeverity.Error
: MarkerSeverity.Warning,
position: {
start: {
line: ((lineColumn.start && lineColumn.start.line) || 0) + 1,
column: ((lineColumn.start && lineColumn.start.column) || 0) + 1,
},
end: {
line: ((lineColumn.end && lineColumn.end.line) || 0) + 1,
column: ((lineColumn.end && lineColumn.end.column) || 0) + 1,
},
},
file: filePath,
});
const getLinebreakPositions = (source) => {
const ret = [];
for (let pos = source.indexOf('\n'); pos >= 0; pos = source.indexOf('\n', pos + 1)) {
ret.push(pos);
}
return ret;
};
const convertOffsetToLineColumn = (sourceLocation, lineBreakPositions) => {
if (sourceLocation.start >= 0 && sourceLocation.length >= 0) {
return {
start: convertFromCharPosition(sourceLocation.start, lineBreakPositions),
end: convertFromCharPosition(sourceLocation.start + sourceLocation.length, lineBreakPositions),
};
}
return { start: null, end: null };
};
const convertFromCharPosition = (pos, lineBreakPositions) => {
let line = findLowerBound(pos, lineBreakPositions);
if (lineBreakPositions[line] !== pos) {
line += 1;
}
const beginColumn = line === 0 ? 0 : lineBreakPositions[line - 1] + 1;
const column = pos - beginColumn;
return { line, column };
};
const findLowerBound = (target, array) => {
let start = 0;
let { length } = array;
while (length > 0) {
const half = length >> 1;
const middle = start + half;
if (array[middle] <= target) {
length = length - 1 - half;
start = middle + 1;
}
else {
length = half;
}
}
return start - 1;
};
const getPositionForImportErrors = (importedFileName, text) => __awaiter(void 0, void 0, void 0, function* () {
const re = new RegExp(escapeRegExp(importedFileName), 'gi');
const result = findLinesInStringWithMatch(text, re);
return result;
});
const findLinesInStringWithMatch = (str, re) => str
.split(/\r?\n/)
.map((line, i) => {
const matchResult = matchesInString(line, re);
if (matchResult.length) {
return {
lines: splitLines(matchResult, i),
};
}
return null;
})
.filter(Boolean);
const matchesInString = (str, re) => {
let a;
const results = [];
// @ts-ignore
// eslint-disable-next-line no-cond-assign
while ((a = re.exec(str || '')) !== null) {
results.push(a);
}
return results;
};
const splitLines = (matchResult, lineNumber) => matchResult.map((matchResultPart) => {
const result = {
left: matchResultPart.input.substring(0, matchResultPart.index),
right: matchResultPart.input.substring(matchResultPart.index + matchResultPart[0].length),
center: matchResultPart[0],
position: {
start: {
line: lineNumber,
column: matchResultPart.index,
},
end: {
line: lineNumber,
column: matchResultPart.index + matchResultPart[0].length,
},
},
};
return result;
});
const escapeRegExp = (str) => str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
export { CompilerRetriggerMode, MarkerSeverity, baseURLBin, baseURLWasm, canUseWorker, convertFromCharPosition, convertOffsetToLineColumn, createErrorMarker, findLinesInStringWithMatch, findLowerBound, getContract, getLinebreakPositions, getPositionDetails, getPositionForImportErrors, isEventDescription, isFunctionDescription, makeCompilerInput, pathToURL, visitContracts };