Make class methods that don't use 'this' static

This commit is contained in:
Amir Bandeali
2017-11-30 22:11:44 -08:00
parent d44d6ccfd8
commit ca9518c48c
4 changed files with 92 additions and 89 deletions

View File

@@ -20,77 +20,6 @@ import {utils} from './utils/utils';
const SOLIDITY_FILE_EXTENSION = '.sol';
/**
* Recursively retrieves Solidity source code from directory.
* @param dirPath Directory to search.
* @return Mapping of contract name to contract source.
*/
async function getContractSourcesAsync(dirPath: string): Promise<ContractSources> {
let dirContents: string[] = [];
try {
dirContents = await fsWrapper.readdirAsync(dirPath);
} catch (err) {
throw new Error(`No directory found at ${dirPath}`);
}
let sources: ContractSources = {};
for (const name of dirContents) {
const contentPath = `${dirPath}/${name}`;
if (path.extname(name) === SOLIDITY_FILE_EXTENSION) {
try {
const opts = {
encoding: 'utf8',
};
sources[name] = await fsWrapper.readFileAsync(contentPath, opts);
utils.consoleLog(`Reading ${name} source...`);
} catch (err) {
utils.consoleLog(`Could not find file at ${contentPath}`);
}
} else {
try {
const nestedSources = await getContractSourcesAsync(contentPath);
sources = {
...sources,
...nestedSources,
};
} catch (err) {
utils.consoleLog(`${contentPath} is not a directory or ${SOLIDITY_FILE_EXTENSION} file`);
}
}
}
return sources;
}
/**
* Searches Solidity source code for compiler version.
* @param source Source code of contract.
* @return Solc compiler version.
*/
function parseSolidityVersion(source: string): string {
const solcVersionMatch = source.match(/(?:solidity\s\^?)([0-9]{1,2}[.][0-9]{1,2}[.][0-9]{1,2})/);
if (_.isNull(solcVersionMatch)) {
throw new Error('Could not find Solidity version in source');
}
const solcVersion = solcVersionMatch[1];
return solcVersion;
}
/**
* 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.
*/
function getNormalizedErrMsg(errMsg: string): string {
const errPathMatch = errMsg.match(/(.*\.sol)/);
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;
}
export class Compiler {
private contractsDir: string;
private networkId: number;
@@ -98,7 +27,81 @@ export class Compiler {
private artifactsDir: string;
private contractSourcesIfExists?: ContractSources;
private solcErrors: Set<string>;
/**
* Recursively retrieves Solidity source code from directory.
* @param dirPath Directory to search.
* @return Mapping of contract name to contract source.
*/
private static async getContractSourcesAsync(dirPath: string): Promise<ContractSources> {
let dirContents: string[] = [];
try {
dirContents = await fsWrapper.readdirAsync(dirPath);
} catch (err) {
throw new Error(`No directory found at ${dirPath}`);
}
let sources: ContractSources = {};
for (const name of dirContents) {
const contentPath = `${dirPath}/${name}`;
if (path.extname(name) === SOLIDITY_FILE_EXTENSION) {
try {
const opts = {
encoding: 'utf8',
};
sources[name] = await fsWrapper.readFileAsync(contentPath, opts);
utils.consoleLog(`Reading ${name} source...`);
} catch (err) {
utils.consoleLog(`Could not find file at ${contentPath}`);
}
} else {
try {
const nestedSources = await Compiler.getContractSourcesAsync(contentPath);
sources = {
...sources,
...nestedSources,
};
} catch (err) {
utils.consoleLog(`${contentPath} is not a directory or ${SOLIDITY_FILE_EXTENSION} file`);
}
}
}
return sources;
}
/**
* Searches Solidity source code for compiler version.
* @param source Source code of contract.
* @return Solc compiler version.
*/
private static parseSolidityVersion(source: string): string {
const solcVersionMatch = source.match(/(?:solidity\s\^?)([0-9]{1,2}[.][0-9]{1,2}[.][0-9]{1,2})/);
if (_.isNull(solcVersionMatch)) {
throw new Error('Could not find Solidity version in source');
}
const solcVersion = solcVersionMatch[1];
return solcVersion;
}
/**
* 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.
*/
private static getNormalizedErrMsg(errMsg: string): string {
const errPathMatch = errMsg.match(/(.*\.sol)/);
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;
}
/**
* Instantiates a new instance of the Compiler class.
* @param opts Options specifying directories, network, and optimization settings.
* @return An instance of the Compiler class.
*/
constructor(opts: CompilerOptions) {
this.contractsDir = opts.contractsDir;
this.networkId = opts.networkId;
@@ -111,7 +114,7 @@ export class Compiler {
*/
public async compileAllAsync(): Promise<void> {
await this.createArtifactsDirIfDoesNotExistAsync();
this.contractSourcesIfExists = await getContractSourcesAsync(this.contractsDir);
this.contractSourcesIfExists = await Compiler.getContractSourcesAsync(this.contractsDir);
const contractBaseNames = _.keys(this.contractSourcesIfExists);
const compiledContractPromises = _.map(contractBaseNames, async (contractBaseName: string): Promise<void> => {
@@ -163,7 +166,7 @@ export class Compiler {
const input = {
[contractBaseName]: source,
};
const solcVersion = parseSolidityVersion(source);
const solcVersion = Compiler.parseSolidityVersion(source);
const fullSolcVersion = binPaths[solcVersion];
const solcBinPath = `./../solc/solc_bin/${fullSolcVersion}`;
const solcBin = require(solcBinPath);
@@ -179,7 +182,7 @@ export class Compiler {
if (!_.isUndefined(compiled.errors)) {
_.each(compiled.errors, errMsg => {
const normalizedErrMsg = getNormalizedErrMsg(errMsg);
const normalizedErrMsg = Compiler.getNormalizedErrMsg(errMsg);
this.solcErrors.add(normalizedErrMsg);
});
}

View File

@@ -14,7 +14,7 @@
"migrate:truffle": "npm run build; truffle migrate",
"migrate": "npm run build; node lib/deploy/cli.js migrate",
"lint": "tslint --project . 'migrations/*.ts' 'test/**/*.ts' 'util/*.ts' 'deploy/**/*.ts'",
"mocha": "npm run build; mocha lib/deploy/test/*_test.js"
"test:deployer": "npm run build; mocha lib/deploy/test/*_test.js"
},
"repository": {
"type": "git",

View File

@@ -42,13 +42,13 @@ contract('MultiSigWalletWithTimeLockExceptRemoveAuthorizedAddress', (accounts: s
describe('isFunctionRemoveAuthorizedAddress', () => {
it('should throw if data is not for removeAuthorizedAddress', async () => {
const data = multiSigWrapper.encodeFnArgs('addAuthorizedAddress', PROXY_ABI, [owners[0]]);
const data = MultiSigWrapper.encodeFnArgs('addAuthorizedAddress', PROXY_ABI, [owners[0]]);
return expect(multiSig.isFunctionRemoveAuthorizedAddress.call(data))
.to.be.rejectedWith(constants.INVALID_OPCODE);
});
it('should return true if data is for removeAuthorizedAddress', async () => {
const data = multiSigWrapper.encodeFnArgs('removeAuthorizedAddress', PROXY_ABI, [owners[0]]);
const data = MultiSigWrapper.encodeFnArgs('removeAuthorizedAddress', PROXY_ABI, [owners[0]]);
const isFunctionRemoveAuthorizedAddress = await multiSig.isFunctionRemoveAuthorizedAddress.call(data);
expect(isFunctionRemoveAuthorizedAddress).to.be.true();
});

View File

@@ -7,17 +7,7 @@ import {ContractInstance, TransactionDataParams} from './types';
export class MultiSigWrapper {
private multiSig: ContractInstance;
constructor(multiSigContractInstance: ContractInstance) {
this.multiSig = multiSigContractInstance;
}
public async submitTransactionAsync(destination: string, from: string,
dataParams: TransactionDataParams,
value: number = 0) {
const {name, abi, args = []} = dataParams;
const encoded = this.encodeFnArgs(name, abi, args);
return this.multiSig.submitTransaction(destination, value, encoded, {from});
}
public encodeFnArgs(name: string, abi: Web3.AbiDefinition[], args: any[]) {
public static encodeFnArgs(name: string, abi: Web3.AbiDefinition[], args: any[]) {
const abiEntity = _.find(abi, {name}) as Web3.MethodAbi;
if (_.isUndefined(abiEntity)) {
throw new Error(`Did not find abi entry for name: ${name}`);
@@ -31,4 +21,14 @@ export class MultiSigWrapper {
});
return funcSig + argsData.join('');
}
constructor(multiSigContractInstance: ContractInstance) {
this.multiSig = multiSigContractInstance;
}
public async submitTransactionAsync(destination: string, from: string,
dataParams: TransactionDataParams,
value: number = 0) {
const {name, abi, args = []} = dataParams;
const encoded = MultiSigWrapper.encodeFnArgs(name, abi, args);
return this.multiSig.submitTransaction(destination, value, encoded, {from});
}
}