diff --git a/lib/contracts/code_generator.js b/lib/contracts/code_generator.js index 6b8306ae..9ff898af 100644 --- a/lib/contracts/code_generator.js +++ b/lib/contracts/code_generator.js @@ -1,5 +1,6 @@ let async = require('async'); let fs = require('../core/fs.js'); +const utils = require('../utils/utils.js'); require('ejs'); const Templates = { @@ -96,6 +97,15 @@ class CodeGenerator { cb(vanillaABI, contractsJSON); }); + this.events.setCommandHandlerOnce('code-generator:web3js', function(cb) { + self.buildWeb3JS(cb); + }); + + self.events.setCommandHandler('code-generator:contract', (contractName, cb) => { + let contract = self.contractsManager.contracts[contractName]; + self.buildContractJS(contractName, self.generateContractJSON(contractName, contract), cb); + }); + } generateContext() { @@ -250,24 +260,28 @@ class CodeGenerator { return result; } + generateContractJSON(className, contract) { + let contractJSON = {}; + + contractJSON.contract_name = className; + contractJSON.address = contract.deployedAddress; + contractJSON.code = contract.code; + contractJSON.runtime_bytecode = contract.runtimeBytecode; + contractJSON.real_runtime_bytecode = contract.realRuntimeBytecode; + contractJSON.swarm_hash = contract.swarmHash; + contractJSON.gas_estimates = contract.gasEstimates; + contractJSON.function_hashes = contract.functionHashes; + contractJSON.abi = contract.abiDefinition; + + return contractJSON; + } + generateContractsJSON() { let contracts = {}; for (let className in this.contractsManager.contracts) { let contract = this.contractsManager.contracts[className]; - let contractJSON = {}; - - contractJSON.contract_name = className; - contractJSON.address = contract.deployedAddress; - contractJSON.code = contract.code; - contractJSON.runtime_bytecode = contract.runtimeBytecode; - contractJSON.real_runtime_bytecode = contract.realRuntimeBytecode; - contractJSON.swarm_hash = contract.swarmHash; - contractJSON.gas_estimates = contract.gasEstimates; - contractJSON.function_hashes = contract.functionHashes; - contractJSON.abi = contract.abiDefinition; - - contracts[className] = contractJSON; + contracts[className] = this.generateContractJSON(className, contract); } return contracts; @@ -318,6 +332,58 @@ class CodeGenerator { cb(); }); } + + buildContractJS(contractName, contractJSON, cb) { + let contractCode = ""; + contractCode += "import web3 from 'Embark/web3';\n"; + contractCode += "import EmbarkJS from 'Embark/EmbarkJS';\n"; + contractCode += "let " + contractName + "JSONConfig = " + JSON.stringify(contractJSON) + ";\n"; + contractCode += "let " + contractName + " = new EmbarkJS.Contract(" + contractName + "JSONConfig);\n"; + + contractCode += "\n__embarkContext.execWhenReady(function() {\n"; + contractCode += "\n" + contractName + ".setProvider(web3.currentProvider);\n"; + contractCode += "\n" + contractName + ".options.from = web3.eth.defaultAccount;\n"; + contractCode += "\n});\n"; + + contractCode += "export default " + contractName + ";\n"; + cb(contractCode); + } + + buildWeb3JS(cb) { + const self = this; + let code = ""; + + async.waterfall([ + function getWeb3Location(next) { + self.events.request("version:get:web3", function(web3Version) { + if (web3Version === "1.0.0-beta") { + return next(null, utils.joinPath(fs.embarkPath("js/web3-1.0.min.js"))); + } else { + self.events.request("version:getPackageLocation", "web3", web3Version, function(err, location) { + return next(null, fs.dappPath(location)); + }); + } + }); + }, + function getImports(web3Location, next) { + web3Location = web3Location.replace(/\\/g, '/'); // Import paths must always have forward slashes + code += "\nimport Web3 from '" + web3Location + "';\n"; + + code += "\n if (typeof web3 !== 'undefined') {"; + code += "\n } else {"; + code += "\n var web3 = new Web3();\n"; + code += "\n }"; + + let providerCode = self.generateProvider(false); + code += providerCode; + code += "\nglobal.__embarkContext = __mainContext.__loadManagerInstance;\n"; + code += "\nwindow.web3 = web3;\n"; + code += "\nexport default web3;\n"; + next(null, code); + } + ], cb); + } + } module.exports = CodeGenerator; diff --git a/lib/contracts/contracts.js b/lib/contracts/contracts.js index 5b8a9329..6b12bc67 100644 --- a/lib/contracts/contracts.js +++ b/lib/contracts/contracts.js @@ -25,6 +25,11 @@ class ContractsManager { this.events.on(constants.events.contractConfigChanged, (newContracts) => { this.contractsConfig = newContracts; }); + + const self = this; + self.events.setCommandHandler('contracts:list', (cb) => { + cb(self.listContracts()); + }); } build(done) { diff --git a/lib/core/events.js b/lib/core/events.js index de406fd3..de28c189 100644 --- a/lib/core/events.js +++ b/lib/core/events.js @@ -41,9 +41,12 @@ EventEmitter.prototype.request = function() { EventEmitter.prototype.setCommandHandler = function(requestName, cb) { log("setting command handler for: ", requestName); - return this.on('request:' + requestName, function(_cb) { + let listener = function(_cb) { cb.call(this, ...arguments); - }); + }; + // unlike events, commands can only have 1 handler + this.removeAllListeners('request:' + requestName); + return this.on('request:' + requestName, listener); }; EventEmitter.prototype.setCommandHandlerOnce = function(requestName, cb) { diff --git a/lib/pipeline/pipeline.js b/lib/pipeline/pipeline.js index a9f2ee2f..b1129932 100644 --- a/lib/pipeline/pipeline.js +++ b/lib/pipeline/pipeline.js @@ -28,7 +28,7 @@ class Pipeline { async.waterfall([ function buildTheContracts(next) { - self.buildContracts(contractsJSON, next); + self.buildContracts(next); }, function buildWeb3(next) { self.buildWeb3JS(next); @@ -45,13 +45,15 @@ class Pipeline { next(); }, function writeContracts(next) { - async.each(Object.keys(contractsJSON), (contractName, eachCb) => { - self.buildContractJS(contractName, (err, contractCode) => { - let filePath = fs.dappPath(".embark", contractName + '.js'); - importsList["Embark/contracts/" + contractName] = filePath; - fs.writeFile(filePath, contractCode, eachCb); - }); - }, next); + self.events.request('contracts:list', (contracts) => { + async.each(contracts, (contract, eachCb) => { + self.events.request('code-generator:contract', contract.className, (contractCode) => { + let filePath = fs.dappPath(".embark", contract.className + '.js'); + importsList["Embark/contracts/" + contract.className] = filePath; + fs.writeFile(filePath, contractCode, eachCb); + }); + }, next); + }); }, function assetFileWrite(next) { async.eachOf(self.assetFiles, function (files, targetFile, cb) { @@ -172,84 +174,45 @@ class Pipeline { ); } - buildContracts(contractsJSON, callback) { - fs.mkdirp(fs.dappPath(this.buildDir, 'contracts'), (err) => { - if (err) { - return callback(err); + buildContracts(cb) { + const self = this; + + async.waterfall([ + function makeDirectory(next) { + fs.mkdirp(fs.dappPath(self.buildDir, 'contracts'), (err, _result) => { + next(err); + }); + }, + function getContracts(next) { + self.events.request('contracts:list', (contracts) => { + next(null, contracts); + }); + }, + function writeContractsJSON(contracts, next) { + async.each(contracts, (contract, eachCb) => { + fs.writeJson(fs.dappPath(self.buildDir, 'contracts', contract.className + ".json"), contract, {spaces: 2}, eachCb); + }, () => { next(); }); } - async.each(Object.keys(contractsJSON), (className, eachCb) => { - let contract = contractsJSON[className]; - fs.writeJson(fs.dappPath(this.buildDir, 'contracts', className + ".json"), contract, {spaces: 2}, eachCb); - }, callback); - }); - } - - buildContractJS(contractName, callback) { - fs.readFile(fs.dappPath(this.buildDir, 'contracts', contractName + '.json'), (err, contractJSON) => { - if (err) { - return callback(err); - } - contractJSON = contractJSON.toString(); - - let contractCode = ""; - contractCode += "import web3 from 'Embark/web3';\n"; - contractCode += "import EmbarkJS from 'Embark/EmbarkJS';\n"; - contractCode += "let " + contractName + "JSONConfig = " + contractJSON + ";\n"; - contractCode += "let " + contractName + " = new EmbarkJS.Contract(" + contractName + "JSONConfig);\n"; - - contractCode += "\n__embarkContext.execWhenReady(function() {\n"; - contractCode += "\n" + contractName + ".setProvider(web3.currentProvider);\n"; - contractCode += "\n" + contractName + ".options.from = web3.eth.defaultAccount;\n"; - contractCode += "\n});\n"; - - contractCode += "export default " + contractName + ";\n"; - callback(null, contractCode); - }); + ], cb); } buildWeb3JS(cb) { const self = this; - let code = ""; - async.waterfall([ - function getWeb3Location(next) { - self.events.request("version:get:web3", function(web3Version) { - if (web3Version === "1.0.0-beta") { - return next(null, utils.joinPath(fs.embarkPath("js/web3-1.0.min.js"))); - } else { - self.events.request("version:getPackageLocation", "web3", web3Version, function(err, location) { - return next(null, fs.dappPath(location)); - }); - } - }); - }, - function getImports(web3Location, next) { - web3Location = web3Location.replace(/\\/g, '/'); // Import paths must always have forward slashes - code += "\nimport Web3 from '" + web3Location + "';\n"; - - code += "\n if (typeof web3 !== 'undefined') {"; - code += "\n } else {"; - code += "\n var web3 = new Web3();\n"; - code += "\n }"; - - self.events.request('provider-code', function(providerCode) { - code += providerCode; - code += "\nglobal.__embarkContext = __mainContext.__loadManagerInstance;\n"; - code += "\nwindow.web3 = web3;\n"; - code += "\nexport default web3;\n"; - next(); - }); - }, function makeDirectory(next) { fs.mkdirp(fs.dappPath(".embark"), (err, _result) => { next(err); }); }, - function writeFile(next) { + function getWeb3Code(next) { + self.events.request('code-generator:web3js', next); + }, + function writeFile(code, next) { fs.writeFile(fs.dappPath(".embark", 'web3_instance.js'), code, next); } ], cb); } + } module.exports = Pipeline;