diff --git a/apps/remix-ide/src/app.js b/apps/remix-ide/src/app.js index cd04567a53..e2a5625ea4 100644 --- a/apps/remix-ide/src/app.js +++ b/apps/remix-ide/src/app.js @@ -429,13 +429,7 @@ Please make a backup of your contracts and start using http://remix.ethereum.org } // CONTENT VIEWS & DEFAULT PLUGINS - const compileTab = new CompileTab( - editor, - registry.get('config').api, - registry.get('fileproviders/browser').api, - registry.get('filemanager').api, - contentImport - ) + const compileTab = new CompileTab() const run = new RunTab( blockchain, registry.get('config').api, diff --git a/apps/remix-ide/src/app/tabs/compile-tab.js b/apps/remix-ide/src/app/tabs/compile-tab.js index 2276d759e1..a77ccb4737 100644 --- a/apps/remix-ide/src/app/tabs/compile-tab.js +++ b/apps/remix-ide/src/app/tabs/compile-tab.js @@ -2,7 +2,7 @@ import React from 'react' // eslint-disable-line import ReactDOM from 'react-dom' import { SolidityCompiler, CompileTab as CompileTabLogic, parseContracts } from '@remix-ui/solidity-compiler' // eslint-disable-line -import { compile } from '@remix-project/remix-solidity' +import { CompilerApiMixin } from '@remixproject/solidity-compiler-plugin' import { ViewPlugin } from '@remixproject/engine-web' import * as packageJson from '../../../../../package.json' @@ -13,6 +13,8 @@ var QueryParams = require('../../lib/query-params') const addTooltip = require('../ui/tooltip') const globalRegistry = require('../../global/registry') +const css = require('./styles/compile-tab-styles') + const profile = { name: 'solidity', displayName: 'Solidity compiler', @@ -30,51 +32,19 @@ const profile = { // - events: ['compilationFinished'], // - methods: ['getCompilationResult'] -class CompileTab extends ViewPlugin { - constructor (editor, config, fileProvider, fileManager, contentImport) { +class CompileTab extends CompilerApiMixin(ViewPlugin) { + constructor () { super(profile) - this.events = new EventEmitter() - this._view = { - el: null, - warnCompilationSlow: null, - errorContainer: null, - contractEl: null - } - this.contentImport = contentImport - this.queryParams = new QueryParams() - this.fileProvider = fileProvider - // dependencies - this.editor = editor - this.config = config - this.fileManager = fileManager - this.contractsDetails = {} - this.data = { - eventHandlers: {}, - loading: false - } - this.compileTabLogic = new CompileTabLogic(this, this.contentImport) - this.compiler = this.compileTabLogic.compiler - this.compileTabLogic.init() - this.contractMap = {} - this.isHardHatProject = false - this.compileErrors = {} - this.compiledFileName = '' - this.selectedVersion = '' - this.configurationSettings = null - - this.el = document.createElement('div') - this.el.setAttribute('id', 'compileTabView') + this.initCompilerApi() } - resetResults () { - this.currentFile = '' - this.contractsDetails = {} - this.emit('statusChanged', { key: 'none' }) - this.renderComponent() + renderComponent () { + ReactDOM.render( + + , this.el) } - setCompileErrors (data) { - this.compileErrors = data + onCurrentFileChanged () { this.renderComponent() } @@ -191,6 +161,10 @@ class CompileTab extends ViewPlugin { }) } + onResetResults () { + this.renderComponent() + } + setHardHatCompilation (value) { this.hhCompilation = value } @@ -199,46 +173,27 @@ class CompileTab extends ViewPlugin { this.selectedVersion = version } - getCompilationResult () { - return this.compileTabLogic.compiler.state.lastCompilationResult + onSetWorkspace () { + this.renderComponent() } - addExternalFile (fileName, content) { - this.fileProvider.addExternal(fileName, content) + onNoFileSelected () { + this.renderComponent() } - /** - * compile using @arg fileName. - * The module UI will be updated accordingly to the new compilation result. - * This function is used by remix-plugin compiler API. - * @param {string} fileName to compile - */ - compile (fileName) { - addTooltip(yo`
${this.currentRequest.from} is requiring to compile ${fileName}
`) - return this.compileTabLogic.compileFile(fileName) + onCompilationFinished () { + this.renderComponent() } - /** - * compile using @arg compilationTargets and @arg settings - * The module UI will *not* be updated, the compilation result is returned - * This function is used by remix-plugin compiler API. - * @param {object} map of source files. - * @param {object} settings {evmVersion, optimize, runs, version, language} - */ - async compileWithParameters (compilationTargets, settings) { - settings.version = settings.version || this.selectedVersion - const res = await compile(compilationTargets, settings) - return res - } + render () { + if (this.el) return this.el + this.el = yo` +
+
+
` + this.renderComponent() - // This function is used for passing the compiler configuration to 'remix-tests' - getCurrentCompilerConfig () { - return { - currentVersion: this.selectedVersion, - evmVersion: this.compileTabLogic.evmVersion, - optimize: this.compileTabLogic.optimize, - runs: this.compileTabLogic.runs - } + return this.el } /** @@ -246,89 +201,20 @@ class CompileTab extends ViewPlugin { * This function is used by remix-plugin compiler API. * @param {object} settings {evmVersion, optimize, runs, version, language} */ - setCompilerConfig (settings) { - this.configurationSettings = settings + setCompilerConfig (settings) { + super.setCompilerConfig(settings) this.renderComponent() // @todo(#2875) should use loading compiler return value to check whether the compiler is loaded instead of "setInterval" addTooltip(yo`
${this.currentRequest.from} is updating the Solidity compiler configuration.
${JSON.stringify(settings, null, '\t')}
`) } - // TODO : Add success alert when compilation succeed - contractCompiledSuccess () { - return yo`
` - } - - // TODO : Add error alert when compilation failed - contractCompiledError () { - return yo`
` - } - - /************ - * METHODS - */ - - selectContract (contractName) { - this.selectedContract = contractName - } - - render () { - this.renderComponent() - return this.el - } - - renderComponent () { - ReactDOM.render( - - , this.el) - } - - getParameters () { - return this.queryParams.get() - } - - setParameters (params) { - this.queryParams.update(params) - } - - getConfiguration (name) { - return this.config.get(name) - } - - setConfiguration (name, value) { - this.config.set(name, value) - } - - fileProviderOf (fileName) { - return this.fileManager.fileProviderOf(fileName) - } - - getFileManagerMode () { - return this.fileManager.mode - } - - fileExists (fileName) { - return this.call('fileManager', 'exists', fileName) - } - - writeFile (fileName, content) { - return this.call('fileManager', 'writeFile', fileName, content) - } - - readFile (fileName) { - return this.call('fileManager', 'readFile', fileName) - } - - saveCurrentFile () { - return this.fileManager.saveCurrentFile() - } - - open (fileName) { - return this.call('fileManager', 'open', fileName) + compile (fileName) { + addTooltip(yo`
${this.currentRequest.from} is requiring to compile ${fileName}
`) + super.compile(fileName) } onActivation () { - this.call('manager', 'activatePlugin', 'solidity-logic') - this.listenToEvents() + super.onActivation() this.call('filePanel', 'registerContextMenuItem', { id: 'solidity', name: 'compileFile', @@ -339,32 +225,6 @@ class CompileTab extends ViewPlugin { pattern: [] }) } - - // Returns if the compilation was successfull - async compileFile (event) { - if (event.path.length > 0) { - try { - return await this.compileTabLogic.compileFile(event.path[0]) - } catch (error) { - return false - } - } - return false - } - - onDeactivation () { - this.editor.event.unregister('contentChanged') - this.editor.event.unregister('sessionSwitched') - this.editor.event.unregister('contentChanged', this.data.eventHandlers.onContentChanged) - this.compiler.event.unregister('loadingCompiler', this.data.eventHandlers.onLoadingCompiler) - this.compiler.event.unregister('compilerLoaded', this.data.eventHandlers.onCompilerLoaded) - this.compileTabLogic.event.removeListener('startingCompilation', this.data.eventHandlers.onStartingCompilation) - this.fileManager.events.removeListener('currentFileChanged', this.data.eventHandlers.onCurrentFileChanged) - this.fileManager.events.removeListener('noFileSelected', this.data.eventHandlers.onNoFileSelected) - this.compiler.event.unregister('compilationFinished', this.data.eventHandlers.onCompilationFinished) - globalRegistry.get('themeModule').api.events.removeListener('themeChanged', this.data.eventHandlers.onThemeChanged) - this.call('manager', 'deactivatePlugin', 'solidity-logic') - } } module.exports = CompileTab diff --git a/apps/remix-ide/src/app/tabs/styles/compile-tab-styles.js b/apps/remix-ide/src/app/tabs/styles/compile-tab-styles.js index b80f46bdec..6ab95aed8c 100644 --- a/apps/remix-ide/src/app/tabs/styles/compile-tab-styles.js +++ b/apps/remix-ide/src/app/tabs/styles/compile-tab-styles.js @@ -1,239 +1,11 @@ -const csjs = require('csjs-inject') +var csjs = require('csjs-inject') const css = csjs` - .title { - font-size: 1.1em; - font-weight: bold; - margin-bottom: 1em; + .compilerTabView { + padding: 2%; } - .panicError { - color: red; - font-size: 20px; - } - .crow { - display: flex; - overflow: auto; - clear: both; - padding: .2em; - } - .checkboxText { - font-weight: normal; - } - .crow label { - cursor:pointer; - } - .crowNoFlex { - overflow: auto; - clear: both; - } - .info { - padding: 10px; - word-break: break-word; - } - .contract { - display: block; - margin: 3% 0; - } - .nightlyBuilds { - display: flex; - flex-direction: row; - align-items: center; - } - .autocompileContainer { - display: flex; - align-items: center; - } - .runs { - width: 40%; - } - .hideWarningsContainer { - display: flex; - align-items: center; - } - .autocompile {} - .autocompileTitle { - font-weight: bold; - margin: 1% 0; - } - .autocompileText { - margin: 1% 0; - font-size: 12px; - overflow: hidden; - word-break: normal; - line-height: initial; - } - .warnCompilationSlow { - margin-left: 1%; - } - .compilerConfig { - display: flex; - align-items: center; - } - .compilerConfig label { - margin: 0; - } - .compilerSection { - padding: 12px 24px 16px; - } - .compilerLabel { - margin-bottom: 2px; - font-size: 11px; - line-height: 12px; - text-transform: uppercase; - } - .copyButton { - padding: 6px; - font-weight: bold; - font-size: 11px; - line-height: 15px; - } - .name { - display: flex; - } - .size { - display: flex; - } - .checkboxes { - display: flex; - width: 100%; - justify-content: space-between; - flex-wrap: wrap; - } - .compileButton { - width: 100%; - margin: 15px 0 10px 0; - font-size: 12px; - } - .container { - margin: 0; - margin-bottom: 2%; - } - .optimizeContainer { - display: flex; - } - .noContractAlert { - display: flex; - justify-content: center; - align-items: center; - } - .contractHelperButtons { - margin-top: 6px; - display: flex; - align-items: center; - justify-content: space-between; - float: right; - } - .copyToClipboard { - font-size: 1rem; - } - .copyIcon { - margin-right: 5px; - } - .log { - display: flex; - flex-direction: column; - margin-bottom: 5%; - overflow: visible; - } - .key { - margin-right: 5px; - text-transform: uppercase; - width: 100%; - } - .value { - display: flex; - width: 100%; - margin-top: 1.5%; - } - .questionMark { - margin-left: 2%; - cursor: pointer; - } - .questionMark:hover { - } - .detailsJSON { - padding: 8px 0; - border: none; - } - .icon { - margin-right: 0.3em; - } - .errorBlobs { - padding-left: 5px; - padding-right: 5px; - word-break: break-word; - } - .storageLogo { - width: 20px; - height: 20px; - } - .spinningIcon { - display: inline-block; - position: relative; - animation: spin 2s infinite linear; - -moz-animation: spin 2s infinite linear; - -o-animation: spin 2s infinite linear; - -webkit-animation: spin 2s infinite linear; - } - @keyframes spin { - 0% { transform: rotate(0deg); } - 100% { transform: rotate(360deg); } - } - @-webkit-keyframes spin { - 0% { transform: rotate(0deg); } - 100% { transform: rotate(360deg); } - } - @-moz-keyframes spin { - 0% { transform: rotate(0deg); } - 100% { transform: rotate(360deg); } - } - @-o-keyframes spin { - 0% { transform: rotate(0deg); } - 100% { transform: rotate(360deg); } - } - @-ms-keyframes spin { - 0% { transform: rotate(0deg); } - 100% { transform: rotate(360deg); } - } - - .bouncingIcon { - display: inline-block; - position: relative; - -moz-animation: bounce 2s infinite linear; - -o-animation: bounce 2s infinite linear; - -webkit-animation: bounce 2s infinite linear; - animation: bounce 2s infinite linear; - } - - @-webkit-keyframes bounce { - 0% { top: 0; } - 50% { top: -0.2em; } - 70% { top: -0.3em; } - 100% { top: 0; } - } - @-moz-keyframes bounce { - 0% { top: 0; } - 50% { top: -0.2em; } - 70% { top: -0.3em; } - 100% { top: 0; } - } - @-o-keyframes bounce { - 0% { top: 0; } - 50% { top: -0.2em; } - 70% { top: -0.3em; } - 100% { top: 0; } - } - @-ms-keyframes bounce { - 0% { top: 0; } - 50% { top: -0.2em; } - 70% { top: -0.3em; } - 100% { top: 0; } - } - @keyframes bounce { - 0% { top: 0; } - 50% { top: -0.2em; } - 70% { top: -0.3em; } - 100% { top: 0; } + .compiler { + margin-bottom: 1%; } ` diff --git a/apps/solidity-compiler/.babelrc b/apps/solidity-compiler/.babelrc new file mode 100644 index 0000000000..09d67939cc --- /dev/null +++ b/apps/solidity-compiler/.babelrc @@ -0,0 +1,4 @@ +{ + "presets": ["@nrwl/react/babel"], + "plugins": [] +} diff --git a/apps/solidity-compiler/.browserslistrc b/apps/solidity-compiler/.browserslistrc new file mode 100644 index 0000000000..f1d12df4fa --- /dev/null +++ b/apps/solidity-compiler/.browserslistrc @@ -0,0 +1,16 @@ +# This file is used by: +# 1. autoprefixer to adjust CSS to support the below specified browsers +# 2. babel preset-env to adjust included polyfills +# +# For additional information regarding the format and rule options, please see: +# https://github.com/browserslist/browserslist#queries +# +# If you need to support different browsers in production, you may tweak the list below. + +last 1 Chrome version +last 1 Firefox version +last 2 Edge major versions +last 2 Safari major version +last 2 iOS major versions +Firefox ESR +not IE 9-11 # For IE 9-11 support, remove 'not'. \ No newline at end of file diff --git a/apps/solidity-compiler/src/app/app.tsx b/apps/solidity-compiler/src/app/app.tsx new file mode 100644 index 0000000000..3f3e32eb11 --- /dev/null +++ b/apps/solidity-compiler/src/app/app.tsx @@ -0,0 +1,17 @@ +import React, { useState, useEffect } from 'react'; + +import { SolidityCompiler } from '@remix-ui/solidity-compiler' // eslint-disable-line + +import { CompilerClientApi } from './compiler' + +const remix = new CompilerClientApi() + +export const App = () => { + return ( +
+ +
+ ); +}; + +export default App; diff --git a/apps/solidity-compiler/src/app/compiler-api.ts b/apps/solidity-compiler/src/app/compiler-api.ts new file mode 100644 index 0000000000..d85d05da66 --- /dev/null +++ b/apps/solidity-compiler/src/app/compiler-api.ts @@ -0,0 +1,248 @@ +import { compile } from '@remix-project/remix-solidity' +import { CompileTab as CompileTabLogic, parseContracts } from '@remix-ui/solidity-compiler' // eslint-disable-line + +export const CompilerApiMixin = (Base) => class extends Base { + initCompilerApi () { + this.configurationSettings = null + + this._view = { + warnCompilationSlow: null, + errorContainer: null, + contractEl: null + } + + this.contractsDetails = {} + this.data = { + eventHandlers: {}, + loading: false + } + this.compileTabLogic = new CompileTabLogic(this, this.contentImport) + this.compiler = this.compileTabLogic.compiler + this.compileTabLogic.init() + + this.contractMap = {} + this.contractsDetails = {} + + this.compileErrors = {} + this.compiledFileName = '' + this.selectedVersion = '' + this.currentFile = '' + } + + onActivation () { + this.call('manager', 'activatePlugin', 'solidity-logic') + this.listenToEvents() + } + + onDeactivation () { + this.call('manager', 'deactivatePlugin', 'solidity-logic') + } + + setHardHatCompilation (value) { + this.hhCompilation = value + } + + setSelectedVersion (version) { + this.selectedVersion = version + } + + getCompilationResult () { + return this.compileTabLogic.compiler.state.lastCompilationResult + } + + addExternalFile (fileName, content) { + this.fileProvider.addExternal(fileName, content) + } + + /** + * compile using @arg fileName. + * The module UI will be updated accordingly to the new compilation result. + * This function is used by remix-plugin compiler API. + * @param {string} fileName to compile + */ + compile (fileName) { + return this.compileTabLogic.compileFile(fileName) + } + + compileFile (event) { + if (event.path.length > 0) { + this.compileTabLogic.compileFile(event.path[0]) + } + } + + /** + * compile using @arg compilationTargets and @arg settings + * The module UI will *not* be updated, the compilation result is returned + * This function is used by remix-plugin compiler API. + * @param {object} map of source files. + * @param {object} settings {evmVersion, optimize, runs, version, language} + */ + async compileWithParameters (compilationTargets, settings) { + settings.version = settings.version || this.selectedVersion + const res = await compile(compilationTargets, settings, (url, cb) => this.call('contentImport', 'resolveAndSave', url).then((result) => cb(null, result)).catch((error) => cb(error.message))) + return res + } + + // This function is used for passing the compiler configuration to 'remix-tests' + getCurrentCompilerConfig () { + return { + currentVersion: this.selectedVersion, + evmVersion: this.compileTabLogic.evmVersion, + optimize: this.compileTabLogic.optimize, + runs: this.compileTabLogic.runs + } + } + + + /** + * set the compiler configuration + * This function is used by remix-plugin compiler API. + * @param {object} settings {evmVersion, optimize, runs, version, language} + */ + setCompilerConfig (settings) { + this.configurationSettings = settings + } + + getParameters () { + return {} + } + + setParameters (params) {} + + getConfiguration (name) { + const conf = { + 'currentFile': () => this.currentFile, + 'hideWarnings': () => false, + 'autoCompile': () => false, + 'includeNightlies': () => false, + 'optimise': () => false + } + return conf[name]() + } + + setConfiguration (name, value) {} + + getFileManagerMode () { + return 'browser' + } + + fileExists (fileName) { + return this.call('fileManager', 'exists', fileName) + } + + writeFile (fileName, content) { + return this.call('fileManager', 'writeFile', fileName, content) + } + + readFile (fileName) { + return this.call('fileManager', 'readFile', fileName) + } + + open (fileName) { + return this.call('fileManager', 'open', fileName) + } + + resetResults () { + this.currentFile = '' + this.contractsDetails = {} + this.emit('statusChanged', { key: 'none' }) + if (this.onResetResults()) this.onResetResults() + } + + listenToEvents () { + this.data.eventHandlers.onContentChanged = () => { + this.emit('statusChanged', { key: 'edited', title: 'the content has changed, needs recompilation', type: 'info' }) + } + this.on('editor', 'contentChanged', this.data.eventHandlers.onContentChanged) + + this.data.eventHandlers.onLoadingCompiler = () => { + this.data.loading = true + this.emit('statusChanged', { key: 'loading', title: 'loading compiler...', type: 'info' }) + } + this.compiler.event.register('loadingCompiler', this.data.eventHandlers.onLoadingCompiler) + + this.data.eventHandlers.onCompilerLoaded = () => { + this.data.loading = false + this.emit('statusChanged', { key: 'none' }) + } + this.compiler.event.register('compilerLoaded', this.data.eventHandlers.onCompilerLoaded) + + this.data.eventHandlers.onStartingCompilation = () => { + this.emit('statusChanged', { key: 'loading', title: 'compiling...', type: 'info' }) + } + + this.data.eventHandlers.onRemoveAnnotations = () => { + this.call('editor', 'clearAnnotations') + } + + this.on('filePanel', 'setWorkspace', (workspace) => { + this.resetResults() + if (this.onSetWorkspace) this.onSetWorkspace(workspace) + }) + + this.compileTabLogic.event.on('startingCompilation', this.data.eventHandlers.onStartingCompilation) + this.compileTabLogic.event.on('removeAnnotations', this.data.eventHandlers.onRemoveAnnotations) + + this.data.eventHandlers.onCurrentFileChanged = (name) => { + this.currentFile = name + if (this.onCurrentFileChanged) this.onCurrentFileChanged(name) + } + this.on('fileManager', 'currentFileChanged', this.data.eventHandlers.onCurrentFileChanged) + + this.data.eventHandlers.onNoFileSelected = () => { + this.currentFile = '' + if (this.onNoFileSelected) this.onNoFileSelected() + } + this.on('fileManager', 'noFileSelected', this.data.eventHandlers.onNoFileSelected) + + this.data.eventHandlers.onCompilationFinished = (success, data, source) => { + this.compileErrors = data + if (success) { + // forwarding the event to the appManager infra + this.emit('compilationFinished', source.target, source, 'soljson', data) + if (data.errors && data.errors.length > 0) { + this.emit('statusChanged', { + key: data.errors.length, + title: `compilation finished successful with warning${data.errors.length > 1 ? 's' : ''}`, + type: 'warning' + }) + } else this.emit('statusChanged', { key: 'succeed', title: 'compilation successful', type: 'success' }) + // Store the contracts + this.contractsDetails = {} + this.compiler.visitContracts((contract) => { + this.contractsDetails[contract.name] = parseContracts( + contract.name, + contract.object, + this.compiler.getSource(contract.file) + ) + }) + } else { + const count = (data.errors ? data.errors.filter(error => error.severity === 'error').length : 0 + data.error ? 1 : 0) + this.emit('statusChanged', { key: count, title: `compilation failed with ${count} error${count.length > 1 ? 's' : ''}`, type: 'error' }) + } + // Update contract Selection + this.contractMap = {} + if (success) this.compiler.visitContracts((contract) => { this.contractMap[contract.name] = contract }) + if (this.onCompilationFinished) this.onCompilationFinished(this.contractsDetails, this.contractMap) + } + this.compiler.event.register('compilationFinished', this.data.eventHandlers.onCompilationFinished) + + this.data.eventHandlers.onThemeChanged = (theme) => { + const invert = theme.quality === 'dark' ? 1 : 0 + const img = document.getElementById('swarmLogo') + if (img) { + img.style.filter = `invert(${invert})` + } + } + this.on('themeModule', 'themeChanged', this.data.eventHandlers.onThemeChanged) + + // Run the compiler instead of trying to save the website + window.document.addEventListener('keydown', (e) => { + // ctrl+s or command+s + if ((e.metaKey || e.ctrlKey) && e.keyCode === 83) { + e.preventDefault() + this.compileTabLogic.runCompiler(this.hhCompilation) + } + }) + } +} diff --git a/apps/solidity-compiler/src/app/compiler.ts b/apps/solidity-compiler/src/app/compiler.ts new file mode 100644 index 0000000000..d16c6a5740 --- /dev/null +++ b/apps/solidity-compiler/src/app/compiler.ts @@ -0,0 +1,40 @@ +import { PluginClient } from "@remixproject/plugin"; +import { createClient } from "@remixproject/plugin-webview"; +import { CompilerApiMixin } from './compiler-api' + +export interface ConfigurationSettings { + version: string, + evmVersion: string, + language: string, + optimize: boolean, + runs: string +} + +export class CompilerClientApi extends CompilerApiMixin(PluginClient) { + contractMap: { + file: string + } | Record + compileErrors: any + compileTabLogic: any + contractsDetails: Record + contentImport: any + call: (...args) => void + on: (...args) => void + setSelectedVersion: (value: string) => void + configurationSettings: ConfigurationSettings + getConfiguration: (value: string) => string + setConfiguration: (name: string, value: string) => void + currentFile: string + + onCurrentFileChanged: (fileName: string) => void + onResetResults: () => void + onSetWorkspace: (workspace: any) => void + onNoFileSelected: () => void + onCompilationFinished: (contractsDetails: any, contractMap: any) => void + + constructor () { + super() + createClient(this as any) + this.initCompilerApi() + } +} diff --git a/apps/solidity-compiler/src/assets/.gitkeep b/apps/solidity-compiler/src/assets/.gitkeep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/apps/solidity-compiler/src/environments/environment.prod.ts b/apps/solidity-compiler/src/environments/environment.prod.ts new file mode 100644 index 0000000000..3612073bc3 --- /dev/null +++ b/apps/solidity-compiler/src/environments/environment.prod.ts @@ -0,0 +1,3 @@ +export const environment = { + production: true +}; diff --git a/apps/solidity-compiler/src/environments/environment.ts b/apps/solidity-compiler/src/environments/environment.ts new file mode 100644 index 0000000000..d9370e924b --- /dev/null +++ b/apps/solidity-compiler/src/environments/environment.ts @@ -0,0 +1,6 @@ +// This file can be replaced during build by using the `fileReplacements` array. +// When building for production, this file is replaced with `environment.prod.ts`. + +export const environment = { + production: false +}; diff --git a/apps/solidity-compiler/src/favicon.ico b/apps/solidity-compiler/src/favicon.ico new file mode 100644 index 0000000000..317ebcb233 Binary files /dev/null and b/apps/solidity-compiler/src/favicon.ico differ diff --git a/apps/solidity-compiler/src/index.html b/apps/solidity-compiler/src/index.html new file mode 100644 index 0000000000..20d2fdd17f --- /dev/null +++ b/apps/solidity-compiler/src/index.html @@ -0,0 +1,14 @@ + + + + + SolidityCompiler + + + + + + +
+ + diff --git a/apps/solidity-compiler/src/index.ts b/apps/solidity-compiler/src/index.ts new file mode 100644 index 0000000000..776e9a33df --- /dev/null +++ b/apps/solidity-compiler/src/index.ts @@ -0,0 +1 @@ +export * from './app/compiler-api'; diff --git a/apps/solidity-compiler/src/main.tsx b/apps/solidity-compiler/src/main.tsx new file mode 100644 index 0000000000..89c91fbb14 --- /dev/null +++ b/apps/solidity-compiler/src/main.tsx @@ -0,0 +1,11 @@ +import React from 'react'; +import ReactDOM from 'react-dom'; + +import App from './app/app'; + +ReactDOM.render( + + + , + document.getElementById('root') +); diff --git a/apps/solidity-compiler/src/polyfills.ts b/apps/solidity-compiler/src/polyfills.ts new file mode 100644 index 0000000000..2adf3d05b6 --- /dev/null +++ b/apps/solidity-compiler/src/polyfills.ts @@ -0,0 +1,7 @@ +/** + * Polyfill stable language features. These imports will be optimized by `@babel/preset-env`. + * + * See: https://github.com/zloirock/core-js#babel + */ +import 'core-js/stable'; +import 'regenerator-runtime/runtime'; diff --git a/apps/solidity-compiler/src/styles.css b/apps/solidity-compiler/src/styles.css new file mode 100644 index 0000000000..90d4ee0072 --- /dev/null +++ b/apps/solidity-compiler/src/styles.css @@ -0,0 +1 @@ +/* You can add global styles to this file, and also import other style files */ diff --git a/apps/solidity-compiler/tsconfig.app.json b/apps/solidity-compiler/tsconfig.app.json new file mode 100644 index 0000000000..2151bb6497 --- /dev/null +++ b/apps/solidity-compiler/tsconfig.app.json @@ -0,0 +1,9 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../dist/out-tsc", + "types": ["node"] + }, + "exclude": ["**/*.spec.ts", "**/*.spec.tsx"], + "include": ["**/*.js", "**/*.jsx", "**/*.ts", "**/*.tsx"] +} diff --git a/apps/solidity-compiler/tsconfig.json b/apps/solidity-compiler/tsconfig.json new file mode 100644 index 0000000000..7c6fcde8f2 --- /dev/null +++ b/apps/solidity-compiler/tsconfig.json @@ -0,0 +1,16 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "jsx": "react", + "allowJs": true, + "esModuleInterop": true, + "allowSyntheticDefaultImports": true, + "types": ["node", "jest"], + "resolveJsonModule": true + }, + "files": [ + "../../node_modules/@nrwl/react/typings/cssmodule.d.ts", + "../../node_modules/@nrwl/react/typings/image.d.ts" + ], + "include": ["**/*.js", "**/*.jsx", "**/*.ts", "**/*.tsx"] +} diff --git a/apps/solidity-compiler/tsconfig.spec.json b/apps/solidity-compiler/tsconfig.spec.json new file mode 100644 index 0000000000..559410b96a --- /dev/null +++ b/apps/solidity-compiler/tsconfig.spec.json @@ -0,0 +1,15 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../dist/out-tsc", + "module": "commonjs", + "types": ["jest", "node"] + }, + "include": [ + "**/*.spec.ts", + "**/*.spec.tsx", + "**/*.spec.js", + "**/*.spec.jsx", + "**/*.d.ts" + ] +} diff --git a/apps/solidity-compiler/webpack.config.js b/apps/solidity-compiler/webpack.config.js new file mode 100644 index 0000000000..bacc6e251e --- /dev/null +++ b/apps/solidity-compiler/webpack.config.js @@ -0,0 +1,17 @@ +const nxWebpack = require('@nrwl/react/plugins/webpack') + +module.exports = config => { + const nxWebpackConfig = nxWebpack(config) + + return { + ...nxWebpackConfig, + node: { + fs: 'empty', + tls: 'empty', + readline: 'empty', + net: 'empty', + module: 'empty', + child_process: 'empty' + } + } +} diff --git a/libs/remix-ui/debugger-ui/src/index.ts b/libs/remix-ui/debugger-ui/src/index.ts index bc404baa76..840763d2ef 100644 --- a/libs/remix-ui/debugger-ui/src/index.ts +++ b/libs/remix-ui/debugger-ui/src/index.ts @@ -1,3 +1,2 @@ export * from './lib/debugger-ui' export * from './lib/idebugger-api' -export * from './lib/idebugger-api' diff --git a/libs/remix-ui/solidity-compiler/src/index.ts b/libs/remix-ui/solidity-compiler/src/index.ts index 317c79cefa..073b7eeacc 100644 --- a/libs/remix-ui/solidity-compiler/src/index.ts +++ b/libs/remix-ui/solidity-compiler/src/index.ts @@ -1,2 +1,3 @@ export * from './lib/solidity-compiler' export * from './lib/logic' +export * from './lib/icompiler-api' diff --git a/libs/remix-ui/solidity-compiler/src/lib/icompiler-api.ts b/libs/remix-ui/solidity-compiler/src/lib/icompiler-api.ts new file mode 100644 index 0000000000..8ff1df432e --- /dev/null +++ b/libs/remix-ui/solidity-compiler/src/lib/icompiler-api.ts @@ -0,0 +1,28 @@ +export type onCurrentFileChanged = (fileName: string) => void + +export interface ICompilerApi { + contractMap: { + file: string + } | Record + + compileErrors:any + + currentFile: string + configurationSettings: any + setHardHatCompilation(value: boolean): void + setSelectedVersion(version: string): void + getCompilationResult(): any + setCompilerConfig: (settings: any) => void + getParameters: () => any + setParameters: (params) => void + getConfiguration: (name: string) => string + setConfiguration: (name: string, value: string) => void + fileProviderOf: (file: string) => string + getFileManagerMode: () => string + fileExists: (file: string) => Promise + writeFile: (file: string, content: string) => Promise + readFile: (file: string) => Promise + open: (file: string) => void + addExternalFile: (file: string, content: string) => void + onCurrentFileChanged: (listener: onCurrentFileChanged) => void +} diff --git a/libs/remix-ui/solidity-compiler/src/lib/logic/compileTabLogic.ts b/libs/remix-ui/solidity-compiler/src/lib/logic/compileTabLogic.ts index eaba281abe..09aa9ad66f 100644 --- a/libs/remix-ui/solidity-compiler/src/lib/logic/compileTabLogic.ts +++ b/libs/remix-ui/solidity-compiler/src/lib/logic/compileTabLogic.ts @@ -87,15 +87,14 @@ export class CompileTab extends Plugin { */ compileFile (target) { if (!target) throw new Error('No target provided for compiliation') - const provider = this.api.fileProviderOf(target) - if (!provider) throw new Error(`cannot compile ${target}. Does not belong to any explorer`) return new Promise((resolve, reject) => { - provider.get(target, (error, content) => { - if (error) return reject(error) + this.api.readFile(target).then((content) => { const sources = { [target]: { content } } this.event.emit('startingCompilation') // setTimeout fix the animation on chrome... (animation triggered by 'staringCompilation') setTimeout(() => { this.compiler.compile(sources, target); resolve(true) }, 100) + }).catch((error) => { + reject(error) }) }) } @@ -131,7 +130,8 @@ export class CompileTab extends Plugin { }) } } - this.api.saveCurrentFile() + // TODO readd saving current file + // this.api.saveCurrentFile() this.event.emit('removeAnnotations') var currentFile = this.api.getConfiguration('currentFile') return this.compileFile(currentFile) diff --git a/libs/remix-ui/solidity-compiler/src/lib/solidity-compiler.tsx b/libs/remix-ui/solidity-compiler/src/lib/solidity-compiler.tsx index 46c032d582..57acbbd18b 100644 --- a/libs/remix-ui/solidity-compiler/src/lib/solidity-compiler.tsx +++ b/libs/remix-ui/solidity-compiler/src/lib/solidity-compiler.tsx @@ -9,10 +9,12 @@ import { Renderer } from '@remix-ui/renderer' // eslint-disable-line import './css/style.css' export const SolidityCompiler = (props: SolidityCompilerProps) => { - const { plugin, plugin: { compileTabLogic, contractsDetails, contractMap, compileErrors, configurationSettings } } = props + const { plugin, plugin: { currentFile, compileTabLogic, contractsDetails, contractMap, compileErrors, configurationSettings } } = props const [state, setState] = useState({ + isHardhatProject: false, + currentFile, contractsDetails: {}, - eventHandlers: {}, + contractMap: {}, loading: false, compileTabLogic: null, compiler: null, @@ -30,6 +32,37 @@ export const SolidityCompiler = (props: SolidityCompilerProps) => { }) const [currentVersion, setCurrentVersion] = useState('') + plugin.onCurrentFileChanged = (currentFile: string) => { + setState(prevState => { + return { ...prevState, currentFile } + }) + } + + plugin.onResetResults = () => { + setState(prevState => { + return { ...prevState, currentFile: '', contractsDetails: {}, contractMap: {} } + }) + } + + plugin.onSetWorkspace = async (workspace: any) => { + const isHardhat = workspace.isLocalhost && await compileTabLogic.isHardhatProject() + setState(prevState => { + return { ...prevState, currentFile, isHardhatProject: isHardhat } + }) + } + + plugin.onNoFileSelected = () => { + setState(prevState => { + return { ...prevState, currentFile: '' } + }) + } + + plugin.onCompilationFinished = (contractsDetails: any, contractMap: any) => { + setState(prevState => { + return { ...prevState, contractsDetails, contractMap } + }) + } + const toast = (message: string) => { setState(prevState => { return { ...prevState, toasterMsg: message } @@ -75,11 +108,10 @@ export const SolidityCompiler = (props: SolidityCompilerProps) => { ) - const currentFile = plugin.getConfiguration('currentFile') return ( <>
- +
diff --git a/libs/remix-ui/solidity-compiler/src/lib/types/index.ts b/libs/remix-ui/solidity-compiler/src/lib/types/index.ts index a2106e2205..5aae51ab93 100644 --- a/libs/remix-ui/solidity-compiler/src/lib/types/index.ts +++ b/libs/remix-ui/solidity-compiler/src/lib/types/index.ts @@ -1,5 +1,8 @@ +export type onCurrentFileChanged = (fileName: string) => void + export interface SolidityCompilerProps { plugin: { + currentFile: string contractMap: { file: string } | Record @@ -12,13 +15,19 @@ export interface SolidityCompilerProps { setSelectedVersion: (value: string) => void, configurationSettings: ConfigurationSettings, getConfiguration: (value: string) => string, - setConfiguration: (name: string, value: string) => void + setConfiguration: (name: string, value: string) => void, + onCurrentFileChanged: (fileName: string) => void, + onResetResults: () => void, + onSetWorkspace: (workspace: any) => void, + onNoFileSelected: () => void, + onCompilationFinished: (contractsDetails: any, contractMap: any) => void }, } export interface CompilerContainerProps { api: any, compileTabLogic: any, + isHardhatProject: boolean, tooltip: (message: string | JSX.Element) => void, modal: (title: string, message: string | JSX.Element, okLabel: string, okFn: () => void, cancelLabel?: string, cancelFn?: () => void) => void, compiledFileName: string, diff --git a/nx.json b/nx.json index a5f9bad329..e063294259 100644 --- a/nx.json +++ b/nx.json @@ -98,7 +98,7 @@ "tags": [] }, "remix-ui-settings": { - "tags": [] + "tags": [] }, "remix-ui-static-analyser": { "tags": [] @@ -123,6 +123,9 @@ }, "remix-ui-terminal": { "tags": [] + }, + "solidity-compiler": { + "tags": [] } } } diff --git a/tsconfig.base.json b/tsconfig.base.json index e799c5f3df..7a5534ca12 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -25,6 +25,7 @@ "@remix-project/remix-tests": ["dist/libs/remix-tests/src/index.js"], "@remix-project/remix-url-resolver": ["dist/libs/remix-url-resolver/index.js"], "@remixproject/debugger-plugin": ["apps/debugger/src/index.ts"], + "@remixproject/solidity-compiler-plugin": ["apps/solidity-compiler/src/index.ts"], "@remix-project/remixd": ["dist/libs/remixd/index.js"], "@remix-ui/tree-view": ["libs/remix-ui/tree-view/src/index.ts"], "@remix-ui/debugger-ui": ["libs/remix-ui/debugger-ui/src/index.ts"], diff --git a/workspace.json b/workspace.json index 21f4d1e051..409d4abb37 100644 --- a/workspace.json +++ b/workspace.json @@ -891,6 +891,76 @@ } } } + }, + "solidity-compiler": { + "root": "apps/solidity-compiler", + "sourceRoot": "apps/solidity-compiler/src", + "projectType": "application", + "schematics": {}, + "architect": { + "build": { + "builder": "@nrwl/web:build", + "options": { + "outputPath": "dist/apps/solidity-compiler", + "index": "apps/solidity-compiler/src/index.html", + "main": "apps/solidity-compiler/src/main.tsx", + "polyfills": "apps/solidity-compiler/src/polyfills.ts", + "tsConfig": "apps/solidity-compiler/tsconfig.app.json", + "assets": [ + "apps/solidity-compiler/src/favicon.ico", + "apps/solidity-compiler/src/assets", + "apps/solidity-compiler/src/index.html" + ], + "styles": ["apps/solidity-compiler/src/styles.css"], + "scripts": [], + "webpackConfig": "apps/solidity-compiler/webpack.config.js", + "maxWorkers": 2 + }, + "configurations": { + "production": { + "fileReplacements": [ + { + "replace": "apps/solidity-compiler/src/environments/environment.ts", + "with": "apps/solidity-compiler/src/environments/environment.prod.ts" + } + ], + "optimization": true, + "outputHashing": "all", + "sourceMap": false, + "extractCss": true, + "namedChunks": false, + "extractLicenses": true, + "vendorChunk": false, + "budgets": [ + { + "type": "initial", + "maximumWarning": "2mb", + "maximumError": "5mb" + } + ] + } + } + }, + "serve": { + "builder": "@nrwl/web:dev-server", + "options": { + "buildTarget": "solidity-compiler:build" + }, + "configurations": { + "production": { + "buildTarget": "solidity-compiler:build:production" + } + } + }, + "lint": { + "builder": "@nrwl/linter:lint", + "options": { + "linter": "eslint", + "tsConfig": ["apps/solidity-compiler/tsconfig.app.json"], + "exclude": ["**/node_modules/**", "!apps/solidity-compiler/**/*"] + } + } + } } }, "cli": {