diff --git a/apps/remix-ide-e2e/src/commands/clickLaunchIcon.ts b/apps/remix-ide-e2e/src/commands/clickLaunchIcon.ts index af1a7dbb55..fff9a61929 100644 --- a/apps/remix-ide-e2e/src/commands/clickLaunchIcon.ts +++ b/apps/remix-ide-e2e/src/commands/clickLaunchIcon.ts @@ -4,12 +4,12 @@ import EventEmitter from 'events' class ClickLaunchIcon extends EventEmitter { command (this: NightwatchBrowser, icon: string): NightwatchBrowser { this.api - .waitForElementVisible('#icon-panel div[plugin="' + icon + '"]') - .click('#icon-panel div[plugin="' + icon + '"]') - .perform((done) => { - done() - this.emit('complete') - }) + .waitForElementVisible('#icon-panel div[plugin="' + icon + '"]') + .click('#icon-panel div[plugin="' + icon + '"]') + .perform((done) => { + done() + this.emit('complete') + }) return this } } diff --git a/apps/remix-ide-e2e/src/commands/connectToExternalHttpProvider.ts b/apps/remix-ide-e2e/src/commands/connectToExternalHttpProvider.ts index 8bac04f9fe..5a971c02cb 100644 --- a/apps/remix-ide-e2e/src/commands/connectToExternalHttpProvider.ts +++ b/apps/remix-ide-e2e/src/commands/connectToExternalHttpProvider.ts @@ -2,40 +2,40 @@ import { NightwatchBrowser } from 'nightwatch' import EventEmitter from 'events' class ConnectToExternalHttpProvider extends EventEmitter { - command(this: NightwatchBrowser, url: string, identifier: string): NightwatchBrowser { - this.api.element('xpath', `//*[@class='udapp_environment' and contains(.,'${identifier}')]`, - (result) => { - if (result.status as any === -1) { - console.log("No connection to external provider found. Adding one.", url) - browser - .click({ - locateStrategy: 'css selector', - selector: '[data-id="basic-http-provider-modal-footer-ok-react"]', - abortOnFailure: false, - suppressNotFoundErrors: true, - timeout: 5000 - }) - .switchEnvironment('basic-http-provider') - .waitForElementPresent('[data-id="basic-http-provider-modal-footer-ok-react"]') - .execute(() => { - (document.querySelector('*[data-id="basic-http-providerModalDialogContainer-react"] input[data-id="modalDialogCustomPromp"]') as any).focus() - }, [], () => { }) - .setValue('[data-id="modalDialogCustomPromp"]', url) - .modalFooterOKClick('basic-http-provider') - .perform((done) => { - done() - this.emit('complete') - }) - } else { - this.api.perform((done) => { - done() - this.emit('complete') - }) - } - } - ) - return this - } + command(this: NightwatchBrowser, url: string, identifier: string): NightwatchBrowser { + this.api.element('xpath', `//*[@class='udapp_environment' and contains(.,'${identifier}')]`, + (result) => { + if (result.status as any === -1) { + console.log("No connection to external provider found. Adding one.", url) + browser + .click({ + locateStrategy: 'css selector', + selector: '[data-id="basic-http-provider-modal-footer-ok-react"]', + abortOnFailure: false, + suppressNotFoundErrors: true, + timeout: 5000 + }) + .switchEnvironment('basic-http-provider') + .waitForElementPresent('[data-id="basic-http-provider-modal-footer-ok-react"]') + .execute(() => { + (document.querySelector('*[data-id="basic-http-providerModalDialogContainer-react"] input[data-id="modalDialogCustomPromp"]') as any).focus() + }, [], () => { }) + .setValue('[data-id="modalDialogCustomPromp"]', url) + .modalFooterOKClick('basic-http-provider') + .perform((done) => { + done() + this.emit('complete') + }) + } else { + this.api.perform((done) => { + done() + this.emit('complete') + }) + } + } + ) + return this + } } module.exports = ConnectToExternalHttpProvider diff --git a/apps/remix-ide-e2e/src/commands/createContract.ts b/apps/remix-ide-e2e/src/commands/createContract.ts index 046f747c83..efc874108e 100644 --- a/apps/remix-ide-e2e/src/commands/createContract.ts +++ b/apps/remix-ide-e2e/src/commands/createContract.ts @@ -16,7 +16,9 @@ class CreateContract extends EventEmitter { function createContract (browser: NightwatchBrowser, inputParams: string, callback: VoidFunction) { if (inputParams) { browser.setValue('.udapp_contractActionsContainerSingle > input', inputParams, function () { - browser.click('.udapp_contractActionsContainerSingle > div').pause(500).perform(function () { callback() }) + browser + .waitForElementVisible('.udapp_contractActionsContainerSingle > div') + .click('.udapp_contractActionsContainerSingle > div').pause(500).perform(function () { callback() }) }) } else { browser diff --git a/apps/remix-ide-e2e/src/tests/vyper_api.test.ts b/apps/remix-ide-e2e/src/tests/vyper_api.test.ts index 817b65cd14..5ef312d8a2 100644 --- a/apps/remix-ide-e2e/src/tests/vyper_api.test.ts +++ b/apps/remix-ide-e2e/src/tests/vyper_api.test.ts @@ -9,7 +9,7 @@ declare global { module.exports = { '@disabled': true, before: function (browser: NightwatchBrowser, done: VoidFunction) { - init(browser, done) + init(browser, done, 'http://localhost:8080') }, 'Should connect to vyper plugin #group1': function (browser: NightwatchBrowser) { @@ -47,27 +47,54 @@ module.exports = { .frame(0) .click('[data-id="remote-compiler"]') .click('[data-id="compile"]') - .isVisible({ - selector: '[data-id="copy-abi"]', - timeout: 4000, - abortOnFailure: false, - suppressNotFoundErrors: true - }, (okVisible) => { - if (okVisible.value === null) { - console.log('retrying compilation...') - browser.click('[data-id="compile"]').waitForElementVisible('[data-id="copy-abi"]') - } else{ - browser.assert.ok(okVisible.value === true, 'ABI should be visible') - } + .waitForElementVisible({ + selector:'[data-id="compilation-details"]', + timeout: 120000 + }) + .click('[data-id="compilation-details"]') + .frameParent() + .waitForElementVisible('[data-id="copy-abi"]') + .waitForElementVisible({ + selector: "//*[@class='variable-value' and contains(.,'highestBidder')]", + locateStrategy: 'xpath', }) - + }, + 'Should copy abi after blind_auction compile #group1': function (browser: NightwatchBrowser) { + if (browser.browserName.indexOf('chrome') > -1) { + const chromeBrowser = (browser as any).chrome + chromeBrowser.setPermission('clipboard-read', 'granted') + chromeBrowser.setPermission('clipboard-write', 'granted') + browser + .frame(0) + .click('[data-id="remote-compiler"]') + .click('[data-id="compile"]') + .waitForElementVisible({ + selector:'[data-id="compilation-details"]', + timeout: 120000 + }) + .click('[data-id="compilation-details"]') + .frameParent() + .waitForElementVisible('[data-id="copy-abi"]') + .click('[data-id="copy-abi"]') + .executeAsyncScript(function (done) { + navigator.clipboard.readText() + .then(function (clippedText) { + done(clippedText) + }).catch(function (error) { + console.log('Failed to read clipboard contents: ', error) + done() + }) + }, [], function (result) { + console.log('clipboard result: ' + result) + browser.assert.ok((result as any).value.length > 1, 'abi copied to clipboard') + }) + } }, 'Compile test contract and deploy to remix VM #group1': function (browser: NightwatchBrowser) { let contractAddress browser - .frameParent() .clickLaunchIcon('filePanel') .switchWorkspace('default_workspace') .addFile('test.vy', { content: testContract }) @@ -75,20 +102,13 @@ module.exports = { // @ts-ignore .frame(0) .click('[data-id="compile"]') - .isVisible({ - selector: '[data-id="copy-abi"]', - timeout: 4000, - abortOnFailure: false, - suppressNotFoundErrors: true - }, (okVisible) => { - if (okVisible.value === null) { - console.log('retrying compilation...') - browser.click('[data-id="compile"]').waitForElementVisible('[data-id="copy-abi"]') - } else{ - browser.assert.ok(okVisible.value === true, 'ABI should be visible') - } + .waitForElementVisible({ + selector:'[data-id="compilation-details"]', + timeout: 60000 }) + .click('[data-id="compilation-details"]') .frameParent() + .waitForElementVisible('[data-id="copy-abi"]') .clickLaunchIcon('udapp') .createContract('') .clickInstance(0) @@ -105,7 +125,6 @@ module.exports = { } const testContract = ` -# @version >=0.2.4 <0.3.0 DNA_DIGITS: constant(uint256) = 16 DNA_MODULUS: constant(uint256) = 10 ** DNA_DIGITS @@ -136,4 +155,4 @@ def _createPokemon(_name: String[32], _dna: uint256, _HP: uint256): matches: 0, wins: 0 }) - self.totalPokemonCount += 1` \ No newline at end of file + self.totalPokemonCount += 1` diff --git a/apps/remix-ide-e2e/src/types/index.d.ts b/apps/remix-ide-e2e/src/types/index.d.ts index ada7b9cca9..665a1cc4f5 100644 --- a/apps/remix-ide-e2e/src/types/index.d.ts +++ b/apps/remix-ide-e2e/src/types/index.d.ts @@ -15,6 +15,7 @@ declare module 'nightwatch' { verifyContracts(compiledContractNames: string[], opts?: {wait: number; version?: string; runs?: string}): NightwatchBrowser selectAccount(account?: string): NightwatchBrowser clickFunction(fnFullName: string, expectedInput?: NightwatchClickFunctionExpectedInput): NightwatchBrowser + checkClipboard(): NightwatchBrowser testFunction(txHash: string, expectedInput: NightwatchTestFunctionExpectedInput): NightwatchBrowser goToVMTraceStep(step: number, incr?: number): NightwatchBrowser checkVariableDebug(id: string, debugValue: NightwatchCheckVariableDebugValue): NightwatchBrowser diff --git a/apps/remix-ide/src/app.js b/apps/remix-ide/src/app.js index 30ead7e4fe..eed35827d0 100644 --- a/apps/remix-ide/src/app.js +++ b/apps/remix-ide/src/app.js @@ -47,6 +47,7 @@ import {FileDecorator} from './app/plugins/file-decorator' import {CodeFormat} from './app/plugins/code-format' import {SolidityUmlGen} from './app/plugins/solidity-umlgen' import { CompilationDetailsPlugin } from './app/plugins/compile-details' +import { VyperCompilationDetailsPlugin } from './app/plugins/vyper-compilation-details' import {ContractFlattener} from './app/plugins/contractFlattener' import {OpenAIGpt} from './app/plugins/openaigpt' @@ -130,11 +131,11 @@ class AppComponent { 'remix.ethereum.org': 23, '6fd22d6fe5549ad4c4d8fd3ca0b7816b.mod': 35 // remix desktop } - + this.matomoConfAlreadySet = Registry.getInstance().get('config').api.exists('settings/matomo-analytics') this.matomoCurrentSetting = Registry.getInstance().get('config').api.get('settings/matomo-analytics') this.showMatamo = matomoDomains[window.location.hostname] && !this.matomoConfAlreadySet - + this.walkthroughService = new WalkthroughService(appManager) const hosts = ['127.0.0.1:8080', '192.168.0.101:8080', 'localhost:8080'] @@ -187,7 +188,7 @@ class AppComponent { // ----------------- Compilation Details ---------------------------- const compilationDetails = new CompilationDetailsPlugin(appManager) - + const vyperCompilationDetails = new VyperCompilationDetailsPlugin(appManager) // ----------------- ContractFlattener ---------------------------- const contractFlattener = new ContractFlattener() @@ -314,6 +315,7 @@ class AppComponent { search, solidityumlgen, compilationDetails, + vyperCompilationDetails, contractFlattener, solidityScript, openaigpt, diff --git a/apps/remix-ide/src/app/plugins/copilot/suggestion-service/copilot-suggestion.ts b/apps/remix-ide/src/app/plugins/copilot/suggestion-service/copilot-suggestion.ts index 2edcd81cee..ac1798b400 100644 --- a/apps/remix-ide/src/app/plugins/copilot/suggestion-service/copilot-suggestion.ts +++ b/apps/remix-ide/src/app/plugins/copilot/suggestion-service/copilot-suggestion.ts @@ -1,6 +1,7 @@ import {Plugin} from '@remixproject/engine' import {SuggestionService, SuggestOptions} from './suggestion-service' import axios, {AxiosResponse} from 'axios' +//@ts-ignore const _paq = (window._paq = window._paq || []) //eslint-disable-line const profile = { @@ -28,7 +29,7 @@ export class CopilotSuggestion extends Plugin { }) this.service.events.on('ready', (data) => { this.ready = true - }) + }) } useRemoteService(service: string) { @@ -81,7 +82,7 @@ export class CopilotSuggestion extends Plugin { importsContent += '\n\n' + (await this.call('contentImport', 'resolve', imp)).content } catch (e) { console.log(e) - } + } } return importsContent } diff --git a/apps/remix-ide/src/app/plugins/copilot/suggestion-service/suggestion-service.ts b/apps/remix-ide/src/app/plugins/copilot/suggestion-service/suggestion-service.ts index fefe485490..b85647cb9f 100644 --- a/apps/remix-ide/src/app/plugins/copilot/suggestion-service/suggestion-service.ts +++ b/apps/remix-ide/src/app/plugins/copilot/suggestion-service/suggestion-service.ts @@ -58,11 +58,11 @@ export class SuggestionService { this.responses[e.data.id](null, e.data) } else { this.responses[e.data.id]('aborted') - } + } delete this.responses[e.data.id] this.current = null } - + // Generation complete: re-enable the "Generate" button break; } @@ -95,6 +95,6 @@ export class SuggestionService { if (error) return reject(error) resolve(result) } - }) + }) } -} \ No newline at end of file +} diff --git a/apps/remix-ide/src/app/plugins/vyper-compilation-details.tsx b/apps/remix-ide/src/app/plugins/vyper-compilation-details.tsx new file mode 100644 index 0000000000..6d98009400 --- /dev/null +++ b/apps/remix-ide/src/app/plugins/vyper-compilation-details.tsx @@ -0,0 +1,170 @@ +import React from 'react' +import { ViewPlugin } from '@remixproject/engine-web' +import {PluginViewWrapper} from '@remix-ui/helper' +import { RemixAppManager } from '../../remixAppManager' +import { RemixUiVyperCompileDetails } from '@remix-ui/vyper-compile-details' +import { ThemeKeys, ThemeObject } from '@microlink/react-json-view' +//@ts-ignore +const _paq = (window._paq = window._paq || []) + +const profile = { + name: 'vyperCompilationDetails', + displayName: 'Vyper Compile Details', + description: 'Displays details from vyper compiler', + location: 'mainPanel', + methods: ['showDetails'], + events: [] +} + +export class VyperCompilationDetailsPlugin extends ViewPlugin { + dispatch: React.Dispatch = () => {} + appManager: RemixAppManager + element: HTMLDivElement + payload: any + themeStyle: any + theme: ThemeKeys | ThemeObject + constructor(appManager: RemixAppManager) { + super(profile) + this.appManager = appManager + this.element = document.createElement('div') + this.element.setAttribute('id', 'vypercompileDetails') + this.payload = { + contractProperties: {} as any, + selectedContract: '', + help: {} as any, + insertValue: {} as any, + saveAs: {} as any, + } + } + + async onActivation() { + this.handleThemeChange() + await this.call('tabs', 'focus', 'vyperCompilationDetails') + this.renderComponent() + _paq.push(['trackEvent', 'plugin', 'activated', 'vyperCompilationDetails']) + } + + onDeactivation(): void { + + } + + async showDetails(sentPayload: any) { + const contractName = Object.entries(sentPayload).find(([key, value]) => key ) + await this.call('tabs', 'focus', 'vyperCompilationDetails') + this.profile.displayName = `${contractName}` + this.payload = sentPayload + const active = await this.call('theme', 'currentTheme') + if (active.quality === 'dark') { + switch(active.name) { + case 'HackerOwl': + this.theme = 'harmonic' + this.themeStyle = { backgroundColor: active.backgroundColor } + break + case 'Black': + this.theme = 'eighties' + this.themeStyle = { backgroundColor: active.backgroundColor } + break + case 'Cyborg': + this.theme = 'shapeshifter' + this.themeStyle = { backgroundColor: active.backgroundColor } + break + case 'Dark': + this.theme = 'flat' + this.themeStyle = { backgroundColor: active.backgroundColor } + break + default: + this.theme = 'shapeshifter' + this.themeStyle = { backgroundColor: active.backgroundColor } + break + } + } else { + switch(active.name) { + case 'Candy': + this.theme = 'apathy:inverted' + this.themeStyle = { backgroundColor: active.backgroundColor } + break + case 'Midcentury': + this.theme = 'apathy:inverted' + this.themeStyle = { backgroundColor: active.backgroundColor } + break + case 'Unicorn': + this.theme = 'apathy:inverted' + this.themeStyle = { backgroundColor: active.backgroundColor } + break + case 'Violet': + this.theme = 'summerfruit:inverted' + this.themeStyle = { backgroundColor: active.backgroundColor } + break + default: + this.theme = 'bright:inverted' + break + } + } + this.renderComponent() + } + + private handleThemeChange() { + this.on('theme', 'themeChanged', (theme: any) => { + if (theme.quality === 'dark') { + switch(theme.name) { + case 'HackerOwl': + this.theme = 'solarized' + this.themeStyle = { backgroundColor: theme.backgroundColor } + break + case 'Black': + this.theme = 'shapeshifter' + this.themeStyle = { backgroundColor: theme.backgroundColor } + break + case 'Cyborg': + this.theme = 'shapeshifter' + this.themeStyle = { backgroundColor: theme.backgroundColor } + break + case 'Dark': + this.theme = 'harmonic' + this.themeStyle = { backgroundColor: theme.backgroundColor } + break + default: + this.theme = 'shapeshifter' + this.themeStyle = { backgroundColor: theme.backgroundColor } + break + } + } else { + this.theme = 'bright:inverted' + this.themeStyle = { backgroundColor: theme.backgroundColor } + } + this.renderComponent() + }) + } + + setDispatch(dispatch: React.Dispatch): void { + this.dispatch = dispatch + this.renderComponent() + } + render() { + return ( +
+ +
+ ) + } + + renderComponent() { + this.dispatch({ + ...this, + ...this.payload, + themeStyle: this.themeStyle, + theme: this.theme + }) + } + + updateComponent(state: any) { + return ( + + ) + } + +} diff --git a/apps/remix-ide/src/remixAppManager.js b/apps/remix-ide/src/remixAppManager.js index ef3dda2982..eaaf59cce6 100644 --- a/apps/remix-ide/src/remixAppManager.js +++ b/apps/remix-ide/src/remixAppManager.js @@ -71,6 +71,7 @@ const requiredModules = [ // services + layout views + system views 'codeFormatter', 'solidityumlgen', 'compilationDetails', + 'vyperCompilationDetails', 'contractflattener', 'solidity-script', 'openaigpt', @@ -117,7 +118,8 @@ export function isNative(name) { 'doc-gen', 'doc-viewer', 'circuit-compiler', - 'compilationDetails' + 'compilationDetails', + 'vyperCompilationDetails' ] return nativePlugins.includes(name) || requiredModules.includes(name) } diff --git a/apps/vyper/src/app/app.css b/apps/vyper/src/app/app.css index db9ee76b63..7e4107ba67 100644 --- a/apps/vyper/src/app/app.css +++ b/apps/vyper/src/app/app.css @@ -45,15 +45,7 @@ html, body, #root, main { } #local-url { - width: 90%; -} -#compile-btn { - width: 100%; -} - -#compile-btn * { - width: 100%; } #result { @@ -120,4 +112,4 @@ html, body, #root, main { border: none; height: 100%; width: 100%; -} \ No newline at end of file +} diff --git a/apps/vyper/src/app/app.tsx b/apps/vyper/src/app/app.tsx index aa4ab4093f..b14ee3a172 100644 --- a/apps/vyper/src/app/app.tsx +++ b/apps/vyper/src/app/app.tsx @@ -1,6 +1,6 @@ import React, {useState, useEffect} from 'react' -import {VyperCompilationOutput, remixClient} from './utils' +import {remixClient} from './utils' import {CompilationResult} from '@remixproject/plugin-api' // Components @@ -22,18 +22,19 @@ interface AppState { } interface OutputMap { - [fileName: string]: VyperCompilationOutput + [fileName: string]: any } const App: React.FC = () => { const [contract, setContract] = useState() - const [output, setOutput] = useState({}) + const [output, setOutput] = useState({}) const [state, setState] = useState({ status: 'idle', environment: 'local', - localUrl: 'http://localhost:8000/compile' + localUrl: 'http://localhost:8000/' }) + useEffect(() => { async function start() { try { @@ -61,7 +62,11 @@ const App: React.FC = () => { } function compilerUrl() { - return state.environment === 'remote' ? 'https://vyper.remixproject.org/compile' : state.localUrl + return state.environment === 'remote' ? 'https://vyper2.remixproject.org/' : state.localUrl + } + + function resetCompilerResultState() { + setOutput({}) } return ( @@ -76,14 +81,14 @@ const App: React.FC = () => {
-
-
- Remote Compiler v0.2.16 + Remote Compiler v0.3.10 Local Compiler @@ -91,11 +96,23 @@ const App: React.FC = () => { -
- setOutput({...output, [name]: update})} /> +
+ setOutput({...output, [name]: update})} + resetCompilerState={resetCompilerResultState} + />
-
- + +
+ { + output && Object.keys(output).length > 0 && output.status !== 'failed' ? ( + <> + + + ) : null + }
diff --git a/apps/vyper/src/app/components/CompilerButton.tsx b/apps/vyper/src/app/components/CompilerButton.tsx index 9cb3ac630a..ad04d0ba04 100644 --- a/apps/vyper/src/app/components/CompilerButton.tsx +++ b/apps/vyper/src/app/components/CompilerButton.tsx @@ -1,26 +1,31 @@ -import React from 'react' -import {isVyper, compile, toStandardOutput, VyperCompilationOutput, isCompilationError, remixClient} from '../utils' +import React, { Fragment, useState } from 'react' +import {isVyper, compile, toStandardOutput, isCompilationError, remixClient, normalizeContractPath} from '../utils' import Button from 'react-bootstrap/Button' +import _ from 'lodash' interface Props { compilerUrl: string contract?: string - setOutput: (name: string, output: VyperCompilationOutput) => void + setOutput: (name: string, output: any) => void + resetCompilerState: () => void } -function CompilerButton({contract, setOutput, compilerUrl}: Props) { +function CompilerButton({contract, setOutput, compilerUrl, resetCompilerState}: Props) { + const [loadingSpinner, setLoadingSpinnerState] = useState(false) if (!contract || !contract) { - return + return } if (!isVyper(contract)) { - return + return } /** Compile a Contract */ async function compileContract() { + resetCompilerState() + setLoadingSpinnerState(true) try { - await remixClient.discardHighlight() + // await remixClient.discardHighlight() let _contract: any try { _contract = await remixClient.getContract() @@ -37,10 +42,34 @@ function CompilerButton({contract, setOutput, compilerUrl}: Props) { try { output = await compile(compilerUrl, _contract) } catch (e: any) { - setOutput(_contract.name, {status: 'failed', message: e.message}) + remixClient.changeStatus({ + key: 'failed', + type: 'error', + title: e.message + }) return } - setOutput(_contract.name, output) + 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 @@ -49,27 +78,27 @@ function CompilerButton({contract, setOutput, compilerUrl}: Props) { start: {line: line - 1, column: 10}, end: {line: line - 1, column: 10} } - remixClient.highlight(lineColumnPos as any, _contract.name, '#e0b4b4') + // 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 + 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(':') + const location = errorLocation?.replace('line ', '').split(':') let message = errors[errorIndex] errorIndex = errorIndex + 4 - if (message && message.split('\n\n').length > 0) { + if (message && message?.split('\n\n').length > 0) { try { - message = message.split('\n\n')[message.split('\n\n').length - 1] + message = message?.split('\n\n')[message.split('\n\n').length - 1] } catch (e) {} } - if (location.length > 0) { + 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) + // remixClient.highlight(lineColumnPos as any, _contract.name, message) } }) } @@ -77,14 +106,15 @@ function CompilerButton({contract, setOutput, compilerUrl}: Props) { throw new Error(output.message) } // SUCCESS - remixClient.discardHighlight() + // remixClient.discardHighlight() remixClient.changeStatus({ key: 'succeed', type: 'success', - title: 'succeed' + 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', @@ -95,10 +125,17 @@ function CompilerButton({contract, setOutput, compilerUrl}: Props) { } return ( - + + + ) } diff --git a/apps/vyper/src/app/components/LocalUrl.tsx b/apps/vyper/src/app/components/LocalUrl.tsx index 58f4b3d3c7..560482b5d3 100644 --- a/apps/vyper/src/app/components/LocalUrl.tsx +++ b/apps/vyper/src/app/components/LocalUrl.tsx @@ -17,7 +17,7 @@ function LocalUrlInput({url, setUrl, environment}: Props) { } return ( -
+ {'Currently we support vyper version > 0.2.16'} Local Compiler Url diff --git a/apps/vyper/src/app/components/VyperResult.tsx b/apps/vyper/src/app/components/VyperResult.tsx index 016271805b..56c32702de 100644 --- a/apps/vyper/src/app/components/VyperResult.tsx +++ b/apps/vyper/src/app/components/VyperResult.tsx @@ -1,13 +1,14 @@ import React, {useState} from 'react' -import {VyperCompilationResult, VyperCompilationOutput, isCompilationError} from '../utils' +import {VyperCompilationOutput, isCompilationError} from '../utils' import Tabs from 'react-bootstrap/Tabs' import Tab from 'react-bootstrap/Tab' import Button from 'react-bootstrap/Button' -import JSONTree from 'react-json-view' import {CopyToClipboard} from '@remix-ui/clipboard' +import { VyperCompilationResult } from '../utils/types' interface VyperResultProps { - output?: VyperCompilationOutput + output?: any + plugin?: any } export type ExampleContract = { @@ -15,8 +16,15 @@ export type ExampleContract = { address: string } -function VyperResult({output}: VyperResultProps) { - const [active, setActive] = useState('abi') +type TabContentMembers = { + tabText: string + tabPayload: any + tabMemberType: 'abi' | 'bytecode' | 'bytecode_runtime' | 'ir' + className: string +} + +function VyperResult({ output, plugin }: VyperResultProps) { + // const [active, setActive] = useState('abi') if (!output) return ( @@ -43,42 +51,17 @@ function VyperResult({output}: VyperResultProps) { ) } - return ( - setActive(key)}> - - JSON.stringify(output.abi)}> - - - - - - output.bytecode}> - - - - - - output.bytecode_runtime}> - - - - - - output.ir}> - - - - - + <> +
+
+ +
+ ) } diff --git a/apps/vyper/src/app/utils/compiler.tsx b/apps/vyper/src/app/utils/compiler.tsx index d1312322c4..ed1cc80b50 100644 --- a/apps/vyper/src/app/utils/compiler.tsx +++ b/apps/vyper/src/app/utils/compiler.tsx @@ -1,4 +1,5 @@ -import {CompilationResult, ABIDescription} from '@remixproject/plugin-api' +import { ABIDescription} from '@remixproject/plugin-api' +import axios from 'axios' export interface Contract { name: string @@ -8,6 +9,7 @@ export interface Contract { export interface VyperCompilationResult { status: 'success' bytecode: string + contractName?: string bytecode_runtime: string abi: ABIDescription[] ir: string @@ -30,12 +32,45 @@ export function isCompilationError(output: VyperCompilationOutput): output is Vy return output.status === 'failed' } +export function normalizeContractPath(contractPath: string): string[] { + const paths = contractPath.split('/') + const filename = paths[paths.length - 1].split('.')[0] + let folders = '' + for (let i = 0; i < paths.length - 1; i++) { + if (i !== paths.length -1) { + folders += `${paths[i]}/` + } + } + const resultingPath = `${folders}${filename}` + return [folders,resultingPath, filename] +} + +function parseErrorString(errorString) { + // Split the string into lines + let lines = errorString.trim().split('\n') + // Extract the line number and message + let message = lines[1].trim() + let targetLine = lines[2].split(',') + let lineColumn = targetLine[targetLine.length - 1].split(' ')[2].split(':') + const errorObject = { + status: 'failed', + message: message, + column: parseInt(lineColumn[1]), + line: parseInt(lineColumn[0]) + } + message = null + targetLine = null + lineColumn = null + lines = null + return errorObject +} + /** * Compile the a contract * @param url The url of the compiler * @param contract The name and content of the contract */ -export async function compile(url: string, contract: Contract): Promise { +export async function compile(url: string, contract: Contract): Promise { if (!contract.name) { throw new Error('Set your Vyper contract file.') } @@ -43,19 +78,45 @@ export async function compile(url: string, contract: Contract): Promise setTimeout(() => resolve({}), 3000)) } /** @@ -63,15 +124,21 @@ export async function compile(url: string, contract: Contract): Promise).map(([key, value]) => { + return { [key]: value.replace('0x', '') } + }) return { sources: { [fileName]: { id: 1, - ast: {} as any, - legacyAST: {} as any + ast: compiledAst } }, contracts: { @@ -80,16 +147,17 @@ export function toStandardOutput(fileName: string, compilationResult: VyperCompi [contractName]: { // The Ethereum Contract ABI. If empty, it is represented as an empty array. // See https://github.com/ethereum/wiki/wiki/Ethereum-Contract-ABI - abi: compilationResult['abi'], + abi: compiledAbi, + contractName: contractName, evm: { bytecode: { linkReferences: {}, - object: compilationResult['bytecode'].replace('0x', ''), + object: deployedBytecode, opcodes: '' }, deployedBytecode: { linkReferences: {}, - object: compilationResult['bytecode_runtime'].replace('0x', ''), + object: bytecode, opcodes: '' }, methodIdentifiers: methodIdentifiers @@ -99,6 +167,37 @@ export function toStandardOutput(fileName: string, compilationResult: VyperCompi } } } +export type StandardOutput = { + sources: { + [fileName: string]: { + id: number, + ast: AST + } + }, + contracts: { + [fileName: string]: { + [contractName: string]: { + abi: ABI, + contractName: string, + evm: { + bytecode: BytecodeObject, + deployedBytecode: BytecodeObject, + methodIdentifiers: { + [method: string]: string + } + } + } + } + } +} + +type AST = any // Replace with the actual AST type +type ABI = ABIDescription[] // Replace with the actual ABI type +type BytecodeObject = { + linkReferences: Record, + object: string, + opcodes: string +} /* export function createCompilationResultMessage(name: string, result: any) { diff --git a/apps/vyper/src/app/utils/remix-client.tsx b/apps/vyper/src/app/utils/remix-client.tsx index b9f94320f5..a4fda680cf 100644 --- a/apps/vyper/src/app/utils/remix-client.tsx +++ b/apps/vyper/src/app/utils/remix-client.tsx @@ -45,7 +45,7 @@ export class RemixClient extends PluginClient { await this.call( 'dGitProvider', 'clone', - {url: 'https://github.com/vyperlang/vyper', token: null}, + {url: 'https://github.com/vyperlang/vyper', token: null, branch: 'v0.3.10'}, // @ts-ignore 'vyper-lang' ) @@ -66,6 +66,13 @@ export class RemixClient extends PluginClient { this.client.emit('statusChanged', status) } + checkActiveTheme() { + const active = this.client.call('theme', 'currentTheme') + if (active === 'dark') { + return 'monokai' as any + } + } + /** Highlight a part of the editor */ async highlight(lineColumnPos: HighlightPosition, name: string, message: string) { await this.client.call('editor', 'highlight', lineColumnPos, name) diff --git a/apps/vyper/src/app/utils/types.ts b/apps/vyper/src/app/utils/types.ts new file mode 100644 index 0000000000..fc7b3d56c5 --- /dev/null +++ b/apps/vyper/src/app/utils/types.ts @@ -0,0 +1,540 @@ +import {CompilationResult, ABIDescription} from '@remixproject/plugin-api' + +export interface VyperCompilationResult { + status: 'success' + bytecode: string + bytecode_runtime: string + abi: ABIDescription[] + ir: string + method_identifiers: { + [method: string]: string + } +} + +export interface VyperCompilationError { + status: 'failed' + column?: number + line?: number + message: string +} + + +export type VyperCompilationResultType = { + buildDependencies: any + compilers: [ + contractTypes: [], + name: string, + settings: { + optimize: boolean + outputSelection: { + ['fileName']: { + ['contractName']: string[] + } + } + version: string + } + ] + contractTypes: { + ['fileName']: { + abi: any[] + ast: { + name: string, + children: any[] + classification: number + col_offset: number + end_col_offset: number + end_lineno: number + lineno: number + src: { + length: number + jump_code: string + } + } + contractName: string + deploymentBytecode: { + bytecode: string + } + dev_messages: any + devdoc: { + methods: any + } + pcmap: any + runtimeBytecode: { + bytecode: string + } + sourceId: string + sourcemap: string + userdoc: { + methods: any + } + } + } + deployments: any + manifest: string + meta: any + sources: { + ['fileName'] : { + checksum: any + content: string + imports: string[] + references: [] + urls: [] + } + } + +} + +export interface PackageManifest { + title: string; + description: string; + type: TypeEnum; + required: string[]; + version: string; + properties: PackageManifestProperties; + definitions: Definitions; +} + +export interface Definitions { + packageMeta: ByteString; + contractType: ByteString; + contractInstance: ContractInstance; + byteString: ByteString; + bytecodeObject: BytecodeObject; + linkReference: LinkReference; + linkValue: LinkValue; + identifier: ByteString; + contractInstanceName: ByteString; + deployment: Deployment; + packageContractInstanceName: ByteString; + compilerInformation: CompilerInformation; + address: Address; + transactionHash: Address; + blockHash: Address; + contentURI: ByteString; +} + +export interface Address { + title: string; + description: string; + allOf: AllOf[]; +} + +export interface AllOf { + ref?: string; + minLength?: number; + maxLength?: number; +} + +export interface ByteStringProperties { + contractName?: ByteString; + deploymentBytecode?: Meta; + runtimeBytecode?: Meta; + abi?: ByteString; + natspec?: ByteString; + compiler?: Meta; + authors?: ByteString; + license?: ByteString; + description?: ByteString; + keywords?: ByteString; + links?: Links; +} + +export interface ByteString { + title: string; + description?: string; + type: TypeEnum; + pattern?: string; + format?: string; + items?: Items; + properties?: ByteStringProperties; + patternProperties?: { [key: string]: Meta }; +} + +export interface Meta { + ref: string; +} + +export interface Links { + title: string; + descriptions: string; + type: TypeEnum; + additionalProperties: AdditionalProperties; +} + +export interface AdditionalProperties { + type: TypeEnum; + format: string; +} + +export type TypeEnum = "string" | "array" | "object"; + +export interface Items { + ref?: string; + type?: TypeEnum; +} + +export interface BytecodeObject { + title: string + type: TypeEnum + offsets: number[] + anyOf: BytecodeObjectAnyOf[] + properties: BytecodeObjectProperties + bytecode: string + linkReferences?: { offset?: any; length?: number; name?: string}[] +} + +export interface BytecodeObjectAnyOf { + required: string[]; +} + +export interface BytecodeObjectProperties { + bytecode: Meta; + linkReferences: Link; + linkDependencies: Link; +} + +export interface Link { + type: TypeEnum; + items: Meta; +} + +export interface CompilerInformation { + title: string; + description: string; + type: TypeEnum; + required: string[]; + properties: CompilerInformationProperties; +} + +export interface CompilerInformationProperties { + name: Name; + version: Name; + settings: Name; +} + +export interface Name { + description: string; + type: TypeEnum; +} + +export interface ContractInstance { + title: string; + description: string; + type: TypeEnum; + required: string[]; + properties: ContractInstanceProperties; +} + +export interface ContractInstanceProperties { + contractType: ByteString; + address: Meta; + transaction: Meta; + block: Meta; + runtimeBytecode: Meta; + compiler: Meta; + linkDependencies: ByteString; +} + +export interface Deployment { + title: string; + type: TypeEnum; + patternProperties: DeploymentPatternProperties; +} + +export interface DeploymentPatternProperties { + aZAZAZAZ09_0254$: Meta; +} + +export interface LinkReference { + title: string; + description: string; + type: TypeEnum; + required: string[]; + properties: LinkReferenceProperties; +} + +export interface LinkReferenceProperties { + offsets: Offsets; + length: Length; + name: Meta; +} + +export interface Length { + type: string; + minimum: number; +} + +export interface Offsets { + type: TypeEnum; + items: Length; +} + +export interface LinkValue { + title: string; + description: string; + type: TypeEnum; + required: string[]; + properties: LinkValueProperties; + oneOf: OneOf[]; +} + +export interface OneOf { + properties: OneOfProperties; +} + +export interface OneOfProperties { + type: TypeClass; + value: PurpleValue; +} + +export interface TypeClass { + enum: string[]; +} + +export interface PurpleValue { + ref?: string; + anyOf?: Meta[]; +} + +export interface LinkValueProperties { + offsets: Offsets; + type: Name; + value: FluffyValue; +} + +export interface FluffyValue { + description: string; +} + +export interface PackageManifestProperties { + manifestVersion: ManifestVersion; + packageName: ByteString; + meta: Meta; + version: Version; + sources: Sources; + contractTypes: ByteString; + deployments: ByteString; + buildDependencies: BuildDependencies; +} + +export interface BuildDependencies { + title: string; + type: TypeEnum; + patternProperties: BuildDependenciesPatternProperties; +} + +export interface BuildDependenciesPatternProperties { + aZAZ090254$: Meta; +} + +export interface ManifestVersion { + type: TypeEnum; + title: string; + description: string; + default: string; + enum: string[]; +} + +export interface Sources { + title: string; + type: TypeEnum; + patternProperties: SourcesPatternProperties; +} + +export interface SourcesPatternProperties { + empty: Empty; +} + +export interface Empty { + anyOf: AnyOf[]; +} + +export interface AnyOf { + title?: string; + type?: TypeEnum; + ref?: string; +} + +export interface Version { + title: string; + type: TypeEnum; +} + +export type CompileFormat = { + contractTypes: { + abi?: ABI[] + ast?: AST + contractName?: string + depolymentBytecode?: BytecodeObject + devMessages?: { [key: string]: string } + devdoc?: Devdoc + methodIdentifiers?: { [key: string]: string } + pcmap?: any + runtimeBytecode?: BytecodeObject + sourceId?: string + sourcemap?: string + userdoc?: { [key: string]: string } + } + manifest?: string + sources?: { + [fileName: string]: { + content: string + urls?: string[] + references?: string[] + imports?: string[] + checksum?: { [key: string]: string } + } + } +} + +export type Devdoc = { + methods: any +} + +export type ETHPM3Format = { + manifest: 'ethpm/3' + name: string + version: string + meta: Record + buildDependencies: Record + sources: { + [fileName: string]: { + content: string + checksum?: { + keccak256: string + hash: string + } + type?: any + license?: string + } + } + compilers: CompilerInformationObject[] + contractTypes: { + contractName: string + sourceId?: string + depolymentBytecode: { + bytecode: string + linkReferences: { + offset: any + length: number + name?: string + } + linkDependencies?: { offsets: number[]} + } + runtimeBytecode: { + bytecode: string + linkReferences: { + offset: any + length: number + name?: string + } + linkDependencies?: LinkValueObject + } + abi: ABI[] + ast: AST + userDoc?: { + methods: any + notice: string + } + devDoc?: { + methods: any, + author: string + details: string + title: string + license: string + } +} +deployments: { + [contractName: string]: ContractInstanceObject +} + + +} + +export type CompilerInformationObject = { + name: string + version: string + settings?: { + optimizer: { + enabled: boolean + runs: number + } + outputSelection: { + [fileName: string]: { + [contractName: string]: string[] + } + } + }, + contractTypes?: string[] +} + +export type LinkValueObject = { + offsets: number[] + type: string + value: string +} + +export type PackageMetaDataObject = { + authors?: string[] + description?: string + keywords?: string[] + license?: string + links?: { + [key: string]: string + } +} + +export type ContractInstanceObject = { + contractType: string + address: string + transaction?: string + block?: string + runtimeBytecode?: BytecodeObject + compiler?: string + linkDependencies?: LinkValueObject +} + +export type ASTSrc = { + jumpCode: string; + length: number; +} + +export type Child = { + astType: string; + children: Child[]; + classification: number; + colOffset: number; + endColOffset: number; + endLineno: number; + lineno: number; + name?: string; + src: ChildSrc; + docStr?: Child; +} + +export type ChildSrc = { + jumpCode: string; + length: number; + start: number; +} + +export type AST = { + astType: string; + children: Child[]; + classification: number; + colOffset: number; + endColOffset: number; + endLineno: number; + lineno: number; + name: string; + src: ASTSrc; +} + +export type ABI = { + anonymous?: boolean; + inputs: any[]; + name?: string; + type: any + stateMutability?: any; + outputs?: any[]; +} diff --git a/libs/remix-ui/solidity-compile-details/src/lib/components/solidityCompile.tsx b/libs/remix-ui/solidity-compile-details/src/lib/components/solidityCompile.tsx new file mode 100644 index 0000000000..f951fe9a2e --- /dev/null +++ b/libs/remix-ui/solidity-compile-details/src/lib/components/solidityCompile.tsx @@ -0,0 +1,65 @@ +import { CopyToClipboard } from '@remix-ui/clipboard' +import { CustomTooltip } from '@remix-ui/helper' +import { ContractPropertyName } from '@remix-ui/solidity-compiler' +import React from 'react' +import { TreeView, TreeViewItem } from '@remix-ui/tree-view' +import { useIntl } from 'react-intl' +const _paq = (window._paq = window._paq || []) + + +export default function SolidityCompile({ contractProperties, selectedContract, help, insertValue, saveAs, plugin }: any) { + const intl = useIntl() + const downloadFn = () => { + _paq.push(['trackEvent', 'compiler', 'compilerDetails', 'download']) + saveAs(new Blob([JSON.stringify(contractProperties, null, '\t')]), `${selectedContract}_compData.json`) + } + return ( + <> +
+ {selectedContract} + + Download + +
+
+ { + {Object.keys(contractProperties).map((propertyName: ContractPropertyName, index) => { + const copyDetails = ( + + + + ) + const questionMark = ( + + + + ) + + return ( +
+ + {propertyName} {copyDetails} {questionMark} +
+ } + expand={propertyName === 'metadata' || propertyName === 'bytecode' ? true : false} + iconY='fas fa-caret-down' + > + {insertValue(contractProperties, propertyName)} + +
+ ) + })} + } + + + ) +} diff --git a/libs/remix-ui/solidity-compile-details/src/lib/solidity-compile-details.tsx b/libs/remix-ui/solidity-compile-details/src/lib/solidity-compile-details.tsx index a0cee65d12..f187c37fac 100644 --- a/libs/remix-ui/solidity-compile-details/src/lib/solidity-compile-details.tsx +++ b/libs/remix-ui/solidity-compile-details/src/lib/solidity-compile-details.tsx @@ -4,14 +4,14 @@ import { TreeView, TreeViewItem } from '@remix-ui/tree-view' import { ContractPropertyName } from '@remix-ui/solidity-compiler' import React from 'react' -import { useIntl } from 'react-intl' +import SolidityCompile from './components/solidityCompile' export interface RemixUiCompileDetailsProps { - plugin: any - contractProperties: any - selectedContract: string - help: any - insertValue: any + plugin?: any + contractProperties?: any + selectedContract?: string + help?: any + insertValue?: any saveAs: any } @@ -19,58 +19,16 @@ const _paq = (window._paq = window._paq || []) export function RemixUiCompileDetails({ plugin, contractProperties, selectedContract, saveAs, help, insertValue }: RemixUiCompileDetailsProps) { - const intl = useIntl() - const downloadFn = () => { - _paq.push(['trackEvent', 'compiler', 'compilerDetails', 'download']) - saveAs(new Blob([JSON.stringify(contractProperties, null, '\t')]), `${selectedContract}_compData.json`) - } return ( <> -
- {selectedContract} - - Download - -
-
- - {Object.keys(contractProperties).map((propertyName: ContractPropertyName, index) => { - const copyDetails = ( - - - - ) - const questionMark = ( - - - - ) - - return ( -
- - {propertyName} {copyDetails} {questionMark} -
- } - expand={propertyName === 'metadata' || propertyName === 'bytecode' ? true : false} - iconY='fas fa-caret-down' - > - {insertValue(contractProperties, propertyName)} - -
- ) - })} - - + ) } diff --git a/libs/remix-ui/solidity-compiler/src/lib/contract-selection.tsx b/libs/remix-ui/solidity-compiler/src/lib/contract-selection.tsx index a6436db88b..4410ab2155 100644 --- a/libs/remix-ui/solidity-compiler/src/lib/contract-selection.tsx +++ b/libs/remix-ui/solidity-compiler/src/lib/contract-selection.tsx @@ -310,6 +310,7 @@ export const ContractSelection = (props: ContractSelectionProps) => { + + + {content.eventKey === 'abi' ? ( +
+ +
+ ) : ( +
+ +
+ )} + + + ))} + + + ) +} diff --git a/package.json b/package.json index 060938addd..fa3b757afe 100644 --- a/package.json +++ b/package.json @@ -134,6 +134,7 @@ "@ethereumjs/vm": "^6.4.1", "@ethersphere/bee-js": "^3.2.0", "@isomorphic-git/lightning-fs": "^4.4.1", + "@microlink/react-json-view": "^1.23.0", "@openzeppelin/contracts": "^5.0.0", "@openzeppelin/upgrades-core": "^1.30.0", "@openzeppelin/wizard": "0.4.0", @@ -202,7 +203,6 @@ "react-draggable": "^4.4.4", "react-image-magnifiers": "^1.4.0", "react-intl": "^6.0.4", - "react-json-view": "^1.21.3", "react-markdown": "^8.0.5", "react-multi-carousel": "^2.8.2", "react-router-dom": "^6.3.0", diff --git a/tsconfig.paths.json b/tsconfig.paths.json index 044cb56ed7..73a9d0ff7e 100644 --- a/tsconfig.paths.json +++ b/tsconfig.paths.json @@ -100,6 +100,9 @@ "@remix-ui/solidity-compile-details": [ "libs/remix-ui/solidity-compile-details/src/index.ts" ], + "@remix-ui/vyper-compile-details": [ + "libs/remix-ui/vyper-compile-details/src/index.ts" + ], "@remix-ui/solidity-compiler": [ "libs/remix-ui/solidity-compiler/src/index.ts" ], diff --git a/yarn.lock b/yarn.lock index 9272764444..18ffaad87c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3636,6 +3636,16 @@ semver "^7.3.8" superstruct "^1.0.3" +"@microlink/react-json-view@^1.23.0": + version "1.23.0" + resolved "https://registry.yarnpkg.com/@microlink/react-json-view/-/react-json-view-1.23.0.tgz#641c2483b1a0014818303d4e9cce634d5dacc7e9" + integrity sha512-HYJ1nsfO4/qn8afnAMhuk7+5a1vcjEaS8Gm5Vpr1SqdHDY0yLBJGpA+9DvKyxyVKaUkXzKXt3Mif9RcmFSdtYg== + dependencies: + flux "~4.0.1" + react-base16-styling "~0.6.0" + react-lifecycles-compat "~3.0.4" + react-textarea-autosize "~8.3.2" + "@monaco-editor/loader@^1.3.3": version "1.3.3" resolved "https://registry.yarnpkg.com/@monaco-editor/loader/-/loader-1.3.3.tgz#7f1742bd3cc21c0362a46a4056317f6e5215cfca" @@ -13636,9 +13646,9 @@ fbjs-css-vars@^1.0.0: integrity sha512-b2XGFAFdWZWg0phtAWLHCk836A1Xann+I+Dgd3Gk64MHKZO44FfoD1KxyvbSh0qZsIoXQGGlVztIY+oitJPpRQ== fbjs@^3.0.0, fbjs@^3.0.1: - version "3.0.4" - resolved "https://registry.yarnpkg.com/fbjs/-/fbjs-3.0.4.tgz#e1871c6bd3083bac71ff2da868ad5067d37716c6" - integrity sha512-ucV0tDODnGV3JCnnkmoszb5lf4bNpzjv80K41wd4k798Etq+UYD0y0TIfalLjZoKgjive6/adkRnszwapiDgBQ== + version "3.0.5" + resolved "https://registry.yarnpkg.com/fbjs/-/fbjs-3.0.5.tgz#aa0edb7d5caa6340011790bd9249dbef8a81128d" + integrity sha512-ztsSx77JBtkuMrEypfhgc3cI0+0h+svqeie7xHbh1k/IKdcydnvadp/mUaGgjAOXQmQSxsqgaRhS3q9fy+1kxg== dependencies: cross-fetch "^3.1.5" fbjs-css-vars "^1.0.0" @@ -13646,7 +13656,7 @@ fbjs@^3.0.0, fbjs@^3.0.1: object-assign "^4.1.0" promise "^7.1.1" setimmediate "^1.0.5" - ua-parser-js "^0.7.30" + ua-parser-js "^1.0.35" fd-slicer@~1.1.0: version "1.1.0" @@ -13950,10 +13960,10 @@ flush-write-stream@^1.0.0, flush-write-stream@^1.0.2: inherits "^2.0.3" readable-stream "^2.3.6" -flux@^4.0.1: - version "4.0.3" - resolved "https://registry.yarnpkg.com/flux/-/flux-4.0.3.tgz#573b504a24982c4768fdfb59d8d2ea5637d72ee7" - integrity sha512-yKAbrp7JhZhj6uiT1FTuVMlIAT1J4jqEyBpFApi1kxpGZCvacMVc/t1pMQyotqHhAgvoE3bNvAykhCo2CLjnYw== +flux@~4.0.1: + version "4.0.4" + resolved "https://registry.yarnpkg.com/flux/-/flux-4.0.4.tgz#9661182ea81d161ee1a6a6af10d20485ef2ac572" + integrity sha512-NCj3XlayA2UsapRpM7va6wU1+9rE5FIL7qoMcmxWHRzbp0yujihMBm9BBHZ1MDIk5h5o2Bl6eGiCe8rYELAmYw== dependencies: fbemitter "^3.0.0" fbjs "^3.0.1" @@ -23275,7 +23285,7 @@ re-emitter@1.1.3: resolved "https://registry.yarnpkg.com/re-emitter/-/re-emitter-1.1.3.tgz#fa9e319ffdeeeb35b27296ef0f3d374dac2f52a7" integrity sha1-+p4xn/3u6zWycpbvDz03TawvUqc= -react-base16-styling@^0.6.0: +react-base16-styling@~0.6.0: version "0.6.0" resolved "https://registry.yarnpkg.com/react-base16-styling/-/react-base16-styling-0.6.0.tgz#ef2156d66cf4139695c8a167886cb69ea660792c" integrity sha512-yvh/7CArceR/jNATXOKDlvTnPKPmGZz7zsenQ3jUwLzHkNUR0CvY3yGYJbWJ/nnxsL8Sgmt5cO3/SILVuPO6TQ== @@ -23389,17 +23399,7 @@ react-is@^17.0.1, react-is@^17.0.2: resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.2.tgz#e691d4a8e9c789365655539ab372762b0efb54f0" integrity sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w== -react-json-view@^1.21.3: - version "1.21.3" - resolved "https://registry.yarnpkg.com/react-json-view/-/react-json-view-1.21.3.tgz#f184209ee8f1bf374fb0c41b0813cff54549c475" - integrity sha512-13p8IREj9/x/Ye4WI/JpjhoIwuzEgUAtgJZNBJckfzJt1qyh24BdTm6UQNGnyTq9dapQdrqvquZTo3dz1X6Cjw== - dependencies: - flux "^4.0.1" - react-base16-styling "^0.6.0" - react-lifecycles-compat "^3.0.4" - react-textarea-autosize "^8.3.2" - -react-lifecycles-compat@^3.0.4: +react-lifecycles-compat@^3.0.4, react-lifecycles-compat@~3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz#4f1a273afdfc8f3488a8c516bfda78f872352362" integrity sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA== @@ -23507,7 +23507,7 @@ react-test-renderer@^17.0.2: react-shallow-renderer "^16.13.1" scheduler "^0.20.2" -react-textarea-autosize@^8.3.2: +react-textarea-autosize@~8.3.2: version "8.3.4" resolved "https://registry.yarnpkg.com/react-textarea-autosize/-/react-textarea-autosize-8.3.4.tgz#270a343de7ad350534141b02c9cb78903e553524" integrity sha512-CdtmP8Dc19xL8/R6sWvtknD/eCXkQr30dtvC4VmGInhRsfF8X/ihXCq6+9l9qbxmKRiq407/7z5fxE7cVWQNgQ== @@ -27090,10 +27090,10 @@ typescript@^4.8.4: resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.8.4.tgz#c464abca159669597be5f96b8943500b238e60e6" integrity sha512-QCh+85mCy+h0IGff8r5XWzOVSbBO+KfeYrMQh7NJ58QujwcE22u+NUSmUxqF+un70P9GXKxa2HCNiTTMJknyjQ== -ua-parser-js@^0.7.30: - version "0.7.33" - resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.33.tgz#1d04acb4ccef9293df6f70f2c3d22f3030d8b532" - integrity sha512-s8ax/CeZdK9R/56Sui0WM6y9OFREJarMRHqLB2EwkovemBxNQ+Bqu8GAsUnVcXKgphb++ghr/B2BZx4mahujPw== +ua-parser-js@^1.0.35: + version "1.0.37" + resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-1.0.37.tgz#b5dc7b163a5c1f0c510b08446aed4da92c46373f" + integrity sha512-bhTyI94tZofjo+Dn8SN6Zv8nBDvyXTymAdM3LDI/0IboIUwTu1rEhW7v2TfiVsoYWgkQ4kOVqnI8APUFbIQIFQ== uglify-js@^2.8.16: version "2.8.29"