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: "Circle CI"
working_directory: ~/remix-project
steps:
- 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,
"ignorePatterns": ["**/*"],
"ignorePatterns": [],
"plugins": ["@nrwl/nx"],
"overrides": [
{

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

@ -36,9 +36,9 @@ module.exports = {
.addFile('File.sol', { content: '' })
.executeScript(`remix.loadgist('${gistid}')`)
// .perform((done) => { if (runtimeBrowser === 'chrome') { browser.openFile('gists') } done() })
.waitForElementVisible(`[data-id="treeViewLitreeViewItemgist-${gistid}"]`)
.click(`[data-id="treeViewLitreeViewItemgist-${gistid}"]`)
.openFile(`gist-${gistid}/README.txt`)
.waitForElementVisible(`[data-id="treeViewLitreeViewItem${gistid}"]`)
.click(`[data-id="treeViewLitreeViewItem${gistid}"]`)
.openFile(`${gistid}/README.txt`)
// Remix publish to gist
/* .click('*[data-id="fileExplorerNewFilepublishToGist"]')
.pause(2000)
@ -140,9 +140,9 @@ module.exports = {
})
.setValue('*[data-id="gisthandlerModalDialogModalBody-react"] input[data-id="modalDialogCustomPromp"]', testData.validGistId)
.modalFooterOKClick('gisthandler')
.openFile(`gist-${testData.validGistId}/README.txt`)
.waitForElementVisible(`div[title='default_workspace/gist-${testData.validGistId}/README.txt']`)
.assert.containsText(`div[title='default_workspace/gist-${testData.validGistId}/README.txt'] > span`, 'README.txt')
.openFile(`${testData.validGistId}/README.txt`)
.waitForElementVisible(`div[title='default_workspace/${testData.validGistId}/README.txt']`)
.assert.containsText(`div[title='default_workspace/${testData.validGistId}/README.txt'] > span`, 'README.txt')
.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) => {
browser.useXpath().waitForElementVisible(`//*[@data-id='${buttonText}']`).pause(100)
.click(`//*[@data-id='${buttonText}']`, async () => {
@ -107,7 +107,7 @@ const checkForAcceptAndRemember = async function (browser: NightwatchBrowser) {
* @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) {
await setPayload(browser, payload)
} else {
@ -235,7 +235,9 @@ module.exports = {
},
'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: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) {
await clickAndCheckLog(browser, 'fileManager:setFile', null, { event: 'fileAdded', args: ['new.sol'] }, ['new.sol', 'test'])

@ -11,7 +11,7 @@ module.exports = {
return sources
},
'Test Recorder': function (browser: NightwatchBrowser) {
'Run Scenario': function (browser: NightwatchBrowser) {
let addressRef
browser.addFile('scenario.json', { content: records })
.pause(5000)
@ -34,7 +34,10 @@ module.exports = {
.perform(() => done())
})
.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')
.createContract('12')
.clickInstance(0)
@ -45,7 +48,7 @@ module.exports = {
const modalOk = document.querySelector('[data-id="udappNotify-modal-footer-ok-react"]') as any
modalOk.click()
})
}).pause(1000)
.getEditorValue(function (result) {
const parsed = JSON.parse(result)
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)
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')
// 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'])
.openFile('signMassage.sol')

@ -18,7 +18,7 @@ module.exports = {
'Test Success Import #group1': function (browser: NightwatchBrowser) {
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')
.verifyContracts(['test6', 'test4', 'test5'])
.pause(1000)

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

@ -202,10 +202,10 @@ module.exports = {
.addFile('Storage.sol', sources[6]['Storage.sol'])
.addFile('Owner.sol', sources[6]['Owner.sol'])
.clickLaunchIcon('udapp')
.createContract('42')
.createContract('42, 24')
.openFile('Storage.sol')
.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)
.clickFunction('store - transact (not payable)', { types: 'uint256 num', values: '24' })
.testFunction('last', // we check if the contract is actually reachable.
@ -375,7 +375,7 @@ contract C {
/**
* @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
emit OwnerSet(address(0), owner);
}
@ -412,6 +412,10 @@ contract C {
uint256 number;
constructor(uint p) {
}
/**
* @dev Store value in variable
* @param num value to store

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

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

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

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

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

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

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

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

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

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

@ -1,5 +1,5 @@
import { Plugin } from '@remixproject/engine'
import QueryParams from '../../lib/query-params'
import { QueryParams } from '@remix-project/remix-lib'
import Registry from '../state/registry'
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 { SolidityCompiler } 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 QueryParams from '../../lib/query-params'
import { QueryParams } from '@remix-project/remix-lib'
// import { ICompilerApi } from '@remix-project/remix-lib-ts'
import * as packageJson from '../../../../../package.json'
import { compilerConfigChangedToastMsg, compileToastMsg } from '@remix-ui/helper'

@ -1,5 +1,5 @@
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 * as packageJson from '../../../../../package.json'
import React from 'react' // eslint-disable-line

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

@ -119,7 +119,7 @@ module.exports = class TestTab extends ViewPlugin {
usingWorker: canUseWorker(currentVersion),
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)
resolve(result)
}, (url, cb) => {

@ -1,6 +1,6 @@
import { Plugin } from '@remixproject/engine'
import { EventEmitter } from 'events'
import QueryParams from '../../lib/query-params'
import { QueryParams } from '@remix-project/remix-lib'
import * as packageJson from '../../../../../package.json'
import Registry from '../state/registry'
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) => {
// 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) {
const self = this
waterfall([
function getGasLimit (next) {
if (self.transactionContextAPI.getGasLimit) {
return self.transactionContextAPI.getGasLimit(next)
(next) => { // getGasLimit
if (this.transactionContextAPI.getGasLimit) {
return this.transactionContextAPI.getGasLimit(next)
}
next(null, 3000000)
},
function queryValue (gasLimit, next) {
(gasLimit, next) => { // queryValue
if (args.value) {
return next(null, args.value, gasLimit)
}
if (args.useCall || !self.transactionContextAPI.getValue) {
if (args.useCall || !this.transactionContextAPI.getValue) {
return next(null, 0, gasLimit)
}
self.transactionContextAPI.getValue(function (err, value) {
this.transactionContextAPI.getValue(function (err, value) {
next(err, value, gasLimit)
})
},
function getAccount (value, gasLimit, next) {
(value, gasLimit, next) => { // getAccount
if (args.from) {
return next(null, args.from, value, gasLimit)
}
if (self.transactionContextAPI.getAddress) {
return self.transactionContextAPI.getAddress(function (err, address) {
if (this.transactionContextAPI.getAddress) {
return this.transactionContextAPI.getAddress(function (err, address) {
next(err, address, value, gasLimit)
})
}
self.getAccounts(function (err, accounts) {
this.getAccounts(function (err, accounts) {
const address = accounts[0]
if (err) return next(err)
if (!address) return next('No accounts available')
// if (self.executionContext.isVM() && !self.providers.vm.accounts[address]) {
if (self.executionContext.isVM() && !self.providers.vm.RemixSimulatorProvider.Accounts.accounts[address]) {
if (this.executionContext.isVM() && !this.providers.vm.RemixSimulatorProvider.Accounts.accounts[address]) {
return next('Invalid account selected')
}
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 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()
const timestamp = tx.timestamp
self.event.trigger('initiatingTransaction', [timestamp, tx, payLoad])
self.txRunner.rawRun(tx, confirmationCb, continueCb, promptCb,
this.event.trigger('initiatingTransaction', [timestamp, tx, payLoad])
this.txRunner.rawRun(tx, confirmationCb, continueCb, promptCb,
async (error, result) => {
if (error) return next(error)
const isVM = self.executionContext.isVM()
const isVM = this.executionContext.isVM()
if (isVM && tx.useCall) {
try {
result.transactionHash = await self.web3().eth.getHashFromTagBySimulator(timestamp)
result.transactionHash = await this.web3().eth.getHashFromTagBySimulator(timestamp)
} catch (e) {
console.log('unable to retrieve back the "call" hash', e)
}
}
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.message) error = error.message
else {
try { error = 'error: ' + JSON.stringify(error) } catch (e) {}
try { error = 'error: ' + JSON.stringify(error) } catch (e) { console.log(e) }
}
}
next(error, result, tx)

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

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

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

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

@ -28,6 +28,8 @@
<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">
<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">
<!-- Matomo -->
<script type="text/javascript">
@ -57,60 +59,7 @@
</head>
<body>
<div id="root"></div>
<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 type="text/javascript" src="assets/js/init.js"></script>
<script src="runtime.js" type="module"></script>
<script src="polyfills.js" type="module"></script>
<script src="vendor.js" type="module"></script>

@ -64,7 +64,6 @@ module.exports = {
do {
const isDuplicate = await fileManager.exists(name + counter + prefix + '.' + ext)
if (isDuplicate) counter = (counter | 0) + 1
else exist = false
} 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="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/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">
<!-- Matomo -->
<script type="text/javascript">
@ -57,60 +59,7 @@
</head>
<body>
<div id="root"></div>
<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 type="text/javascript" src="assets/js/init.js"></script>
<script src="polyfills.js" type="module"></script>
<script src="https://kit.fontawesome.com/41dd021e94.js" crossorigin="anonymous"></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 { EventEmitter } from 'events'
import QueryParams from './lib/query-params'
import { QueryParams } from '@remix-project/remix-lib'
import { IframePlugin } from '@remixproject/engine-web'
const _paq = window._paq = window._paq || []
const requiredModules = [ // services + layout views + system views
'manager', 'config', 'compilerArtefacts', 'compilerMetadata', 'contextualListener', 'editor', 'offsetToLineColumnConverter', 'network', 'theme',
'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)
@ -174,7 +173,7 @@ class PluginLoader {
}
this.loaders.queryParams = {
set: () => {},
set: () => { /* Do nothing. */ },
get: () => {
const { activate } = queryParams.get()
if (!activate) return []

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

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

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

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

@ -2,8 +2,7 @@
import { Plugin } from '@remixproject/engine'
import { compile } from '@remix-project/remix-solidity'
import { util } from '@remix-project/remix-lib'
const ethutil = require('ethereumjs-util')
import { toChecksumAddress } from 'ethereumjs-util'
const profile = {
name: 'fetchAndCompile',
@ -32,7 +31,7 @@ export class FetchAndCompile extends Plugin {
* @return {CompilerAbstract} - compilation data targeting the given @arg contractAddress
*/
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

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

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

@ -13,15 +13,17 @@ const profile = {
version: '0.0.1'
}
type GistCallBackFn = (gistId: string) => void
export class GistHandler extends Plugin {
constructor () {
super(profile)
}
async handleLoad (gistId: String | null, cb: Function) {
async handleLoad (gistId: string | null, cb: GistCallBackFn) {
if (!cb) cb = () => {}
var loadingFromGist = false
let loadingFromGist = false
if (!gistId) {
loadingFromGist = true
let value
@ -83,9 +85,9 @@ export class GistHandler extends Plugin {
return loadingFromGist
}
load (gistId: String | null) {
load (gistId: string | null) {
const self = this
return self.handleLoad(gistId, async (gistId: String | null) => {
return self.handleLoad(gistId, async (gistId: string | null) => {
let data: any
try {
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 = {}
Object.keys(data.files).forEach((element) => {
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) => {
if (errorSavingFiles) {
@ -132,7 +134,7 @@ export class GistHandler extends Plugin {
}
const getGistId = (str) => {
var idr = /[0-9A-Fa-f]{8,}/
var match = idr.exec(str)
const idr = /[0-9A-Fa-f]{8,}/
const match = idr.exec(str)
return match ? match[0] : null
}

@ -11,7 +11,7 @@ const profile = {
}
export class OffsetToLineColumnConverter extends Plugin {
lineBreakPositionsByContent: {}
lineBreakPositionsByContent: Record<number, Array<number>>
sourceMappingDecoder: any
constructor () {
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)
this.lineBreakPositionsByContent[file] = this.sourceMappingDecoder.getLinebreakPositions(sources[sourcesArray[0]].content)
} else {
for (var filename in asts) {
for (const filename in asts) {
const source = asts[filename]
if (source.id === file) {
this.lineBreakPositionsByContent[file] = this.sourceMappingDecoder.getLinebreakPositions(sources[filename].content)

@ -64,7 +64,7 @@ export class CmdLine {
source.push('=> ' + (currentLineNumber + 1) + ': ' + currentLine)
const startLine = lineColumnPos.start.line
for (var i = 1; i < 4; i++) {
for (let i = 1; i < 4; i++) {
const line = content[startLine + i]
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' }
*/
remove (sourceLocation) {
var sources = this.breakpoints[sourceLocation.fileName]
const sources = this.breakpoints[sourceLocation.fileName]
if (!sources) {
return
}

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

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

@ -113,11 +113,11 @@ export class VmDebuggerLogic {
const address = this._traceManager.getCurrentCalledAddressAt(index)
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) => {
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])
}
}).catch((_error) => {
@ -197,10 +197,10 @@ export class VmDebuggerLogic {
if (index === this.traceLength - 1) {
return this.event.trigger('traceStorageUpdate', [{}])
}
var storageJSON = {}
for (var k in this.addresses) {
var address = this.addresses[k]
var storageViewer = new StorageViewer({ stepIndex: this.stepManager.currentStepIndex, tx: this.tx, address: address }, this.storageResolver, this._traceManager)
const storageJSON = {}
for (const k in this.addresses) {
const address = this.addresses[k]
const storageViewer = new StorageViewer({ stepIndex: this.stepManager.currentStepIndex, tx: this.tx, address: address }, this.storageResolver, this._traceManager)
try {
storageJSON[address] = await storageViewer.storageRange()
} catch (e) {

@ -81,7 +81,7 @@ export class Debugger {
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])
} else {
this.event.trigger('newSourceLocation', [null])

@ -22,7 +22,7 @@ export class DebuggerSolidityLocals {
init (sourceLocation) {
this._sourceLocation = sourceLocation
var decodeTimeout = null
let decodeTimeout = null
if (!this.storageResolver) {
return this.event.trigger('solidityLocalsMessage', ['storage not ready'])
}
@ -76,11 +76,11 @@ export class DebuggerSolidityLocals {
if (error) {
return error
}
var stack = result[0].value
var memory = result[1].value
var calldata = result[3].value
const stack = result[0].value
const memory = result[1].value
const calldata = result[3].value
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) => {
if (!cursor) {
if (!locals['error']) {

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

@ -27,7 +27,7 @@ function mapping (type, stateDefinitions, contractName) {
const keyType = parseType(keyTypeName, stateDefinitions, contractName, 'storage')
const valueType = parseType(valueTypeName, stateDefinitions, contractName, 'storage')
var underlyingTypes = {
const underlyingTypes = {
keyType: keyType,
valueType: valueType
}
@ -329,9 +329,9 @@ function computeOffsets (types, stateDefinitions, contractName, location) {
offset: 0,
slot: 0
}
for (var i in types) {
var variable = types[i]
var type = parseType(variable.typeDescriptions.typeString, stateDefinitions, contractName, location)
for (const i in types) {
const variable = types[i]
const type = parseType(variable.typeDescriptions.typeString, stateDefinitions, contractName, location)
if (!type) {
console.log('unable to retrieve decode info of ' + variable.typeDescriptions.typeString)
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.
if (variableDeclaration.name !== '') {
states = tree.solidityProxy.extractStatesDefinitions()
var location = extractLocationFromAstVariable(variableDeclaration)
let location = extractLocationFromAstVariable(variableDeclaration)
location = location === 'default' ? 'storage' : location
// we push the new local variable in our tree
tree.scopes[scopeId].locals[variableDeclaration.name] = {

@ -10,7 +10,7 @@ export async function solidityLocals (vmtraceIndex, internalTreeCall, stack, mem
memory = formatMemory(memory)
let anonymousIncr = 1
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) {
let name = variable.name
if (name.indexOf('$') !== -1) {

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

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

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

@ -27,7 +27,7 @@ export class ValueType {
*/
async decodeFromStorage (location, storageResolver) {
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 }
} catch (e) {
console.log(e)

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

@ -13,7 +13,7 @@ export async function decodeMappingsKeys (web3, storage, corrections) {
const ret = {}
if (!corrections.length) corrections.push({ offset: 0, slot: 0 })
for (const hashedLoc in storage) {
var preimage
let preimage
try {
const key = storage[hashedLoc].key
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.
*/
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...
return cached.storage
}

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

@ -48,7 +48,7 @@ export class TraceManager {
this.isLoading = false
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)
this.isLoading = false
throw new Error(mes)
@ -290,7 +290,7 @@ export class TraceManager {
waterfall (calls, stepindex, cb) {
const ret = []
let retError = null
for (var call in calls) {
for (const call in calls) {
calls[call].apply(this, [stepindex, function (error, result) {
retError = error
ret.push({ error: error, value: result })

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

@ -37,7 +37,7 @@ export function encodeData (funABI, values, contractbyteCode) {
*/
export function encodeParams (params, funAbi, callback) {
let data: Buffer | string = ''
let dataHex: string = ''
let dataHex = ''
let funArgs
if (params.indexOf('raw:0x') === 0) {
// 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) {
let funArgs = []
let data: Buffer | string = ''
let dataHex: string = ''
let dataHex = ''
if (params.indexOf('raw:0x') === 0) {
// 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 decoded = abiCoder.decode(inputTypes, data)
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]
}
return ret

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

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

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

@ -45,13 +45,13 @@ export function tryConvertAsciiFormat (memorySlot) {
*/
export function formatCss (css1, css2) {
let ret = ''
for (const arg in arguments) {
for (const k in arguments[arg]) {
if (arguments[arg][k] && ret.indexOf(k) === -1) {
for (const arg in arguments) { // eslint-disable-line
for (const k in arguments[arg]) { // eslint-disable-line
if (arguments[arg][k] && ret.indexOf(k) === -1) { // eslint-disable-line
if (k.indexOf('*') === 0) {
ret += arguments[arg][k]
ret += arguments[arg][k] // eslint-disable-line
} 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 * as txResultHelper from './helpers/txResultHelper'
export { ICompilerApi, ConfigurationSettings } from './types/ICompilerApi'
export { QueryParams } from './query-params'
const helpers = {
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') {
this.safeKeys().forEach(function (name) {
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.removeItem(name)
}

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

@ -152,7 +152,7 @@ export class Web3VmProvider {
const log = data.execResult.logs[l]
const topics = []
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'))
}
} else {

@ -35,7 +35,7 @@ function createContract (payload, from, data, value, gasLimit, txRunner, callbac
}
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
const callbacks = {

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

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

@ -103,7 +103,7 @@ export class Compiler {
onInternalCompilerLoaded (): void {
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) => {
const missingInputs: string[] = []
const missingInputsCallback = (path: string) => {
@ -170,7 +170,7 @@ export class Compiler {
loadRemoteVersion (version: string): void {
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) => {
if (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[]) {
const testAccountContract = require('../sol/tests_accounts.sol')
const testAccountContract = require('../sol/tests_accounts.sol') // eslint-disable-line
let body = `address[${accounts.length}] memory accounts;`
if (!accounts.length) body += ';'
else {
@ -152,7 +152,7 @@ export function compileFileOrFiles (filename: string, isDirectory: boolean, opts
if (result.error) error.push(result.error)
const errors = (result.errors || error).filter((e) => e.type === 'Error' || e.severity === 'error')
if (errors.length > 0) {
if (!isBrowser) require('signale').fatal(errors)
if (!isBrowser) require('signale').fatal(errors) // eslint-disable-line
return cb(new CompilationErrors(errors))
}
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)
const errors = (result.errors || error).filter((e) => e.type === 'Error' || e.severity === 'error')
if (errors.length > 0) {
if (!isBrowser) require('signale').fatal(errors)
if (!isBrowser) require('signale').fatal(errors) // eslint-disable-line
return cb(new CompilationErrors(errors))
}
cb(err, result.contracts, result.sources) // return callback with contract details & ASTs

@ -1,6 +1,6 @@
// Extend fs
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
fs.walkSync = function (start: string, callback) {

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

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

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

@ -1,5 +1,5 @@
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 { AppModal } 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 { ModalDialog } from '@remix-ui/modal-dialog'
import { ModalDialogProps } from 'libs/remix-ui/modal-dialog/src/lib/types'
import { ModalDialog, ModalDialogProps } from '@remix-ui/modal-dialog'
import { ModalTypes } from '../../types'
interface ModalWrapperProps extends ModalDialogProps {

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

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

@ -13,10 +13,11 @@ interface ICopyToClipboard {
className?: string,
title?: string,
children?: JSX.Element,
getContent?: () => {}
getContent?: () => any
}
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 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 { DebuggerUIProps } from './idebugger-api' // eslint-disable-line
import { Toaster } from '@remix-ui/toaster' // eslint-disable-line
import { isValidHash } from '@remix-ui/helper'
/* eslint-disable-next-line */
import './debugger-ui.css'
const helper = require('../../../../../apps/remix-ide/src/lib/helper')
const _paq = (window as any)._paq = (window as any)._paq || []
export const DebuggerUI = (props: DebuggerUIProps) => {
@ -171,7 +171,7 @@ export const DebuggerUI = (props: DebuggerUIProps) => {
txNumber: txNumber
}
})
if (!helper.isValidHash(txNumber)) {
if (!isValidHash(txNumber)) {
setState(prevState => {
return {
...prevState,
@ -230,6 +230,7 @@ export const DebuggerUI = (props: DebuggerUIProps) => {
debugWithGeneratedSources: state.opt.debugWithGeneratedSources
})
setTimeout(async() => {
try {
await debuggerInstance.debug(blockNumber, txNumber, tx, () => {
listenToEvents(debuggerInstance, currentReceipt)
@ -257,6 +258,7 @@ export const DebuggerUI = (props: DebuggerUIProps) => {
}
})
}
}, 300)
}
const debug = (txHash, web3?) => {

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

Loading…
Cancel
Save