diff --git a/.eslintrc b/.eslintrc index b6bd0ec6ec..3ecea66bf6 100644 --- a/.eslintrc +++ b/.eslintrc @@ -7,27 +7,21 @@ "project": "./tsconfig.json" }, "plugins": ["@typescript-eslint", "@nrwl/nx"], - "extends": [ - "eslint:recommended", - "plugin:@typescript-eslint/eslint-recommended", - "plugin:@typescript-eslint/recommended", - "prettier", - "prettier/@typescript-eslint" - ], + "extends": "standard", "rules": { - "@typescript-eslint/explicit-member-accessibility": "off", - "@typescript-eslint/explicit-function-return-type": "off", - "@typescript-eslint/no-parameter-properties": "off", - "@nrwl/nx/enforce-module-boundaries": [ - "error", - { - "enforceBuildableLibDependency": true, - "allow": [], - "depConstraints": [ - { "sourceTag": "*", "onlyDependOnLibsWithTags": ["*"] } - ] - } - ] + // "@typescript-eslint/explicit-member-accessibility": "off", + // "@typescript-eslint/explicit-function-return-type": "off", + // "@typescript-eslint/no-parameter-properties": "off", + // "@nrwl/nx/enforce-module-boundaries": [ + // "error", + // { + // "enforceBuildableLibDependency": true, + // "allow": [], + // "depConstraints": [ + // { "sourceTag": "*", "onlyDependOnLibsWithTags": ["*"] } + // ] + // } + // ] }, "overrides": [ { diff --git a/apps/remix-ide/.eslintrc b/apps/remix-ide/.eslintrc index 65be87f51f..7276b9859c 100644 --- a/apps/remix-ide/.eslintrc +++ b/apps/remix-ide/.eslintrc @@ -13,17 +13,6 @@ "sourceType": "module" }, "rules": { - "@typescript-eslint/no-var-requires": "off", - "@typescript-eslint/no-empty-function": "off", - "@typescript-eslint/explicit-module-boundary-types": "off", - "@typescript-eslint/no-this-alias": "off", - "no-unused-vars": "off", - "no-redeclare": "off", - "no-empty": "off", - "no-constant-condition": "off", - "no-async-promise-executor": "off", - "no-useless-catch": "off", - "no-extra-semi": "off", - "no-undef": "off" + "standard/no-callback-literal": "off" } -} +} diff --git a/apps/remix-ide/src/app.js b/apps/remix-ide/src/app.js index 420b40f95d..37de6debcc 100644 --- a/apps/remix-ide/src/app.js +++ b/apps/remix-ide/src/app.js @@ -1,4 +1,24 @@ 'use strict' +import { basicLogo } from './app/ui/svgLogo' + +import { RunTab, makeUdapp } from './app/udapp' + +import PanelsResize from './lib/panels-resize' +import { Engine } from '@remixproject/engine' +import { RemixAppManager } from './remixAppManager' +import { FramingService } from './framingService' +import { MainView } from './app/panels/main-view' +import { ThemeModule } from './app/tabs/theme-module' +import { NetworkModule } from './app/tabs/network-module' +import { Web3ProviderModule } from './app/tabs/web3-provider' +import { SidePanel } from './app/components/side-panel' +import { HiddenPanel } from './app/components/hidden-panel' +import { VerticalIcons } from './app/components/vertical-icons' +import { LandingPage } from './app/ui/landing-page/landing-page' +import { MainPanel } from './app/components/main-panel' +import FetchAndCompile from './app/compiler/compiler-sourceVerifier-fetchAndCompile' + +import migrateFileSystem from './migrateFileSystem' var isElectron = require('is-electron') var csjs = require('csjs-inject') @@ -36,26 +56,6 @@ const FilePanel = require('./app/panels/file-panel') const Editor = require('./app/editor/editor') const Terminal = require('./app/panels/terminal') const ContextualListener = require('./app/editor/contextualListener') -import { basicLogo } from './app/ui/svgLogo' - -import { RunTab, makeUdapp } from './app/udapp' - -import PanelsResize from './lib/panels-resize' -import { Engine } from '@remixproject/engine' -import { RemixAppManager } from './remixAppManager' -import { FramingService } from './framingService' -import { MainView } from './app/panels/main-view' -import { ThemeModule } from './app/tabs/theme-module' -import { NetworkModule } from './app/tabs/network-module' -import { Web3ProviderModule } from './app/tabs/web3-provider' -import { SidePanel } from './app/components/side-panel' -import { HiddenPanel } from './app/components/hidden-panel' -import { VerticalIcons } from './app/components/vertical-icons' -import { LandingPage } from './app/ui/landing-page/landing-page' -import { MainPanel } from './app/components/main-panel' -import FetchAndCompile from './app/compiler/compiler-sourceVerifier-fetchAndCompile' - -import migrateFileSystem from './migrateFileSystem' var css = csjs` html { box-sizing: border-box; } @@ -139,17 +139,17 @@ class App { // load app config const config = new Config(configStorage) - registry.put({api: config, name: 'config'}) + registry.put({ api: config, name: 'config' }) // load file system self._components.filesProviders = {} - self._components.filesProviders['browser'] = new FileProvider('browser') - registry.put({api: self._components.filesProviders['browser'], name: 'fileproviders/browser'}) - self._components.filesProviders['localhost'] = new RemixDProvider(self.appManager) - registry.put({api: self._components.filesProviders['localhost'], name: 'fileproviders/localhost'}) - registry.put({api: self._components.filesProviders, name: 'fileproviders'}) + self._components.filesProviders.browser = new FileProvider('browser') + registry.put({ api: self._components.filesProviders.browser, name: 'fileproviders/browser' }) + self._components.filesProviders.localhost = new RemixDProvider(self.appManager) + registry.put({ api: self._components.filesProviders.localhost, name: 'fileproviders/localhost' }) + registry.put({ api: self._components.filesProviders, name: 'fileproviders' }) - migrateFileSystem(self._components.filesProviders['browser']) + migrateFileSystem(self._components.filesProviders.browser) } init () { @@ -205,7 +205,7 @@ async function run () { modalDialogCustom.alert('This UNSTABLE ALPHA branch of Remix has been moved to http://ethereum.github.io/remix-live-alpha.') } else if (window.location.hostname === 'remix-alpha.ethereum.org' || (window.location.hostname === 'ethereum.github.io' && window.location.pathname.indexOf('/remix-live-alpha') === 0)) { - modalDialogCustom.alert(`Welcome to the Remix alpha instance. Please use it to try out latest features. But use preferably https://remix.ethereum.org for any production work.`) + modalDialogCustom.alert('Welcome to the Remix alpha instance. Please use it to try out latest features. But use preferably https://remix.ethereum.org for any production work.') } else if (window.location.protocol.indexOf('http') === 0 && window.location.hostname !== 'remix.ethereum.org' && window.location.hostname !== 'localhost' && @@ -233,9 +233,9 @@ Please make a backup of your contracts and start using http://remix.ethereum.org const workspace = pluginLoader.get() const engine = new Engine(appManager) engine.setPluginOption = ({ name, kind }) => { - if (kind === 'provider') return {queueTimeout: 60000 * 2} - if (name === 'LearnEth') return {queueTimeout: 60000} - return {queueTimeout: 10000} + if (kind === 'provider') return { queueTimeout: 60000 * 2 } + if (name === 'LearnEth') return { queueTimeout: 60000 } + return { queueTimeout: 10000 } } await engine.onload() @@ -244,7 +244,7 @@ Please make a backup of your contracts and start using http://remix.ethereum.org const contentImport = new CompilerImport() // ----------------- theme servive --------------------------------- const themeModule = new ThemeModule(registry) - registry.put({api: themeModule, name: 'themeModule'}) + registry.put({ api: themeModule, name: 'themeModule' }) themeModule.initTheme(() => { setTimeout(() => { document.body.removeChild(self._view.splashScreen) @@ -253,12 +253,12 @@ Please make a backup of your contracts and start using http://remix.ethereum.org }) // ----------------- editor servive ---------------------------- const editor = new Editor({}, themeModule) // wrapper around ace editor - registry.put({api: editor, name: 'editor'}) + registry.put({ api: editor, name: 'editor' }) editor.event.register('requiringToSaveCurrentfile', () => fileManager.saveCurrentFile()) // ----------------- fileManager servive ---------------------------- const fileManager = new FileManager(editor, appManager) - registry.put({api: fileManager, name: 'filemanager'}) + registry.put({ api: fileManager, name: 'filemanager' }) const blockchain = new Blockchain(registry.get('config').api) const pluginUdapp = new PluginUDapp(blockchain) @@ -267,7 +267,7 @@ Please make a backup of your contracts and start using http://remix.ethereum.org const compilerMetadataGenerator = new CompilerMetadata(blockchain, fileManager, registry.get('config').api) // ----------------- compilation result service (can keep track of compilation results) ---------------------------- const compilersArtefacts = new CompilersArtefacts() // store all the compilation results (key represent a compiler name) - registry.put({api: compilersArtefacts, name: 'compilersartefacts'}) + registry.put({ api: compilersArtefacts, name: 'compilersartefacts' }) // service which fetch contract artifacts from sourve-verify, put artifacts in remix and compile it const fetchAndCompile = new FetchAndCompile() @@ -277,7 +277,7 @@ Please make a backup of your contracts and start using http://remix.ethereum.org const web3Provider = new Web3ProviderModule(blockchain) // ----------------- convert offset to line/column service ----------- const offsetToLineColumnConverter = new OffsetToLineColumnConverter() - registry.put({api: offsetToLineColumnConverter, name: 'offsettolinecolumnconverter'}) + registry.put({ api: offsetToLineColumnConverter, name: 'offsettolinecolumnconverter' }) // -------------------Terminal---------------------------------------- @@ -296,7 +296,7 @@ Please make a backup of your contracts and start using http://remix.ethereum.org ) makeUdapp(blockchain, compilersArtefacts, (domEl) => terminal.logHtml(domEl)) - const contextualListener = new ContextualListener({editor}) + const contextualListener = new ContextualListener({ editor }) engine.register([ contentImport, @@ -327,7 +327,7 @@ Please make a backup of your contracts and start using http://remix.ethereum.org const hiddenPanel = new HiddenPanel() const pluginManagerComponent = new PluginManagerComponent(appManager, engine) const filePanel = new FilePanel(appManager) - let settings = new SettingsTab( + const settings = new SettingsTab( registry.get('config').api, editor, appManager @@ -367,7 +367,7 @@ Please make a backup of your contracts and start using http://remix.ethereum.org registry.get('compilersartefacts').api, networkModule, mainview, - registry.get('fileproviders/browser').api, + registry.get('fileproviders/browser').api ) const analysis = new AnalysisTab(registry) const debug = new DebuggerTab( @@ -407,7 +407,7 @@ Please make a backup of your contracts and start using http://remix.ethereum.org const params = queryParams.get() // Set workspace after initial activation - if (Array.isArray(workspace)) { + if (Array.isArray(workspace)) { appManager.activatePlugin(workspace).then(() => { try { if (params.deactivate) { @@ -416,7 +416,7 @@ Please make a backup of your contracts and start using http://remix.ethereum.org } catch (e) { console.log(e) } - + // If plugins are loaded from the URL params, we focus on the last one. if (pluginLoader.current === 'queryParams' && workspace.length > 0) menuicons.select(workspace[workspace.length - 1]) @@ -430,7 +430,7 @@ Please make a backup of your contracts and start using http://remix.ethereum.org }, 5000) } } - }).catch(console.error) + }).catch(console.error) } else { // activate solidity plugin appManager.ensureActivated('solidity') @@ -449,10 +449,10 @@ Please make a backup of your contracts and start using http://remix.ethereum.org const loadedFromGist = gistHandler.loadFromGist(params, fileManager) if (!loadedFromGist) { // insert example contracts if there are no files to show - self._components.filesProviders['browser'].resolveDirectory('/', (error, filesList) => { + self._components.filesProviders.browser.resolveDirectory('/', (error, filesList) => { if (error) console.error(error) if (Object.keys(filesList).length === 0) { - for (let file in examples) { + for (const file in examples) { fileManager.writeFile(examples[file].name, examples[file].content) } } diff --git a/apps/remix-ide/src/app/compiler/compiler-artefacts.js b/apps/remix-ide/src/app/compiler/compiler-artefacts.js index 327c9c3e36..ce5a24e8f4 100644 --- a/apps/remix-ide/src/app/compiler/compiler-artefacts.js +++ b/apps/remix-ide/src/app/compiler/compiler-artefacts.js @@ -28,22 +28,22 @@ module.exports = class CompilerArtefacts extends Plugin { } this.on('solidity', 'compilationFinished', (file, source, languageVersion, data) => { - this.compilersArtefacts['__last'] = new CompilerAbstract(languageVersion, data, source) + this.compilersArtefacts.__last = new CompilerAbstract(languageVersion, data, source) saveCompilationPerFileResult(file, source, languageVersion, data) }) this.on('vyper', 'compilationFinished', (file, source, languageVersion, data) => { - this.compilersArtefacts['__last'] = new CompilerAbstract(languageVersion, data, source) + this.compilersArtefacts.__last = new CompilerAbstract(languageVersion, data, source) saveCompilationPerFileResult(file, source, languageVersion, data) }) this.on('lexon', 'compilationFinished', (file, source, languageVersion, data) => { - this.compilersArtefacts['__last'] = new CompilerAbstract(languageVersion, data, source) + this.compilersArtefacts.__last = new CompilerAbstract(languageVersion, data, source) saveCompilationPerFileResult(file, source, languageVersion, data) }) this.on('yulp', 'compilationFinished', (file, source, languageVersion, data) => { - this.compilersArtefacts['__last'] = new CompilerAbstract(languageVersion, data, source) + this.compilersArtefacts.__last = new CompilerAbstract(languageVersion, data, source) saveCompilationPerFileResult(file, source, languageVersion, data) }) } @@ -55,8 +55,8 @@ module.exports = class CompilerArtefacts extends Plugin { Object.keys(contracts).map((file) => { contractsData[file] = contracts[file] }) }) // making sure we save last compilation result in there - if (this.compilersArtefacts['__last']) { - const contracts = this.compilersArtefacts['__last'].getContracts() + if (this.compilersArtefacts.__last) { + const contracts = this.compilersArtefacts.__last.getContracts() Object.keys(contracts).map((file) => { contractsData[file] = contracts[file] }) } return contractsData diff --git a/apps/remix-ide/src/app/compiler/compiler-imports.js b/apps/remix-ide/src/app/compiler/compiler-imports.js index 343ca2875e..219131f67c 100644 --- a/apps/remix-ide/src/app/compiler/compiler-imports.js +++ b/apps/remix-ide/src/app/compiler/compiler-imports.js @@ -1,11 +1,11 @@ 'use strict' +import { Plugin } from '@remixproject/engine' +import * as packageJson from '../../../../../package.json' const globalRegistry = require('../../global/registry') var base64 = require('js-base64').Base64 var swarmgw = require('swarmgw')() var resolver = require('@resolver-engine/imports').ImportsEngine() var request = require('request') -import { Plugin } from '@remixproject/engine' -import * as packageJson from '../../../../../package.json' const profile = { name: 'contentImport', @@ -79,12 +79,12 @@ module.exports = class CompilerImports extends Plugin { { url }, - (err, r, data) => { - if (err) { - return cb(err || 'Unknown transport error') - } - cb(null, data, cleanUrl) - }) + (err, r, data) => { + if (err) { + return cb(err || 'Unknown transport error') + } + cb(null, data, cleanUrl) + }) } handlers () { @@ -112,7 +112,7 @@ module.exports = class CompilerImports extends Plugin { import (url, force, loadingCb, cb) { if (typeof force !== 'boolean') { - let temp = loadingCb + const temp = loadingCb loadingCb = force cb = temp force = false @@ -156,19 +156,19 @@ module.exports = class CompilerImports extends Plugin { if (found) return resolver - .resolve(url) - .then(result => { - return resolver.require(url) - }) - .then(result => { - if (url.indexOf(result.provider + ':') === 0) { - url = url.substring(result.provider.length + 1) // remove the github prefix - } - cb(null, result.source, url, result.provider, result.url) - }) - .catch(err => { - err - cb('Unable to import "' + url + '": File not found') - }) + .resolve(url) + .then(result => { + return resolver.require(url) + }) + .then(result => { + if (url.indexOf(result.provider + ':') === 0) { + url = url.substring(result.provider.length + 1) // remove the github prefix + } + cb(null, result.source, url, result.provider, result.url) + }) + .catch(err => { + console.error(err) + cb('Unable to import "' + url + '": File not found') + }) } } diff --git a/apps/remix-ide/src/app/compiler/compiler-input.js b/apps/remix-ide/src/app/compiler/compiler-input.js new file mode 100644 index 0000000000..a0be3c499d --- /dev/null +++ b/apps/remix-ide/src/app/compiler/compiler-input.js @@ -0,0 +1,21 @@ +'use strict' + +module.exports = (sources, opts) => { + return JSON.stringify({ + language: 'Solidity', + sources: sources, + settings: { + optimizer: { + enabled: opts.optimize === true || opts.optimize === 1, + runs: 200 + }, + libraries: opts.libraries, + outputSelection: { + '*': { + '': ['ast'], + '*': ['abi', 'metadata', 'devdoc', 'userdoc', 'evm.legacyAssembly', 'evm.bytecode', 'evm.deployedBytecode', 'evm.methodIdentifiers', 'evm.gasEstimates'] + } + } + } + }) +} diff --git a/apps/remix-ide/src/app/compiler/compiler-sourceVerifier-fetchAndCompile.js b/apps/remix-ide/src/app/compiler/compiler-sourceVerifier-fetchAndCompile.js index 62f0d87411..60b8cacc78 100644 --- a/apps/remix-ide/src/app/compiler/compiler-sourceVerifier-fetchAndCompile.js +++ b/apps/remix-ide/src/app/compiler/compiler-sourceVerifier-fetchAndCompile.js @@ -1,10 +1,10 @@ -const ethutil = require('ethereumjs-util') import * as packageJson from '../../../../../package.json' import { Plugin } from '@remixproject/engine' import { compile } from './compiler-helpers' import globalRegistry from '../../global/registry' import remixLib from '@remix-project/remix-lib' +const ethutil = require('ethereumjs-util') const profile = { name: 'fetchAndCompile', @@ -13,7 +13,6 @@ const profile = { } export default class FetchAndCompile extends Plugin { - constructor () { super(profile) this.unresolvedAddresses = [] @@ -86,12 +85,12 @@ export default class FetchAndCompile extends Plugin { // set the solidity contract code using metadata await this.call('fileManager', 'setFile', `${targetPath}/${name}/${contractAddress}/metadata.json`, JSON.stringify(data.metadata, null, '\t')) - let compilationTargets = {} + const compilationTargets = {} for (let file in data.metadata.sources) { const urls = data.metadata.sources[file].urls - for (let url of urls) { + for (const url of urls) { if (url.includes('ipfs')) { - let stdUrl = `ipfs://${url.split('/')[2]}` + const stdUrl = `ipfs://${url.split('/')[2]}` const source = await this.call('contentImport', 'resolve', stdUrl) file = file.replace('browser/', '') // should be fixed in the remix IDE end. const path = `${targetPath}/${name}/${contractAddress}/${file}` diff --git a/apps/remix-ide/src/app/compiler/compiler-utils.js b/apps/remix-ide/src/app/compiler/compiler-utils.js index f7222f582d..90606f4a95 100644 --- a/apps/remix-ide/src/app/compiler/compiler-utils.js +++ b/apps/remix-ide/src/app/compiler/compiler-utils.js @@ -26,7 +26,7 @@ export function canUseWorker (selectedVersion) { const isNightly = selectedVersion.includes('nightly') return browserSupportWorker() && ( semver.gt(version, '0.6.3') || - semver.gt(version, '0.3.6') && !isNightly + (semver.gt(version, '0.3.6') && !isNightly) ) } diff --git a/apps/remix-ide/src/app/components/hidden-panel.js b/apps/remix-ide/src/app/components/hidden-panel.js index d3724f9274..77f67c6f4c 100644 --- a/apps/remix-ide/src/app/components/hidden-panel.js +++ b/apps/remix-ide/src/app/components/hidden-panel.js @@ -18,7 +18,6 @@ const profile = { } export class HiddenPanel extends AbstractPanel { - constructor () { super(profile) } diff --git a/apps/remix-ide/src/app/components/local-plugin.js b/apps/remix-ide/src/app/components/local-plugin.js index 39d8c5fc68..1db3cae6e5 100644 --- a/apps/remix-ide/src/app/components/local-plugin.js +++ b/apps/remix-ide/src/app/components/local-plugin.js @@ -51,15 +51,15 @@ module.exports = class LocalPlugin { return profile } - updateName ({target}) { + updateName ({ target }) { this.profile.name = target.value } - updateUrl ({target}) { + updateUrl ({ target }) { this.profile.url = target.value } - updateDisplayName ({target}) { + updateDisplayName ({ target }) { this.profile.displayName = target.value } diff --git a/apps/remix-ide/src/app/components/panel.js b/apps/remix-ide/src/app/components/panel.js index bd1d59d176..91b1c07e85 100644 --- a/apps/remix-ide/src/app/components/panel.js +++ b/apps/remix-ide/src/app/components/panel.js @@ -1,7 +1,7 @@ import { EventEmitter } from 'events' +import { HostPlugin } from '@remixproject/engine' const csjs = require('csjs-inject') const yo = require('yo-yo') -import { HostPlugin } from '@remixproject/engine' const css = csjs` .plugins { @@ -27,7 +27,6 @@ const css = csjs` /** Abstract class used for hosting the view of a plugin */ export class AbstractPanel extends HostPlugin { - constructor (profile) { super(profile) this.events = new EventEmitter() @@ -109,4 +108,3 @@ export class AbstractPanel extends HostPlugin { this.showContent(name) } } - diff --git a/apps/remix-ide/src/app/components/plugin-manager-component.js b/apps/remix-ide/src/app/components/plugin-manager-component.js index 9538182662..556a8df5b3 100644 --- a/apps/remix-ide/src/app/components/plugin-manager-component.js +++ b/apps/remix-ide/src/app/components/plugin-manager-component.js @@ -1,10 +1,10 @@ +import { ViewPlugin, IframePlugin, WebsocketPlugin } from '@remixproject/engine' +import { PluginManagerSettings } from './plugin-manager-settings' +import * as packageJson from '../../../../../package.json' const yo = require('yo-yo') const csjs = require('csjs-inject') const EventEmitter = require('events') const LocalPlugin = require('./local-plugin') -import { ViewPlugin, IframePlugin, WebsocketPlugin } from '@remixproject/engine' -import { PluginManagerSettings } from './plugin-manager-settings' -import * as packageJson from '../../../../../package.json' const addToolTip = require('../ui/tooltip') const css = csjs` @@ -71,7 +71,6 @@ const profile = { } class PluginManagerComponent extends ViewPlugin { - constructor (appManager, engine) { super(profile) this.event = new EventEmitter() @@ -172,12 +171,12 @@ class PluginManagerComponent extends ViewPlugin { } // Filter all active and inactive modules that are not required - const {actives, inactives} = this.appManager.getAll() + const { actives, inactives } = this.appManager.getAll() .filter(isFiltered) .filter(isNotRequired) .filter(isNotHome) .sort(sortByName) - .reduce(({actives, inactives}, profile) => { + .reduce(({ actives, inactives }, profile) => { return this.isActive(profile.name) ? { actives: [...actives, profile], inactives } : { inactives: [...inactives, profile], actives } diff --git a/apps/remix-ide/src/app/components/plugin-manager-settings.js b/apps/remix-ide/src/app/components/plugin-manager-settings.js index 04f2744f63..3b6cc291cf 100644 --- a/apps/remix-ide/src/app/components/plugin-manager-settings.js +++ b/apps/remix-ide/src/app/components/plugin-manager-settings.js @@ -44,13 +44,12 @@ const css = csjs` ` export class PluginManagerSettings { - openDialog () { const fromLocal = window.localStorage.getItem('plugins/permissions') this.permissions = JSON.parse(fromLocal || '{}') this.currentSetting = this.settings() modalDialog('Plugin Manager Permissions', this.currentSetting, - { fn: () => this.onValidation() }, + { fn: () => this.onValidation() } ) } @@ -138,5 +137,4 @@ export class PluginManagerSettings { ` } - } diff --git a/apps/remix-ide/src/app/components/side-panel.js b/apps/remix-ide/src/app/components/side-panel.js index 53a8e4fc8e..b2a242ab7d 100644 --- a/apps/remix-ide/src/app/components/side-panel.js +++ b/apps/remix-ide/src/app/components/side-panel.js @@ -59,7 +59,6 @@ const sidePanel = { // TODO merge with vertical-icons.js export class SidePanel extends AbstractPanel { - constructor (appManager, verticalIcons) { super(sidePanel) this.appManager = appManager diff --git a/apps/remix-ide/src/app/components/vertical-icons.js b/apps/remix-ide/src/app/components/vertical-icons.js index 6e8ea6a370..d59c3d0722 100644 --- a/apps/remix-ide/src/app/components/vertical-icons.js +++ b/apps/remix-ide/src/app/components/vertical-icons.js @@ -1,10 +1,10 @@ +import * as packageJson from '../../../../../package.json' +import { basicLogo } from '../ui/svgLogo' var yo = require('yo-yo') var csjs = require('csjs-inject') var helper = require('../../lib/helper') -let globalRegistry = require('../../global/registry') +const globalRegistry = require('../../global/registry') const { Plugin } = require('@remixproject/engine') -import * as packageJson from '../../../../../package.json' -import { basicLogo } from '../ui/svgLogo' const EventEmitter = require('events') @@ -18,7 +18,6 @@ const profile = { // TODO merge with side-panel.js. VerticalIcons should not be a plugin export class VerticalIcons extends Plugin { - constructor (appManager) { super(profile) this.events = new EventEmitter() @@ -27,7 +26,7 @@ export class VerticalIcons extends Plugin { this.iconKind = {} this.iconStatus = {} - let themeModule = globalRegistry.get('themeModule').api + const themeModule = globalRegistry.get('themeModule').api themeModule.events.on('themeChanged', (theme) => { this.onThemeChanged(theme.quality) }) @@ -49,7 +48,7 @@ export class VerticalIcons extends Plugin { const types = ['error', 'warning', 'success', 'info', ''] const fn = (status) => { if (!types.includes(status.type) && status.type) throw new Error(`type should be ${keys.join()}`) - if (status.key === undefined) throw new Error(`status key should be defined`) + if (status.key === undefined) throw new Error('status key should be defined') if (typeof status.key === 'string' && (!keys.includes(status.key))) { throw new Error('key should contain either number or ' + keys.join()) @@ -64,7 +63,7 @@ export class VerticalIcons extends Plugin { * Add an icon to the map * @param {ModuleProfile} profile The profile of the module */ - addIcon ({kind, name, icon, displayName, tooltip}) { + addIcon ({ kind, name, icon, displayName, tooltip }) { let title = (tooltip || displayName || name) title = title.replace(/^\w/, c => c.toUpperCase()) this.icons[name] = yo` @@ -114,7 +113,7 @@ export class VerticalIcons extends Plugin { setIconStatus (name, status) { const el = this.icons[name] if (!el) return - let statusEl = el.querySelector('span') + const statusEl = el.querySelector('span') if (statusEl) { el.removeChild(statusEl) } @@ -131,7 +130,7 @@ export class VerticalIcons extends Plugin { if (status.type === 'error') { type = 'danger' // to use with bootstrap } else type = helper.checkSpecialChars(status.type) ? '' : status.type - let title = helper.checkSpecialChars(status.title) ? '' : status.title + const title = helper.checkSpecialChars(status.title) ? '' : status.title el.appendChild(yo`100 for icons with color const nextActive = this.view.querySelector(`[plugin="${name}"]`) if (nextActive) { - let image = nextActive.querySelector('.image') - nextActive.classList.add(`active`) + const image = nextActive.querySelector('.image') + nextActive.classList.add('active') image.style.setProperty('filter', `invert(${invert}) grayscale(1) brightness(${brightness}%)`) } } @@ -215,15 +214,15 @@ export class VerticalIcons extends Plugin { onThemeChanged (themeType) { const invert = themeType === 'dark' ? 1 : 0 - const active = this.view.querySelector(`.active`) + const active = this.view.querySelector('.active') if (active) { - let image = active.querySelector('.image') + const image = active.querySelector('.image') image.style.setProperty('filter', `invert(${invert})`) } } render () { - let home = yo` + const home = yo`
` - this.iconKind['compiler'] = yo`
` - this.iconKind['udapp'] = yo`
` - this.iconKind['testing'] = yo`
` - this.iconKind['analysis'] = yo`
` - this.iconKind['debugging'] = yo`
` - this.iconKind['none'] = yo`
` - this.iconKind['settings'] = yo`
` + this.iconKind.fileexplorer = yo`
` + this.iconKind.compiler = yo`
` + this.iconKind.udapp = yo`
` + this.iconKind.testing = yo`
` + this.iconKind.analysis = yo`
` + this.iconKind.debugging = yo`
` + this.iconKind.none = yo`
` + this.iconKind.settings = yo`
` this.view = yo`
${home} - ${this.iconKind['fileexplorer']} - ${this.iconKind['compiler']} - ${this.iconKind['udapp']} - ${this.iconKind['testing']} - ${this.iconKind['analysis']} - ${this.iconKind['debugging']} - ${this.iconKind['none']} - ${this.iconKind['settings']} + ${this.iconKind.fileexplorer} + ${this.iconKind.compiler} + ${this.iconKind.udapp} + ${this.iconKind.testing} + ${this.iconKind.analysis} + ${this.iconKind.debugging} + ${this.iconKind.none} + ${this.iconKind.settings}
` return this.view diff --git a/apps/remix-ide/src/app/editor/SourceHighlighters.js b/apps/remix-ide/src/app/editor/SourceHighlighters.js index 203a612dd2..1cb05c8f3d 100644 --- a/apps/remix-ide/src/app/editor/SourceHighlighters.js +++ b/apps/remix-ide/src/app/editor/SourceHighlighters.js @@ -2,12 +2,12 @@ const SourceHighlighter = require('./sourceHighlighter') class SourceHighlighters { - constructor () { this.highlighters = {} } highlight (position, filePath, hexColor, from) { + // eslint-disable-next-line try { if (!this.highlighters[from]) this.highlighters[from] = [] const sourceHighlight = new SourceHighlighter() @@ -27,6 +27,7 @@ class SourceHighlighters { // highlights all locations for @from plugin highlightAllFrom (from) { + // eslint-disable-next-line try { if (!this.highlighters[from]) return const sourceHighlight = new SourceHighlighter() diff --git a/apps/remix-ide/src/app/editor/contextView.js b/apps/remix-ide/src/app/editor/contextView.js index 797ca69d12..4746082729 100644 --- a/apps/remix-ide/src/app/editor/contextView.js +++ b/apps/remix-ide/src/app/editor/contextView.js @@ -25,9 +25,9 @@ class ContextView { config: this._components.registry.get('config').api, fileManager: this._components.registry.get('filemanager').api } - this._view - this._nodes - this._current + this._view = null + this._nodes = null + this._current = null this.sourceMappingDecoder = new SourceMappingDecoder() this.previousElement = null this.contextualListener.event.register('contextChanged', nodes => { @@ -98,7 +98,7 @@ class ContextView { this.editor.gotoLine(lineColumn.start.line, lineColumn.end.column + 1) } } - let lastCompilationResult = this._deps.compilersArtefacts['__last'] + const lastCompilationResult = this._deps.compilersArtefacts.__last if (lastCompilationResult && lastCompilationResult.languageversion.indexOf('soljson') === 0 && lastCompilationResult.data) { const lineColumn = this._deps.offsetToLineColumnConverter.offsetToLineColumn( position, diff --git a/apps/remix-ide/src/app/editor/contextualListener.js b/apps/remix-ide/src/app/editor/contextualListener.js index d4d2c5a534..26ebdd5a88 100644 --- a/apps/remix-ide/src/app/editor/contextualListener.js +++ b/apps/remix-ide/src/app/editor/contextualListener.js @@ -1,12 +1,13 @@ 'use strict' +import { Plugin } from '@remixproject/engine' +import * as packageJson from '../../../../../package.json' + const remixdebug = require('@remix-project/remix-debug') const { AstWalker } = require('@remix-project/remix-astwalker') const csjs = require('csjs-inject') const SourceMappingDecoder = remixdebug.SourceMappingDecoder const EventManager = require('../../lib/events') const globalRegistry = require('../../global/registry') -import { Plugin } from '@remixproject/engine' -import * as packageJson from '../../../../../package.json' const profile = { name: 'contextualListener', @@ -54,8 +55,8 @@ class ContextualListener extends Plugin { }) setInterval(() => { - if (this._deps.compilersArtefacts['__last'] && this._deps.compilersArtefacts['__last'].languageversion.indexOf('soljson') === 0) { - this._highlightItems(this.editor.getCursorPosition(), this._deps.compilersArtefacts['__last'], this._deps.config.get('currentFile')) + if (this._deps.compilersArtefacts.__last && this._deps.compilersArtefacts.__last.languageversion.indexOf('soljson') === 0) { + this._highlightItems(this.editor.getCursorPosition(), this._deps.compilersArtefacts.__last, this._deps.config.get('currentFile')) } }, 1000) } @@ -66,13 +67,13 @@ class ContextualListener extends Plugin { declarationOf (node) { if (node && node.referencedDeclaration) { - return this._index['FlatReferences'][node.referencedDeclaration] + return this._index.FlatReferences[node.referencedDeclaration] } return null } referencesOf (node) { - return this._index['Declarations'][node.id] + return this._index.Declarations[node.id] } _highlightItems (cursorPosition, compilationResult, file) { @@ -99,12 +100,12 @@ class ContextualListener extends Plugin { if (compilationResult && compilationResult.sources) { const callback = (node) => { if (node && node.referencedDeclaration) { - if (!this._index['Declarations'][node.referencedDeclaration]) { - this._index['Declarations'][node.referencedDeclaration] = [] + if (!this._index.Declarations[node.referencedDeclaration]) { + this._index.Declarations[node.referencedDeclaration] = [] } - this._index['Declarations'][node.referencedDeclaration].push(node) + this._index.Declarations[node.referencedDeclaration].push(node) } - this._index['FlatReferences'][node.id] = node + this._index.FlatReferences[node.id] = node } for (const s in compilationResult.sources) { this.astWalker.walkFull(compilationResult.sources[s].ast, callback) @@ -116,7 +117,7 @@ class ContextualListener extends Plugin { if (!node) return const position = this.sourceMappingDecoder.decode(node.src) const eventId = this._highlightInternal(position, node) - let lastCompilationResult = this._deps.compilersArtefacts['__last'] + const lastCompilationResult = this._deps.compilersArtefacts.__last if (eventId && lastCompilationResult && lastCompilationResult.languageversion.indexOf('soljson') === 0) { this._activeHighlights.push({ eventId, position, fileTarget: lastCompilationResult.getSourceName(position.file), nodeId: node.id }) } @@ -124,7 +125,7 @@ class ContextualListener extends Plugin { _highlightInternal (position, node) { if (node.nodeType === 'Block') return - let lastCompilationResult = this._deps.compilersArtefacts['__last'] + const lastCompilationResult = this._deps.compilersArtefacts.__last if (lastCompilationResult && lastCompilationResult.languageversion.indexOf('soljson') === 0) { let lineColumn = this._deps.offsetToLineColumnConverter.offsetToLineColumn(position, position.file, lastCompilationResult.getSourceCode().sources, lastCompilationResult.getAsts()) const css = csjs` @@ -158,8 +159,8 @@ class ContextualListener extends Plugin { _highlightExpressions (node, compilationResult) { const highlights = (id) => { - if (this._index['Declarations'] && this._index['Declarations'][id]) { - const refs = this._index['Declarations'][id] + if (this._index.Declarations && this._index.Declarations[id]) { + const refs = this._index.Declarations[id] for (const ref in refs) { const node = refs[ref] this._highlight(node, compilationResult) @@ -168,7 +169,7 @@ class ContextualListener extends Plugin { } if (node && node.referencedDeclaration) { highlights(node.referencedDeclaration) - const current = this._index['FlatReferences'][node.referencedDeclaration] + const current = this._index.FlatReferences[node.referencedDeclaration] this._highlight(current, compilationResult) } else { highlights(node.id) @@ -206,7 +207,7 @@ class ContextualListener extends Plugin { } else { executionCost = '-' } - return {executionCost, codeDepositCost} + return { executionCost, codeDepositCost } } _loadContractInfos (node) { @@ -223,7 +224,7 @@ class ContextualListener extends Plugin { _getInputParams (node) { const params = [] - let target = node.parameters + const target = node.parameters // for (const i in node.children) { // if (node.children[i].name === 'ParameterList') { // target = node.children[i] diff --git a/apps/remix-ide/src/app/editor/editor.js b/apps/remix-ide/src/app/editor/editor.js index 1d32e52bf7..ba5d0dad15 100644 --- a/apps/remix-ide/src/app/editor/editor.js +++ b/apps/remix-ide/src/app/editor/editor.js @@ -1,10 +1,11 @@ 'use strict' +import { Plugin } from '@remixproject/engine' +import * as packageJson from '../../../../../package.json' + const EventManager = require('../../lib/events') const yo = require('yo-yo') const csjs = require('csjs-inject') const ace = require('brace') -import { Plugin } from '@remixproject/engine' -import * as packageJson from '../../../../../package.json' const globalRegistry = require('../../global/registry') const SourceHighlighters = require('./SourceHighlighters') @@ -52,7 +53,6 @@ const profile = { } class Editor extends Plugin { - constructor (opts = {}, themeModule) { super(profile) // Dependancies @@ -63,9 +63,9 @@ class Editor extends Plugin { } this._themes = { - 'light': 'chrome', - 'dark': 'chaos', - 'remixDark': 'remixDark' + light: 'chrome', + dark: 'chaos', + remixDark: 'remixDark' } themeModule.events.on('themeChanged', (theme) => { this.setTheme(theme.name === 'Dark' ? 'remixDark' : theme.quality) @@ -110,7 +110,7 @@ class Editor extends Plugin { // shortcuts for "Ctrl-"" and "Ctrl+"" to increase/decrease font size of the editor this.editor.commands.addCommand({ name: 'increasefontsizeEqual', - bindKey: {win: 'Ctrl-=', mac: 'Command-='}, + bindKey: { win: 'Ctrl-=', mac: 'Command-=' }, exec: (editor) => { this.editorFontSize(1) }, @@ -119,7 +119,7 @@ class Editor extends Plugin { this.editor.commands.addCommand({ name: 'increasefontsizePlus', - bindKey: {win: 'Ctrl-+', mac: 'Command-+'}, + bindKey: { win: 'Ctrl-+', mac: 'Command-+' }, exec: (editor) => { this.editorFontSize(1) }, @@ -128,7 +128,7 @@ class Editor extends Plugin { this.editor.commands.addCommand({ name: 'decreasefontsize', - bindKey: {win: 'Ctrl--', mac: 'Command--'}, + bindKey: { win: 'Ctrl--', mac: 'Command--' }, exec: (editor) => { this.editorFontSize(-1) }, @@ -263,12 +263,12 @@ class Editor extends Plugin { * @param {string} path Path of the file */ _getMode (path) { - if (!path) return this.modes['txt'] + if (!path) return this.modes.txt const root = path.split('#')[0].split('?')[0] let ext = root.indexOf('.') !== -1 ? /[^.]+$/.exec(root) : null if (ext) ext = ext[0] else ext = 'txt' - return ext && this.modes[ext] ? this.modes[ext] : this.modes['txt'] + return ext && this.modes[ext] ? this.modes[ext] : this.modes.txt } /** @@ -316,7 +316,7 @@ class Editor extends Plugin { * @param {number} incr The amount of pixels to add to the font. */ editorFontSize (incr) { - let newSize = this.editor.getFontSize() + incr + const newSize = this.editor.getFontSize() + incr if (newSize >= 6) { this.editor.setFontSize(newSize) } diff --git a/apps/remix-ide/src/app/editor/sourceHighlighter.js b/apps/remix-ide/src/app/editor/sourceHighlighter.js index 5c51225670..e25e2c948f 100644 --- a/apps/remix-ide/src/app/editor/sourceHighlighter.js +++ b/apps/remix-ide/src/app/editor/sourceHighlighter.js @@ -22,7 +22,7 @@ class SourceHighlighter { currentSourceLocation (lineColumnPos, location) { if (this.statementMarker) this._deps.editor.removeMarker(this.statementMarker, this.source) if (this.fullLineMarker) this._deps.editor.removeMarker(this.fullLineMarker, this.source) - let lastCompilationResult = this._deps.compilerArtefacts['__last'] + const lastCompilationResult = this._deps.compilerArtefacts.__last if (location && location.file !== undefined && lastCompilationResult) { const path = lastCompilationResult.getSourceName(location.file) if (path) { @@ -40,7 +40,7 @@ class SourceHighlighter { if (lineColumnPos) { this.source = filePath this.style = style || 'var(--info)' - //if (!this.source) this.source = this._deps.fileManager.currentFile() + // if (!this.source) this.source = this._deps.fileManager.currentFile() if (this._deps.fileManager.currentFile() !== this.source) { await this._deps.fileManager.open(this.source) this.source = this._deps.fileManager.currentFile() diff --git a/apps/remix-ide/src/app/files/compiler-metadata.js b/apps/remix-ide/src/app/files/compiler-metadata.js index 721457464a..6f0bf907dd 100644 --- a/apps/remix-ide/src/app/files/compiler-metadata.js +++ b/apps/remix-ide/src/app/files/compiler-metadata.js @@ -1,7 +1,7 @@ 'use strict' -var CompilerAbstract = require('../compiler/compiler-abstract') import { Plugin } from '@remixproject/engine' import * as packageJson from '../../../../../package.json' +var CompilerAbstract = require('../compiler/compiler-abstract') const profile = { name: 'compilerMetadata', @@ -32,7 +32,7 @@ class CompilerMetadata extends Plugin { var self = this this.on('solidity', 'compilationFinished', (file, source, languageVersion, data) => { if (!self.config.get('settings/generate-contract-metadata')) return - let compiler = new CompilerAbstract(languageVersion, data, source) + const compiler = new CompilerAbstract(languageVersion, data, source) var provider = self.fileManager.currentFileProvider() var path = self.fileManager.currentPath() if (provider && path) { @@ -84,8 +84,8 @@ class CompilerMetadata extends Plugin { } _syncContext (contract, metadata) { - var linkReferences = metadata['linkReferences'] - var autoDeployLib = metadata['autoDeployLib'] + var linkReferences = metadata.linkReferences + var autoDeployLib = metadata.autoDeployLib if (!linkReferences) linkReferences = {} if (autoDeployLib === undefined) autoDeployLib = true @@ -97,8 +97,8 @@ class CompilerMetadata extends Plugin { } } } - metadata['linkReferences'] = linkReferences - metadata['autoDeployLib'] = autoDeployLib + metadata.linkReferences = linkReferences + metadata.autoDeployLib = autoDeployLib return metadata } @@ -138,7 +138,7 @@ class CompilerMetadata extends Plugin { } }) } else { - reject(`Please select the folder in the file explorer where the metadata of ${contractName} can be found`) + reject(new Error(`Please select the folder in the file explorer where the metadata of ${contractName} can be found`)) } }) } diff --git a/apps/remix-ide/src/app/files/file-explorer.js b/apps/remix-ide/src/app/files/file-explorer.js index 4ef7f85cd4..f458963ce3 100644 --- a/apps/remix-ide/src/app/files/file-explorer.js +++ b/apps/remix-ide/src/app/files/file-explorer.js @@ -25,21 +25,25 @@ function fileExplorer (localRegistry, files, menuItems, plugin) { this.focusElement = null // path currently focused on this.focusPath = null - let allItems = + const allItems = [ - { action: 'createNewFile', + { + action: 'createNewFile', title: 'Create New File', icon: 'fas fa-plus-circle' }, - { action: 'publishToGist', + { + action: 'publishToGist', title: 'Publish all [browser] explorer files to a github gist', icon: 'fab fa-github' }, - { action: 'uploadFile', + { + action: 'uploadFile', title: 'Add Local file to the Browser Storage Explorer', icon: 'far fa-folder-open' }, - { action: 'updateGist', + { + action: 'updateGist', title: 'Update the current [gist] explorer', icon: 'fab fa-github' } @@ -213,7 +217,7 @@ function fileExplorer (localRegistry, files, menuItems, plugin) { if (self.files.readonly) return if (key === self.files.type) return MENU_HANDLE && MENU_HANDLE.hide(null, true) - let actions = {} + const actions = {} const provider = self._deps.fileManager.fileProviderOf(key) actions['Create File'] = () => self.createNewFile(key) actions['Create Folder'] = () => self.createNewFolder(key) @@ -229,16 +233,16 @@ function fileExplorer (localRegistry, files, menuItems, plugin) { } */ } else { const folderPath = extractExternalFolder(key) - actions['Rename'] = () => { + actions.Rename = () => { if (self.files.isReadOnly(key)) { return tooltip('cannot rename folder. ' + self.files.type + ' is a read only explorer') } var name = label.querySelector('span[data-path="' + key + '"]') if (name) editModeOn(name) } - actions['Delete'] = () => { + actions.Delete = () => { if (self.files.isReadOnly(key)) { return tooltip('cannot delete folder. ' + self.files.type + ' is a read only explorer') } const currentFoldername = extractNameFromKey(key) - modalDialogCustom.confirm(`Confirm to delete folder`, `Are you sure you want to delete ${currentFoldername} folder?`, + modalDialogCustom.confirm('Confirm to delete folder', `Are you sure you want to delete ${currentFoldername} folder?`, async () => { const fileManager = self._deps.fileManager const removeFolder = await fileManager.remove(key) @@ -266,21 +270,21 @@ function fileExplorer (localRegistry, files, menuItems, plugin) { self.treeView.event.register('leafRightClick', function (key, data, label, event) { if (key === self.files.type) return MENU_HANDLE && MENU_HANDLE.hide(null, true) - let actions = {} + const actions = {} const provider = self._deps.fileManager.fileProviderOf(key) if (!provider.isExternalFolder(key)) { actions['Create Folder'] = () => self.createNewFolder(self._deps.fileManager.extractPathOf(key)) - actions['Rename'] = () => { + actions.Rename = () => { if (self.files.isReadOnly(key)) { return tooltip('cannot rename file. ' + self.files.type + ' is a read only explorer') } var name = label.querySelector('span[data-path="' + key + '"]') if (name) editModeOn(name) } - actions['Delete'] = () => { + actions.Delete = () => { if (self.files.isReadOnly(key)) { return tooltip('cannot delete file. ' + self.files.type + ' is a read only explorer') } const currentFilename = extractNameFromKey(key) modalDialogCustom.confirm( - `Delete file`, `Are you sure you want to delete ${currentFilename} file?`, + 'Delete file', `Are you sure you want to delete ${currentFilename} file?`, async () => { const fileManager = self._deps.fileManager const removeFile = await fileManager.remove(key) @@ -293,7 +297,7 @@ function fileExplorer (localRegistry, files, menuItems, plugin) { ) } if (key.endsWith('.js')) { - actions['Run'] = async () => { + actions.Run = async () => { provider.get(key, (error, content) => { if (error) return console.log(error) plugin.call('scriptRunner', 'execute', content) @@ -358,7 +362,7 @@ function fileExplorer (localRegistry, files, menuItems, plugin) { } function editModeOff (event) { - let label = this + const label = this const isFolder = label.className.indexOf('folder') !== -1 function rename () { @@ -438,10 +442,10 @@ fileExplorer.prototype.uploadFile = function (event) { // a file and then just use `files.add`. The file explorer will // pick that up via the 'fileAdded' event from the files module. - let self = this + const self = this ;[...event.target.files].forEach((file) => { - let files = this.files + const files = this.files function loadFile () { var fileReader = new FileReader() fileReader.onload = async function (event) { @@ -471,7 +475,7 @@ fileExplorer.prototype.uploadFile = function (event) { } fileExplorer.prototype.toGist = function (id) { - let proccedResult = function (error, data) { + const proccedResult = function (error, data) { if (error) { modalDialogCustom.alert('Failed to manage gist: ' + error) console.log('Failed to manage gist: ' + error) @@ -568,7 +572,7 @@ fileExplorer.prototype.toGist = function (id) { // return all the files, except the temporary/readonly ones.. fileExplorer.prototype.packageFiles = function (filesProvider, directory, callback) { - let ret = {} + const ret = {} filesProvider.resolveDirectory(directory, (error, files) => { if (error) callback(error) else { @@ -593,7 +597,7 @@ fileExplorer.prototype.packageFiles = function (filesProvider, directory, callba } fileExplorer.prototype.createNewFile = function (parentFolder = 'browser') { - let self = this + const self = this modalDialogCustom.prompt('Create new file', 'File Name (e.g Untitled.sol)', 'Untitled.sol', (input) => { if (!input) input = 'New file' helper.createNonClashingName(parentFolder + '/' + input, self.files, async (error, newName) => { @@ -614,7 +618,7 @@ fileExplorer.prototype.createNewFile = function (parentFolder = 'browser') { } fileExplorer.prototype.createNewFolder = function (parentFolder) { - let self = this + const self = this modalDialogCustom.prompt('Create new folder', '', 'New folder', (input) => { if (!input) { return tooltip('Failed to create folder. The name can not be empty') @@ -638,7 +642,7 @@ fileExplorer.prototype.createNewFolder = function (parentFolder) { fileExplorer.prototype.renderMenuItems = function () { let items = '' if (this.menuItems) { - items = this.menuItems.map(({action, title, icon}) => { + items = this.menuItems.map(({ action, title, icon }) => { if (action === 'uploadFile') { return yo`