refactor vyper to work with context command.

pull/4525/head
Joseph Izang 9 months ago
parent 11e26cd092
commit 6cbf72aa2e
  1. 28
      apps/vyper/src/app/app.tsx
  2. 111
      apps/vyper/src/app/components/CompilerButton.tsx
  3. 127
      apps/vyper/src/app/utils/compiler.tsx
  4. 23
      apps/vyper/src/app/utils/remix-client.tsx
  5. 12
      libs/remix-ui/vyper-compile-details/src/lib/vyper-compile-details.tsx
  6. 1
      libs/remix-ui/vyper-compile-details/src/lib/vyperCompile.tsx

@ -28,7 +28,7 @@ interface OutputMap {
const App = () => { const App = () => {
const [contract, setContract] = useState<string>() const [contract, setContract] = useState<string>()
const [output, setOutput] = useState<any>({}) const [output, setOutput] = useState<any>(remixClient.compilerOutput)
const [state, setState] = useState<AppState>({ const [state, setState] = useState<AppState>({
status: 'idle', status: 'idle',
environment: 'remote', environment: 'remote',
@ -53,6 +53,30 @@ const App = () => {
start() start()
}, []) }, [])
useEffect(() => {
remixClient.eventEmitter.on('resetCompilerState', () => {
resetCompilerResultState()
})
return () => {
remixClient.eventEmitter.off('resetCompilerState', () => {
resetCompilerResultState()
})
}
}, [])
useEffect(() => {
remixClient.eventEmitter.on('setOutput', (payload) => {
setOutput(payload)
})
return () => {
remixClient.eventEmitter.off('setOutput', (payload) => {
setOutput(payload)
})
}
}, [])
/** Update the environment state value */ /** Update the environment state value */
function setEnvironment(environment: 'local' | 'remote') { function setEnvironment(environment: 'local' | 'remote') {
setState({...state, environment}) setState({...state, environment})
@ -67,7 +91,7 @@ const App = () => {
} }
function resetCompilerResultState() { function resetCompilerResultState() {
setOutput({}) setOutput(remixClient.compilerOutput)
} }
return ( return (

@ -1,7 +1,6 @@
import React, { Fragment, useState } from 'react' import React, { Fragment, useState } from 'react'
import {isVyper, compile, toStandardOutput, isCompilationError, remixClient, normalizeContractPath} from '../utils' import {isVyper, compile, toStandardOutput, isCompilationError, remixClient, normalizeContractPath, compileContract} from '../utils'
import Button from 'react-bootstrap/Button' import Button from 'react-bootstrap/Button'
import _ from 'lodash'
interface Props { interface Props {
compilerUrl: string compilerUrl: string
@ -21,112 +20,14 @@ function CompilerButton({contract, setOutput, compilerUrl, resetCompilerState}:
} }
/** Compile a Contract */ /** Compile a Contract */
async function compileContract() {
resetCompilerState()
setLoadingSpinnerState(true)
try {
// await remixClient.discardHighlight()
let _contract: any
try {
_contract = await remixClient.getContract()
} catch (e: any) {
setOutput('', {status: 'failed', message: e.message})
return
}
remixClient.changeStatus({
key: 'loading',
type: 'info',
title: 'Compiling'
})
let output
try {
output = await compile(compilerUrl, _contract)
} catch (e: any) {
remixClient.changeStatus({
key: 'failed',
type: 'error',
title: e.message
})
return
}
const compileReturnType = () => {
const t: any = toStandardOutput(contract, output)
const temp = _.merge(t['contracts'][contract])
const normal = normalizeContractPath(contract)[2]
const abi = temp[normal]['abi']
const evm = _.merge(temp[normal]['evm'])
const dpb = evm.deployedBytecode
const runtimeBytecode = evm.bytecode
const methodIdentifiers = evm.methodIdentifiers
const result = {
contractName: normal,
abi: abi,
bytecode: dpb,
runtimeBytecode: runtimeBytecode,
ir: '',
methodIdentifiers: methodIdentifiers
}
return result
}
// ERROR
if (isCompilationError(output)) {
const line = output.line
if (line) {
const lineColumnPos = {
start: {line: line - 1, column: 10},
end: {line: line - 1, column: 10}
}
// remixClient.highlight(lineColumnPos as any, _contract.name, '#e0b4b4')
} else {
const regex = output?.message?.match(/line ((\d+):(\d+))+/g)
const errors = output?.message?.split(/line ((\d+):(\d+))+/g) // extract error message
if (regex) {
let errorIndex = 0
regex.map((errorLocation) => {
const location = errorLocation?.replace('line ', '').split(':')
let message = errors[errorIndex]
errorIndex = errorIndex + 4
if (message && message?.split('\n\n').length > 0) {
try {
message = message?.split('\n\n')[message.split('\n\n').length - 1]
} catch (e) {}
}
if (location?.length > 0) {
const lineColumnPos = {
start: {line: parseInt(location[0]) - 1, column: 10},
end: {line: parseInt(location[0]) - 1, column: 10}
}
// remixClient.highlight(lineColumnPos as any, _contract.name, message)
}
})
}
}
throw new Error(output.message)
}
// SUCCESS
// remixClient.discardHighlight()
remixClient.changeStatus({
key: 'succeed',
type: 'success',
title: 'success'
})
const data = toStandardOutput(_contract.name, output)
remixClient.compilationFinish(_contract.name, _contract.content, data)
setOutput(_contract.name, compileReturnType())
} catch (err: any) {
remixClient.changeStatus({
key: 'failed',
type: 'error',
title: err.message
})
}
}
return ( return (
<Fragment> <Fragment>
<button data-id="compile" onClick={compileContract} title={contract} className="btn btn-primary w-100 d-block btn-block text-break remixui_disabled mb-1 mt-3"> <button data-id="compile"
onClick={() => compileContract(contract, compilerUrl, setOutput)}
title={contract}
className="btn btn-primary w-100 d-block btn-block text-break remixui_disabled mb-1 mt-3"
>
<div className="d-flex align-items-center justify-content-center fa-1x"> <div className="d-flex align-items-center justify-content-center fa-1x">
<span className="fas fa-sync fa-pulse mr-1" /> <span className="fas fa-sync fa-pulse mr-1" />
<div className="text-truncate overflow-hidden text-nowrap"> <div className="text-truncate overflow-hidden text-nowrap">

@ -1,5 +1,8 @@
import { ABIDescription} from '@remixproject/plugin-api' import { ABIDescription} from '@remixproject/plugin-api'
import axios from 'axios' import axios from 'axios'
import { remixClient } from './remix-client'
import _ from 'lodash'
export interface Contract { export interface Contract {
name: string name: string
@ -167,6 +170,130 @@ export function toStandardOutput(fileName: string, compilationResult: any): any
} }
} }
} }
export async function compileContract(contract: string, compilerUrl: string, setOutput?: any) {
remixClient.eventEmitter.emit('resetCompilerState', {})
try {
// await remixClient.discardHighlight()
let _contract: any
try {
_contract = await remixClient.getContract()
} catch (e: any) {
if (setOutput === null || setOutput === undefined) {
const compileResult = {
status: 'failed',
message: e.message
}
const compileResultKey = ''
remixClient.eventEmitter.emit('setOutput', { compileResultKey, compileResult })
} else {
setOutput('', {status: 'failed', message: e.message})
}
return
}
remixClient.changeStatus({
key: 'loading',
type: 'info',
title: 'Compiling'
})
let output
try {
output = await compile(compilerUrl, _contract)
} catch (e: any) {
remixClient.changeStatus({
key: 'failed',
type: 'error',
title: e.message
})
return
}
const compileReturnType = () => {
const t: any = toStandardOutput(contract, output)
const temp = _.merge(t['contracts'][contract])
const normal = normalizeContractPath(contract)[2]
const abi = temp[normal]['abi']
const evm = _.merge(temp[normal]['evm'])
const dpb = evm.deployedBytecode
const runtimeBytecode = evm.bytecode
const methodIdentifiers = evm.methodIdentifiers
const result = {
contractName: normal,
abi: abi,
bytecode: dpb,
runtimeBytecode: runtimeBytecode,
ir: '',
methodIdentifiers: methodIdentifiers
}
return result
}
// ERROR
if (isCompilationError(output)) {
const line = output.line
if (line) {
const lineColumnPos = {
start: {line: line - 1, column: 10},
end: {line: line - 1, column: 10}
}
// remixClient.highlight(lineColumnPos as any, _contract.name, '#e0b4b4')
} else {
const regex = output?.message?.match(/line ((\d+):(\d+))+/g)
const errors = output?.message?.split(/line ((\d+):(\d+))+/g) // extract error message
if (regex) {
let errorIndex = 0
regex.map((errorLocation) => {
const location = errorLocation?.replace('line ', '').split(':')
let message = errors[errorIndex]
errorIndex = errorIndex + 4
if (message && message?.split('\n\n').length > 0) {
try {
message = message?.split('\n\n')[message.split('\n\n').length - 1]
} catch (e) {}
}
if (location?.length > 0) {
const lineColumnPos = {
start: {line: parseInt(location[0]) - 1, column: 10},
end: {line: parseInt(location[0]) - 1, column: 10}
}
// remixClient.highlight(lineColumnPos as any, _contract.name, message)
}
})
}
}
throw new Error(output.message)
}
// SUCCESS
// remixClient.discardHighlight()
remixClient.changeStatus({
key: 'succeed',
type: 'success',
title: 'success'
})
const data = toStandardOutput(_contract.name, output)
remixClient.compilationFinish(_contract.name, _contract.content, data)
if (setOutput === null || setOutput === undefined) {
const contractName = _contract['name']
const compileResult = compileReturnType()
remixClient.eventEmitter.emit('setOutput', { contractName, compileResult })
} else {
setOutput(_contract.name, compileReturnType())
}
} catch (err: any) {
remixClient.changeStatus({
key: 'failed',
type: 'error',
title: err.message
})
}
}
export type StandardOutput = { export type StandardOutput = {
sources: { sources: {
[fileName: string]: { [fileName: string]: {

@ -2,11 +2,22 @@ import {HighlightPosition, CompilationResult, RemixApi, customAction} from '@rem
import {Api, Status} from '@remixproject/plugin-utils' import {Api, Status} from '@remixproject/plugin-utils'
import {createClient} from '@remixproject/plugin-webview' import {createClient} from '@remixproject/plugin-webview'
import {PluginClient} from '@remixproject/plugin' import {PluginClient} from '@remixproject/plugin'
import {Contract} from './compiler' import {Contract, compileContract} from './compiler'
import {ExampleContract} from '../components/VyperResult' import {ExampleContract} from '../components/VyperResult'
import EventEmitter from 'events'
export type VyperComplierAddress = 'https://vyper2.remixproject.org/' | 'http://localhost:8000/'
export class RemixClient extends PluginClient { export class RemixClient extends PluginClient {
private client = createClient<Api, Readonly<RemixApi>>(this) private client = createClient<Api, Readonly<RemixApi>>(this)
compilerUrl: VyperComplierAddress = 'https://vyper2.remixproject.org/'
compilerOutput: any
eventEmitter = new EventEmitter()
constructor() {
super()
this.compilerOutput = {}
}
loaded() { loaded() {
return this.client.onload() return this.client.onload()
@ -26,8 +37,16 @@ export class RemixClient extends PluginClient {
}) })
} }
resetCompilerState() {
this.compilerOutput = {}
this.eventEmitter.emit('resetCompilerState', {})
}
async vyperCompileCustomAction(action: customAction) { async vyperCompileCustomAction(action: customAction) {
console.log('vyperCompileCustomAction', action) //read selected contract from file explorer and create contract type
const contract = await this.getContract()
//compile contract
await compileContract(contract.name, this.compilerUrl)
} }
/** Load Ballot contract example into the file manager */ /** Load Ballot contract example into the file manager */

@ -10,12 +10,12 @@ interface RemixUiVyperCompileDetailsProps {
} }
export function RemixUiVyperCompileDetails({ payload, theme, themeStyle }: RemixUiVyperCompileDetailsProps) { export function RemixUiVyperCompileDetails({ payload, theme, themeStyle }: RemixUiVyperCompileDetailsProps) {
const dpayload = Object.values(payload) as any ?? {} const compileResult = payload['compileResult'] ?? {}
const bcode = dpayload[0].bytecode ? dpayload[0].bytecode.object : '' const bcode = compileResult.bytecode ? compileResult.bytecode.object : ''
const runtimeBcode = dpayload[0].runtimeBytecode ? dpayload[0].runtimeBytecode.object : '' const runtimeBcode = compileResult.runtimeBytecode ? compileResult.runtimeBytecode.object : ''
const ir = dpayload[0].ir const ir = compileResult.ir
const methodIdentifiers= dpayload[0].methodIdentifiers const methodIdentifiers= compileResult.methodIdentifiers
const abi= dpayload[0].abi const abi= compileResult.abi
return ( return (
<> <>
<VyperCompile <VyperCompile

@ -25,7 +25,6 @@ export interface VyperCompileProps {
} }
export default function VyperCompile({result, theme, themeStyle}: VyperCompileProps) { export default function VyperCompile({result, theme, themeStyle}: VyperCompileProps) {
const [active, setActive] = useState<keyof VyperCompilationResult>('abi') const [active, setActive] = useState<keyof VyperCompilationResult>('abi')
const tabContent = [ const tabContent = [
{ {

Loading…
Cancel
Save