pull/2054/head
Kosala Hemachandra 3 years ago
commit cc61424d5a
  1. 1
      .circleci/config.yml
  2. 21
      .eslintrc
  3. 2
      .eslintrc.json
  4. 2
      apps/remix-ide-e2e/src/helpers/init.ts
  5. 12
      apps/remix-ide-e2e/src/tests/gist.test.ts
  6. 39
      apps/remix-ide-e2e/src/tests/migrateFileSystem.test.ts
  7. 8
      apps/remix-ide-e2e/src/tests/plugin_api.ts
  8. 9
      apps/remix-ide-e2e/src/tests/recorder.test.ts
  9. 2
      apps/remix-ide-e2e/src/tests/signingMessage.test.ts
  10. 2
      apps/remix-ide-e2e/src/tests/solidityImport.test.ts
  11. 17
      apps/remix-ide-e2e/src/tests/solidityUnittests.test.ts
  12. 10
      apps/remix-ide-e2e/src/tests/transactionExecution.test.ts
  13. 4
      apps/remix-ide-e2e/src/tests/workspace.test.ts
  14. 167
      apps/remix-ide/src/app.js
  15. 3
      apps/remix-ide/src/app/components/vertical-icons.tsx
  16. 4
      apps/remix-ide/src/app/editor/editor.js
  17. 67
      apps/remix-ide/src/app/files/dgitProvider.js
  18. 235
      apps/remix-ide/src/app/files/fileManager.ts
  19. 235
      apps/remix-ide/src/app/files/fileProvider.js
  20. 4
      apps/remix-ide/src/app/files/workspaceFileProvider.js
  21. 10
      apps/remix-ide/src/app/panels/layout.ts
  22. 32
      apps/remix-ide/src/app/panels/tab-proxy.js
  23. 1
      apps/remix-ide/src/app/panels/terminal.js
  24. 2
      apps/remix-ide/src/app/plugins/config.ts
  25. 22
      apps/remix-ide/src/app/plugins/storage.ts
  26. 4
      apps/remix-ide/src/app/tabs/compile-tab.js
  27. 2
      apps/remix-ide/src/app/tabs/debugger-tab.js
  28. 77
      apps/remix-ide/src/app/tabs/runTab/model/recorder.js
  29. 2
      apps/remix-ide/src/app/tabs/test-tab.js
  30. 2
      apps/remix-ide/src/app/tabs/theme-module.js
  31. 107
      apps/remix-ide/src/assets/js/init.js
  32. 1
      apps/remix-ide/src/assets/js/lightning-fs.min.js
  33. 139
      apps/remix-ide/src/assets/js/migrate.js
  34. 40
      apps/remix-ide/src/blockchain/blockchain.js
  35. 6
      apps/remix-ide/src/blockchain/execution-context.js
  36. 1
      apps/remix-ide/src/blockchain/providers/injected.js
  37. 1
      apps/remix-ide/src/blockchain/providers/node.js
  38. 2
      apps/remix-ide/src/config.js
  39. 57
      apps/remix-ide/src/index.html
  40. 1
      apps/remix-ide/src/lib/helper.js
  41. 42
      apps/remix-ide/src/lib/query-params.js
  42. 57
      apps/remix-ide/src/production.index.html
  43. 7
      apps/remix-ide/src/remixAppManager.js
  44. 2
      libs/remix-astwalker/src/sourceMappings.ts
  45. 1
      libs/remix-astwalker/tsconfig.json
  46. 31
      libs/remix-astwalker/tsconfig.lib.json
  47. 14
      libs/remix-core-plugin/src/lib/compiler-content-imports.ts
  48. 5
      libs/remix-core-plugin/src/lib/compiler-fetch-and-compile.ts
  49. 26
      libs/remix-core-plugin/src/lib/compiler-metadata.ts
  50. 7
      libs/remix-core-plugin/src/lib/editor-context-listener.ts
  51. 16
      libs/remix-core-plugin/src/lib/gist-handler.ts
  52. 4
      libs/remix-core-plugin/src/lib/offset-line-to-column-converter.ts
  53. 2
      libs/remix-debug/src/cmdline/index.ts
  54. 2
      libs/remix-debug/src/code/breakpointManager.ts
  55. 2
      libs/remix-debug/src/code/codeManager.ts
  56. 2
      libs/remix-debug/src/code/codeUtils.ts
  57. 12
      libs/remix-debug/src/debugger/VmDebugger.ts
  58. 2
      libs/remix-debug/src/debugger/debugger.ts
  59. 10
      libs/remix-debug/src/debugger/solidityLocals.ts
  60. 9
      libs/remix-debug/src/debugger/stepManager.ts
  61. 8
      libs/remix-debug/src/solidity-decoder/decodeInfo.ts
  62. 2
      libs/remix-debug/src/solidity-decoder/internalCallTree.ts
  63. 2
      libs/remix-debug/src/solidity-decoder/localDecoder.ts
  64. 4
      libs/remix-debug/src/solidity-decoder/stateDecoder.ts
  65. 6
      libs/remix-debug/src/solidity-decoder/types/ArrayType.ts
  66. 2
      libs/remix-debug/src/solidity-decoder/types/DynamicByteArray.ts
  67. 6
      libs/remix-debug/src/solidity-decoder/types/Struct.ts
  68. 2
      libs/remix-debug/src/solidity-decoder/types/ValueType.ts
  69. 2
      libs/remix-debug/src/source/sourceMappingDecoder.ts
  70. 2
      libs/remix-debug/src/storage/mappingPreimages.ts
  71. 2
      libs/remix-debug/src/storage/storageResolver.ts
  72. 6
      libs/remix-debug/src/trace/traceCache.ts
  73. 4
      libs/remix-debug/src/trace/traceManager.ts
  74. 2
      libs/remix-debug/src/trace/traceStepManager.ts
  75. 4
      libs/remix-lib/src/execution/txFormat.ts
  76. 2
      libs/remix-lib/src/execution/txListener.ts
  77. 2
      libs/remix-lib/src/execution/txRunnerVM.ts
  78. 2
      libs/remix-lib/src/execution/txRunnerWeb3.ts
  79. 4
      libs/remix-lib/src/execution/typeConversion.ts
  80. 10
      libs/remix-lib/src/helpers/uiHelper.ts
  81. 1
      libs/remix-lib/src/index.ts
  82. 38
      libs/remix-lib/src/query-params.ts
  83. 2
      libs/remix-lib/src/storage.ts
  84. 2
      libs/remix-lib/src/types/ICompilerApi.ts
  85. 2
      libs/remix-lib/src/web3Provider/web3VmProvider.ts
  86. 2
      libs/remix-simulator/src/methods/txProcess.ts
  87. 4
      libs/remix-simulator/src/provider.ts
  88. 4
      libs/remix-solidity/src/compiler/compiler-utils.ts
  89. 4
      libs/remix-solidity/src/compiler/compiler.ts
  90. 6
      libs/remix-tests/src/compiler.ts
  91. 2
      libs/remix-tests/src/fileSystem.ts
  92. 2
      libs/remix-tests/src/index.ts
  93. 2
      libs/remix-tests/src/run.ts
  94. 2
      libs/remix-tests/src/runTestFiles.ts
  95. 2
      libs/remix-ui/app/src/index.ts
  96. 3
      libs/remix-ui/app/src/lib/remix-app/components/modals/modal-wrapper.tsx
  97. 1
      libs/remix-ui/app/src/lib/remix-app/context/context.tsx
  98. 3
      libs/remix-ui/app/src/lib/remix-app/remix-app.tsx
  99. 5
      libs/remix-ui/clipboard/src/lib/copy-to-clipboard/copy-to-clipboard.tsx
  100. 6
      libs/remix-ui/debugger-ui/src/lib/debugger-ui.tsx
  101. Some files were not shown because too many files have changed in this diff Show More

@ -20,7 +20,6 @@ jobs:
- COMMIT_AUTHOR_EMAIL: "yann@ethereum.org" - COMMIT_AUTHOR_EMAIL: "yann@ethereum.org"
- COMMIT_AUTHOR: "Circle CI" - COMMIT_AUTHOR: "Circle CI"
working_directory: ~/remix-project working_directory: ~/remix-project
steps: steps:
- checkout - checkout

@ -1,21 +0,0 @@
{
"root": true,
"parser": "@typescript-eslint/parser",
"parserOptions": {
"ecmaVersion": 2018,
"sourceType": "module",
"project": "./tsconfig.base.json"
},
"plugins": ["@typescript-eslint", "@nrwl/nx"],
"extends": "standard",
"rules": {
},
"overrides": [
{
"files": ["*.tsx"],
"rules": {
"@typescript-eslint/no-unused-vars": "off"
}
}
]
}

@ -1,6 +1,6 @@
{ {
"root": true, "root": true,
"ignorePatterns": ["**/*"], "ignorePatterns": [],
"plugins": ["@nrwl/nx"], "plugins": ["@nrwl/nx"],
"overrides": [ "overrides": [
{ {

@ -13,7 +13,7 @@ export default function (browser: NightwatchBrowser, callback: VoidFunction, url
.fullscreenWindow(() => { .fullscreenWindow(() => {
if (preloadPlugins) { if (preloadPlugins) {
initModules(browser, () => { initModules(browser, () => {
browser.clickLaunchIcon('solidity') browser.pause(2000).clickLaunchIcon('solidity')
.waitForElementVisible('[for="autoCompile"]') .waitForElementVisible('[for="autoCompile"]')
.click('[for="autoCompile"]') .click('[for="autoCompile"]')
.verify.elementPresent('[data-id="compilerContainerAutoCompile"]:checked') .verify.elementPresent('[data-id="compilerContainerAutoCompile"]:checked')

@ -36,9 +36,9 @@ module.exports = {
.addFile('File.sol', { content: '' }) .addFile('File.sol', { content: '' })
.executeScript(`remix.loadgist('${gistid}')`) .executeScript(`remix.loadgist('${gistid}')`)
// .perform((done) => { if (runtimeBrowser === 'chrome') { browser.openFile('gists') } done() }) // .perform((done) => { if (runtimeBrowser === 'chrome') { browser.openFile('gists') } done() })
.waitForElementVisible(`[data-id="treeViewLitreeViewItemgist-${gistid}"]`) .waitForElementVisible(`[data-id="treeViewLitreeViewItem${gistid}"]`)
.click(`[data-id="treeViewLitreeViewItemgist-${gistid}"]`) .click(`[data-id="treeViewLitreeViewItem${gistid}"]`)
.openFile(`gist-${gistid}/README.txt`) .openFile(`${gistid}/README.txt`)
// Remix publish to gist // Remix publish to gist
/* .click('*[data-id="fileExplorerNewFilepublishToGist"]') /* .click('*[data-id="fileExplorerNewFilepublishToGist"]')
.pause(2000) .pause(2000)
@ -140,9 +140,9 @@ module.exports = {
}) })
.setValue('*[data-id="gisthandlerModalDialogModalBody-react"] input[data-id="modalDialogCustomPromp"]', testData.validGistId) .setValue('*[data-id="gisthandlerModalDialogModalBody-react"] input[data-id="modalDialogCustomPromp"]', testData.validGistId)
.modalFooterOKClick('gisthandler') .modalFooterOKClick('gisthandler')
.openFile(`gist-${testData.validGistId}/README.txt`) .openFile(`${testData.validGistId}/README.txt`)
.waitForElementVisible(`div[title='default_workspace/gist-${testData.validGistId}/README.txt']`) .waitForElementVisible(`div[title='default_workspace/${testData.validGistId}/README.txt']`)
.assert.containsText(`div[title='default_workspace/gist-${testData.validGistId}/README.txt'] > span`, 'README.txt') .assert.containsText(`div[title='default_workspace/${testData.validGistId}/README.txt'] > span`, 'README.txt')
.end() .end()
} }
} }

@ -0,0 +1,39 @@
'use strict'
import { NightwatchBrowser } from 'nightwatch'
import init from '../helpers/init'
module.exports = {
before: function (browser: NightwatchBrowser, done: VoidFunction) {
init(browser, done, 'http://127.0.0.1:8080?e2e_testmigration=true', false)
},
'Should have README file with TEST README as content': function (browser: NightwatchBrowser) {
browser.waitForElementVisible('*[data-id="remixIdeSidePanel"]', 5000)
.waitForElementVisible('div[data-id="filePanelFileExplorerTree"]')
.openFile('TEST_README.txt')
.getEditorValue((content) => {
browser.assert.equal(content, 'TEST README')
})
},
'Should have a workspace_test': function (browser: NightwatchBrowser) {
browser.waitForElementVisible('*[data-id="remixIdeSidePanel"]', 5000)
.click('*[data-id="workspacesSelect"] option[value="workspace_test"]')
.waitForElementVisible('*[data-id="treeViewLitreeViewItemtest_contracts"]')
},
'Should have a sol file with test data': function (browser: NightwatchBrowser) {
browser.waitForElementVisible('*[data-id="remixIdeSidePanel"]', 5000)
.click('*[data-id="treeViewLitreeViewItemtest_contracts"]')
.openFile('test_contracts/1_Storage.sol')
.getEditorValue((content) => {
browser.assert.equal(content, 'testing')
})
},
'Should have a artifacts file with JSON test data': function (browser: NightwatchBrowser) {
browser.waitForElementVisible('*[data-id="remixIdeSidePanel"]', 5000)
.click('*[data-id="treeViewLitreeViewItemtest_contracts/artifacts"]')
.openFile('test_contracts/artifacts/Storage_metadata.json')
.getEditorValue((content) => {
const metadata = JSON.parse(content)
browser.assert.equal(metadata.test, 'data')
})
}
}

@ -64,7 +64,7 @@ const clearPayLoad = async (browser: NightwatchBrowser) => {
}) })
} }
const clickButton = async (browser: NightwatchBrowser, buttonText: string, waitResult: boolean = true) => { const clickButton = async (browser: NightwatchBrowser, buttonText: string, waitResult: boolean = true) => { // eslint-disable-line
return new Promise((resolve) => { return new Promise((resolve) => {
browser.useXpath().waitForElementVisible(`//*[@data-id='${buttonText}']`).pause(100) browser.useXpath().waitForElementVisible(`//*[@data-id='${buttonText}']`).pause(100)
.click(`//*[@data-id='${buttonText}']`, async () => { .click(`//*[@data-id='${buttonText}']`, async () => {
@ -107,7 +107,7 @@ const checkForAcceptAndRemember = async function (browser: NightwatchBrowser) {
* @return {Promise} * @return {Promise}
*/ */
const clickAndCheckLog = async (browser: NightwatchBrowser, buttonText: string, methodResult: any, eventResult: any, payload: any, waitResult: boolean = true) => { const clickAndCheckLog = async (browser: NightwatchBrowser, buttonText: string, methodResult: any, eventResult: any, payload: any, waitResult: boolean = true) => { // eslint-disable-line
if (payload) { if (payload) {
await setPayload(browser, payload) await setPayload(browser, payload)
} else { } else {
@ -235,7 +235,9 @@ module.exports = {
}, },
'Should write to file #group2': async function (browser: NightwatchBrowser) { 'Should write to file #group2': async function (browser: NightwatchBrowser) {
await clickAndCheckLog(browser, 'fileManager:writeFile', null, { event: 'fileSaved', args: ['README.txt'] }, ['README.txt', 'test']) await clickAndCheckLog(browser, 'fileManager:writeFile', null, { event: 'fileSaved', args: ['README.txt'] }, ['README.txt', 'test'])
await clickAndCheckLog(browser, 'fileManager:readFile', 'test', null, 'README.txt') browser.pause(4000, async () => {
await clickAndCheckLog(browser, 'fileManager:getFile', 'test', null, 'README.txt')
})
}, },
'Should set file #group2': async function (browser: NightwatchBrowser) { 'Should set file #group2': async function (browser: NightwatchBrowser) {
await clickAndCheckLog(browser, 'fileManager:setFile', null, { event: 'fileAdded', args: ['new.sol'] }, ['new.sol', 'test']) await clickAndCheckLog(browser, 'fileManager:setFile', null, { event: 'fileAdded', args: ['new.sol'] }, ['new.sol', 'test'])

@ -11,7 +11,7 @@ module.exports = {
return sources return sources
}, },
'Test Recorder': function (browser: NightwatchBrowser) { 'Run Scenario': function (browser: NightwatchBrowser) {
let addressRef let addressRef
browser.addFile('scenario.json', { content: records }) browser.addFile('scenario.json', { content: records })
.pause(5000) .pause(5000)
@ -34,7 +34,10 @@ module.exports = {
.perform(() => done()) .perform(() => done())
}) })
.click('*[data-id="deployAndRunClearInstances"]') .click('*[data-id="deployAndRunClearInstances"]')
.testContracts('testRecorder.sol', sources[0]['testRecorder.sol'], ['testRecorder'])
},
'Save scenario': function (browser: NightwatchBrowser) {
browser.testContracts('testRecorder.sol', sources[0]['testRecorder.sol'], ['testRecorder'])
.clickLaunchIcon('udapp') .clickLaunchIcon('udapp')
.createContract('12') .createContract('12')
.clickInstance(0) .clickInstance(0)
@ -45,7 +48,7 @@ module.exports = {
const modalOk = document.querySelector('[data-id="udappNotify-modal-footer-ok-react"]') as any const modalOk = document.querySelector('[data-id="udappNotify-modal-footer-ok-react"]') as any
modalOk.click() modalOk.click()
}) }).pause(1000)
.getEditorValue(function (result) { .getEditorValue(function (result) {
const parsed = JSON.parse(result) const parsed = JSON.parse(result)
browser.assert.equal(JSON.stringify(parsed.transactions[0].record.parameters), JSON.stringify(scenario.transactions[0].record.parameters)) browser.assert.equal(JSON.stringify(parsed.transactions[0].record.parameters), JSON.stringify(scenario.transactions[0].record.parameters))

@ -23,6 +23,8 @@ module.exports = {
console.log('signature', signature) console.log('signature', signature)
browser.assert.ok(typeof hash.value === 'string', 'type of hash.value must be String') browser.assert.ok(typeof hash.value === 'string', 'type of hash.value must be String')
browser.assert.ok(typeof signature.value === 'string', 'type of signature.value must be String') browser.assert.ok(typeof signature.value === 'string', 'type of signature.value must be String')
// we check here that the input is strictly "test message"
browser.assert.equal(signature.value, '0xaa8873317ebf3f34fbcc0eab3e9808d851352674c28a3d6b88dc84db6e10fc183a45bcec983a105964a13b54f18e43eceae29d982bf379826fb7ecfe0d42c6ba1b', 'signature should be tied to the input "test message"')
}) })
.addFile('signMassage.sol', sources[0]['signMassage.sol']) .addFile('signMassage.sol', sources[0]['signMassage.sol'])
.openFile('signMassage.sol') .openFile('signMassage.sol')

@ -18,7 +18,7 @@ module.exports = {
'Test Success Import #group1': function (browser: NightwatchBrowser) { 'Test Success Import #group1': function (browser: NightwatchBrowser) {
browser.addFile('Untitled1.sol', sources[1]['Untitled1.sol']) browser.addFile('Untitled1.sol', sources[1]['Untitled1.sol'])
.addFile('Untitled2.sol', sources[1]['Untitled2.sol']) .addFile('Untitled2.sol', sources[1]['Untitled2.sol']).pause(4000)
.openFile('Untitled1.sol') .openFile('Untitled1.sol')
.verifyContracts(['test6', 'test4', 'test5']) .verifyContracts(['test6', 'test4', 'test5'])
.pause(1000) .pause(1000)

@ -263,7 +263,7 @@ module.exports = {
.removeFile('tests/ballotFailedLog_test.sol', 'workspace_new') .removeFile('tests/ballotFailedLog_test.sol', 'workspace_new')
}, },
'Debug tests using debugger #group5': function (browser: NightwatchBrowser) { 'Debug tests using debugger #group7': function (browser: NightwatchBrowser) {
browser browser
.waitForElementPresent('*[data-id="verticalIconsKindfilePanel"]') .waitForElementPresent('*[data-id="verticalIconsKindfilePanel"]')
.addFile('tests/ballotFailedDebug_test.sol', sources[0]['tests/ballotFailedDebug_test.sol']) .addFile('tests/ballotFailedDebug_test.sol', sources[0]['tests/ballotFailedDebug_test.sol'])
@ -288,9 +288,10 @@ module.exports = {
.setValue('*[data-id="slider"]', new Array(1).fill(browser.Keys.RIGHT_ARROW)) .setValue('*[data-id="slider"]', new Array(1).fill(browser.Keys.RIGHT_ARROW))
.waitForElementContainsText('*[data-id="functionPanel"]', 'checkWinningProposalFailed()', 60000) .waitForElementContainsText('*[data-id="functionPanel"]', 'checkWinningProposalFailed()', 60000)
.waitForElementContainsText('*[data-id="functionPanel"]', 'vote(proposal)', 60000) .waitForElementContainsText('*[data-id="functionPanel"]', 'vote(proposal)', 60000)
.pause(1000) .pause(5000)
.checkVariableDebug('soliditylocals', locals) .checkVariableDebug('soliditylocals', locals)
.clickLaunchIcon('solidityUnitTesting') .pause(5000)
.clickLaunchIcon('solidityUnitTesting').pause(2000)
.scrollAndClick('#Check_winning_proposal_passed') .scrollAndClick('#Check_winning_proposal_passed')
.waitForElementContainsText('*[data-id="sidePanelSwapitTitle"]', 'DEBUGGER', 60000) .waitForElementContainsText('*[data-id="sidePanelSwapitTitle"]', 'DEBUGGER', 60000)
.waitForElementContainsText('*[data-id="functionPanel"]', 'checkWinningProposalPassed()', 60000) .waitForElementContainsText('*[data-id="functionPanel"]', 'checkWinningProposalPassed()', 60000)
@ -301,8 +302,8 @@ module.exports = {
.waitForElementContainsText('*[data-id="functionPanel"]', 'checkWinningProposalPassed()', 60000) .waitForElementContainsText('*[data-id="functionPanel"]', 'checkWinningProposalPassed()', 60000)
// remix_test.sol should be opened in editor // remix_test.sol should be opened in editor
.getEditorValue((content) => browser.assert.ok(content.indexOf('library Assert {') !== -1)) .getEditorValue((content) => browser.assert.ok(content.indexOf('library Assert {') !== -1))
.pause(1000) .pause(5000)
.clickLaunchIcon('solidityUnitTesting') .clickLaunchIcon('solidityUnitTesting').pause(2000)
.scrollAndClick('#Check_winning_proposal_again') .scrollAndClick('#Check_winning_proposal_again')
.waitForElementContainsText('*[data-id="sidePanelSwapitTitle"]', 'DEBUGGER', 60000) .waitForElementContainsText('*[data-id="sidePanelSwapitTitle"]', 'DEBUGGER', 60000)
.waitForElementContainsText('*[data-id="functionPanel"]', 'checkWinningProposalAgain()', 60000) .waitForElementContainsText('*[data-id="functionPanel"]', 'checkWinningProposalAgain()', 60000)
@ -311,9 +312,9 @@ module.exports = {
.setValue('*[data-id="slider"]', new Array(1).fill(browser.Keys.RIGHT_ARROW)) .setValue('*[data-id="slider"]', new Array(1).fill(browser.Keys.RIGHT_ARROW))
.waitForElementContainsText('*[data-id="functionPanel"]', 'equal(a, b, message)', 60000) .waitForElementContainsText('*[data-id="functionPanel"]', 'equal(a, b, message)', 60000)
.waitForElementContainsText('*[data-id="functionPanel"]', 'checkWinningProposalAgain()', 60000) .waitForElementContainsText('*[data-id="functionPanel"]', 'checkWinningProposalAgain()', 60000)
.pause(1000) .pause(5000)
.clickLaunchIcon('solidityUnitTesting') .clickLaunchIcon('solidityUnitTesting').pause(5000)
.scrollAndClick('#Check_winnin_proposal_with_return_value') .scrollAndClick('#Check_winnin_proposal_with_return_value').pause(5000)
.waitForElementContainsText('*[data-id="sidePanelSwapitTitle"]', 'DEBUGGER', 60000) .waitForElementContainsText('*[data-id="sidePanelSwapitTitle"]', 'DEBUGGER', 60000)
.waitForElementContainsText('*[data-id="functionPanel"]', 'checkWinninProposalWithReturnValue()', 60000) .waitForElementContainsText('*[data-id="functionPanel"]', 'checkWinninProposalWithReturnValue()', 60000)
// eslint-disable-next-line dot-notation // eslint-disable-next-line dot-notation

@ -202,10 +202,10 @@ module.exports = {
.addFile('Storage.sol', sources[6]['Storage.sol']) .addFile('Storage.sol', sources[6]['Storage.sol'])
.addFile('Owner.sol', sources[6]['Owner.sol']) .addFile('Owner.sol', sources[6]['Owner.sol'])
.clickLaunchIcon('udapp') .clickLaunchIcon('udapp')
.createContract('42') .createContract('42, 24')
.openFile('Storage.sol') .openFile('Storage.sol')
.clickLaunchIcon('udapp') .clickLaunchIcon('udapp')
.createContract('') // this creation will fail if the component hasn't been properly reset. .createContract('102') // this creation will fail if the component hasn't been properly reset.
.clickInstance(1) .clickInstance(1)
.clickFunction('store - transact (not payable)', { types: 'uint256 num', values: '24' }) .clickFunction('store - transact (not payable)', { types: 'uint256 num', values: '24' })
.testFunction('last', // we check if the contract is actually reachable. .testFunction('last', // we check if the contract is actually reachable.
@ -375,7 +375,7 @@ contract C {
/** /**
* @dev Set contract deployer as owner * @dev Set contract deployer as owner
*/ */
constructor(uint p) { constructor(uint p, uint o) {
owner = msg.sender; // 'msg.sender' is sender of current call, contract deployer for a constructor owner = msg.sender; // 'msg.sender' is sender of current call, contract deployer for a constructor
emit OwnerSet(address(0), owner); emit OwnerSet(address(0), owner);
} }
@ -412,6 +412,10 @@ contract C {
uint256 number; uint256 number;
constructor(uint p) {
}
/** /**
* @dev Store value in variable * @dev Store value in variable
* @param num value to store * @param num value to store

@ -19,9 +19,9 @@ module.exports = {
browser browser
.pause(5000) .pause(5000)
.refresh() .refresh()
.pause(10000) .waitForElementVisible('#editorView', 30000)
.getEditorValue((content) => { .getEditorValue((content) => {
browser.assert.ok(content.indexOf('contract Ballot {') !== -1, 'content doesn\'t include Ballot contract') browser.assert.ok(content.indexOf('contract Ballot {') !== -1, 'content includes Ballot contract')
}) })
}, },

@ -11,6 +11,7 @@ import { VerticalIcons } from './app/components/vertical-icons'
import { LandingPage } from './app/ui/landing-page/landing-page' import { LandingPage } from './app/ui/landing-page/landing-page'
import { MainPanel } from './app/components/main-panel' import { MainPanel } from './app/components/main-panel'
import { PermissionHandlerPlugin } from './app/plugins/permission-handler-plugin' import { PermissionHandlerPlugin } from './app/plugins/permission-handler-plugin'
import { AstWalker } from '@remix-project/remix-astwalker'
import { WalkthroughService } from './walkthroughService' import { WalkthroughService } from './walkthroughService'
@ -18,6 +19,7 @@ import { OffsetToLineColumnConverter, CompilerMetadata, CompilerArtefacts, Fetch
import Registry from './app/state/registry' import Registry from './app/state/registry'
import { ConfigPlugin } from './app/plugins/config' import { ConfigPlugin } from './app/plugins/config'
import { StoragePlugin } from './app/plugins/storage'
import { Layout } from './app/panels/layout' import { Layout } from './app/panels/layout'
import { NotificationPlugin } from './app/plugins/notification' import { NotificationPlugin } from './app/plugins/notification'
import { Blockchain } from './blockchain/blockchain.js' import { Blockchain } from './blockchain/blockchain.js'
@ -27,7 +29,7 @@ const isElectron = require('is-electron')
const remixLib = require('@remix-project/remix-lib') const remixLib = require('@remix-project/remix-lib')
const QueryParams = require('./lib/query-params') import { QueryParams } from '@remix-project/remix-lib'
const Storage = remixLib.Storage const Storage = remixLib.Storage
const RemixDProvider = require('./app/files/remixDProvider') const RemixDProvider = require('./app/files/remixDProvider')
const Config = require('./config') const Config = require('./config')
@ -51,10 +53,9 @@ const { TabProxy } = require('./app/panels/tab-proxy.js')
class AppComponent { class AppComponent {
constructor () { constructor () {
const self = this this.appManager = new RemixAppManager({})
self.appManager = new RemixAppManager({}) this.queryParams = new QueryParams()
self.queryParams = new QueryParams() this._components = {}
self._components = {}
// setup storage // setup storage
const configStorage = new Storage('config-v0.8:') const configStorage = new Storage('config-v0.8:')
@ -63,54 +64,55 @@ class AppComponent {
Registry.getInstance().put({ api: config, name: 'config' }) Registry.getInstance().put({ api: config, name: 'config' })
// load file system // load file system
self._components.filesProviders = {} this._components.filesProviders = {}
self._components.filesProviders.browser = new FileProvider('browser') this._components.filesProviders.browser = new FileProvider('browser')
Registry.getInstance().put({ Registry.getInstance().put({
api: self._components.filesProviders.browser, api: this._components.filesProviders.browser,
name: 'fileproviders/browser' name: 'fileproviders/browser'
}) })
self._components.filesProviders.localhost = new RemixDProvider( this._components.filesProviders.localhost = new RemixDProvider(
self.appManager this.appManager
) )
Registry.getInstance().put({ Registry.getInstance().put({
api: self._components.filesProviders.localhost, api: this._components.filesProviders.localhost,
name: 'fileproviders/localhost' name: 'fileproviders/localhost'
}) })
self._components.filesProviders.workspace = new WorkspaceFileProvider() this._components.filesProviders.workspace = new WorkspaceFileProvider()
Registry.getInstance().put({ Registry.getInstance().put({
api: self._components.filesProviders.workspace, api: this._components.filesProviders.workspace,
name: 'fileproviders/workspace' name: 'fileproviders/workspace'
}) })
Registry.getInstance().put({ Registry.getInstance().put({
api: self._components.filesProviders, api: this._components.filesProviders,
name: 'fileproviders' name: 'fileproviders'
}) })
} }
async run () { async run () {
const self = this
// APP_MANAGER // APP_MANAGER
const appManager = self.appManager const appManager = this.appManager
const pluginLoader = self.appManager.pluginLoader const pluginLoader = this.appManager.pluginLoader
self.panels = {} this.panels = {}
self.workspace = pluginLoader.get() this.workspace = pluginLoader.get()
self.engine = new RemixEngine() this.engine = new RemixEngine()
self.engine.register(appManager) this.engine.register(appManager);
const matomoDomains = { const matomoDomains = {
'remix-alpha.ethereum.org': 27, 'remix-alpha.ethereum.org': 27,
'remix-beta.ethereum.org': 25, 'remix-beta.ethereum.org': 25,
'remix.ethereum.org': 23 'remix.ethereum.org': 23
} }
self.showMatamo = this.showMatamo =
matomoDomains[window.location.hostname] && matomoDomains[window.location.hostname] &&
!Registry.getInstance() !Registry.getInstance()
.get('config') .get('config')
.api.exists('settings/matomo-analytics') .api.exists('settings/matomo-analytics')
self.walkthroughService = new WalkthroughService( this.walkthroughService = new WalkthroughService(
appManager, appManager,
self.showMatamo this.showMatamo
) )
const hosts = ['127.0.0.1:8080', '192.168.0.101:8080', 'localhost:8080'] const hosts = ['127.0.0.1:8080', '192.168.0.101:8080', 'localhost:8080']
@ -124,10 +126,10 @@ class AppComponent {
// SERVICES // SERVICES
// ----------------- gist service --------------------------------- // ----------------- gist service ---------------------------------
self.gistHandler = new GistHandler() this.gistHandler = new GistHandler()
// ----------------- theme service --------------------------------- // ----------------- theme service ---------------------------------
self.themeModule = new ThemeModule() this.themeModule = new ThemeModule()
Registry.getInstance().put({ api: self.themeModule, name: 'themeModule' }) Registry.getInstance().put({ api: this.themeModule, name: 'themeModule' })
// ----------------- editor service ---------------------------- // ----------------- editor service ----------------------------
const editor = new Editor() // wrapper around ace editor const editor = new Editor() // wrapper around ace editor
@ -142,6 +144,9 @@ class AppComponent {
// ----------------- dGit provider --------------------------------- // ----------------- dGit provider ---------------------------------
const dGitProvider = new DGitProvider() const dGitProvider = new DGitProvider()
// ----------------- Storage plugin ---------------------------------
const storagePlugin = new StoragePlugin()
// ----------------- import content service ------------------------ // ----------------- import content service ------------------------
const contentImport = new CompilerImports() const contentImport = new CompilerImports()
@ -185,24 +190,24 @@ class AppComponent {
} }
} }
) )
const contextualListener = new EditorContextListener() const contextualListener = new EditorContextListener(new AstWalker())
self.notification = new NotificationPlugin() this.notification = new NotificationPlugin()
const configPlugin = new ConfigPlugin() const configPlugin = new ConfigPlugin()
self.layout = new Layout() this.layout = new Layout()
const permissionHandler = new PermissionHandlerPlugin() const permissionHandler = new PermissionHandlerPlugin()
self.engine.register([ this.engine.register([
permissionHandler, permissionHandler,
self.layout, this.layout,
self.notification, this.notification,
self.gistHandler, this.gistHandler,
configPlugin, configPlugin,
blockchain, blockchain,
contentImport, contentImport,
self.themeModule, this.themeModule,
editor, editor,
fileManager, fileManager,
compilerMetadataGenerator, compilerMetadataGenerator,
@ -214,47 +219,48 @@ class AppComponent {
web3Provider, web3Provider,
fetchAndCompile, fetchAndCompile,
dGitProvider, dGitProvider,
storagePlugin,
hardhatProvider, hardhatProvider,
self.walkthroughService this.walkthroughService
]) ])
// LAYOUT & SYSTEM VIEWS // LAYOUT & SYSTEM VIEWS
const appPanel = new MainPanel() const appPanel = new MainPanel()
Registry.getInstance().put({ api: self.mainview, name: 'mainview' }) Registry.getInstance().put({ api: this.mainview, name: 'mainview' })
const tabProxy = new TabProxy(fileManager, editor) const tabProxy = new TabProxy(fileManager, editor)
self.engine.register([appPanel, tabProxy]) this.engine.register([appPanel, tabProxy])
// those views depend on app_manager // those views depend on app_manager
self.menuicons = new VerticalIcons() this.menuicons = new VerticalIcons()
self.sidePanel = new SidePanel() this.sidePanel = new SidePanel()
self.hiddenPanel = new HiddenPanel() this.hiddenPanel = new HiddenPanel()
const pluginManagerComponent = new PluginManagerComponent( const pluginManagerComponent = new PluginManagerComponent(
appManager, appManager,
self.engine this.engine
) )
const filePanel = new FilePanel(appManager) const filePanel = new FilePanel(appManager)
const landingPage = new LandingPage( const landingPage = new LandingPage(
appManager, appManager,
self.menuicons, this.menuicons,
fileManager, fileManager,
filePanel, filePanel,
contentImport contentImport
) )
self.settings = new SettingsTab( this.settings = new SettingsTab(
Registry.getInstance().get('config').api, Registry.getInstance().get('config').api,
editor, editor,
appManager appManager
) )
self.engine.register([ this.engine.register([
self.menuicons, this.menuicons,
landingPage, landingPage,
self.hiddenPanel, this.hiddenPanel,
self.sidePanel, this.sidePanel,
filePanel, filePanel,
pluginManagerComponent, pluginManagerComponent,
self.settings this.settings
]) ])
// CONTENT VIEWS & DEFAULT PLUGINS // CONTENT VIEWS & DEFAULT PLUGINS
@ -283,7 +289,7 @@ class AppComponent {
contentImport contentImport
) )
self.engine.register([ this.engine.register([
compileTab, compileTab,
run, run,
debug, debug,
@ -295,7 +301,7 @@ class AppComponent {
filePanel.slitherHandle filePanel.slitherHandle
]) ])
self.layout.panels = { this.layout.panels = {
tabs: { plugin: tabProxy, active: true }, tabs: { plugin: tabProxy, active: true },
editor: { plugin: editor, active: true }, editor: { plugin: editor, active: true },
main: { plugin: appPanel, active: false }, main: { plugin: appPanel, active: false },
@ -306,47 +312,46 @@ class AppComponent {
async activate () { async activate () {
const queryParams = new QueryParams() const queryParams = new QueryParams()
const params = queryParams.get() const params = queryParams.get()
const self = this
if (isElectron()) { if (isElectron()) {
self.appManager.activatePlugin('remixd') this.appManager.activatePlugin('remixd')
} }
try { try {
self.engine.register(await self.appManager.registeredPlugins()) this.engine.register(await this.appManager.registeredPlugins())
} catch (e) { } catch (e) {
console.log("couldn't register iframe plugins", e.message) console.log("couldn't register iframe plugins", e.message)
} }
await self.appManager.activatePlugin(['layout']) await this.appManager.activatePlugin(['layout'])
await self.appManager.activatePlugin(['notification']) await this.appManager.activatePlugin(['notification'])
await self.appManager.activatePlugin(['editor']) await this.appManager.activatePlugin(['editor'])
await self.appManager.activatePlugin(['permissionhandler', 'theme', 'fileManager', 'compilerMetadata', 'compilerArtefacts', 'network', 'web3Provider', 'offsetToLineColumnConverter']) await this.appManager.activatePlugin(['permissionhandler', 'theme', 'fileManager', 'compilerMetadata', 'compilerArtefacts', 'network', 'web3Provider', 'offsetToLineColumnConverter'])
await self.appManager.activatePlugin(['mainPanel', 'menuicons', 'tabs']) await this.appManager.activatePlugin(['mainPanel', 'menuicons', 'tabs'])
await self.appManager.activatePlugin(['sidePanel']) // activating host plugin separately await this.appManager.activatePlugin(['sidePanel']) // activating host plugin separately
await self.appManager.activatePlugin(['home']) await this.appManager.activatePlugin(['home'])
await self.appManager.activatePlugin(['settings', 'config']) await this.appManager.activatePlugin(['settings', 'config'])
await self.appManager.activatePlugin(['hiddenPanel', 'pluginManager', 'contextualListener', 'terminal', 'blockchain', 'fetchAndCompile', 'contentImport', 'gistHandler']) await this.appManager.activatePlugin(['hiddenPanel', 'pluginManager', 'contextualListener', 'terminal', 'blockchain', 'fetchAndCompile', 'contentImport', 'gistHandler'])
await self.appManager.activatePlugin(['settings']) await this.appManager.activatePlugin(['settings'])
await self.appManager.activatePlugin(['walkthrough']) await this.appManager.activatePlugin(['walkthrough','storage'])
self.appManager.on( this.appManager.on(
'filePanel', 'filePanel',
'workspaceInitializationCompleted', 'workspaceInitializationCompleted',
async () => { async () => {
await self.appManager.registerContextMenuItems() await this.appManager.registerContextMenuItems()
} }
) )
await self.appManager.activatePlugin(['filePanel']) await this.appManager.activatePlugin(['filePanel'])
// Set workspace after initial activation // Set workspace after initial activation
self.appManager.on('editor', 'editorMounted', () => { this.appManager.on('editor', 'editorMounted', () => {
if (Array.isArray(self.workspace)) { if (Array.isArray(this.workspace)) {
self.appManager this.appManager
.activatePlugin(self.workspace) .activatePlugin(this.workspace)
.then(async () => { .then(async () => {
try { try {
if (params.deactivate) { if (params.deactivate) {
await self.appManager.deactivatePlugin( await this.appManager.deactivatePlugin(
params.deactivate.split(',') params.deactivate.split(',')
) )
} }
@ -355,21 +360,21 @@ class AppComponent {
} }
if (params.code) { if (params.code) {
// if code is given in url we focus on solidity plugin // if code is given in url we focus on solidity plugin
self.menuicons.select('solidity') this.menuicons.select('solidity')
} else { } else {
// If plugins are loaded from the URL params, we focus on the last one. // If plugins are loaded from the URL params, we focus on the last one.
if ( if (
self.appManager.pluginLoader.current === 'queryParams' && this.appManager.pluginLoader.current === 'queryParams' &&
self.workspace.length > 0 this.workspace.length > 0
) { self.menuicons.select(self.workspace[self.workspace.length - 1]) } ) { this.menuicons.select(this.workspace[this.workspace.length - 1]) }
} }
if (params.call) { if (params.call) {
const callDetails = params.call.split('//') const callDetails = params.call.split('//')
if (callDetails.length > 1) { if (callDetails.length > 1) {
self.appManager.call('notification', 'toast', `initiating ${callDetails[0]} ...`) this.appManager.call('notification', 'toast', `initiating ${callDetails[0]} ...`)
// @todo(remove the timeout when activatePlugin is on 0.3.0) // @todo(remove the timeout when activatePlugin is on 0.3.0)
self.appManager.call(...callDetails).catch(console.error) this.appManager.call(...callDetails).catch(console.error)
} }
} }
}) })
@ -377,7 +382,7 @@ class AppComponent {
} }
}) })
// activate solidity plugin // activate solidity plugin
self.appManager.activatePlugin(['solidity', 'udapp']) this.appManager.activatePlugin(['solidity', 'udapp'])
// Load and start the service who manager layout and frame // Load and start the service who manager layout and frame
} }
} }

@ -1,13 +1,11 @@
// eslint-disable-next-line no-use-before-define // eslint-disable-next-line no-use-before-define
import React from 'react' import React from 'react'
import ReactDOM from 'react-dom' import ReactDOM from 'react-dom'
import Registry from '../state/registry'
import packageJson from '../../../../../package.json' import packageJson from '../../../../../package.json'
import { Plugin } from '@remixproject/engine' import { Plugin } from '@remixproject/engine'
import { EventEmitter } from 'events' import { EventEmitter } from 'events'
import { IconRecord, RemixUiVerticalIconsPanel } from '@remix-ui/vertical-icons-panel' import { IconRecord, RemixUiVerticalIconsPanel } from '@remix-ui/vertical-icons-panel'
import { Profile } from '@remixproject/plugin-utils' import { Profile } from '@remixproject/plugin-utils'
import { timeStamp } from 'console'
const profile = { const profile = {
name: 'menuicons', name: 'menuicons',
@ -95,7 +93,6 @@ export class VerticalIcons extends Plugin {
*/ */
select (name: string) { select (name: string) {
// TODO: Only keep `this.emit` (issue#2210) // TODO: Only keep `this.emit` (issue#2210)
console.log(name, this)
this.emit('showContent', name) this.emit('showContent', name)
this.events.emit('showContent', name) this.events.emit('showContent', name)
} }

@ -149,11 +149,11 @@ class Editor extends Plugin {
if (this.saveTimeout) { if (this.saveTimeout) {
window.clearTimeout(this.saveTimeout) window.clearTimeout(this.saveTimeout)
} }
this.triggerEvent('contentChanged', [])
this.saveTimeout = window.setTimeout(() => { this.saveTimeout = window.setTimeout(() => {
this.triggerEvent('contentChanged', [])
this.triggerEvent('requiringToSaveCurrentfile', []) this.triggerEvent('requiringToSaveCurrentfile', [])
}, 5000) }, 500)
} }
_switchSession (path) { _switchSession (path) {

@ -51,8 +51,8 @@ class DGitProvider extends Plugin {
async getGitConfig () { async getGitConfig () {
const workspace = await this.call('filePanel', 'getCurrentWorkspace') const workspace = await this.call('filePanel', 'getCurrentWorkspace')
return { return {
fs: window.remixFileSystem, fs: window.remixFileSystemCallback,
dir: workspace.absolutePath dir: addSlash(workspace.absolutePath)
} }
} }
@ -61,6 +61,7 @@ class DGitProvider extends Plugin {
corsProxy: 'https://corsproxy.remixproject.org/', corsProxy: 'https://corsproxy.remixproject.org/',
http, http,
onAuth: url => { onAuth: url => {
url
const auth = { const auth = {
username: input.token, username: input.token,
password: '' password: ''
@ -90,7 +91,9 @@ class DGitProvider extends Plugin {
...await this.getGitConfig(), ...await this.getGitConfig(),
...cmd ...cmd
}) })
await this.call('fileManager', 'refresh') setTimeout(async () => {
await this.call('fileManager', 'refresh')
}, 1000)
} }
async rm (cmd) { async rm (cmd) {
@ -98,7 +101,9 @@ class DGitProvider extends Plugin {
...await this.getGitConfig(), ...await this.getGitConfig(),
...cmd ...cmd
}) })
await this.call('fileManager', 'refresh') setTimeout(async () => {
await this.call('fileManager', 'refresh')
}, 1000)
} }
async checkout (cmd) { async checkout (cmd) {
@ -106,7 +111,9 @@ class DGitProvider extends Plugin {
...await this.getGitConfig(), ...await this.getGitConfig(),
...cmd ...cmd
}) })
await this.call('fileManager', 'refresh') setTimeout(async () => {
await this.call('fileManager', 'refresh')
}, 1000)
} }
async log (cmd) { async log (cmd) {
@ -122,6 +129,7 @@ class DGitProvider extends Plugin {
try { try {
remotes = await git.listRemotes({ ...await this.getGitConfig() }) remotes = await git.listRemotes({ ...await this.getGitConfig() })
} catch (e) { } catch (e) {
console.log(e)
} }
return remotes return remotes
} }
@ -131,7 +139,9 @@ class DGitProvider extends Plugin {
...await this.getGitConfig(), ...await this.getGitConfig(),
...cmd ...cmd
}) })
await this.call('fileManager', 'refresh') setTimeout(async () => {
await this.call('fileManager', 'refresh')
}, 1000)
return status return status
} }
@ -196,7 +206,7 @@ class DGitProvider extends Plugin {
async setIpfsConfig (config) { async setIpfsConfig (config) {
this.ipfsconfig = config this.ipfsconfig = config
return new Promise((resolve, reject) => { return new Promise((resolve) => {
resolve(this.checkIpfsConfig()) resolve(this.checkIpfsConfig())
}) })
} }
@ -239,7 +249,9 @@ class DGitProvider extends Plugin {
} }
const result = await git.clone(cmd) const result = await git.clone(cmd)
await this.call('fileManager', 'refresh') setTimeout(async () => {
await this.call('fileManager', 'refresh')
}, 1000)
return result return result
} }
@ -272,7 +284,9 @@ class DGitProvider extends Plugin {
...await this.getGitConfig() ...await this.getGitConfig()
} }
const result = await git.pull(cmd) const result = await git.pull(cmd)
await this.call('fileManager', 'refresh') setTimeout(async () => {
await this.call('fileManager', 'refresh')
}, 1000)
return result return result
} }
@ -289,7 +303,9 @@ class DGitProvider extends Plugin {
...await this.getGitConfig() ...await this.getGitConfig()
} }
const result = await git.fetch(cmd) const result = await git.fetch(cmd)
await this.call('fileManager', 'refresh') setTimeout(async () => {
await this.call('fileManager', 'refresh')
}, 1000)
return result return result
} }
@ -299,7 +315,7 @@ class DGitProvider extends Plugin {
const files = await this.getDirectory('/') const files = await this.getDirectory('/')
this.filesToSend = [] this.filesToSend = []
for (const file of files) { for (const file of files) {
const c = window.remixFileSystem.readFileSync(`${workspace.absolutePath}/${file}`) const c = await window.remixFileSystem.readFile(`${workspace.absolutePath}/${file}`)
const ob = { const ob = {
path: file, path: file,
content: c content: c
@ -319,10 +335,10 @@ class DGitProvider extends Plugin {
this.filesToSend = [] this.filesToSend = []
const data = new FormData() const data = new FormData()
files.forEach(async (file) => { for (const file of files) {
const c = window.remixFileSystem.readFileSync(`${workspace.absolutePath}/${file}`) const c = await window.remixFileSystem.readFile(`${workspace.absolutePath}/${file}`)
data.append('file', new Blob([c]), `base/${file}`) data.append('file', new Blob([c]), `base/${file}`)
}) }
// get last commit data // get last commit data
let ob let ob
try { try {
@ -409,7 +425,7 @@ class DGitProvider extends Plugin {
} catch (error) { } catch (error) {
throw new Error(error) throw new Error(error)
} }
}; }
async importIPFSFiles (config, cid, workspace) { async importIPFSFiles (config, cid, workspace) {
const ipfs = IpfsHttpClient(config) const ipfs = IpfsHttpClient(config)
@ -428,10 +444,10 @@ class DGitProvider extends Plugin {
} }
const dir = path.dirname(file.path) const dir = path.dirname(file.path)
try { try {
this.createDirectories(`${workspace.absolutePath}/${dir}`) await this.createDirectories(`${workspace.absolutePath}/${dir}`)
} catch (e) { throw new Error(e) } } catch (e) { throw new Error(e) }
try { try {
window.remixFileSystem.writeFileSync(`${workspace.absolutePath}/${file.path}`, Buffer.concat(content) || new Uint8Array()) await window.remixFileSystem.writeFile(`${workspace.absolutePath}/${file.path}`, Buffer.concat(content) || new Uint8Array())
} catch (e) { throw new Error(e) } } catch (e) { throw new Error(e) }
} }
} catch (e) { } catch (e) {
@ -450,7 +466,7 @@ class DGitProvider extends Plugin {
} }
_xLen = ((localStorage[_x].length + _x.length) * 2) _xLen = ((localStorage[_x].length + _x.length) * 2)
_lsTotal += _xLen _lsTotal += _xLen
}; }
return (_lsTotal / 1024).toFixed(2) return (_lsTotal / 1024).toFixed(2)
} }
@ -467,7 +483,9 @@ class DGitProvider extends Plugin {
} else { } else {
result = await this.importIPFSFiles(this.remixIPFS, cid, workspace) || await this.importIPFSFiles(this.ipfsconfig, cid, workspace) || await this.importIPFSFiles(this.globalIPFSConfig, cid, workspace) result = await this.importIPFSFiles(this.remixIPFS, cid, workspace) || await this.importIPFSFiles(this.ipfsconfig, cid, workspace) || await this.importIPFSFiles(this.globalIPFSConfig, cid, workspace)
} }
await this.call('fileManager', 'refresh') setTimeout(async () => {
await this.call('fileManager', 'refresh')
}, 1000)
if (!result) throw new Error(`Cannot pull files from IPFS at ${cid}`) if (!result) throw new Error(`Cannot pull files from IPFS at ${cid}`)
} }
@ -495,7 +513,7 @@ class DGitProvider extends Plugin {
const files = await this.getDirectory('/') const files = await this.getDirectory('/')
this.filesToSend = [] this.filesToSend = []
for (const file of files) { for (const file of files) {
const c = window.remixFileSystem.readFileSync(`${workspace.absolutePath}/${file}`) const c = await window.remixFileSystem.readFile(`${workspace.absolutePath}/${file}`)
zip.file(file, c) zip.file(file, c)
} }
await zip.generateAsync({ await zip.generateAsync({
@ -515,8 +533,8 @@ class DGitProvider extends Plugin {
if (i > 0) previouspath = '/' + directories.slice(0, i).join('/') if (i > 0) previouspath = '/' + directories.slice(0, i).join('/')
const finalPath = previouspath + '/' + directories[i] const finalPath = previouspath + '/' + directories[i]
try { try {
if (!window.remixFileSystem.existsSync(finalPath)) { if (!await window.remixFileSystem.exists(finalPath)) {
window.remixFileSystem.mkdirSync(finalPath) await window.remixFileSystem.mkdir(finalPath)
} }
} catch (e) { } catch (e) {
console.log(e) console.log(e)
@ -547,6 +565,11 @@ class DGitProvider extends Plugin {
} }
} }
const addSlash = (file) => {
if (!file.startsWith('/'))file = '/' + file
return file
}
const normalize = (filesList) => { const normalize = (filesList) => {
const folders = [] const folders = []
const files = [] const files = []

@ -1,12 +1,11 @@
'use strict' 'use strict'
import async from 'async'
import { Plugin } from '@remixproject/engine' import { Plugin } from '@remixproject/engine'
import * as packageJson from '../../../../../package.json' import * as packageJson from '../../../../../package.json'
import Registry from '../state/registry' import Registry from '../state/registry'
import { EventEmitter } from 'events' import { EventEmitter } from 'events'
import { RemixAppManager } from '../../../../../libs/remix-ui/plugin-manager/src/types' import { RemixAppManager } from '../../../../../libs/remix-ui/plugin-manager/src/types'
import { fileChangedToastMsg } from '@remix-ui/helper' import { fileChangedToastMsg } from '@remix-ui/helper'
const helper = require('../../lib/helper.js') import helper from '../../lib/helper.js'
/* /*
attach to files event (removed renamed) attach to files event (removed renamed)
@ -47,7 +46,7 @@ class FileManager extends Plugin {
getFolder: (path: any) => Promise<unknown> getFolder: (path: any) => Promise<unknown>
setFile: (path: any, data: any) => Promise<unknown> setFile: (path: any, data: any) => Promise<unknown>
switchFile: (path: any) => Promise<void> switchFile: (path: any) => Promise<void>
constructor (editor, appManager) { constructor(editor, appManager) {
super(profile) super(profile)
this.mode = 'browser' this.mode = 'browser'
this.openedFiles = {} // list all opened files this.openedFiles = {} // list all opened files
@ -59,19 +58,19 @@ class FileManager extends Plugin {
this.init() this.init()
} }
getOpenedFiles () { getOpenedFiles() {
return this.openedFiles return this.openedFiles
} }
setMode (mode) { setMode(mode) {
this.mode = mode this.mode = mode
} }
limitPluginScope (path) { limitPluginScope(path) {
return path.replace(/^\/browser\//, '').replace(/^browser\//, '') // forbids plugin to access the root filesystem return path.replace(/^\/browser\//, '').replace(/^browser\//, '') // forbids plugin to access the root filesystem
} }
normalize (path) { normalize(path) {
return path.replace(/^\/+/, '') return path.replace(/^\/+/, '')
} }
@ -80,7 +79,7 @@ class FileManager extends Plugin {
* @param {string} path path of the file/directory * @param {string} path path of the file/directory
* @param {string} message message to display if path doesn't exist. * @param {string} message message to display if path doesn't exist.
*/ */
async _handleExists (path: string, message?:string) { async _handleExists(path: string, message?: string) {
const exists = await this.exists(path) const exists = await this.exists(path)
if (!exists) { if (!exists) {
@ -93,7 +92,7 @@ class FileManager extends Plugin {
* @param {string} path path of the file/directory * @param {string} path path of the file/directory
* @param {string} message message to display if path is not a file. * @param {string} message message to display if path is not a file.
*/ */
async _handleIsFile (path, message) { async _handleIsFile(path, message) {
const isFile = await this.isFile(path) const isFile = await this.isFile(path)
if (!isFile) { if (!isFile) {
@ -106,7 +105,7 @@ class FileManager extends Plugin {
* @param {string} path path of the file/directory * @param {string} path path of the file/directory
* @param {string} message message to display if path is not a directory. * @param {string} message message to display if path is not a directory.
*/ */
async _handleIsDir (path: string, message?: string) { async _handleIsDir(path: string, message?: string) {
const isDir = await this.isDirectory(path) const isDir = await this.isDirectory(path)
if (!isDir) { if (!isDir) {
@ -115,7 +114,7 @@ class FileManager extends Plugin {
} }
/** The current opened file */ /** The current opened file */
file () { file() {
try { try {
const file = this.currentFile() const file = this.currentFile()
@ -131,12 +130,12 @@ class FileManager extends Plugin {
* @param {string} path path of the directory or file * @param {string} path path of the directory or file
* @returns {boolean} true if the path exists * @returns {boolean} true if the path exists
*/ */
exists (path) { async exists(path) {
try { try {
path = this.normalize(path) path = this.normalize(path)
path = this.limitPluginScope(path) path = this.limitPluginScope(path)
const provider = this.fileProviderOf(path) const provider = this.fileProviderOf(path)
const result = provider.exists(path) const result = await provider.exists(path)
return result return result
} catch (e) { } catch (e) {
@ -147,7 +146,7 @@ class FileManager extends Plugin {
/* /*
* refresh the file explorer * refresh the file explorer
*/ */
refresh () { refresh() {
const provider = this.fileProviderOf('/') const provider = this.fileProviderOf('/')
// emit rootFolderChanged so that File Explorer reloads the file tree // emit rootFolderChanged so that File Explorer reloads the file tree
provider.event.emit('rootFolderChanged', provider.workspace || '/') provider.event.emit('rootFolderChanged', provider.workspace || '/')
@ -159,10 +158,9 @@ class FileManager extends Plugin {
* @param {string} path path of the directory or file * @param {string} path path of the directory or file
* @returns {boolean} true if path is a file. * @returns {boolean} true if path is a file.
*/ */
isFile (path) { async isFile(path) {
const provider = this.fileProviderOf(path) const provider = this.fileProviderOf(path)
const result = provider.isFile(path) const result = await provider.isFile(path)
return result return result
} }
@ -171,7 +169,7 @@ class FileManager extends Plugin {
* @param {string} path path of the directory * @param {string} path path of the directory
* @returns {boolean} true if path is a directory. * @returns {boolean} true if path is a directory.
*/ */
async isDirectory (path) { async isDirectory(path) {
const provider = this.fileProviderOf(path) const provider = this.fileProviderOf(path)
const result = await provider.isDirectory(path) const result = await provider.isDirectory(path)
@ -183,7 +181,7 @@ class FileManager extends Plugin {
* @param {string} path path of the file * @param {string} path path of the file
* @returns {void} * @returns {void}
*/ */
async open (path) { async open(path) {
path = this.normalize(path) path = this.normalize(path)
path = this.limitPluginScope(path) path = this.limitPluginScope(path)
path = this.getPathFromUrl(path).file path = this.getPathFromUrl(path).file
@ -198,7 +196,7 @@ class FileManager extends Plugin {
* @param {string} data content to write on the file * @param {string} data content to write on the file
* @returns {void} * @returns {void}
*/ */
async writeFile (path, data) { async writeFile(path, data) {
try { try {
path = this.normalize(path) path = this.normalize(path)
path = this.limitPluginScope(path) path = this.limitPluginScope(path)
@ -220,7 +218,7 @@ class FileManager extends Plugin {
* @param {string} path path of the file * @param {string} path path of the file
* @returns {string} content of the file * @returns {string} content of the file
*/ */
async readFile (path) { async readFile(path) {
try { try {
path = this.normalize(path) path = this.normalize(path)
path = this.limitPluginScope(path) path = this.limitPluginScope(path)
@ -238,7 +236,7 @@ class FileManager extends Plugin {
* @param {string} dest path of the destrination file * @param {string} dest path of the destrination file
* @returns {void} * @returns {void}
*/ */
async copyFile (src, dest, customName) { async copyFile(src, dest, customName) {
try { try {
src = this.normalize(src) src = this.normalize(src)
dest = this.normalize(dest) dest = this.normalize(dest)
@ -264,7 +262,7 @@ class FileManager extends Plugin {
* @param {string} dest path of the destination dir * @param {string} dest path of the destination dir
* @returns {void} * @returns {void}
*/ */
async copyDir (src, dest) { async copyDir(src, dest) {
try { try {
src = this.normalize(src) src = this.normalize(src)
dest = this.normalize(dest) dest = this.normalize(dest)
@ -280,7 +278,7 @@ class FileManager extends Plugin {
} }
} }
async inDepthCopy (src, dest, count = 0) { async inDepthCopy(src, dest, count = 0) {
const content = await this.readdir(src) const content = await this.readdir(src)
let copiedFolderPath = count === 0 ? dest + '/' + `Copy_${helper.extractNameFromKey(src)}` : dest + '/' + helper.extractNameFromKey(src) let copiedFolderPath = count === 0 ? dest + '/' + `Copy_${helper.extractNameFromKey(src)}` : dest + '/' + helper.extractNameFromKey(src)
copiedFolderPath = await helper.createNonClashingDirNameAsync(copiedFolderPath, this) copiedFolderPath = await helper.createNonClashingDirNameAsync(copiedFolderPath, this)
@ -302,7 +300,7 @@ class FileManager extends Plugin {
* @param {string} newPath new path of the file/directory * @param {string} newPath new path of the file/directory
* @returns {void} * @returns {void}
*/ */
async rename (oldPath, newPath) { async rename(oldPath, newPath) {
try { try {
oldPath = this.normalize(oldPath) oldPath = this.normalize(oldPath)
newPath = this.normalize(newPath) newPath = this.normalize(newPath)
@ -342,7 +340,7 @@ class FileManager extends Plugin {
* @param {string} path path of the new directory * @param {string} path path of the new directory
* @returns {void} * @returns {void}
*/ */
async mkdir (path) { async mkdir(path) {
try { try {
path = this.normalize(path) path = this.normalize(path)
path = this.limitPluginScope(path) path = this.limitPluginScope(path)
@ -350,8 +348,7 @@ class FileManager extends Plugin {
throw createError({ code: 'EEXIST', message: `Cannot create directory ${path}` }) throw createError({ code: 'EEXIST', message: `Cannot create directory ${path}` })
} }
const provider = this.fileProviderOf(path) const provider = this.fileProviderOf(path)
return await provider.createDir(path)
return provider.createDir(path)
} catch (e) { } catch (e) {
throw new Error(e) throw new Error(e)
} }
@ -362,7 +359,7 @@ class FileManager extends Plugin {
* @param {string} path path of the directory * @param {string} path path of the directory
* @returns {string[]} list of the file/directory name in this directory * @returns {string[]} list of the file/directory name in this directory
*/ */
async readdir (path) { async readdir(path) {
try { try {
path = this.normalize(path) path = this.normalize(path)
path = this.limitPluginScope(path) path = this.limitPluginScope(path)
@ -387,7 +384,7 @@ class FileManager extends Plugin {
* @param {string} path path of the directory/file to remove * @param {string} path path of the directory/file to remove
* @returns {void} * @returns {void}
*/ */
async remove (path) { async remove(path) {
try { try {
path = this.normalize(path) path = this.normalize(path)
path = this.limitPluginScope(path) path = this.limitPluginScope(path)
@ -399,7 +396,7 @@ class FileManager extends Plugin {
} }
} }
init () { init() {
this._deps = { this._deps = {
config: this._components.registry.get('config').api, config: this._components.registry.get('config').api,
browserExplorer: this._components.registry.get('fileproviders/browser').api, browserExplorer: this._components.registry.get('fileproviders/browser').api,
@ -427,15 +424,15 @@ class FileManager extends Plugin {
this.switchFile = this.open this.switchFile = this.open
} }
fileAddedEvent (path) { fileAddedEvent(path) {
this.emit('fileAdded', path) this.emit('fileAdded', path)
} }
fileChangedEvent (path) { fileChangedEvent(path) {
this.emit('fileChanged', path) this.emit('fileChanged', path)
} }
fileRenamedEvent (oldName, newName, isFolder) { fileRenamedEvent(oldName, newName, isFolder) {
if (!isFolder) { if (!isFolder) {
this._deps.config.set('currentFile', '') this._deps.config.set('currentFile', '')
this.editor.discard(oldName) this.editor.discard(oldName)
@ -445,9 +442,9 @@ class FileManager extends Plugin {
} }
this.openFile(newName) this.openFile(newName)
} else { } else {
for (var k in this.openedFiles) { for (const k in this.openedFiles) {
if (k.indexOf(oldName + '/') === 0) { if (k.indexOf(oldName + '/') === 0) {
var newAbsolutePath = k.replace(oldName, newName) const newAbsolutePath = k.replace(oldName, newName)
this.openedFiles[newAbsolutePath] = newAbsolutePath this.openedFiles[newAbsolutePath] = newAbsolutePath
delete this.openedFiles[k] delete this.openedFiles[k]
if (this._deps.config.get('currentFile') === k) { if (this._deps.config.get('currentFile') === k) {
@ -461,19 +458,19 @@ class FileManager extends Plugin {
this.events.emit('fileRenamed', oldName, newName, isFolder) this.events.emit('fileRenamed', oldName, newName, isFolder)
} }
currentFileProvider () { currentFileProvider() {
var path = this.currentPath() const path = this.currentPath()
if (path) { if (path) {
return this.fileProviderOf(path) return this.fileProviderOf(path)
} }
return null return null
} }
currentFile () { currentFile() {
return this.editor.current() return this.editor.current()
} }
async closeAllFiles () { async closeAllFiles() {
// TODO: Only keep `this.emit` (issue#2210) // TODO: Only keep `this.emit` (issue#2210)
this.emit('filesAllClosed') this.emit('filesAllClosed')
this.events.emit('filesAllClosed') this.events.emit('filesAllClosed')
@ -482,7 +479,7 @@ class FileManager extends Plugin {
} }
} }
async closeFile (name) { async closeFile(name) {
delete this.openedFiles[name] delete this.openedFiles[name]
if (!Object.keys(this.openedFiles).length) { if (!Object.keys(this.openedFiles).length) {
this._deps.config.set('currentFile', '') this._deps.config.set('currentFile', '')
@ -495,18 +492,18 @@ class FileManager extends Plugin {
this.events.emit('fileClosed', name) this.events.emit('fileClosed', name)
} }
currentPath () { currentPath() {
var currentFile = this._deps.config.get('currentFile') const currentFile = this._deps.config.get('currentFile')
return this.extractPathOf(currentFile) return this.extractPathOf(currentFile)
} }
extractPathOf (file) { extractPathOf(file) {
var reg = /(.*)(\/).*/ const reg = /(.*)(\/).*/
var path = reg.exec(file) const path = reg.exec(file)
return path ? path[1] : '/' return path ? path[1] : '/'
} }
getFileContent (path) { getFileContent(path) {
const provider = this.fileProviderOf(path) const provider = this.fileProviderOf(path)
if (!provider) throw createError({ code: 'ENOENT', message: `${path} not available` }) if (!provider) throw createError({ code: 'ENOENT', message: `${path} not available` })
@ -520,19 +517,19 @@ class FileManager extends Plugin {
}) })
} }
async setFileContent (path, content) { async setFileContent(path, content) {
if (this.currentRequest) { if (this.currentRequest) {
const canCall = await this.askUserPermission('writeFile', '') const canCall = await this.askUserPermission('writeFile', '')
const required = this.appManager.isRequired(this.currentRequest.from) const required = this.appManager.isRequired(this.currentRequest.from)
if (canCall && !required) { if (canCall && !required) {
// inform the user about modification after permission is granted and even if permission was saved before // inform the user about modification after permission is granted and even if permission was saved before
this.call('notification','toast', fileChangedToastMsg(this.currentRequest.from, path)) this.call('notification', 'toast', fileChangedToastMsg(this.currentRequest.from, path))
} }
} }
return await this._setFileInternal(path, content) return await this._setFileInternal(path, content)
} }
_setFileInternal (path, content) { _setFileInternal(path, content) {
const provider = this.fileProviderOf(path) const provider = this.fileProviderOf(path)
if (!provider) throw createError({ code: 'ENOENT', message: `${path} not available` }) if (!provider) throw createError({ code: 'ENOENT', message: `${path} not available` })
// TODO : Add permission // TODO : Add permission
@ -547,19 +544,6 @@ class FileManager extends Plugin {
}) })
} }
_saveAsCopy (path, content) {
const fileProvider = this.fileProviderOf(path)
if (fileProvider) {
helper.createNonClashingNameWithPrefix(path, fileProvider, '', (error, copyName) => {
if (error) {
copyName = path + '.' + this.currentRequest.from
}
this._setFileInternal(copyName, content)
this.openFile(copyName)
})
}
}
/** /**
* Try to resolve the given file path (the actual path in the file system) * Try to resolve the given file path (the actual path in the file system)
* e.g if it's specified a github link, npm library, or any external content, * e.g if it's specified a github link, npm library, or any external content,
@ -567,7 +551,7 @@ class FileManager extends Plugin {
* @param {string} file url we are trying to resolve * @param {string} file url we are trying to resolve
* @returns {{ string, provider }} file path resolved and its provider. * @returns {{ string, provider }} file path resolved and its provider.
*/ */
getPathFromUrl (file) { getPathFromUrl(file) {
const provider = this.fileProviderOf(file) const provider = this.fileProviderOf(file)
if (!provider) throw new Error(`no provider for ${file}`) if (!provider) throw new Error(`no provider for ${file}`)
return { return {
@ -581,7 +565,7 @@ class FileManager extends Plugin {
* @param {string} file path we are trying to resolve * @param {string} file path we are trying to resolve
* @returns {{ string, provider }} file url resolved and its provider. * @returns {{ string, provider }} file url resolved and its provider.
*/ */
getUrlFromPath (file) { getUrlFromPath(file) {
const provider = this.fileProviderOf(file) const provider = this.fileProviderOf(file)
if (!provider) throw new Error(`no provider for ${file}`) if (!provider) throw new Error(`no provider for ${file}`)
return { return {
@ -590,15 +574,15 @@ class FileManager extends Plugin {
} }
} }
removeTabsOf (provider) { removeTabsOf(provider) {
for (var tab in this.openedFiles) { for (const tab in this.openedFiles) {
if (this.fileProviderOf(tab).type === provider.type) { if (this.fileProviderOf(tab).type === provider.type) {
this.fileRemovedEvent(tab) this.fileRemovedEvent(tab)
} }
} }
} }
fileRemovedEvent (path) { fileRemovedEvent(path) {
if (path === this._deps.config.get('currentFile')) { if (path === this._deps.config.get('currentFile')) {
this._deps.config.set('currentFile', '') this._deps.config.set('currentFile', '')
} }
@ -610,32 +594,35 @@ class FileManager extends Plugin {
this.openFile() this.openFile()
} }
unselectCurrentFile () { async unselectCurrentFile() {
this.saveCurrentFile() await this.saveCurrentFile()
this._deps.config.set('currentFile', '') this._deps.config.set('currentFile', '')
// TODO: Only keep `this.emit` (issue#2210) // TODO: Only keep `this.emit` (issue#2210)
this.emit('noFileSelected') this.emit('noFileSelected')
this.events.emit('noFileSelected') this.events.emit('noFileSelected')
} }
async openFile (file?: string) { async openFile(file?: string) {
if (!file) { if (!file) {
this.emit('noFileSelected') this.emit('noFileSelected')
this.events.emit('noFileSelected') this.events.emit('noFileSelected')
} else { } else {
file = this.normalize(file) file = this.normalize(file)
this.saveCurrentFile() await this.saveCurrentFile()
const resolved = this.getPathFromUrl(file) const resolved = this.getPathFromUrl(file)
file = resolved.file file = resolved.file
const provider = resolved.provider const provider = resolved.provider
this._deps.config.set('currentFile', file) this._deps.config.set('currentFile', file)
this.openedFiles[file] = file this.openedFiles[file] = file
await (() => {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
provider.get(file, (error, content) => { provider.get(file, (error, content) => {
if (error) { if (error) {
console.log(error) console.log(error)
reject(error) reject(error)
} else {
if (provider.isReadOnly(file)) {
this.editor.openReadOnly(file, content)
} else { } else {
if (provider.isReadOnly(file)) { if (provider.isReadOnly(file)) {
this.editor.openReadOnly(file, content) this.editor.openReadOnly(file, content)
@ -647,9 +634,13 @@ class FileManager extends Plugin {
this.events.emit('currentFileChanged', file) this.events.emit('currentFileChanged', file)
resolve(true) resolve(true)
} }
}) // TODO: Only keep `this.emit` (issue#2210)
this.emit('currentFileChanged', file)
this.events.emit('currentFileChanged', file)
resolve(true)
}
}) })
})() })
} }
} }
@ -659,7 +650,7 @@ class FileManager extends Plugin {
* *
*/ */
async getProviderOf (file) { async getProviderOf(file) {
const cancall = await this.askUserPermission('getProviderByName') const cancall = await this.askUserPermission('getProviderByName')
if (cancall) { if (cancall) {
return file ? this.fileProviderOf(file) : this.currentFileProvider() return file ? this.fileProviderOf(file) : this.currentFileProvider()
@ -672,18 +663,18 @@ class FileManager extends Plugin {
* *
*/ */
async getProviderByName (name) { async getProviderByName(name) {
const cancall = await this.askUserPermission('getProviderByName') const cancall = await this.askUserPermission('getProviderByName')
if (cancall) { if (cancall) {
return this.getProvider(name) return this.getProvider(name)
} }
} }
getProvider (name) { getProvider(name) {
return this._deps.filesProviders[name] return this._deps.filesProviders[name]
} }
fileProviderOf (file) { fileProviderOf(file) {
if (file.startsWith('localhost') || this.mode === 'localhost') { if (file.startsWith('localhost') || this.mode === 'localhost') {
return this._deps.filesProviders.localhost return this._deps.filesProviders.localhost
} }
@ -694,7 +685,7 @@ class FileManager extends Plugin {
} }
// returns the list of directories inside path // returns the list of directories inside path
dirList (path) { dirList(path) {
const dirPaths = [] const dirPaths = []
const collectList = (path) => { const collectList = (path) => {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
@ -713,18 +704,18 @@ class FileManager extends Plugin {
return collectList(path) return collectList(path)
} }
isRemixDActive () { isRemixDActive() {
return this.appManager.isActive('remixd') return this.appManager.isActive('remixd')
} }
saveCurrentFile () { async saveCurrentFile() {
var currentFile = this._deps.config.get('currentFile') const currentFile = this._deps.config.get('currentFile')
if (currentFile && this.editor.current()) { if (currentFile && this.editor.current()) {
var input = this.editor.get(currentFile) const input = this.editor.get(currentFile)
if ((input !== null) && (input !== undefined)) { if ((input !== null) && (input !== undefined)) {
var provider = this.fileProviderOf(currentFile) const provider = this.fileProviderOf(currentFile)
if (provider) { if (provider) {
provider.set(currentFile, input) await provider.set(currentFile, input)
this.emit('fileSaved', currentFile) this.emit('fileSaved', currentFile)
} else { } else {
console.log('cannot save ' + currentFile + '. Does not belong to any explorer') console.log('cannot save ' + currentFile + '. Does not belong to any explorer')
@ -733,64 +724,64 @@ class FileManager extends Plugin {
} }
} }
syncEditor (path) { async syncEditor(path) {
var currentFile = this._deps.config.get('currentFile') const currentFile = this._deps.config.get('currentFile')
if (path !== currentFile) return if (path !== currentFile) return
var provider = this.fileProviderOf(currentFile) const provider = this.fileProviderOf(currentFile)
if (provider) { if (provider) {
provider.get(currentFile, (error, content) => { try{
if (error) console.log(error) const content = await provider.get(currentFile)
this.editor.setText(content) this.editor.setText(content)
}) }catch(error){
console.log(error)
}
} else { } else {
console.log('cannot save ' + currentFile + '. Does not belong to any explorer') console.log('cannot save ' + currentFile + '. Does not belong to any explorer')
} }
} }
setBatchFiles (filesSet, fileProvider, override, callback) { async setBatchFiles(filesSet, fileProvider, override, callback) {
const self = this const self = this
if (!fileProvider) fileProvider = 'browser' if (!fileProvider) fileProvider = 'workspace'
if (override === undefined) override = false if (override === undefined) override = false
for (const file of Object.keys(filesSet)) {
async.each(Object.keys(filesSet), (file, callback) => {
if (override) { if (override) {
try { try {
self._deps.filesProviders[fileProvider].set(file, filesSet[file].content) await self._deps.filesProviders[fileProvider].set(file, filesSet[file].content)
} catch (e) { } catch (e) {
return callback(e.message || e) callback(e.message || e)
} }
self.syncEditor(fileProvider + file) await self.syncEditor(fileProvider + file)
return callback() } else {
} try{
const name = await helper.createNonClashingNameAsync(file, self._deps.filesProviders[fileProvider])
helper.createNonClashingName(file, self._deps.filesProviders[fileProvider], if (helper.checkSpecialChars(name)) {
(error, name) => {
if (error) {
this.call('notification', 'alert', {
id: 'fileManagerAlert',
message: 'Unexpected error loading file ' + file + ': ' + error
})
} else if (helper.checkSpecialChars(name)) {
this.call('notification', 'alert', { this.call('notification', 'alert', {
id: 'fileManagerAlert', id: 'fileManagerAlert',
message: 'Special characters are not allowed in file names.' message: 'Special characters are not allowed in file names.'
}) })
} else { } else {
try { try {
self._deps.filesProviders[fileProvider].set(name, filesSet[file].content) await self._deps.filesProviders[fileProvider].set(name, filesSet[file].content)
} catch (e) { } catch (e) {
return callback(e.message || e) return callback(e.message || e)
} }
self.syncEditor(fileProvider + name) self.syncEditor(fileProvider + name)
} }
callback() }catch(error){
}) if (error) {
}, (error) => { this.call('notification', 'alert', {
if (callback) callback(error) id: 'fileManagerAlert',
}) message: 'Unexpected error loading file ' + file + ': ' + error
})
}
}
}
}
callback()
} }
currentWorkspace () { currentWorkspace() {
if (this.mode !== 'localhost') { if (this.mode !== 'localhost') {
const file = this.currentFile() || '' const file = this.currentFile() || ''
const provider = this.fileProviderOf(file) const provider = this.fileProviderOf(file)

@ -47,7 +47,7 @@ class FileProvider {
return this.externalFolders.includes(path) return this.externalFolders.includes(path)
} }
discardChanges (path, toastCb, modalCb) { async discardChanges (path, toastCb, modalCb) {
this.remove(path) this.remove(path)
const compilerImport = new CompilerImports() const compilerImport = new CompilerImports()
this.providerExternalsStorage.keys().map(value => { this.providerExternalsStorage.keys().map(value => {
@ -56,11 +56,11 @@ class FileProvider {
this.getNormalizedName(value), this.getNormalizedName(value),
true, true,
(loadingMsg) => { toastCb(loadingMsg) }, (loadingMsg) => { toastCb(loadingMsg) },
(error, content, cleanUrl, type, url) => { async (error, content, cleanUrl, type, url) => {
if (error) { if (error) {
modalCb(error) modalCb(error)
} else { } else {
this.addExternal(type + '/' + cleanUrl, content, url) await this.addExternal(type + '/' + cleanUrl, content, url)
} }
} }
) )
@ -71,48 +71,48 @@ class FileProvider {
async exists (path) { async exists (path) {
// todo check the type (directory/file) as well #2386 // todo check the type (directory/file) as well #2386
// currently it is not possible to have a file and folder with same path // currently it is not possible to have a file and folder with same path
const ret = this._exists(path) const ret = await this._exists(path)
return ret return ret
} }
_exists (path) { async _exists (path) {
path = this.getPathFromUrl(path) || path // ensure we actually use the normalized path from here path = this.getPathFromUrl(path) || path // ensure we actually use the normalized path from here
var unprefixedpath = this.removePrefix(path) var unprefixedpath = this.removePrefix(path)
return path === this.type ? true : window.remixFileSystem.existsSync(unprefixedpath) return path === this.type ? true : await window.remixFileSystem.exists(unprefixedpath)
} }
init (cb) { init (cb) {
cb() cb()
} }
get (path, cb) { async get (path, cb) {
cb = cb || function () {} cb = cb || function () { /* do nothing. */ }
path = this.getPathFromUrl(path) || path // ensure we actually use the normalized path from here path = this.getPathFromUrl(path) || path // ensure we actually use the normalized path from here
var unprefixedpath = this.removePrefix(path) var unprefixedpath = this.removePrefix(path)
var exists = window.remixFileSystem.existsSync(unprefixedpath) try {
if (!exists) return cb(null, null) const content = await window.remixFileSystem.readFile(unprefixedpath, 'utf8')
window.remixFileSystem.readFile(unprefixedpath, 'utf8', (err, content) => { if (cb) cb(null, content)
cb(err, content) return content
}) } catch (err) {
if (cb) cb(err, null)
throw new Error(err)
}
} }
set (path, content, cb) { async set (path, content, cb) {
cb = cb || function () {} cb = cb || function () { /* do nothing. */ }
var unprefixedpath = this.removePrefix(path) var unprefixedpath = this.removePrefix(path)
var exists = window.remixFileSystem.existsSync(unprefixedpath) const exists = await window.remixFileSystem.exists(unprefixedpath)
if (exists && window.remixFileSystem.readFileSync(unprefixedpath, 'utf8') === content) { if (exists && await window.remixFileSystem.readFile(unprefixedpath, 'utf8') === content) {
cb() if (cb) cb()
return true return null
}
if (!exists && unprefixedpath.indexOf('/') !== -1) {
// the last element is the filename and we should remove it
this.createDir(path.substr(0, path.lastIndexOf('/')))
} }
await this.createDir(path.substr(0, path.lastIndexOf('/')))
try { try {
window.remixFileSystem.writeFileSync(unprefixedpath, content) await window.remixFileSystem.writeFile(unprefixedpath, content, 'utf8')
} catch (e) { } catch (e) {
cb(e) if (cb) cb(e)
return false return false
} }
if (!exists) { if (!exists) {
@ -120,84 +120,88 @@ class FileProvider {
} else { } else {
this.event.emit('fileChanged', this._normalizePath(unprefixedpath)) this.event.emit('fileChanged', this._normalizePath(unprefixedpath))
} }
cb() if (cb) cb()
return true return true
} }
createDir (path, cb) { async createDir (path, cb) {
const unprefixedpath = this.removePrefix(path) const unprefixedpath = this.removePrefix(path)
const paths = unprefixedpath.split('/') const paths = unprefixedpath.split('/')
if (paths.length && paths[0] === '') paths.shift() if (paths.length && paths[0] === '') paths.shift()
let currentCheck = '' let currentCheck = ''
paths.forEach((value) => { for (const value of paths) {
currentCheck = currentCheck + '/' + value currentCheck = currentCheck + '/' + value
if (!window.remixFileSystem.existsSync(currentCheck)) { if (!await window.remixFileSystem.exists(currentCheck)) {
window.remixFileSystem.mkdirSync(currentCheck) try {
this.event.emit('folderAdded', this._normalizePath(currentCheck)) await window.remixFileSystem.mkdir(currentCheck)
} catch (error) {
console.log(error)
}
} }
}) }
currentCheck = ''
for (const value of paths) {
currentCheck = currentCheck + '/' + value
this.event.emit('folderAdded', this._normalizePath(currentCheck))
}
if (cb) cb() if (cb) cb()
} }
// this will not add a folder as readonly but keep the original url to be able to restore it later // this will not add a folder as readonly but keep the original url to be able to restore it later
addExternal (path, content, url) { async addExternal (path, content, url) {
if (url) this.addNormalizedName(path, url) if (url) this.addNormalizedName(path, url)
return this.set(path, content) return await this.set(path, content)
} }
isReadOnly (path) { isReadOnly (path) {
return false return false
} }
isDirectory (path) { async isDirectory (path) {
const unprefixedpath = this.removePrefix(path) const unprefixedpath = this.removePrefix(path)
return path === this.type ? true : (await window.remixFileSystem.stat(unprefixedpath)).isDirectory()
return path === this.type ? true : window.remixFileSystem.statSync(unprefixedpath).isDirectory()
} }
isFile (path) { async isFile (path) {
path = this.getPathFromUrl(path) || path // ensure we actually use the normalized path from here path = this.getPathFromUrl(path) || path // ensure we actually use the normalized path from here
path = this.removePrefix(path) path = this.removePrefix(path)
return window.remixFileSystem.statSync(path).isFile() return (await window.remixFileSystem.stat(path)).isFile()
} }
/** /**
* Removes the folder recursively * Removes the folder recursively
* @param {*} path is the folder to be removed * @param {*} path is the folder to be removed
*/ */
remove (path) { async remove (path) {
return new Promise((resolve, reject) => { path = this.removePrefix(path)
path = this.removePrefix(path) if (await window.remixFileSystem.exists(path)) {
if (window.remixFileSystem.existsSync(path)) { const stat = await window.remixFileSystem.stat(path)
const stat = window.remixFileSystem.statSync(path) try {
try { if (!stat.isDirectory()) {
if (!stat.isDirectory()) { return (this.removeFile(path))
resolve(this.removeFile(path)) } else {
} else { const items = await window.remixFileSystem.readdir(path)
const items = window.remixFileSystem.readdirSync(path) if (items.length !== 0) {
if (items.length !== 0) { for (const item of items) {
items.forEach((item, index) => { const curPath = `${path}${path.endsWith('/') ? '' : '/'}${item}`
const curPath = `${path}${path.endsWith('/') ? '' : '/'}${item}` if ((await window.remixFileSystem.stat(curPath)).isDirectory()) { // delete folder
if (window.remixFileSystem.statSync(curPath).isDirectory()) { // delete folder await this.remove(curPath)
this.remove(curPath) } else { // delete file
} else { // delete file await this.removeFile(curPath)
this.removeFile(curPath) }
}
})
if (window.remixFileSystem.readdirSync(path).length === 0) window.remixFileSystem.rmdirSync(path, console.log)
} else {
// folder is empty
window.remixFileSystem.rmdirSync(path, console.log)
} }
this.event.emit('fileRemoved', this._normalizePath(path)) await window.remixFileSystem.rmdir(path)
} else {
// folder is empty
await window.remixFileSystem.rmdir(path)
} }
} catch (e) { this.event.emit('fileRemoved', this._normalizePath(path))
console.log(e)
return resolve(false)
} }
} catch (e) {
console.log(e)
return false
} }
return resolve(true) }
})
} }
/** /**
@ -206,36 +210,35 @@ class FileProvider {
* @param {Function} visitFile is a function called for each visited files * @param {Function} visitFile is a function called for each visited files
* @param {Function} visitFolder is a function called for each visited folders * @param {Function} visitFolder is a function called for each visited folders
*/ */
_copyFolderToJsonInternal (path, visitFile, visitFolder) { async _copyFolderToJsonInternal (path, visitFile, visitFolder) {
visitFile = visitFile || (() => {}) visitFile = visitFile || function () { /* do nothing. */ }
visitFolder = visitFolder || (() => {}) visitFolder = visitFolder || function () { /* do nothing. */ }
return new Promise((resolve, reject) => {
const json = {} const json = {}
path = this.removePrefix(path) path = this.removePrefix(path)
if (window.remixFileSystem.existsSync(path)) { if (await window.remixFileSystem.exists(path)) {
try { try {
const items = window.remixFileSystem.readdirSync(path) const items = await window.remixFileSystem.readdir(path)
visitFolder({ path }) visitFolder({ path })
if (items.length !== 0) { if (items.length !== 0) {
items.forEach(async (item, index) => { for (const item of items) {
const file = {} const file = {}
const curPath = `${path}${path.endsWith('/') ? '' : '/'}${item}` const curPath = `${path}${path.endsWith('/') ? '' : '/'}${item}`
if (window.remixFileSystem.statSync(curPath).isDirectory()) { if ((await window.remixFileSystem.stat(curPath)).isDirectory()) {
file.children = await this._copyFolderToJsonInternal(curPath, visitFile, visitFolder) file.children = await this._copyFolderToJsonInternal(curPath, visitFile, visitFolder)
} else { } else {
file.content = window.remixFileSystem.readFileSync(curPath, 'utf8') file.content = await window.remixFileSystem.readFile(curPath, 'utf8')
visitFile({ path: curPath, content: file.content }) visitFile({ path: curPath, content: file.content })
} }
json[curPath] = file json[curPath] = file
})
} }
} catch (e) {
console.log(e)
return reject(e)
} }
} catch (e) {
console.log(e)
throw new Error(e)
} }
return resolve(json) }
}) return json
} }
/** /**
@ -244,26 +247,26 @@ class FileProvider {
* @param {Function} visitFile is a function called for each visited files * @param {Function} visitFile is a function called for each visited files
* @param {Function} visitFolder is a function called for each visited folders * @param {Function} visitFolder is a function called for each visited folders
*/ */
copyFolderToJson (path, visitFile, visitFolder) { async copyFolderToJson (path, visitFile, visitFolder) {
visitFile = visitFile || (() => {}) visitFile = visitFile || function () { /* do nothing. */ }
visitFolder = visitFolder || (() => {}) visitFolder = visitFolder || function () { /* do nothing. */ }
return this._copyFolderToJsonInternal(path, visitFile, visitFolder) return await this._copyFolderToJsonInternal(path, visitFile, visitFolder)
} }
removeFile (path) { async removeFile (path) {
path = this.removePrefix(path) path = this.removePrefix(path)
if (window.remixFileSystem.existsSync(path) && !window.remixFileSystem.statSync(path).isDirectory()) { if (await window.remixFileSystem.exists(path) && !(await window.remixFileSystem.stat(path)).isDirectory()) {
window.remixFileSystem.unlinkSync(path, console.log) await window.remixFileSystem.unlink(path)
this.event.emit('fileRemoved', this._normalizePath(path)) this.event.emit('fileRemoved', this._normalizePath(path))
return true return true
} else return false } else return false
} }
rename (oldPath, newPath, isFolder) { async rename (oldPath, newPath, isFolder) {
var unprefixedoldPath = this.removePrefix(oldPath) var unprefixedoldPath = this.removePrefix(oldPath)
var unprefixednewPath = this.removePrefix(newPath) var unprefixednewPath = this.removePrefix(newPath)
if (this._exists(unprefixedoldPath)) { if (await this._exists(unprefixedoldPath)) {
window.remixFileSystem.renameSync(unprefixedoldPath, unprefixednewPath) await window.remixFileSystem.rename(unprefixedoldPath, unprefixednewPath)
this.event.emit('fileRenamed', this.event.emit('fileRenamed',
this._normalizePath(unprefixedoldPath), this._normalizePath(unprefixedoldPath),
this._normalizePath(unprefixednewPath), this._normalizePath(unprefixednewPath),
@ -274,24 +277,26 @@ class FileProvider {
return false return false
} }
resolveDirectory (path, callback) { async resolveDirectory (path, cb) {
path = this.removePrefix(path) path = this.removePrefix(path)
if (path.indexOf('/') !== 0) path = '/' + path if (path.indexOf('/') !== 0) path = '/' + path
try {
window.remixFileSystem.readdir(path, (error, files) => { const files = await window.remixFileSystem.readdir(path)
var ret = {} const ret = {}
if (files) { if (files) {
files.forEach(element => { for (let element of files) {
path = path.replace(/^\/|\/$/g, '') // remove first and last slash path = path.replace(/^\/|\/$/g, '') // remove first and last slash
element = element.replace(/^\/|\/$/g, '') // remove first and last slash element = element.replace(/^\/|\/$/g, '') // remove first and last slash
const absPath = (path === '/' ? '' : path) + '/' + element const absPath = (path === '/' ? '' : path) + '/' + element
ret[absPath.indexOf('/') === 0 ? absPath.substr(1, absPath.length) : absPath] = { isDirectory: window.remixFileSystem.statSync(absPath).isDirectory() } ret[absPath.indexOf('/') === 0 ? absPath.substr(1, absPath.length) : absPath] = { isDirectory: (await window.remixFileSystem.stat(absPath)).isDirectory() }
// ^ ret does not accept path starting with '/' // ^ ret does not accept path starting with '/'
}) }
} }
callback(error, ret) if (cb) cb(null, ret)
}) return ret
} catch (error) {
if (cb) cb(error, null)
}
} }
removePrefix (path) { removePrefix (path) {

@ -68,8 +68,8 @@ class WorkspaceFileProvider extends FileProvider {
} }
async copyFolderToJson (directory, visitFile, visitFolder) { async copyFolderToJson (directory, visitFile, visitFolder) {
visitFile = visitFile || (() => {}) visitFile = visitFile || function () { /* do nothing. */ }
visitFolder = visitFolder || (() => {}) visitFolder = visitFolder || function () { /* do nothing. */ }
const regex = new RegExp(`.workspaces/${this.workspace}/`, 'g') const regex = new RegExp(`.workspaces/${this.workspace}/`, 'g')
let json = await super._copyFolderToJsonInternal(directory, ({ path, content }) => { let json = await super._copyFolderToJsonInternal(directory, ({ path, content }) => {
visitFile({ path: path.replace(regex, ''), content }) visitFile({ path: path.replace(regex, ''), content })

@ -1,7 +1,7 @@
import { Plugin } from '@remixproject/engine' import { Plugin } from '@remixproject/engine'
import { Profile } from '@remixproject/plugin-utils' import { Profile } from '@remixproject/plugin-utils'
import { EventEmitter } from 'events' import { EventEmitter } from 'events'
import QueryParams from '../../lib/query-params' import { QueryParams } from '@remix-project/remix-lib'
const profile: Profile = { const profile: Profile = {
name: 'layout', name: 'layout',
@ -21,6 +21,12 @@ interface panels {
terminal: panelState terminal: panelState
} }
export type PanelConfiguration = {
minimizeterminal: boolean,
minimizesidepanel: boolean,
embed: boolean
}
export class Layout extends Plugin { export class Layout extends Plugin {
event: any event: any
panels: panels panels: panels
@ -77,7 +83,7 @@ export class Layout extends Plugin {
} }
}) })
const queryParams = new QueryParams() const queryParams = new QueryParams()
const params = queryParams.get() const params = queryParams.get() as PanelConfiguration
if (params.minimizeterminal || params.embed) { if (params.minimizeterminal || params.embed) {
this.panels.terminal.minimized = true this.panels.terminal.minimized = true
this.event.emit('change', this.panels) this.event.emit('change', this.panels)

@ -2,8 +2,8 @@ import React from 'react' // eslint-disable-line
import ReactDOM from 'react-dom' import ReactDOM from 'react-dom'
import { Plugin } from '@remixproject/engine' import { Plugin } from '@remixproject/engine'
import { TabsUI } from '@remix-ui/tabs' import { TabsUI } from '@remix-ui/tabs'
import { getPathIcon } from '@remix-ui/helper'
const EventEmitter = require('events') const EventEmitter = require('events')
const helper = require('../../lib/helper')
const profile = { const profile = {
name: 'tabs', name: 'tabs',
@ -70,13 +70,13 @@ export class TabProxy extends Plugin {
this.tabsApi.activateTab(workspacePath) this.tabsApi.activateTab(workspacePath)
return return
} }
this.addTab(workspacePath, '', () => { this.addTab(workspacePath, '', async () => {
this.fileManager.open(file) await this.fileManager.open(file)
this.event.emit('openFile', file) this.event.emit('openFile', file)
this.emit('openFile', file) this.emit('openFile', file)
}, },
() => { async () => {
this.fileManager.closeFile(file) await this.fileManager.closeFile(file)
this.event.emit('closeFile', file) this.event.emit('closeFile', file)
this.emit('closeFile', file) this.emit('closeFile', file)
}) })
@ -88,13 +88,13 @@ export class TabProxy extends Plugin {
this.tabsApi.activateTab(path) this.tabsApi.activateTab(path)
return return
} }
this.addTab(path, '', () => { this.addTab(path, '', async () => {
this.fileManager.open(file) await this.fileManager.open(file)
this.event.emit('openFile', file) this.event.emit('openFile', file)
this.emit('openFile', file) this.emit('openFile', file)
}, },
() => { async () => {
this.fileManager.closeFile(file) await this.fileManager.closeFile(file)
this.event.emit('closeFile', file) this.event.emit('closeFile', file)
this.emit('closeFile', file) this.emit('closeFile', file)
}) })
@ -197,12 +197,12 @@ export class TabProxy extends Plugin {
} }
renameTab (oldName, newName) { renameTab (oldName, newName) {
this.addTab(newName, '', () => { this.addTab(newName, '', async () => {
this.fileManager.open(newName) await this.fileManager.open(newName)
this.event.emit('openFile', newName) this.event.emit('openFile', newName)
}, },
() => { async () => {
this.fileManager.closeFile(newName) await this.fileManager.closeFile(newName)
this.event.emit('closeFile', newName) this.event.emit('closeFile', newName)
this.emit('closeFile', newName) this.emit('closeFile', newName)
}) })
@ -231,7 +231,7 @@ export class TabProxy extends Plugin {
title, title,
icon, icon,
tooltip: name, tooltip: name,
iconClass: helper.getPathIcon(name) iconClass: getPathIcon(name)
}) })
formatPath.shift() formatPath.shift()
if (formatPath.length > 0) { if (formatPath.length > 0) {
@ -247,7 +247,7 @@ export class TabProxy extends Plugin {
title: duplicateTabTitle, title: duplicateTabTitle,
icon, icon,
tooltip: duplicateTabName, tooltip: duplicateTabName,
iconClass: helper.getPathIcon(duplicateTabName) iconClass: getPathIcon(duplicateTabName)
} }
} }
} }
@ -261,7 +261,7 @@ export class TabProxy extends Plugin {
title, title,
icon, icon,
tooltip: name, tooltip: name,
iconClass: helper.getPathIcon(name) iconClass: getPathIcon(name)
}) })
} }

@ -117,6 +117,7 @@ class Terminal extends Plugin {
scroll2bottom () { scroll2bottom () {
setTimeout(function () { setTimeout(function () {
// do nothing.
}, 0) }, 0)
} }
} }

@ -1,5 +1,5 @@
import { Plugin } from '@remixproject/engine' import { Plugin } from '@remixproject/engine'
import QueryParams from '../../lib/query-params' import { QueryParams } from '@remix-project/remix-lib'
import Registry from '../state/registry' import Registry from '../state/registry'
const profile = { const profile = {

@ -0,0 +1,22 @@
import { Plugin } from '@remixproject/engine';
const profile = {
name: 'storage',
displayName: 'Storage',
description: 'Storage',
methods: ['getStorage']
};
export class StoragePlugin extends Plugin {
constructor() {
super(profile);
}
async getStorage() {
if ('storage' in navigator && 'estimate' in navigator.storage) {
return navigator.storage.estimate()
} else {
throw new Error("Can't get storage quota");
}
}
}

@ -3,9 +3,9 @@ import React from 'react' // eslint-disable-line
import ReactDOM from 'react-dom' import ReactDOM from 'react-dom'
import { SolidityCompiler } from '@remix-ui/solidity-compiler' // eslint-disable-line import { SolidityCompiler } from '@remix-ui/solidity-compiler' // eslint-disable-line
import { CompileTabLogic } from '@remix-ui/solidity-compiler' // eslint-disable-line import { CompileTabLogic } from '@remix-ui/solidity-compiler' // eslint-disable-line
import { CompilerApiMixin } from '@remixproject/solidity-compiler-plugin' import { CompilerApiMixin } from '@remixproject/solidity-compiler-plugin' // eslint-disable-line
import { ViewPlugin } from '@remixproject/engine-web' import { ViewPlugin } from '@remixproject/engine-web'
import QueryParams from '../../lib/query-params' import { QueryParams } from '@remix-project/remix-lib'
// import { ICompilerApi } from '@remix-project/remix-lib-ts' // import { ICompilerApi } from '@remix-project/remix-lib-ts'
import * as packageJson from '../../../../../package.json' import * as packageJson from '../../../../../package.json'
import { compilerConfigChangedToastMsg, compileToastMsg } from '@remix-ui/helper' import { compilerConfigChangedToastMsg, compileToastMsg } from '@remix-ui/helper'

@ -1,5 +1,5 @@
import { DebuggerUI } from '@remix-ui/debugger-ui' // eslint-disable-line import { DebuggerUI } from '@remix-ui/debugger-ui' // eslint-disable-line
import { DebuggerApiMixin } from '@remixproject/debugger-plugin' import { DebuggerApiMixin } from '@remixproject/debugger-plugin' // eslint-disable-line
import { ViewPlugin } from '@remixproject/engine-web' import { ViewPlugin } from '@remixproject/engine-web'
import * as packageJson from '../../../../../package.json' import * as packageJson from '../../../../../package.json'
import React from 'react' // eslint-disable-line import React from 'react' // eslint-disable-line

@ -11,10 +11,9 @@ const helper = require('../../../../lib/helper')
*/ */
class Recorder { class Recorder {
constructor (blockchain) { constructor (blockchain) {
var self = this this.event = new EventManager()
self.event = new EventManager() this.blockchain = blockchain
self.blockchain = blockchain this.data = { _listen: true, _replay: false, journal: [], _createdContracts: {}, _createdContractsReverse: {}, _usedAccounts: {}, _abis: {}, _contractABIReferences: {}, _linkReferences: {} }
self.data = { _listen: true, _replay: false, journal: [], _createdContracts: {}, _createdContractsReverse: {}, _usedAccounts: {}, _abis: {}, _contractABIReferences: {}, _linkReferences: {} }
this.blockchain.event.register('initiatingTransaction', (timestamp, tx, payLoad) => { this.blockchain.event.register('initiatingTransaction', (timestamp, tx, payLoad) => {
if (tx.useCall) return if (tx.useCall) return
@ -33,11 +32,11 @@ class Recorder {
if (record.linkReferences && Object.keys(record.linkReferences).length) { if (record.linkReferences && Object.keys(record.linkReferences).length) {
for (var file in record.linkReferences) { for (var file in record.linkReferences) {
for (var lib in record.linkReferences[file]) { for (var lib in record.linkReferences[file]) {
self.data._linkReferences[lib] = '<address>' this.data._linkReferences[lib] = '<address>'
} }
} }
} }
self.data._abis[keccak] = abi this.data._abis[keccak] = abi
this.data._contractABIReferences[timestamp] = keccak this.data._contractABIReferences[timestamp] = keccak
} else { } else {
@ -57,8 +56,8 @@ class Recorder {
this.blockchain.getAccounts((error, accounts) => { this.blockchain.getAccounts((error, accounts) => {
if (error) return console.log(error) if (error) return console.log(error)
record.from = `account{${accounts.indexOf(from)}}` record.from = `account{${accounts.indexOf(from)}}`
self.data._usedAccounts[record.from] = from this.data._usedAccounts[record.from] = from
self.append(timestamp, record) this.append(timestamp, record)
}) })
} }
}) })
@ -128,9 +127,8 @@ class Recorder {
* *
*/ */
append (timestamp, record) { append (timestamp, record) {
var self = this this.data.journal.push({ timestamp, record })
self.data.journal.push({ timestamp, record }) this.event.trigger('newTxRecorded', [this.data.journal.length])
self.event.trigger('newTxRecorded', [self.data.journal.length])
} }
/** /**
@ -138,17 +136,16 @@ class Recorder {
* *
*/ */
getAll () { getAll () {
var self = this var records = [].concat(this.data.journal)
var records = [].concat(self.data.journal)
return { return {
accounts: self.data._usedAccounts, accounts: this.data._usedAccounts,
linkReferences: self.data._linkReferences, linkReferences: this.data._linkReferences,
transactions: records.sort((A, B) => { transactions: records.sort((A, B) => {
var stampA = A.timestamp var stampA = A.timestamp
var stampB = B.timestamp var stampB = B.timestamp
return stampA - stampB return stampA - stampB
}), }),
abis: self.data._abis abis: this.data._abis
} }
} }
@ -157,17 +154,16 @@ class Recorder {
* *
*/ */
clearAll () { clearAll () {
var self = this this.data._listen = true
self.data._listen = true this.data._replay = false
self.data._replay = false this.data.journal = []
self.data.journal = [] this.data._createdContracts = {}
self.data._createdContracts = {} this.data._createdContractsReverse = {}
self.data._createdContractsReverse = {} this.data._usedAccounts = {}
self.data._usedAccounts = {} this.data._abis = {}
self.data._abis = {} this.data._contractABIReferences = {}
self.data._contractABIReferences = {} this.data._linkReferences = {}
self.data._linkReferences = {} this.event.trigger('cleared', [])
self.event.trigger('cleared', [])
} }
/** /**
@ -180,11 +176,10 @@ class Recorder {
* *
*/ */
run (records, accounts, options, abis, linkReferences, confirmationCb, continueCb, promptCb, alertCb, logCallBack, newContractFn) { run (records, accounts, options, abis, linkReferences, confirmationCb, continueCb, promptCb, alertCb, logCallBack, newContractFn) {
var self = this this.setListen(false)
self.setListen(false)
logCallBack(`Running ${records.length} transaction(s) ...`) logCallBack(`Running ${records.length} transaction(s) ...`)
async.eachOfSeries(records, function (tx, index, cb) { async.eachOfSeries(records, (tx, index, cb) => {
var record = self.resolveAddress(tx.record, accounts, options) var record = this.resolveAddress(tx.record, accounts, options)
var abi = abis[tx.record.abi] var abi = abis[tx.record.abi]
if (!abi) { if (!abi) {
return alertCb('cannot find ABI for ' + tx.record.abi + '. Execution stopped at ' + index) return alertCb('cannot find ABI for ' + tx.record.abi + '. Execution stopped at ' + index)
@ -193,9 +188,9 @@ class Recorder {
if (record.linkReferences && Object.keys(record.linkReferences).length) { if (record.linkReferences && Object.keys(record.linkReferences).length) {
for (var k in linkReferences) { for (var k in linkReferences) {
var link = linkReferences[k] var link = linkReferences[k]
var timestamp = self.extractTimestamp(link) var timestamp = this.extractTimestamp(link)
if (timestamp && self.data._createdContractsReverse[timestamp]) { if (timestamp && this.data._createdContractsReverse[timestamp]) {
link = self.data._createdContractsReverse[timestamp] link = this.data._createdContractsReverse[timestamp]
} }
tx.record.bytecode = format.linkLibraryStandardFromlinkReferences(k, link.replace('0x', ''), tx.record.bytecode, tx.record.linkReferences) tx.record.bytecode = format.linkLibraryStandardFromlinkReferences(k, link.replace('0x', ''), tx.record.bytecode, tx.record.linkReferences)
} }
@ -224,8 +219,8 @@ class Recorder {
isString = false isString = false
value = JSON.stringify(value) value = JSON.stringify(value)
} }
for (var timestamp in self.data._createdContractsReverse) { for (var timestamp in this.data._createdContractsReverse) {
value = value.replace(new RegExp('created\\{' + timestamp + '\\}', 'g'), self.data._createdContractsReverse[timestamp]) value = value.replace(new RegExp('created\\{' + timestamp + '\\}', 'g'), this.data._createdContractsReverse[timestamp])
} }
if (!isString) value = JSON.parse(value) if (!isString) value = JSON.parse(value)
tx.record.parameters[index] = value tx.record.parameters[index] = value
@ -243,8 +238,8 @@ class Recorder {
logCallBack(`(${index}) data: ${data.data}`) logCallBack(`(${index}) data: ${data.data}`)
record.data = { dataHex: data.data, funArgs: tx.record.parameters, funAbi: fnABI, contractBytecode: tx.record.bytecode, contractName: tx.record.contractName, timestamp: tx.timestamp } record.data = { dataHex: data.data, funArgs: tx.record.parameters, funAbi: fnABI, contractBytecode: tx.record.bytecode, contractName: tx.record.contractName, timestamp: tx.timestamp }
self.blockchain.runTx(record, confirmationCb, continueCb, promptCb, this.blockchain.runTx(record, confirmationCb, continueCb, promptCb,
function (err, txResult, rawAddress) { (err, txResult, rawAddress) => {
if (err) { if (err) {
console.error(err) console.error(err)
return logCallBack(err + '. Execution failed at ' + index) return logCallBack(err + '. Execution failed at ' + index)
@ -252,14 +247,14 @@ class Recorder {
if (rawAddress) { if (rawAddress) {
const address = helper.addressToString(rawAddress) const address = helper.addressToString(rawAddress)
// save back created addresses for the convertion from tokens to real adresses // save back created addresses for the convertion from tokens to real adresses
self.data._createdContracts[address] = tx.timestamp this.data._createdContracts[address] = tx.timestamp
self.data._createdContractsReverse[tx.timestamp] = address this.data._createdContractsReverse[tx.timestamp] = address
newContractFn(abi, address, record.contractName) newContractFn(abi, address, record.contractName)
} }
cb(err) cb(err)
} }
) )
}, () => { self.setListen(true) }) }, () => { this.setListen(true) })
} }
runScenario (json, continueCb, promptCb, alertCb, confirmationCb, logCallBack, cb) { runScenario (json, continueCb, promptCb, alertCb, confirmationCb, logCallBack, cb) {

@ -119,7 +119,7 @@ module.exports = class TestTab extends ViewPlugin {
usingWorker: canUseWorker(currentVersion), usingWorker: canUseWorker(currentVersion),
runs runs
} }
this.testRunner.runTestSources(runningTest, compilerConfig, () => {}, () => {}, null, (error, result) => { this.testRunner.runTestSources(runningTest, compilerConfig, () => { /* Do nothing. */ }, () => { /* Do nothing. */ }, null, (error, result) => {
if (error) return reject(error) if (error) return reject(error)
resolve(result) resolve(result)
}, (url, cb) => { }, (url, cb) => {

@ -1,6 +1,6 @@
import { Plugin } from '@remixproject/engine' import { Plugin } from '@remixproject/engine'
import { EventEmitter } from 'events' import { EventEmitter } from 'events'
import QueryParams from '../../lib/query-params' import { QueryParams } from '@remix-project/remix-lib'
import * as packageJson from '../../../../../package.json' import * as packageJson from '../../../../../package.json'
import Registry from '../state/registry' import Registry from '../state/registry'
const _paq = window._paq = window._paq || [] const _paq = window._paq = window._paq || []

@ -0,0 +1,107 @@
/* eslint-disable prefer-promise-reject-errors */
function urlParams () {
var qs = window.location.hash.substr(1)
if (window.location.search.length > 0) {
// use legacy query params instead of hash
window.location.hash = window.location.search.substr(1)
window.location.search = ''
}
var params = {}
var parts = qs.split('&')
for (var x in parts) {
var keyValue = parts[x].split('=')
if (keyValue[0] !== '') {
params[keyValue[0]] = keyValue[1]
}
}
return params
}
const defaultVersion = '0.8.0'
const versionToLoad = urlParams().appVersion ? urlParams().appVersion : defaultVersion
const assets = {
'0.8.0': ['https://use.fontawesome.com/releases/v5.8.1/css/all.css', 'assets/css/pygment_trac.css'],
'0.7.7': ['assets/css/font-awesome.min.css', 'assets/css/pygment_trac.css']
}
const versions = {
'0.7.7': 'assets/js/0.7.7/app.js', // commit 7b5c7ae3de935e0ccc32eadfd83bf7349478491e
'0.8.0': 'main.js'
}
for (const k in assets[versionToLoad]) {
const app = document.createElement('link')
app.setAttribute('rel', 'stylesheet')
app.setAttribute('href', assets[versionToLoad][k])
if (assets[versionToLoad][k] === 'https://use.fontawesome.com/releases/v5.8.1/css/all.css') {
app.setAttribute('integrity', 'sha384-50oBUHEmvpQ+1lW4y57PTFmhCaXp0ML5d60M1M7uH2+nqUivzIebhndOJK28anvf')
app.setAttribute('crossorigin', 'anonymous')
}
document.head.appendChild(app)
}
window.onload = () => {
// eslint-disable-next-line no-undef
class RemixFileSystem extends LightningFS {
constructor (...t) {
super(...t)
this.addSlash = (file) => {
if (!file.startsWith('/')) file = '/' + file
return file
}
this.base = this.promises
this.promises = {
...this.promises,
exists: async (path) => {
return new Promise((resolve, reject) => {
this.base.stat(this.addSlash(path)).then(() => resolve(true)).catch(() => resolve(false))
})
},
rmdir: async (path) => {
return this.base.rmdir(this.addSlash(path))
},
readdir: async (path) => {
return this.base.readdir(this.addSlash(path))
},
unlink: async (path) => {
return this.base.unlink(this.addSlash(path))
},
mkdir: async (path) => {
return this.base.mkdir(this.addSlash(path))
},
readFile: async (path, options) => {
return this.base.readFile(this.addSlash(path), options)
},
rename: async (from, to) => {
return this.base.rename(this.addSlash(from), this.addSlash(to))
},
writeFile: async (path, content, options) => {
return this.base.writeFile(this.addSlash(path), content, options)
},
stat: async (path) => {
return this.base.stat(this.addSlash(path))
}
}
}
}
function loadApp () {
const app = document.createElement('script')
app.setAttribute('src', versions[versionToLoad])
document.body.appendChild(app)
}
window.remixFileSystemCallback = new RemixFileSystem()
window.remixFileSystemCallback.init('RemixFileSystem').then(() => {
window.remixFileSystem = window.remixFileSystemCallback.promises
// check if .workspaces is present in indexeddb
window.remixFileSystem.stat('.workspaces').then((dir) => {
if (dir.isDirectory()) loadApp()
}).catch(() => {
// no indexeddb .workspaces -> run migration
// eslint-disable-next-line no-undef
migrateFilesFromLocalStorage(loadApp)
})
})
}

File diff suppressed because one or more lines are too long

@ -0,0 +1,139 @@
// eslint-disable-next-line no-unused-vars
async function migrateFilesFromLocalStorage (cb) {
let testmigration = false // migration loads test data into localstorage with browserfs
// indexeddb will be empty by this point, so there is no danger but do a check for the origin to load test data so it runs only locally
testmigration = window.location.hash.includes('e2e_testmigration=true') && window.location.host === '127.0.0.1:8080' && window.location.protocol === 'http:'
// eslint-disable-next-line no-undef
BrowserFS.install(window)
// eslint-disable-next-line no-undef
BrowserFS.configure({
fs: 'LocalStorage'
}, async function (e) {
if (e) console.log(e)
const browserFS = window.require('fs')
/**
* copy the folder recursively (internal use)
* @param {string} path is the folder to be copied over
* @param {Function} visitFile is a function called for each visited files
* @param {Function} visitFolder is a function called for each visited folders
*/
async function _copyFolderToJsonInternal (path, visitFile, visitFolder, fs) {
visitFile = visitFile || (() => { })
visitFolder = visitFolder || (() => { })
return new Promise((resolve, reject) => {
const json = {}
if (fs.existsSync(path)) {
try {
const items = fs.readdirSync(path)
visitFolder({ path })
if (items.length !== 0) {
items.forEach(async (item, index) => {
const file = {}
const curPath = `${path}${path.endsWith('/') ? '' : '/'}${item}`
if (fs.statSync(curPath).isDirectory()) {
file.children = await _copyFolderToJsonInternal(curPath, visitFile, visitFolder, fs)
} else {
file.content = fs.readFileSync(curPath, 'utf8')
visitFile({ path: curPath, content: file.content })
}
json[curPath] = file
})
}
} catch (e) {
console.log(e)
return reject(e)
}
}
return resolve(json)
})
}
/**
* copy the folder recursively
* @param {string} path is the folder to be copied over
* @param {Function} visitFile is a function called for each visited files
* @param {Function} visitFolder is a function called for each visited folders
*/
async function copyFolderToJson (path, visitFile, visitFolder, fs) {
visitFile = visitFile || (() => { })
visitFolder = visitFolder || (() => { })
return _copyFolderToJsonInternal(path, visitFile, visitFolder, fs)
}
const populateWorkspace = async (json, fs) => {
for (const item in json) {
const isFolder = json[item].content === undefined
if (isFolder) {
await createDir(item, fs)
await populateWorkspace(json[item].children, fs)
} else {
try {
await fs.writeFile(item, json[item].content, 'utf8')
} catch (error) {
console.log(error)
}
}
}
}
const createDir = async (path, fs) => {
const paths = path.split('/')
if (paths.length && paths[0] === '') paths.shift()
let currentCheck = ''
for (const value of paths) {
currentCheck = currentCheck + (currentCheck ? '/' : '') + value
if (!await fs.exists(currentCheck)) {
try {
await fs.mkdir(currentCheck)
} catch (error) {
console.log(error)
}
}
}
}
//
if (testmigration) await populateWorkspace(testData, browserFS)
const files = await copyFolderToJson('/', null, null, browserFS)
await populateWorkspace(files, window.remixFileSystem)
// eslint-disable-next-line no-undef
if (cb) cb()
})
}
/* eslint-disable no-template-curly-in-string */
const testData = {
'.workspaces': {
children: {
'.workspaces/default_workspace': {
children: {
'.workspaces/default_workspace/README.txt': {
content: 'TEST README'
}
}
},
'.workspaces/workspace_test': {
children: {
'.workspaces/workspace_test/TEST_README.txt': {
content: 'TEST README'
},
'.workspaces/workspace_test/test_contracts': {
children: {
'.workspaces/workspace_test/test_contracts/1_Storage.sol': {
content: 'testing'
},
'.workspaces/workspace_test/test_contracts/artifacts': {
children: {
'.workspaces/workspace_test/test_contracts/artifacts/Storage_metadata.json': {
content: '{ "test": "data" }'
}
}
}
}
}
}
}
}
}
}

@ -303,7 +303,7 @@ export class Blockchain extends Plugin {
}, },
(data, runTxCallback) => { (data, runTxCallback) => {
// called for libraries deployment // called for libraries deployment
this.runTx(data, confirmationCb, runTxCallback, promptCb, () => {}) this.runTx(data, confirmationCb, runTxCallback, promptCb, () => { /* Do nothing. */ })
}) })
} }
@ -422,72 +422,70 @@ export class Blockchain extends Plugin {
} }
runTx (args, confirmationCb, continueCb, promptCb, cb) { runTx (args, confirmationCb, continueCb, promptCb, cb) {
const self = this
waterfall([ waterfall([
function getGasLimit (next) { (next) => { // getGasLimit
if (self.transactionContextAPI.getGasLimit) { if (this.transactionContextAPI.getGasLimit) {
return self.transactionContextAPI.getGasLimit(next) return this.transactionContextAPI.getGasLimit(next)
} }
next(null, 3000000) next(null, 3000000)
}, },
function queryValue (gasLimit, next) { (gasLimit, next) => { // queryValue
if (args.value) { if (args.value) {
return next(null, args.value, gasLimit) return next(null, args.value, gasLimit)
} }
if (args.useCall || !self.transactionContextAPI.getValue) { if (args.useCall || !this.transactionContextAPI.getValue) {
return next(null, 0, gasLimit) return next(null, 0, gasLimit)
} }
self.transactionContextAPI.getValue(function (err, value) { this.transactionContextAPI.getValue(function (err, value) {
next(err, value, gasLimit) next(err, value, gasLimit)
}) })
}, },
function getAccount (value, gasLimit, next) { (value, gasLimit, next) => { // getAccount
if (args.from) { if (args.from) {
return next(null, args.from, value, gasLimit) return next(null, args.from, value, gasLimit)
} }
if (self.transactionContextAPI.getAddress) { if (this.transactionContextAPI.getAddress) {
return self.transactionContextAPI.getAddress(function (err, address) { return this.transactionContextAPI.getAddress(function (err, address) {
next(err, address, value, gasLimit) next(err, address, value, gasLimit)
}) })
} }
self.getAccounts(function (err, accounts) { this.getAccounts(function (err, accounts) {
const address = accounts[0] const address = accounts[0]
if (err) return next(err) if (err) return next(err)
if (!address) return next('No accounts available') if (!address) return next('No accounts available')
// if (self.executionContext.isVM() && !self.providers.vm.accounts[address]) { if (this.executionContext.isVM() && !this.providers.vm.RemixSimulatorProvider.Accounts.accounts[address]) {
if (self.executionContext.isVM() && !self.providers.vm.RemixSimulatorProvider.Accounts.accounts[address]) {
return next('Invalid account selected') return next('Invalid account selected')
} }
next(null, address, value, gasLimit) next(null, address, value, gasLimit)
}) })
}, },
function runTransaction (fromAddress, value, gasLimit, next) { (fromAddress, value, gasLimit, next) => { // runTransaction
const tx = { to: args.to, data: args.data.dataHex, useCall: args.useCall, from: fromAddress, value: value, gasLimit: gasLimit, timestamp: args.data.timestamp } const tx = { to: args.to, data: args.data.dataHex, useCall: args.useCall, from: fromAddress, value: value, gasLimit: gasLimit, timestamp: args.data.timestamp }
const payLoad = { funAbi: args.data.funAbi, funArgs: args.data.funArgs, contractBytecode: args.data.contractBytecode, contractName: args.data.contractName, contractABI: args.data.contractABI, linkReferences: args.data.linkReferences } const payLoad = { funAbi: args.data.funAbi, funArgs: args.data.funArgs, contractBytecode: args.data.contractBytecode, contractName: args.data.contractName, contractABI: args.data.contractABI, linkReferences: args.data.linkReferences }
if (!tx.timestamp) tx.timestamp = Date.now() if (!tx.timestamp) tx.timestamp = Date.now()
const timestamp = tx.timestamp const timestamp = tx.timestamp
self.event.trigger('initiatingTransaction', [timestamp, tx, payLoad]) this.event.trigger('initiatingTransaction', [timestamp, tx, payLoad])
self.txRunner.rawRun(tx, confirmationCb, continueCb, promptCb, this.txRunner.rawRun(tx, confirmationCb, continueCb, promptCb,
async (error, result) => { async (error, result) => {
if (error) return next(error) if (error) return next(error)
const isVM = self.executionContext.isVM() const isVM = this.executionContext.isVM()
if (isVM && tx.useCall) { if (isVM && tx.useCall) {
try { try {
result.transactionHash = await self.web3().eth.getHashFromTagBySimulator(timestamp) result.transactionHash = await this.web3().eth.getHashFromTagBySimulator(timestamp)
} catch (e) { } catch (e) {
console.log('unable to retrieve back the "call" hash', e) console.log('unable to retrieve back the "call" hash', e)
} }
} }
const eventName = (tx.useCall ? 'callExecuted' : 'transactionExecuted') const eventName = (tx.useCall ? 'callExecuted' : 'transactionExecuted')
self.event.trigger(eventName, [error, tx.from, tx.to, tx.data, tx.useCall, result, timestamp, payLoad]) this.event.trigger(eventName, [error, tx.from, tx.to, tx.data, tx.useCall, result, timestamp, payLoad])
if (error && (typeof (error) !== 'string')) { if (error && (typeof (error) !== 'string')) {
if (error.message) error = error.message if (error.message) error = error.message
else { else {
try { error = 'error: ' + JSON.stringify(error) } catch (e) {} try { error = 'error: ' + JSON.stringify(error) } catch (e) { console.log(e) }
} }
} }
next(error, result, tx) next(error, result, tx)

@ -129,9 +129,9 @@ export class ExecutionContext {
async executionContextChange (value, endPointUrl, confirmCb, infoCb, cb) { async executionContextChange (value, endPointUrl, confirmCb, infoCb, cb) {
const context = value.context const context = value.context
if (!cb) cb = () => {} if (!cb) cb = () => { /* Do nothing. */ }
if (!confirmCb) confirmCb = () => {} if (!confirmCb) confirmCb = () => { /* Do nothing. */ }
if (!infoCb) infoCb = () => {} if (!infoCb) infoCb = () => { /* Do nothing. */ }
if (context === 'vm') { if (context === 'vm') {
this.executionContext = context this.executionContext = context
this.currentFork = value.fork this.currentFork = value.fork

@ -17,6 +17,7 @@ class InjectedProvider {
} }
resetEnvironment () { resetEnvironment () {
/* Do nothing. */
} }
getBalanceInEther (address, cb) { getBalanceInEther (address, cb) {

@ -25,6 +25,7 @@ class NodeProvider {
} }
resetEnvironment () { resetEnvironment () {
/* Do nothing. */
} }
getBalanceInEther (address, cb) { getBalanceInEther (address, cb) {

@ -15,6 +15,7 @@ function Config (storage) {
this.items = JSON.parse(config) this.items = JSON.parse(config)
} }
} catch (exception) { } catch (exception) {
/* Do nothing. */
} }
this.exists = function (key) { this.exists = function (key) {
@ -31,6 +32,7 @@ function Config (storage) {
storage.set(CONFIG_FILE, JSON.stringify(this.items)) storage.set(CONFIG_FILE, JSON.stringify(this.items))
this.events.emit(key + '_changed', content) this.events.emit(key + '_changed', content)
} catch (exception) { } catch (exception) {
/* Do nothing. */
} }
} }

@ -28,6 +28,8 @@
<link rel="icon" type="x-icon" href="assets/img/icon.png"> <link rel="icon" type="x-icon" href="assets/img/icon.png">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/intro.js/4.1.0/introjs.min.css"> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/intro.js/4.1.0/introjs.min.css">
<script src="assets/js/browserfs.min.js"></script> <script src="assets/js/browserfs.min.js"></script>
<script src="assets/js/migrate.js"></script>
<script src="assets/js/lightning-fs.min.js"></script>
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no"> <meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no">
<!-- Matomo --> <!-- Matomo -->
<script type="text/javascript"> <script type="text/javascript">
@ -57,60 +59,7 @@
</head> </head>
<body> <body>
<div id="root"></div> <div id="root"></div>
<script> <script type="text/javascript" src="assets/js/init.js"></script>
function urlParams () {
var qs = window.location.hash.substr(1)
if (window.location.search.length > 0) {
// use legacy query params instead of hash
window.location.hash = window.location.search.substr(1)
window.location.search = ''
}
var params = {}
var parts = qs.split('&')
for (var x in parts) {
var keyValue = parts[x].split('=')
if (keyValue[0] !== '') {
params[keyValue[0]] = keyValue[1]
}
}
return params
}
const defaultVersion = '0.8.0'
let versionToLoad = urlParams().appVersion ? urlParams().appVersion : defaultVersion
let assets = {
'0.8.0': ['https://use.fontawesome.com/releases/v5.8.1/css/all.css', 'assets/css/pygment_trac.css'],
'0.7.7': ['assets/css/font-awesome.min.css', 'assets/css/pygment_trac.css']
}
let versions = {
'0.7.7': 'assets/js/0.7.7/app.js', // commit 7b5c7ae3de935e0ccc32eadfd83bf7349478491e
'0.8.0': 'main.js'
}
for (let k in assets[versionToLoad]) {
let app = document.createElement('link')
app.setAttribute('rel', 'stylesheet')
app.setAttribute('href', assets[versionToLoad][k])
if (assets[versionToLoad][k] === 'https://use.fontawesome.com/releases/v5.8.1/css/all.css') {
app.setAttribute('integrity', 'sha384-50oBUHEmvpQ+1lW4y57PTFmhCaXp0ML5d60M1M7uH2+nqUivzIebhndOJK28anvf')
app.setAttribute('crossorigin', 'anonymous')
}
document.head.appendChild(app)
}
window.onload = () => {
BrowserFS.install(window)
BrowserFS.configure({
fs: "LocalStorage"
}, function(e) {
if (e) console.log(e)
let app = document.createElement('script')
app.setAttribute('src', versions[versionToLoad])
document.body.appendChild(app)
window.remixFileSystem = require('fs')
})
}
</script>
<script src="runtime.js" type="module"></script> <script src="runtime.js" type="module"></script>
<script src="polyfills.js" type="module"></script> <script src="polyfills.js" type="module"></script>
<script src="vendor.js" type="module"></script> <script src="vendor.js" type="module"></script>

@ -64,7 +64,6 @@ module.exports = {
do { do {
const isDuplicate = await fileManager.exists(name + counter + prefix + '.' + ext) const isDuplicate = await fileManager.exists(name + counter + prefix + '.' + ext)
if (isDuplicate) counter = (counter | 0) + 1 if (isDuplicate) counter = (counter | 0) + 1
else exist = false else exist = false
} while (exist) } while (exist)

@ -1,42 +0,0 @@
'use strict'
// Allowing window to be overriden for testing
function QueryParams (_window) {
if (_window === undefined) _window = window
this.get = function () {
var qs = _window.location.hash.substr(1)
if (_window.location.search.length > 0) {
// use legacy query params instead of hash
_window.location.hash = _window.location.search.substr(1)
_window.location.search = ''
}
var params = {}
var parts = qs.split('&')
for (var x in parts) {
var keyValue = parts[x].split('=')
if (keyValue[0] !== '') {
params[keyValue[0]] = keyValue[1]
}
}
return params
}
this.update = function (params) {
var currentParams = this.get()
var keys = Object.keys(params)
for (var x in keys) {
currentParams[keys[x]] = params[keys[x]]
}
var queryString = '#'
var updatedKeys = Object.keys(currentParams)
for (var y in updatedKeys) {
queryString += updatedKeys[y] + '=' + currentParams[updatedKeys[y]] + '&'
}
_window.location.hash = queryString.slice(0, -1)
}
}
module.exports = QueryParams

@ -28,6 +28,8 @@
<link rel="icon" type="x-icon" href="assets/img/icon.png"> <link rel="icon" type="x-icon" href="assets/img/icon.png">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/intro.js/4.1.0/introjs.min.css"> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/intro.js/4.1.0/introjs.min.css">
<script src="assets/js/browserfs.min.js"></script> <script src="assets/js/browserfs.min.js"></script>
<script src="assets/js/migrate.js"></script>
<script src="assets/js/lightning-fs.min.js"></script>
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no"> <meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no">
<!-- Matomo --> <!-- Matomo -->
<script type="text/javascript"> <script type="text/javascript">
@ -57,60 +59,7 @@
</head> </head>
<body> <body>
<div id="root"></div> <div id="root"></div>
<script> <script type="text/javascript" src="assets/js/init.js"></script>
function urlParams () {
var qs = window.location.hash.substr(1)
if (window.location.search.length > 0) {
// use legacy query params instead of hash
window.location.hash = window.location.search.substr(1)
window.location.search = ''
}
var params = {}
var parts = qs.split('&')
for (var x in parts) {
var keyValue = parts[x].split('=')
if (keyValue[0] !== '') {
params[keyValue[0]] = keyValue[1]
}
}
return params
}
const defaultVersion = '0.8.0'
let versionToLoad = urlParams().appVersion ? urlParams().appVersion : defaultVersion
let assets = {
'0.8.0': ['https://use.fontawesome.com/releases/v5.8.1/css/all.css', 'assets/css/pygment_trac.css'],
'0.7.7': ['assets/css/font-awesome.min.css', 'assets/css/pygment_trac.css']
}
let versions = {
'0.7.7': 'assets/js/0.7.7/app.js', // commit 7b5c7ae3de935e0ccc32eadfd83bf7349478491e
'0.8.0': 'main.js'
}
for (let k in assets[versionToLoad]) {
let app = document.createElement('link')
app.setAttribute('rel', 'stylesheet')
app.setAttribute('href', assets[versionToLoad][k])
if (assets[versionToLoad][k] === 'https://use.fontawesome.com/releases/v5.8.1/css/all.css') {
app.setAttribute('integrity', 'sha384-50oBUHEmvpQ+1lW4y57PTFmhCaXp0ML5d60M1M7uH2+nqUivzIebhndOJK28anvf')
app.setAttribute('crossorigin', 'anonymous')
}
document.head.appendChild(app)
}
window.onload = () => {
BrowserFS.install(window)
BrowserFS.configure({
fs: "LocalStorage"
}, function(e) {
if (e) console.log(e)
let app = document.createElement('script')
app.setAttribute('src', versions[versionToLoad])
document.body.appendChild(app)
window.remixFileSystem = require('fs')
})
}
</script>
<script src="polyfills.js" type="module"></script> <script src="polyfills.js" type="module"></script>
<script src="https://kit.fontawesome.com/41dd021e94.js" crossorigin="anonymous"></script> <script src="https://kit.fontawesome.com/41dd021e94.js" crossorigin="anonymous"></script>
<script type="text/javascript" src="assets/js/intro.min.js"></script> <script type="text/javascript" src="assets/js/intro.min.js"></script>

@ -1,14 +1,13 @@
/* global localStorage, fetch */
import { PluginManager } from '@remixproject/engine' import { PluginManager } from '@remixproject/engine'
import { EventEmitter } from 'events' import { EventEmitter } from 'events'
import QueryParams from './lib/query-params' import { QueryParams } from '@remix-project/remix-lib'
import { IframePlugin } from '@remixproject/engine-web' import { IframePlugin } from '@remixproject/engine-web'
const _paq = window._paq = window._paq || [] const _paq = window._paq = window._paq || []
const requiredModules = [ // services + layout views + system views const requiredModules = [ // services + layout views + system views
'manager', 'config', 'compilerArtefacts', 'compilerMetadata', 'contextualListener', 'editor', 'offsetToLineColumnConverter', 'network', 'theme', 'manager', 'config', 'compilerArtefacts', 'compilerMetadata', 'contextualListener', 'editor', 'offsetToLineColumnConverter', 'network', 'theme',
'fileManager', 'contentImport', 'blockchain', 'web3Provider', 'scriptRunner', 'fetchAndCompile', 'mainPanel', 'hiddenPanel', 'sidePanel', 'menuicons', 'fileManager', 'contentImport', 'blockchain', 'web3Provider', 'scriptRunner', 'fetchAndCompile', 'mainPanel', 'hiddenPanel', 'sidePanel', 'menuicons',
'filePanel', 'terminal', 'settings', 'pluginManager', 'tabs', 'udapp', 'dGitProvider', 'solidity-logic', 'gistHandler', 'layout', 'notification', 'permissionhandler', 'walkthrough'] 'filePanel', 'terminal', 'settings', 'pluginManager', 'tabs', 'udapp', 'dGitProvider', 'solidity-logic', 'gistHandler', 'layout', 'notification', 'permissionhandler', 'walkthrough', 'storage']
const dependentModules = ['git', 'hardhat', 'slither'] // module which shouldn't be manually activated (e.g git is activated by remixd) const dependentModules = ['git', 'hardhat', 'slither'] // module which shouldn't be manually activated (e.g git is activated by remixd)
@ -174,7 +173,7 @@ class PluginLoader {
} }
this.loaders.queryParams = { this.loaders.queryParams = {
set: () => {}, set: () => { /* Do nothing. */ },
get: () => { get: () => {
const { activate } = queryParams.get() const { activate } = queryParams.get()
if (!activate) return [] if (!activate) return []

@ -73,7 +73,7 @@ export class SourceMappings {
lineBreaks.push(pos) lineBreaks.push(pos)
} }
this.lineBreaks = lineBreaks this.lineBreaks = lineBreaks
}; }
/** /**
* Get a list of nodes that are at the given "position". * Get a list of nodes that are at the given "position".

@ -2,7 +2,6 @@
"extends": "../../tsconfig.base.json", "extends": "../../tsconfig.base.json",
"compilerOptions": { "compilerOptions": {
"types": ["node"], "types": ["node"],
"module": "commonjs",
"esModuleInterop": true "esModuleInterop": true
}, },
"include": ["**/*.ts"] "include": ["**/*.ts"]

@ -1,16 +1,17 @@
{ {
"extends": "./tsconfig.json", "extends": "./tsconfig.json",
"compilerOptions": { "compilerOptions": {
"module": "commonjs", "module": "commonjs",
"outDir": "../../dist/out-tsc", "outDir": "../../dist/out-tsc",
"declaration": true, "allowSyntheticDefaultImports": true,
"rootDir": "./src", "esModuleInterop": true,
"types": ["node"] "declaration": true,
}, "rootDir": "./src",
"exclude": [ "types": ["node"]
"**/*.spec.ts", },
"tests/" "exclude": [
], "**/*.spec.ts",
"include": ["**/*.ts"] "tests/"
} ],
"include": ["**/*.ts"]
}

@ -9,8 +9,14 @@ const profile = {
methods: ['resolve', 'resolveAndSave', 'isExternalUrl'] methods: ['resolve', 'resolveAndSave', 'isExternalUrl']
} }
export type ResolvedImport = {
content: string,
cleanUrl: string
type: string
}
export class CompilerImports extends Plugin { export class CompilerImports extends Plugin {
previouslyHandled: {} previouslyHandled: Record<string, ResolvedImport>
urlResolver: any urlResolver: any
constructor () { constructor () {
super(profile) super(profile)
@ -64,9 +70,9 @@ export class CompilerImports extends Plugin {
if (!loadingCb) loadingCb = () => {} if (!loadingCb) loadingCb = () => {}
if (!cb) cb = () => {} if (!cb) cb = () => {}
var self = this const self = this
if (force) delete this.previouslyHandled[url] if (force) delete this.previouslyHandled[url]
var imported = this.previouslyHandled[url] const imported = this.previouslyHandled[url]
if (imported) { if (imported) {
return cb(null, imported.content, imported.cleanUrl, imported.type, url) return cb(null, imported.content, imported.cleanUrl, imported.type, url)
} }
@ -97,7 +103,7 @@ export class CompilerImports extends Plugin {
try { try {
const provider = await this.call('fileManager', 'getProviderOf', null) const provider = await this.call('fileManager', 'getProviderOf', null)
const path = targetPath || type + '/' + cleanUrl const path = targetPath || type + '/' + cleanUrl
if (provider) provider.addExternal('.deps/' + path, content, url) if (provider) await provider.addExternal('.deps/' + path, content, url)
} catch (err) { } catch (err) {
console.error(err) console.error(err)
} }

@ -2,8 +2,7 @@
import { Plugin } from '@remixproject/engine' import { Plugin } from '@remixproject/engine'
import { compile } from '@remix-project/remix-solidity' import { compile } from '@remix-project/remix-solidity'
import { util } from '@remix-project/remix-lib' import { util } from '@remix-project/remix-lib'
import { toChecksumAddress } from 'ethereumjs-util'
const ethutil = require('ethereumjs-util')
const profile = { const profile = {
name: 'fetchAndCompile', name: 'fetchAndCompile',
@ -32,7 +31,7 @@ export class FetchAndCompile extends Plugin {
* @return {CompilerAbstract} - compilation data targeting the given @arg contractAddress * @return {CompilerAbstract} - compilation data targeting the given @arg contractAddress
*/ */
async resolve (contractAddress, codeAtAddress, targetPath) { async resolve (contractAddress, codeAtAddress, targetPath) {
contractAddress = ethutil.toChecksumAddress(contractAddress) contractAddress = toChecksumAddress(contractAddress)
const localCompilation = async () => await this.call('compilerArtefacts', 'get', contractAddress) ? await this.call('compilerArtefacts', 'get', contractAddress) : await this.call('compilerArtefacts', 'get', '__last') ? await this.call('compilerArtefacts', 'get', '__last') : null const localCompilation = async () => await this.call('compilerArtefacts', 'get', contractAddress) ? await this.call('compilerArtefacts', 'get', contractAddress) : await this.call('compilerArtefacts', 'get', '__last') ? await this.call('compilerArtefacts', 'get', '__last') : null

@ -27,11 +27,11 @@ export class CompilerMetadata extends Plugin {
} }
onActivation () { onActivation () {
var self = this const self = this
this.on('solidity', 'compilationFinished', async (file, source, languageVersion, data) => { this.on('solidity', 'compilationFinished', async (file, source, languageVersion, data) => {
if (!await this.call('settings', 'get', 'settings/generate-contract-metadata')) return if (!await this.call('settings', 'get', 'settings/generate-contract-metadata')) return
const compiler = new CompilerAbstract(languageVersion, data, source) const compiler = new CompilerAbstract(languageVersion, data, source)
var path = self._extractPathOf(source.target) const path = self._extractPathOf(source.target)
compiler.visitContracts((contract) => { compiler.visitContracts((contract) => {
if (contract.file !== source.target) return if (contract.file !== source.target) return
(async () => { (async () => {
@ -44,23 +44,23 @@ export class CompilerMetadata extends Plugin {
} }
_extractPathOf (file) { _extractPathOf (file) {
var reg = /(.*)(\/).*/ const reg = /(.*)(\/).*/
var path = reg.exec(file) const path = reg.exec(file)
return path ? path[1] : '/' return path ? path[1] : '/'
} }
async _setArtefacts (content, contract, path) { async _setArtefacts (content, contract, path) {
content = content || '{}' content = content || '{}'
var metadata let metadata
try { try {
metadata = JSON.parse(content) metadata = JSON.parse(content)
} catch (e) { } catch (e) {
console.log(e) console.log(e)
} }
var fileName = this._JSONFileName(path, contract.name) const fileName = this._JSONFileName(path, contract.name)
var metadataFileName = this._MetadataFileName(path, contract.name) const metadataFileName = this._MetadataFileName(path, contract.name)
var deploy = metadata.deploy || {} const deploy = metadata.deploy || {}
this.networks.forEach((network) => { this.networks.forEach((network) => {
deploy[network] = this._syncContext(contract, deploy[network] || {}) deploy[network] = this._syncContext(contract, deploy[network] || {})
}) })
@ -73,7 +73,7 @@ export class CompilerMetadata extends Plugin {
} }
if (parsedMetadata) await this.call('fileManager', 'writeFile', metadataFileName, JSON.stringify(parsedMetadata, null, '\t')) if (parsedMetadata) await this.call('fileManager', 'writeFile', metadataFileName, JSON.stringify(parsedMetadata, null, '\t'))
var data = { const data = {
deploy, deploy,
data: { data: {
bytecode: contract.object.evm.bytecode, bytecode: contract.object.evm.bytecode,
@ -87,14 +87,14 @@ export class CompilerMetadata extends Plugin {
} }
_syncContext (contract, metadata) { _syncContext (contract, metadata) {
var linkReferences = metadata.linkReferences let linkReferences = metadata.linkReferences
var autoDeployLib = metadata.autoDeployLib let autoDeployLib = metadata.autoDeployLib
if (!linkReferences) linkReferences = {} if (!linkReferences) linkReferences = {}
if (autoDeployLib === undefined) autoDeployLib = true if (autoDeployLib === undefined) autoDeployLib = true
for (var libFile in contract.object.evm.bytecode.linkReferences) { for (const libFile in contract.object.evm.bytecode.linkReferences) {
if (!linkReferences[libFile]) linkReferences[libFile] = {} if (!linkReferences[libFile]) linkReferences[libFile] = {}
for (var lib in contract.object.evm.bytecode.linkReferences[libFile]) { for (const lib in contract.object.evm.bytecode.linkReferences[libFile]) {
if (!linkReferences[libFile][lib]) { if (!linkReferences[libFile][lib]) {
linkReferences[libFile][lib] = '<address>' linkReferences[libFile][lib] = '<address>'
} }

@ -2,7 +2,6 @@
import { Plugin } from '@remixproject/engine' import { Plugin } from '@remixproject/engine'
import { sourceMappingDecoder } from '@remix-project/remix-debug' import { sourceMappingDecoder } from '@remix-project/remix-debug'
const { AstWalker } = require('@remix-project/remix-astwalker')
const profile = { const profile = {
name: 'contextualListener', name: 'contextualListener',
@ -19,7 +18,7 @@ export class EditorContextListener extends Plugin {
_activeHighlights: Array<any> _activeHighlights: Array<any>
astWalker: any astWalker: any
currentPosition: any currentPosition: any
currentFile: String currentFile: string
nodes: Array<any> nodes: Array<any>
results: any results: any
estimationObj: any estimationObj: any
@ -28,7 +27,7 @@ export class EditorContextListener extends Plugin {
contract: any contract: any
activated: boolean activated: boolean
constructor () { constructor (astWalker) {
super(profile) super(profile)
this.activated = false this.activated = false
this._index = { this._index = {
@ -37,7 +36,7 @@ export class EditorContextListener extends Plugin {
} }
this._activeHighlights = [] this._activeHighlights = []
this.astWalker = new AstWalker() this.astWalker = astWalker
} }
onActivation () { onActivation () {

@ -13,15 +13,17 @@ const profile = {
version: '0.0.1' version: '0.0.1'
} }
type GistCallBackFn = (gistId: string) => void
export class GistHandler extends Plugin { export class GistHandler extends Plugin {
constructor () { constructor () {
super(profile) super(profile)
} }
async handleLoad (gistId: String | null, cb: Function) { async handleLoad (gistId: string | null, cb: GistCallBackFn) {
if (!cb) cb = () => {} if (!cb) cb = () => {}
var loadingFromGist = false let loadingFromGist = false
if (!gistId) { if (!gistId) {
loadingFromGist = true loadingFromGist = true
let value let value
@ -83,9 +85,9 @@ export class GistHandler extends Plugin {
return loadingFromGist return loadingFromGist
} }
load (gistId: String | null) { load (gistId: string | null) {
const self = this const self = this
return self.handleLoad(gistId, async (gistId: String | null) => { return self.handleLoad(gistId, async (gistId: string | null) => {
let data: any let data: any
try { try {
data = await (await fetch(`https://api.github.com/gists/${gistId}`)).json() as any data = await (await fetch(`https://api.github.com/gists/${gistId}`)).json() as any
@ -114,7 +116,7 @@ export class GistHandler extends Plugin {
const obj: StringByString = {} const obj: StringByString = {}
Object.keys(data.files).forEach((element) => { Object.keys(data.files).forEach((element) => {
const path = element.replace(/\.\.\./g, '/') const path = element.replace(/\.\.\./g, '/')
obj['/' + 'gist-' + gistId + '/' + path] = data.files[element] obj['/' + gistId + '/' + path] = data.files[element]
}) })
this.call('fileManager', 'setBatchFiles', obj, 'workspace', true, async (errorSavingFiles: any) => { this.call('fileManager', 'setBatchFiles', obj, 'workspace', true, async (errorSavingFiles: any) => {
if (errorSavingFiles) { if (errorSavingFiles) {
@ -132,7 +134,7 @@ export class GistHandler extends Plugin {
} }
const getGistId = (str) => { const getGistId = (str) => {
var idr = /[0-9A-Fa-f]{8,}/ const idr = /[0-9A-Fa-f]{8,}/
var match = idr.exec(str) const match = idr.exec(str)
return match ? match[0] : null return match ? match[0] : null
} }

@ -11,7 +11,7 @@ const profile = {
} }
export class OffsetToLineColumnConverter extends Plugin { export class OffsetToLineColumnConverter extends Plugin {
lineBreakPositionsByContent: {} lineBreakPositionsByContent: Record<number, Array<number>>
sourceMappingDecoder: any sourceMappingDecoder: any
constructor () { constructor () {
super(profile) super(profile)
@ -36,7 +36,7 @@ export class OffsetToLineColumnConverter extends Plugin {
// if we don't have ast, we process the only one available content (applicable also for compiler older than 0.4.12) // if we don't have ast, we process the only one available content (applicable also for compiler older than 0.4.12)
this.lineBreakPositionsByContent[file] = this.sourceMappingDecoder.getLinebreakPositions(sources[sourcesArray[0]].content) this.lineBreakPositionsByContent[file] = this.sourceMappingDecoder.getLinebreakPositions(sources[sourcesArray[0]].content)
} else { } else {
for (var filename in asts) { for (const filename in asts) {
const source = asts[filename] const source = asts[filename]
if (source.id === file) { if (source.id === file) {
this.lineBreakPositionsByContent[file] = this.sourceMappingDecoder.getLinebreakPositions(sources[filename].content) this.lineBreakPositionsByContent[file] = this.sourceMappingDecoder.getLinebreakPositions(sources[filename].content)

@ -64,7 +64,7 @@ export class CmdLine {
source.push('=> ' + (currentLineNumber + 1) + ': ' + currentLine) source.push('=> ' + (currentLineNumber + 1) + ': ' + currentLine)
const startLine = lineColumnPos.start.line const startLine = lineColumnPos.start.line
for (var i = 1; i < 4; i++) { for (let i = 1; i < 4; i++) {
const line = content[startLine + i] const line = content[startLine + i]
source.push(' ' + (startLine + i + 1) + ': ' + line) source.push(' ' + (startLine + i + 1) + ': ' + line)
} }

@ -185,7 +185,7 @@ export class BreakpointManager {
* @param {Object} sourceLocation - position of the breakpoint { file: '<file index>', row: '<line number' } * @param {Object} sourceLocation - position of the breakpoint { file: '<file index>', row: '<line number' }
*/ */
remove (sourceLocation) { remove (sourceLocation) {
var sources = this.breakpoints[sourceLocation.fileName] const sources = this.breakpoints[sourceLocation.fileName]
if (!sources) { if (!sources) {
return return
} }

@ -77,7 +77,7 @@ export class CodeManager {
const code = await this.codeResolver.resolveCode(address) const code = await this.codeResolver.resolveCode(address)
return code return code
} }
var codes = this.codeResolver.getExecutingCodeFromCache(address) let codes = this.codeResolver.getExecutingCodeFromCache(address)
if (codes) { if (codes) {
return codes return codes
} }

@ -36,7 +36,7 @@ export function nameOpCodes (raw, hardfork) {
} }
type Opcode = { type Opcode = {
name: String, name: string,
pushData?: Array<number> pushData?: Array<number>
in?: number in?: number
out?: number out?: number

@ -113,11 +113,11 @@ export class VmDebuggerLogic {
const address = this._traceManager.getCurrentCalledAddressAt(index) const address = this._traceManager.getCurrentCalledAddressAt(index)
if (!this.storageResolver) return if (!this.storageResolver) return
var storageViewer = new StorageViewer({ stepIndex: this.stepManager.currentStepIndex, tx: this.tx, address: address }, this.storageResolver, this._traceManager) const storageViewer = new StorageViewer({ stepIndex: this.stepManager.currentStepIndex, tx: this.tx, address: address }, this.storageResolver, this._traceManager)
storageViewer.storageRange().then((storage) => { storageViewer.storageRange().then((storage) => {
if (this.stepManager.currentStepIndex === index) { if (this.stepManager.currentStepIndex === index) {
var header = storageViewer.isComplete(address) ? '[Completely Loaded]' : '[Partially Loaded]' const header = storageViewer.isComplete(address) ? '[Completely Loaded]' : '[Partially Loaded]'
this.event.trigger('traceManagerStorageUpdate', [storage, header]) this.event.trigger('traceManagerStorageUpdate', [storage, header])
} }
}).catch((_error) => { }).catch((_error) => {
@ -197,10 +197,10 @@ export class VmDebuggerLogic {
if (index === this.traceLength - 1) { if (index === this.traceLength - 1) {
return this.event.trigger('traceStorageUpdate', [{}]) return this.event.trigger('traceStorageUpdate', [{}])
} }
var storageJSON = {} const storageJSON = {}
for (var k in this.addresses) { for (const k in this.addresses) {
var address = this.addresses[k] const address = this.addresses[k]
var storageViewer = new StorageViewer({ stepIndex: this.stepManager.currentStepIndex, tx: this.tx, address: address }, this.storageResolver, this._traceManager) const storageViewer = new StorageViewer({ stepIndex: this.stepManager.currentStepIndex, tx: this.tx, address: address }, this.storageResolver, this._traceManager)
try { try {
storageJSON[address] = await storageViewer.storageRange() storageJSON[address] = await storageViewer.storageRange()
} catch (e) { } catch (e) {

@ -81,7 +81,7 @@ export class Debugger {
sources[genSource.name] = { content: genSource.contents } sources[genSource.name] = { content: genSource.contents }
} }
} }
var lineColumnPos = await this.offsetToLineColumnConverter.offsetToLineColumn(rawLocation, rawLocation.file, sources, astSources) const lineColumnPos = await this.offsetToLineColumnConverter.offsetToLineColumn(rawLocation, rawLocation.file, sources, astSources)
this.event.trigger('newSourceLocation', [lineColumnPos, rawLocation, generatedSources, address]) this.event.trigger('newSourceLocation', [lineColumnPos, rawLocation, generatedSources, address])
} else { } else {
this.event.trigger('newSourceLocation', [null]) this.event.trigger('newSourceLocation', [null])

@ -22,7 +22,7 @@ export class DebuggerSolidityLocals {
init (sourceLocation) { init (sourceLocation) {
this._sourceLocation = sourceLocation this._sourceLocation = sourceLocation
var decodeTimeout = null let decodeTimeout = null
if (!this.storageResolver) { if (!this.storageResolver) {
return this.event.trigger('solidityLocalsMessage', ['storage not ready']) return this.event.trigger('solidityLocalsMessage', ['storage not ready'])
} }
@ -76,11 +76,11 @@ export class DebuggerSolidityLocals {
if (error) { if (error) {
return error return error
} }
var stack = result[0].value const stack = result[0].value
var memory = result[1].value const memory = result[1].value
var calldata = result[3].value const calldata = result[3].value
try { try {
var storageViewer = new StorageViewer({ stepIndex: this.stepManager.currentStepIndex, tx: this.tx, address: result[2].value }, this.storageResolver, this.traceManager) const storageViewer = new StorageViewer({ stepIndex: this.stepManager.currentStepIndex, tx: this.tx, address: result[2].value }, this.storageResolver, this.traceManager)
solidityLocals(this.stepManager.currentStepIndex, this.internalTreeCall, stack, memory, storageViewer, calldata, sourceLocation, cursor).then((locals) => { solidityLocals(this.stepManager.currentStepIndex, this.internalTreeCall, stack, memory, storageViewer, calldata, sourceLocation, cursor).then((locals) => {
if (!cursor) { if (!cursor) {
if (!locals['error']) { if (!locals['error']) {

@ -55,8 +55,8 @@ export class DebuggerStepManager {
this.revertionPoint = this.currentCall.return this.revertionPoint = this.currentCall.return
return this.event.trigger('revertWarning', [revertedReason]) return this.event.trigger('revertWarning', [revertedReason])
} }
for (var k = callsPath.length - 2; k >= 0; k--) { for (let k = callsPath.length - 2; k >= 0; k--) {
var parent = callsPath[k] const parent = callsPath[k]
if (!parent.reverted) continue if (!parent.reverted) continue
this.revertionPoint = parent.return this.revertionPoint = parent.return
this.event.trigger('revertWarning', ['parenthasthrown']) this.event.trigger('revertWarning', ['parenthasthrown'])
@ -82,7 +82,6 @@ export class DebuggerStepManager {
} }
const jumpOutDisabled = (step === this.traceManager.findStepOut(step)) const jumpOutDisabled = (step === this.traceManager.findStepOut(step))
this.event.trigger('stepChanged', [step, stepState, jumpOutDisabled]) this.event.trigger('stepChanged', [step, stepState, jumpOutDisabled])
}) })
} }
@ -140,7 +139,7 @@ export class DebuggerStepManager {
jumpOut (solidityMode) { jumpOut (solidityMode) {
if (!this.traceManager.isLoaded()) return if (!this.traceManager.isLoaded()) return
var step = this.traceManager.findStepOut(this.currentStepIndex) let step = this.traceManager.findStepOut(this.currentStepIndex)
if (solidityMode) { if (solidityMode) {
step = this.resolveToReducedTrace(step, 0) step = this.resolveToReducedTrace(step, 0)
} }
@ -201,7 +200,7 @@ export class DebuggerStepManager {
if (!this.debugger.callTree.reducedTrace.length) { if (!this.debugger.callTree.reducedTrace.length) {
return value return value
} }
var nextSource = util.findClosestIndex(value, this.debugger.callTree.reducedTrace) let nextSource = util.findClosestIndex(value, this.debugger.callTree.reducedTrace)
nextSource = nextSource + incr nextSource = nextSource + incr
if (nextSource <= 0) { if (nextSource <= 0) {
nextSource = 0 nextSource = 0

@ -27,7 +27,7 @@ function mapping (type, stateDefinitions, contractName) {
const keyType = parseType(keyTypeName, stateDefinitions, contractName, 'storage') const keyType = parseType(keyTypeName, stateDefinitions, contractName, 'storage')
const valueType = parseType(valueTypeName, stateDefinitions, contractName, 'storage') const valueType = parseType(valueTypeName, stateDefinitions, contractName, 'storage')
var underlyingTypes = { const underlyingTypes = {
keyType: keyType, keyType: keyType,
valueType: valueType valueType: valueType
} }
@ -329,9 +329,9 @@ function computeOffsets (types, stateDefinitions, contractName, location) {
offset: 0, offset: 0,
slot: 0 slot: 0
} }
for (var i in types) { for (const i in types) {
var variable = types[i] const variable = types[i]
var type = parseType(variable.typeDescriptions.typeString, stateDefinitions, contractName, location) const type = parseType(variable.typeDescriptions.typeString, stateDefinitions, contractName, location)
if (!type) { if (!type) {
console.log('unable to retrieve decode info of ' + variable.typeDescriptions.typeString) console.log('unable to retrieve decode info of ' + variable.typeDescriptions.typeString)
return null return null

@ -262,7 +262,7 @@ async function includeVariableDeclaration (tree, step, sourceLocation, scopeId,
// so, either this is the direct value, or the offset in memory. That depends on the type. // so, either this is the direct value, or the offset in memory. That depends on the type.
if (variableDeclaration.name !== '') { if (variableDeclaration.name !== '') {
states = tree.solidityProxy.extractStatesDefinitions() states = tree.solidityProxy.extractStatesDefinitions()
var location = extractLocationFromAstVariable(variableDeclaration) let location = extractLocationFromAstVariable(variableDeclaration)
location = location === 'default' ? 'storage' : location location = location === 'default' ? 'storage' : location
// we push the new local variable in our tree // we push the new local variable in our tree
tree.scopes[scopeId].locals[variableDeclaration.name] = { tree.scopes[scopeId].locals[variableDeclaration.name] = {

@ -10,7 +10,7 @@ export async function solidityLocals (vmtraceIndex, internalTreeCall, stack, mem
memory = formatMemory(memory) memory = formatMemory(memory)
let anonymousIncr = 1 let anonymousIncr = 1
for (const local in scope.locals) { for (const local in scope.locals) {
var variable = scope.locals[local] const variable = scope.locals[local]
if (variable.stackDepth < stack.length && variable.sourceLocation.start <= currentSourceLocation.start) { if (variable.stackDepth < stack.length && variable.sourceLocation.start <= currentSourceLocation.start) {
let name = variable.name let name = variable.name
if (name.indexOf('$') !== -1) { if (name.indexOf('$') !== -1) {

@ -10,8 +10,8 @@ import { computeOffsets } from './decodeInfo'
*/ */
export async function decodeState (stateVars, storageResolver) { export async function decodeState (stateVars, storageResolver) {
const ret = {} const ret = {}
for (var k in stateVars) { for (const k in stateVars) {
var stateVar = stateVars[k] const stateVar = stateVars[k]
try { try {
const decoded = await stateVar.type.decodeFromStorage(stateVar.storagelocation, storageResolver) const decoded = await stateVar.type.decodeFromStorage(stateVar.storagelocation, storageResolver)
decoded.constant = stateVar.constant decoded.constant = stateVar.constant

@ -50,7 +50,7 @@ export class ArrayType extends RefType {
} else { } else {
size = new BN(this.arraySize) size = new BN(this.arraySize)
} }
var k = toBN(0) const k = toBN(0)
for (; k.lt(size) && k.ltn(300); k.iaddn(1)) { for (; k.lt(size) && k.ltn(300); k.iaddn(1)) {
try { try {
ret.push(await this.underlyingType.decodeFromStorage(currentLocation, storageResolver)) ret.push(await this.underlyingType.decodeFromStorage(currentLocation, storageResolver))
@ -92,8 +92,8 @@ export class ArrayType extends RefType {
if (skip) offset = offset + (32 * skip) if (skip) offset = offset + (32 * skip)
let limit = length - skip let limit = length - skip
if (limit > 10) limit = 10 if (limit > 10) limit = 10
for (var k = 0; k < limit; k++) { for (let k = 0; k < limit; k++) {
var contentOffset = offset const contentOffset = offset
ret.push(this.underlyingType.decodeFromMemory(contentOffset, memory)) ret.push(this.underlyingType.decodeFromMemory(contentOffset, memory))
offset += 32 offset += 32
} }

@ -42,7 +42,7 @@ export class DynamicByteArray extends RefType {
} }
return { value: '0x' + ret.replace(/(00)+$/, ''), length: '0x' + length.toString(16), type: this.typeName } return { value: '0x' + ret.replace(/(00)+$/, ''), length: '0x' + length.toString(16), type: this.typeName }
} else { } else {
var size = parseInt(value.substr(value.length - 2, 2), 16) / 2 const size = parseInt(value.substr(value.length - 2, 2), 16) / 2
return { value: '0x' + value.substr(0, size * 2), length: '0x' + size.toString(16), type: this.typeName } return { value: '0x' + value.substr(0, size * 2), length: '0x' + size.toString(16), type: this.typeName }
} }
} }

@ -13,7 +13,7 @@ export class Struct extends RefType {
async decodeFromStorage (location, storageResolver) { async decodeFromStorage (location, storageResolver) {
const ret = {} const ret = {}
for (var item of this.members) { for (const item of this.members) {
const globalLocation = { const globalLocation = {
offset: location.offset + item.storagelocation.offset, offset: location.offset + item.storagelocation.offset,
slot: add(location.slot, item.storagelocation.slot) slot: add(location.slot, item.storagelocation.slot)
@ -31,8 +31,8 @@ export class Struct extends RefType {
decodeFromMemoryInternal (offset, memory) { decodeFromMemoryInternal (offset, memory) {
const ret = {} const ret = {}
this.members.map((item, i) => { this.members.map((item, i) => {
var contentOffset = offset const contentOffset = offset
var member = item.type.decodeFromMemory(contentOffset, memory) const member = item.type.decodeFromMemory(contentOffset, memory)
ret[item.name] = member ret[item.name] = member
if (!(item.type instanceof Mapping)) offset += 32 if (!(item.type instanceof Mapping)) offset += 32
}) })

@ -27,7 +27,7 @@ export class ValueType {
*/ */
async decodeFromStorage (location, storageResolver) { async decodeFromStorage (location, storageResolver) {
try { try {
var value = await extractHexValue(location, storageResolver, this.storageBytes) const value = await extractHexValue(location, storageResolver, this.storageBytes)
return { value: this.decodeValue(value), type: this.typeName } return { value: this.decodeValue(value), type: this.typeName }
} catch (e) { } catch (e) {
console.log(e) console.log(e)

@ -142,7 +142,7 @@ export function nodesAtPosition (astNodeType, position, ast) {
const astWalker = new AstWalker() const astWalker = new AstWalker()
const found = [] const found = []
const callback = function (node) { const callback = function (node) {
var nodeLocation = sourceLocationFromAstNode(node) const nodeLocation = sourceLocationFromAstNode(node)
if (!nodeLocation) { if (!nodeLocation) {
return return
} }

@ -13,7 +13,7 @@ export async function decodeMappingsKeys (web3, storage, corrections) {
const ret = {} const ret = {}
if (!corrections.length) corrections.push({ offset: 0, slot: 0 }) if (!corrections.length) corrections.push({ offset: 0, slot: 0 })
for (const hashedLoc in storage) { for (const hashedLoc in storage) {
var preimage let preimage
try { try {
const key = storage[hashedLoc].key const key = storage[hashedLoc].key
for (const k in corrections) { for (const k in corrections) {

@ -85,7 +85,7 @@ export class StorageResolver {
* - If @arg slot is not cached, the corresponding value will be resolved and the next 1000 slots. * - If @arg slot is not cached, the corresponding value will be resolved and the next 1000 slots.
*/ */
async storageRangeInternal (self, slotKey, tx, stepIndex, address) { async storageRangeInternal (self, slotKey, tx, stepIndex, address) {
var cached = this.fromCache(self, address) const cached = this.fromCache(self, address)
if (cached && cached.storage[slotKey]) { // we have the current slot in the cache and maybe the next 1000... if (cached && cached.storage[slotKey]) { // we have the current slot in the cache and maybe the next 1000...
return cached.storage return cached.storage
} }

@ -62,7 +62,7 @@ export class TraceCache {
if (!validReturnStep) { if (!validReturnStep) {
this.currentCall.call.reverted = reverted this.currentCall.call.reverted = reverted
} }
var parent = this.currentCall.parent const parent = this.currentCall.parent
if (parent) this.currentCall = { call: parent.call, parent: parent.parent } if (parent) this.currentCall = { call: parent.call, parent: parent.parent }
return return
} }
@ -123,12 +123,12 @@ export class TraceCache {
accumulateStorageChanges (index, address, storage) { accumulateStorageChanges (index, address, storage) {
const ret = Object.assign({}, storage) const ret = Object.assign({}, storage)
for (var k in this.storageChanges) { for (const k in this.storageChanges) {
const changesIndex = this.storageChanges[k] const changesIndex = this.storageChanges[k]
if (changesIndex > index) { if (changesIndex > index) {
return ret return ret
} }
var sstore = this.sstore[changesIndex] const sstore = this.sstore[changesIndex]
if (sstore.address === address && sstore.key) { if (sstore.address === address && sstore.key) {
ret[sstore.hashedKey] = { ret[sstore.hashedKey] = {
key: sstore.key, key: sstore.key,

@ -48,7 +48,7 @@ export class TraceManager {
this.isLoading = false this.isLoading = false
return true return true
} }
var mes = tx.hash + ' is not a contract invocation or contract creation.' const mes = tx.hash + ' is not a contract invocation or contract creation.'
console.log(mes) console.log(mes)
this.isLoading = false this.isLoading = false
throw new Error(mes) throw new Error(mes)
@ -290,7 +290,7 @@ export class TraceManager {
waterfall (calls, stepindex, cb) { waterfall (calls, stepindex, cb) {
const ret = [] const ret = []
let retError = null let retError = null
for (var call in calls) { for (const call in calls) {
calls[call].apply(this, [stepindex, function (error, result) { calls[call].apply(this, [stepindex, function (error, result) {
retError = error retError = error
ret.push({ error: error, value: result }) ret.push({ error: error, value: result })

@ -40,7 +40,7 @@ export class TraceStepManager {
const call = util.findCall(currentStep, this.traceAnalyser.traceCache.callsTree.call) const call = util.findCall(currentStep, this.traceAnalyser.traceCache.callsTree.call)
const subCalls = Object.keys(call.calls) const subCalls = Object.keys(call.calls)
if (subCalls.length) { if (subCalls.length) {
var callStart = util.findLowerBound(currentStep, subCalls) + 1 const callStart = util.findLowerBound(currentStep, subCalls) + 1
if (subCalls.length > callStart) { if (subCalls.length > callStart) {
return parseInt(subCalls[callStart]) - 1 return parseInt(subCalls[callStart]) - 1
} }

@ -37,7 +37,7 @@ export function encodeData (funABI, values, contractbyteCode) {
*/ */
export function encodeParams (params, funAbi, callback) { export function encodeParams (params, funAbi, callback) {
let data: Buffer | string = '' let data: Buffer | string = ''
let dataHex: string = '' let dataHex = ''
let funArgs let funArgs
if (params.indexOf('raw:0x') === 0) { if (params.indexOf('raw:0x') === 0) {
// in that case we consider that the input is already encoded and *does not* contain the method signature // in that case we consider that the input is already encoded and *does not* contain the method signature
@ -167,7 +167,7 @@ export function encodeConstructorCallAndDeployLibraries (contractName, contract,
export function buildData (contractName, contract, contracts, isConstructor, funAbi, params, callback, callbackStep, callbackDeployLibrary) { export function buildData (contractName, contract, contracts, isConstructor, funAbi, params, callback, callbackStep, callbackDeployLibrary) {
let funArgs = [] let funArgs = []
let data: Buffer | string = '' let data: Buffer | string = ''
let dataHex: string = '' let dataHex = ''
if (params.indexOf('raw:0x') === 0) { if (params.indexOf('raw:0x') === 0) {
// in that case we consider that the input is already encoded and *does not* contain the method signature // in that case we consider that the input is already encoded and *does not* contain the method signature

@ -369,7 +369,7 @@ export class TxListener {
const abiCoder = new ethers.utils.AbiCoder() const abiCoder = new ethers.utils.AbiCoder()
const decoded = abiCoder.decode(inputTypes, data) const decoded = abiCoder.decode(inputTypes, data)
const ret = {} const ret = {}
for (var k in abi.inputs) { for (const k in abi.inputs) {
ret[abi.inputs[k].type + ' ' + abi.inputs[k].name] = decoded[k] ret[abi.inputs[k].type + ' ' + abi.inputs[k].name] = decoded[k]
} }
return ret return ret

@ -106,7 +106,7 @@ export class TxRunnerVM {
const coinbases = ['0x0e9281e9c6a0808672eaba6bd1220e144c9bb07a', '0x8945a1288dc78a6d8952a92c77aee6730b414778', '0x94d76e24f818426ae84aa404140e8d5f60e10e7e'] const coinbases = ['0x0e9281e9c6a0808672eaba6bd1220e144c9bb07a', '0x8945a1288dc78a6d8952a92c77aee6730b414778', '0x94d76e24f818426ae84aa404140e8d5f60e10e7e']
const difficulties = [new BN('69762765929000', 10), new BN('70762765929000', 10), new BN('71762765929000', 10)] const difficulties = [new BN('69762765929000', 10), new BN('70762765929000', 10), new BN('71762765929000', 10)]
var block = Block.fromBlockData({ const block = Block.fromBlockData({
header: { header: {
timestamp: timestamp || (new Date().getTime() / 1000 | 0), timestamp: timestamp || (new Date().getTime() / 1000 | 0),
number: self.blockNumber, number: self.blockNumber,

@ -52,7 +52,7 @@ export class TxRunnerWeb3 {
return callback(err, resp) return callback(err, resp)
} }
this.event.trigger('transactionBroadcasted', [resp]) this.event.trigger('transactionBroadcasted', [resp])
var listenOnResponse = () => { const listenOnResponse = () => {
// eslint-disable-next-line no-async-promise-executor // eslint-disable-next-line no-async-promise-executor
return new Promise(async (resolve, reject) => { return new Promise(async (resolve, reject) => {
const receipt = await tryTillReceiptAvailable(resp, this.getWeb3()) const receipt = await tryTillReceiptAvailable(resp, this.getWeb3())

@ -10,13 +10,13 @@ export function toInt (h) {
return h return h
} }
export var stringify = convertToString export const stringify = convertToString
function convertToString (v) { function convertToString (v) {
try { try {
if (v instanceof Array) { if (v instanceof Array) {
const ret = [] const ret = []
for (var k in v) { for (const k in v) {
ret.push(convertToString(v[k])) ret.push(convertToString(v[k]))
} }
return ret return ret

@ -45,13 +45,13 @@ export function tryConvertAsciiFormat (memorySlot) {
*/ */
export function formatCss (css1, css2) { export function formatCss (css1, css2) {
let ret = '' let ret = ''
for (const arg in arguments) { for (const arg in arguments) { // eslint-disable-line
for (const k in arguments[arg]) { for (const k in arguments[arg]) { // eslint-disable-line
if (arguments[arg][k] && ret.indexOf(k) === -1) { if (arguments[arg][k] && ret.indexOf(k) === -1) { // eslint-disable-line
if (k.indexOf('*') === 0) { if (k.indexOf('*') === 0) {
ret += arguments[arg][k] ret += arguments[arg][k] // eslint-disable-line
} else { } else {
ret += k + ':' + arguments[arg][k] + ';' ret += k + ':' + arguments[arg][k] + ';' // eslint-disable-line
} }
} }
} }

@ -19,6 +19,7 @@ import { TxRunnerVM } from './execution/txRunnerVM'
import { TxRunnerWeb3 } from './execution/txRunnerWeb3' import { TxRunnerWeb3 } from './execution/txRunnerWeb3'
import * as txResultHelper from './helpers/txResultHelper' import * as txResultHelper from './helpers/txResultHelper'
export { ICompilerApi, ConfigurationSettings } from './types/ICompilerApi' export { ICompilerApi, ConfigurationSettings } from './types/ICompilerApi'
export { QueryParams } from './query-params'
const helpers = { const helpers = {
ui: uiHelper, ui: uiHelper,

@ -0,0 +1,38 @@
'use strict'
export class QueryParams {
update (params) {
const currentParams = this.get()
const keys = Object.keys(params)
for (const x in keys) {
currentParams[keys[x]] = params[keys[x]]
}
let queryString = '#'
const updatedKeys = Object.keys(currentParams)
for (const y in updatedKeys) {
queryString += updatedKeys[y] + '=' + currentParams[updatedKeys[y]] + '&'
}
window.location.hash = queryString.slice(0, -1)
}
get () {
const qs = window.location.hash.substr(1)
if (window.location.search.length > 0) {
// use legacy query params instead of hash
window.location.hash = window.location.search.substr(1)
window.location.search = ''
}
const params = {}
const parts = qs.split('&')
for (const x in parts) {
const keyValue = parts[x].split('=')
if (keyValue[0] !== '') {
params[keyValue[0]] = keyValue[1]
}
}
return params
}
}

@ -10,7 +10,7 @@ export class Storage {
if (typeof window !== 'undefined') { if (typeof window !== 'undefined') {
this.safeKeys().forEach(function (name) { this.safeKeys().forEach(function (name) {
if (name.indexOf('sol-cache-file-', 0) === 0) { if (name.indexOf('sol-cache-file-', 0) === 0) {
var content = window.localStorage.getItem(name) const content = window.localStorage.getItem(name)
window.localStorage.setItem(name.replace(/^sol-cache-file-/, 'sol:'), content) window.localStorage.setItem(name.replace(/^sol-cache-file-/, 'sol:'), content)
window.localStorage.removeItem(name) window.localStorage.removeItem(name)
} }

@ -34,7 +34,7 @@ export interface ICompilerApi {
open: (file: string) => void open: (file: string) => void
saveCurrentFile: () => void saveCurrentFile: () => void
logToTerminal: (log: terminalLog) => {} logToTerminal: (log: terminalLog) => void
compileWithHardhat: (configPath: string) => Promise<string> compileWithHardhat: (configPath: string) => Promise<string>
} }

@ -152,7 +152,7 @@ export class Web3VmProvider {
const log = data.execResult.logs[l] const log = data.execResult.logs[l]
const topics = [] const topics = []
if (log[1].length > 0) { if (log[1].length > 0) {
for (var k in log[1]) { for (const k in log[1]) {
topics.push('0x' + log[1][k].toString('hex')) topics.push('0x' + log[1][k].toString('hex'))
} }
} else { } else {

@ -35,7 +35,7 @@ function createContract (payload, from, data, value, gasLimit, txRunner, callbac
} }
export function processTx (txRunnerInstance, payload, isCall, callback) { export function processTx (txRunnerInstance, payload, isCall, callback) {
let { from, to, data, value, gas } = payload.params[0] let { from, to, data, value, gas } = payload.params[0] // eslint-disable-line
gas = gas || 3000000 gas = gas || 3000000
const callbacks = { const callbacks = {

@ -77,11 +77,11 @@ export class Provider {
disconnect () { disconnect () {
return false return false
}; }
supportsSubscriptions () { supportsSubscriptions () {
return true return true
}; }
on (type, cb) { on (type, cb) {
this.vmContext.logsManager.addListener(type, cb) this.vmContext.logsManager.addListener(type, cb)

@ -1,5 +1,5 @@
const semver = require('semver') import * as semver from 'semver'
const minixhr = require('minixhr') import * as minixhr from 'minixhr'
/* global Worker */ /* global Worker */
export const baseURLBin = 'https://binaries.soliditylang.org/bin' export const baseURLBin = 'https://binaries.soliditylang.org/bin'

@ -103,7 +103,7 @@ export class Compiler {
onInternalCompilerLoaded (): void { onInternalCompilerLoaded (): void {
if (this.state.worker === null) { if (this.state.worker === null) {
const compiler: any = typeof (window) !== 'undefined' && window['Module'] ? require('solc/wrapper')(window['Module']) : require('solc') const compiler: any = typeof (window) !== 'undefined' && window['Module'] ? require('solc/wrapper')(window['Module']) : require('solc') // eslint-disable-line
this.state.compileJSON = (source: SourceWithTarget) => { this.state.compileJSON = (source: SourceWithTarget) => {
const missingInputs: string[] = [] const missingInputs: string[] = []
const missingInputsCallback = (path: string) => { const missingInputsCallback = (path: string) => {
@ -170,7 +170,7 @@ export class Compiler {
loadRemoteVersion (version: string): void { loadRemoteVersion (version: string): void {
console.log(`Loading remote solc version ${version} ...`) console.log(`Loading remote solc version ${version} ...`)
const compiler: any = require('solc') const compiler: any = require('solc') // eslint-disable-line
compiler.loadRemoteVersion(version, (err, remoteCompiler) => { compiler.loadRemoteVersion(version, (err, remoteCompiler) => {
if (err) { if (err) {
console.error('Error in loading remote solc compiler: ', err) console.error('Error in loading remote solc compiler: ', err)

@ -14,7 +14,7 @@ function regexIndexOf (inputString: string, regex: RegExp, startpos = 0) {
} }
export function writeTestAccountsContract (accounts: string[]) { export function writeTestAccountsContract (accounts: string[]) {
const testAccountContract = require('../sol/tests_accounts.sol') const testAccountContract = require('../sol/tests_accounts.sol') // eslint-disable-line
let body = `address[${accounts.length}] memory accounts;` let body = `address[${accounts.length}] memory accounts;`
if (!accounts.length) body += ';' if (!accounts.length) body += ';'
else { else {
@ -152,7 +152,7 @@ export function compileFileOrFiles (filename: string, isDirectory: boolean, opts
if (result.error) error.push(result.error) if (result.error) error.push(result.error)
const errors = (result.errors || error).filter((e) => e.type === 'Error' || e.severity === 'error') const errors = (result.errors || error).filter((e) => e.type === 'Error' || e.severity === 'error')
if (errors.length > 0) { if (errors.length > 0) {
if (!isBrowser) require('signale').fatal(errors) if (!isBrowser) require('signale').fatal(errors) // eslint-disable-line
return cb(new CompilationErrors(errors)) return cb(new CompilationErrors(errors))
} }
cb(err, result.contracts, result.sources) // return callback with contract details & ASTs cb(err, result.contracts, result.sources) // return callback with contract details & ASTs
@ -217,7 +217,7 @@ export function compileContractSources (sources: SrcIfc, newCompConfig: any, imp
if (result.error) error.push(result.error) if (result.error) error.push(result.error)
const errors = (result.errors || error).filter((e) => e.type === 'Error' || e.severity === 'error') const errors = (result.errors || error).filter((e) => e.type === 'Error' || e.severity === 'error')
if (errors.length > 0) { if (errors.length > 0) {
if (!isBrowser) require('signale').fatal(errors) if (!isBrowser) require('signale').fatal(errors) // eslint-disable-line
return cb(new CompilationErrors(errors)) return cb(new CompilationErrors(errors))
} }
cb(err, result.contracts, result.sources) // return callback with contract details & ASTs cb(err, result.contracts, result.sources) // return callback with contract details & ASTs

@ -1,6 +1,6 @@
// Extend fs // Extend fs
import path from 'path' import path from 'path'
const fs: any = require('fs') const fs: any = require('fs') // eslint-disable-line
// https://github.com/mikeal/node-utils/blob/master/file/lib/main.js // https://github.com/mikeal/node-utils/blob/master/file/lib/main.js
fs.walkSync = function (start: string, callback) { fs.walkSync = function (start: string, callback) {

@ -2,5 +2,5 @@ export { runTestFiles } from './runTestFiles'
export { UnitTestRunner } from './runTestSources' export { UnitTestRunner } from './runTestSources'
export { runTest } from './testRunner' export { runTest } from './testRunner'
export * from './types' export * from './types'
export const assertLibCode = require('../sol/tests.sol') export const assertLibCode = require('../sol/tests.sol') // eslint-disable-line
export { writeTestAccountsContract } from './compiler' export { writeTestAccountsContract } from './compiler'

@ -32,7 +32,7 @@ function mapOptimize (v: string) {
return optimize[v] return optimize[v]
} }
const version = require('../package.json').version const version = require('../package.json').version // eslint-disable-line
commander.version(version) commander.version(version)

@ -22,7 +22,7 @@ export function runTestFiles (filepath: string, isDirectory: boolean, web3: Web3
opts = opts || {} opts = opts || {}
compilerConfig = compilerConfig || {} as CompilerConfiguration compilerConfig = compilerConfig || {} as CompilerConfiguration
const sourceASTs: any = {} const sourceASTs: any = {}
const { Signale } = require('signale') const { Signale } = require('signale') // eslint-disable-line
// signale configuration // signale configuration
const options = { const options = {
types: { types: {

@ -1,5 +1,5 @@
export { default as RemixApp } from './lib/remix-app/remix-app' export { default as RemixApp } from './lib/remix-app/remix-app'
export { dispatchModalContext } from './lib/remix-app/context/context' export { dispatchModalContext, AppContext } from './lib/remix-app/context/context'
export { ModalProvider } from './lib/remix-app/context/provider' export { ModalProvider } from './lib/remix-app/context/provider'
export { AppModal } from './lib/remix-app/interface/index' export { AppModal } from './lib/remix-app/interface/index'
export { AlertModal } from './lib/remix-app/interface/index' export { AlertModal } from './lib/remix-app/interface/index'

@ -1,6 +1,5 @@
import React, { useEffect, useRef, useState } from 'react' import React, { useEffect, useRef, useState } from 'react'
import { ModalDialog } from '@remix-ui/modal-dialog' import { ModalDialog, ModalDialogProps } from '@remix-ui/modal-dialog'
import { ModalDialogProps } from 'libs/remix-ui/modal-dialog/src/lib/types'
import { ModalTypes } from '../../types' import { ModalTypes } from '../../types'
interface ModalWrapperProps extends ModalDialogProps { interface ModalWrapperProps extends ModalDialogProps {

@ -1,7 +1,6 @@
import React from 'react' import React from 'react'
import { AlertModal, AppModal } from '../interface' import { AlertModal, AppModal } from '../interface'
import { ModalInitialState } from '../state/modals' import { ModalInitialState } from '../state/modals'
import { ModalTypes } from '../types'
export const AppContext = React.createContext<any>(null) export const AppContext = React.createContext<any>(null)

@ -7,6 +7,7 @@ import DragBar from './components/dragbar/dragbar'
import { AppProvider } from './context/provider' import { AppProvider } from './context/provider'
import AppDialogs from './components/modals/dialogs' import AppDialogs from './components/modals/dialogs'
import DialogViewPlugin from './components/modals/dialogViewPlugin' import DialogViewPlugin from './components/modals/dialogViewPlugin'
import { AppContext } from './context/context'
interface IRemixAppUi { interface IRemixAppUi {
app: any app: any
@ -96,7 +97,7 @@ const RemixApp = (props: IRemixAppUi) => {
{components.sidePanel} {components.sidePanel}
<DragBar minWidth={250} refObject={sidePanelRef} hidden={hideSidePanel} setHideStatus={setHideSidePanel}></DragBar> <DragBar minWidth={250} refObject={sidePanelRef} hidden={hideSidePanel} setHideStatus={setHideSidePanel}></DragBar>
<div id="main-panel" data-id="remixIdeMainPanel" className='mainpanel'> <div id="main-panel" data-id="remixIdeMainPanel" className='mainpanel'>
<RemixUIMainPanel></RemixUIMainPanel> <RemixUIMainPanel Context={AppContext}></RemixUIMainPanel>
</div> </div>
</div> </div>
{components.hiddenPanel} {components.hiddenPanel}

@ -13,10 +13,11 @@ interface ICopyToClipboard {
className?: string, className?: string,
title?: string, title?: string,
children?: JSX.Element, children?: JSX.Element,
getContent?: () => {} getContent?: () => any
} }
export const CopyToClipboard = (props: ICopyToClipboard) => { export const CopyToClipboard = (props: ICopyToClipboard) => {
let { content, tip = 'Copy', icon = 'fa-copy', direction = 'right', children, getContent, ...otherProps } = props const { tip = 'Copy', icon = 'fa-copy', direction = 'right', getContent, children, ...otherProps } = props
let { content } = props
const [message, setMessage] = useState(tip) const [message, setMessage] = useState(tip)
const copyData = () => { const copyData = () => {

@ -6,9 +6,9 @@ import VmDebuggerHead from './vm-debugger/vm-debugger-head' // eslint-disable-li
import { TransactionDebugger as Debugger } from '@remix-project/remix-debug' // eslint-disable-line import { TransactionDebugger as Debugger } from '@remix-project/remix-debug' // eslint-disable-line
import { DebuggerUIProps } from './idebugger-api' // eslint-disable-line import { DebuggerUIProps } from './idebugger-api' // eslint-disable-line
import { Toaster } from '@remix-ui/toaster' // eslint-disable-line import { Toaster } from '@remix-ui/toaster' // eslint-disable-line
import { isValidHash } from '@remix-ui/helper'
/* eslint-disable-next-line */ /* eslint-disable-next-line */
import './debugger-ui.css' import './debugger-ui.css'
const helper = require('../../../../../apps/remix-ide/src/lib/helper')
const _paq = (window as any)._paq = (window as any)._paq || [] const _paq = (window as any)._paq = (window as any)._paq || []
export const DebuggerUI = (props: DebuggerUIProps) => { export const DebuggerUI = (props: DebuggerUIProps) => {
@ -171,7 +171,7 @@ export const DebuggerUI = (props: DebuggerUIProps) => {
txNumber: txNumber txNumber: txNumber
} }
}) })
if (!helper.isValidHash(txNumber)) { if (!isValidHash(txNumber)) {
setState(prevState => { setState(prevState => {
return { return {
...prevState, ...prevState,
@ -230,6 +230,7 @@ export const DebuggerUI = (props: DebuggerUIProps) => {
debugWithGeneratedSources: state.opt.debugWithGeneratedSources debugWithGeneratedSources: state.opt.debugWithGeneratedSources
}) })
setTimeout(async() => {
try { try {
await debuggerInstance.debug(blockNumber, txNumber, tx, () => { await debuggerInstance.debug(blockNumber, txNumber, tx, () => {
listenToEvents(debuggerInstance, currentReceipt) listenToEvents(debuggerInstance, currentReceipt)
@ -257,6 +258,7 @@ export const DebuggerUI = (props: DebuggerUIProps) => {
} }
}) })
} }
}, 300)
} }
const debug = (txHash, web3?) => { const debug = (txHash, web3?) => {

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save