blob: d8b5f78c927a375d140aa57f33e9f9bdc7f2cfae (
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
109
110
111
112
113
114
115
116
117
118
119
120
|
import { logUtils } from '@0xproject/utils';
import * as _ from 'lodash';
import * as path from 'path';
import * as solc from 'solc';
import { constants } from './constants';
import { fsWrapper } from './fs_wrapper';
import { ContractArtifact, ContractSources } from './types';
/**
* Gets contract data on network or returns if an artifact does not exist.
* @param fileName Name of contract file.
* @return Contract data on network or undefined.
*/
export async function getContractArtifactIfExistsAsync(
artifactsDir: string,
fileName: string,
): Promise<ContractArtifact | void> {
let contractArtifact;
const contractName = path.basename(fileName, constants.SOLIDITY_FILE_EXTENSION);
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.log(`Artifact for ${fileName} does not exist`);
return undefined;
}
}
/**
* Creates the artifacts directory if it does not already exist.
*/
export async function createArtifactsDirIfDoesNotExistAsync(artifactsDir: string): Promise<void> {
if (!fsWrapper.doesPathExistSync(artifactsDir)) {
logUtils.log('Creating artifacts directory...');
await fsWrapper.mkdirAsync(artifactsDir);
}
}
/**
* 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.
* 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)) {
throw new Error('Could not find a path in error message');
}
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(source: string): string[] {
// TODO: Use a proper parser
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)) {
const dependencyPath = dependencyMatch[1];
const basenName = path.basename(dependencyPath);
dependencies.push(basenName);
}
}
});
return dependencies;
}
/**
* Callback to resolve dependencies with `solc.compile`.
* Throws error if contractSources not yet initialized.
* @param importPath Path to an imported dependency.
* @return Import contents object containing source code of dependency.
*/
export function findImportIfExist(contractSources: ContractSources, importPath: string): solc.ImportContents {
const fileName = path.basename(importPath);
const source = contractSources[fileName];
if (_.isUndefined(source)) {
throw new Error(`Contract source not found for ${fileName}`);
}
const importContents: solc.ImportContents = {
contents: source,
};
return importContents;
}
|