blob: cda67a4149f0bbf6a3778c431ce7e607f178c32d (
plain) (
blame)
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
|
import { ContractSource } from '@0x/sol-resolver';
import { logUtils } from '@0x/utils';
import { ContractArtifact } from 'ethereum-types';
import * as _ from 'lodash';
import * as path from 'path';
import { fsWrapper } from './fs_wrapper';
/**
* Gets contract data on network or returns if an artifact does not exist.
* @param artifactsDir Path to the artifacts directory.
* @param contractName Name of contract.
* @return Contract data on network or undefined.
*/
export async function getContractArtifactIfExistsAsync(
artifactsDir: string,
contractName: string,
): Promise<ContractArtifact | void> {
let contractArtifact;
const currentArtifactPath = `${artifactsDir}/${contractName}.json`;
try {
const opts = {
encoding: 'utf8',
};
const contractArtifactString = await fsWrapper.readFileAsync(currentArtifactPath, opts);
contractArtifact = JSON.parse(contractArtifactString);
return contractArtifact;
} catch (err) {
logUtils.warn(`Artifact for ${contractName} does not exist`);
return undefined;
}
}
/**
* Creates a directory if it does not already exist.
* @param artifactsDir Path to the directory.
*/
export async function createDirIfDoesNotExistAsync(dirPath: string): Promise<void> {
if (!fsWrapper.doesPathExistSync(dirPath)) {
logUtils.warn(`Creating directory at ${dirPath}...`);
await fsWrapper.mkdirpAsync(dirPath);
}
}
/**
* Searches Solidity source code for compiler version range.
* @param source Source code of contract.
* @return Solc compiler version range.
*/
export function parseSolidityVersionRange(source: string): string {
const SOLIDITY_VERSION_RANGE_REGEX = /pragma\s+solidity\s+(.*);/;
const solcVersionRangeMatch = source.match(SOLIDITY_VERSION_RANGE_REGEX);
if (_.isNull(solcVersionRangeMatch)) {
throw new Error('Could not find Solidity version range in source');
}
const solcVersionRange = solcVersionRangeMatch[1];
return solcVersionRange;
}
/**
* Normalizes the path found in the error message. If it cannot be normalized
* the original error message is returned.
* Example: converts 'base/Token.sol:6:46: Warning: Unused local variable'
* to 'Token.sol:6:46: Warning: Unused local variable'
* This is used to prevent logging the same error multiple times.
* @param errMsg An error message from the compiled output.
* @return The error message with directories truncated from the contract path.
*/
export function getNormalizedErrMsg(errMsg: string): string {
const SOLIDITY_FILE_EXTENSION_REGEX = /(.*\.sol)/;
const errPathMatch = errMsg.match(SOLIDITY_FILE_EXTENSION_REGEX);
if (_.isNull(errPathMatch)) {
// This can occur if solidity outputs a general warning, e.g
// Warning: This is a pre-release compiler version, please do not use it in production.
return errMsg;
}
const errPath = errPathMatch[0];
const baseContract = path.basename(errPath);
const normalizedErrMsg = errMsg.replace(errPath, baseContract);
return normalizedErrMsg;
}
/**
* Parses the contract source code and extracts the dendencies
* @param source Contract source code
* @return List of dependendencies
*/
export function parseDependencies(contractSource: ContractSource): string[] {
// TODO: Use a proper parser
const source = contractSource.source;
const IMPORT_REGEX = /(import\s)/;
const DEPENDENCY_PATH_REGEX = /"([^"]+)"/; // Source: https://github.com/BlockChainCompany/soljitsu/blob/master/lib/shared.js
const dependencies: string[] = [];
const lines = source.split('\n');
_.forEach(lines, line => {
if (!_.isNull(line.match(IMPORT_REGEX))) {
const dependencyMatch = line.match(DEPENDENCY_PATH_REGEX);
if (!_.isNull(dependencyMatch)) {
let dependencyPath = dependencyMatch[1];
if (dependencyPath.startsWith('.')) {
dependencyPath = path.join(path.dirname(contractSource.path), dependencyPath);
}
dependencies.push(dependencyPath);
}
}
});
return dependencies;
}
|