Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
104 commits
Select commit Hold shift + click to select a range
e1898d5
add sol2uml package
joeizang Dec 20, 2022
928f70c
add react-viewer to view generated artifacts
joeizang Dec 21, 2022
f566f93
trying out convertAST2UML function
joeizang Dec 21, 2022
35034e0
remove direct installation of solidity-parser package
joeizang Dec 21, 2022
1c8a9ff
parser
Dec 21, 2022
3eed4aa
trying out convertAST2UML function
joeizang Dec 21, 2022
dffa2d2
remove direct installation of solidity-parser package
joeizang Dec 21, 2022
4db9eb6
import file writer
joeizang Dec 21, 2022
9a32abd
generate svg
joeizang Dec 22, 2022
074564b
generateUML function refactor
joeizang Dec 22, 2022
42e51c1
Move markup to after contract selector
joeizang Dec 23, 2022
bf169e9
move
joeizang Dec 23, 2022
ae5b368
add transalationslots. fix flatter logic
joeizang Dec 23, 2022
f1cd5a6
add comments
joeizang Dec 23, 2022
8ec02ee
load svg in viewer. add pdf packages
joeizang Dec 23, 2022
86b2d92
finish conditional display of flattener button
joeizang Dec 26, 2022
a0056fc
fix e2e test
joeizang Dec 26, 2022
6831b66
cleanup
joeizang Dec 26, 2022
b7c5b80
move custom tooltip position
joeizang Dec 26, 2022
503d358
disable custom tooltip from verticalIconPanel
joeizang Dec 26, 2022
e18e1e3
fix e2e caused by showFlattener && git push
joeizang Dec 27, 2022
325d8ec
simplify condition to show flatten button
joeizang Dec 27, 2022
0ed4f45
fix e2e
joeizang Dec 27, 2022
5cd920e
fix e2e
joeizang Dec 27, 2022
89fc395
uncomment customtooltip
joeizang Dec 27, 2022
ad6eae5
cache result
joeizang Jan 2, 2023
9518074
save flattened sol file
joeizang Jan 2, 2023
4b9c37d
intercept blob and encode to base64 string for file explorer
joeizang Jan 2, 2023
cf9c734
remove exception throwing logc and replace
joeizang Jan 2, 2023
b6d9ffa
localize pdf logic
joeizang Jan 4, 2023
2c92333
install missing dependencies after fixing conflicts
joeizang Jan 4, 2023
48f399e
add changes as @Aniket-Engg comments
joeizang Jan 12, 2023
fceb7d7
add changes from @lianaHus & @aniket_engg
joeizang Jan 18, 2023
ea1a449
clean out redundancies in file explorer
joeizang Jan 19, 2023
7a9f056
cleanup
joeizang Jan 19, 2023
87b3abe
fix false positive about react-intl
joeizang Jan 20, 2023
7b625fd
generate uml svg. persist flattened contract and svg to file explorer
joeizang Jan 20, 2023
fd629a1
add solidity-uml-gen react lib
joeizang Jan 20, 2023
ac2ba3e
add solidity-umlgen builtin plugin
joeizang Jan 21, 2023
3698939
clean up contract-selection
joeizang Jan 21, 2023
535eee8
finish cleanup of contract-selection
joeizang Jan 21, 2023
7f7713f
add react viewer to solidityumlgen react lib
joeizang Jan 21, 2023
b3c4876
remove solidityumlgen from auto-activated plugins in app.js
joeizang Jan 21, 2023
a397963
add required react import
joeizang Jan 21, 2023
b53409d
cleanup app.js and other files
joeizang Jan 21, 2023
fdaa778
add uml display logic to plugin. call plugin from react lib
joeizang Jan 21, 2023
3a6a222
add plugin class properties. update plugin interface. clean up redund…
joeizang Jan 23, 2023
251bd9d
changes to plugin
joeizang Jan 23, 2023
4341bf7
tried some changes
joeizang Jan 23, 2023
da21e05
fix state
Jan 24, 2023
e39c1e9
add sol2uml package
joeizang Dec 20, 2022
2ff1c5a
trying out convertAST2UML function
joeizang Dec 21, 2022
5c16050
remove direct installation of solidity-parser package
joeizang Dec 21, 2022
c3020c7
import file writer
joeizang Dec 21, 2022
f0da7c0
generate svg
joeizang Dec 22, 2022
09e970f
generateUML function refactor
joeizang Dec 22, 2022
c3cbf85
Move markup to after contract selector
joeizang Dec 23, 2022
fd83e06
move
joeizang Dec 23, 2022
5cced4b
add transalationslots. fix flatter logic
joeizang Dec 23, 2022
5a16253
add comments
joeizang Dec 23, 2022
1e350ca
load svg in viewer. add pdf packages
joeizang Dec 23, 2022
633f270
finish conditional display of flattener button
joeizang Dec 26, 2022
e50cfc0
fix e2e test
joeizang Dec 26, 2022
9732f11
cleanup
joeizang Dec 26, 2022
3e5f36b
disable custom tooltip from verticalIconPanel
joeizang Dec 26, 2022
6852d82
fix e2e caused by showFlattener && git push
joeizang Dec 27, 2022
728852d
simplify condition to show flatten button
joeizang Dec 27, 2022
dab7ed0
fix e2e
joeizang Dec 27, 2022
12ce2c5
fix e2e
joeizang Dec 27, 2022
7a18759
uncomment customtooltip
joeizang Dec 27, 2022
41b6f04
cache result
joeizang Jan 2, 2023
a4ffdd2
save flattened sol file
joeizang Jan 2, 2023
82c24fa
intercept blob and encode to base64 string for file explorer
joeizang Jan 2, 2023
140f45b
remove exception throwing logc and replace
joeizang Jan 2, 2023
60afe22
install missing dependencies after fixing conflicts
joeizang Jan 4, 2023
4523d3d
add changes as @Aniket-Engg comments
joeizang Jan 12, 2023
15f0d9d
add changes from @lianaHus & @aniket_engg
joeizang Jan 18, 2023
68330d8
clean out redundancies in file explorer
joeizang Jan 19, 2023
acd168a
generate uml svg. persist flattened contract and svg to file explorer
joeizang Jan 20, 2023
ea76a62
add solidity-umlgen builtin plugin
joeizang Jan 21, 2023
348ba10
clean up contract-selection
joeizang Jan 21, 2023
ec13a5d
finish cleanup of contract-selection
joeizang Jan 21, 2023
8bd18a9
remove solidityumlgen from auto-activated plugins in app.js
joeizang Jan 21, 2023
766a574
cleanup app.js and other files
joeizang Jan 21, 2023
3b50930
context menu
Jan 24, 2023
3c69435
remove react-viewer. cleanup compiler-container
joeizang Jan 24, 2023
81e9c99
add reac-zoom-pan-pinch
joeizang Jan 24, 2023
c4fcaa2
show uml in tab
joeizang Jan 24, 2023
9aa4e8c
fix multiple issues identified by @bunsentraat and @Aniket_Eng
joeizang Jan 24, 2023
3b38336
remove writing files to explorer as per @bunsentraat's recommendations
joeizang Jan 25, 2023
44b210d
clean up and fix auto focus on uml gen
joeizang Jan 25, 2023
9dddf66
fix spacing
joeizang Jan 25, 2023
32f3546
clean up file-explorer and context menu
joeizang Jan 25, 2023
efed920
clean up filesystemprovider and context
joeizang Jan 25, 2023
2dcaf76
clean up utils/index.ts
joeizang Jan 25, 2023
7d2bd32
fixing css
joeizang Jan 25, 2023
c203b0a
remove event listeners on deactivation. fix css
joeizang Jan 25, 2023
3a01bfb
remove logic to write file during uml gen
joeizang Jan 25, 2023
1a899fa
add types and defaults.
joeizang Jan 30, 2023
a43a5b8
update packages. add async await to plugin
joeizang Jan 30, 2023
e148cd9
add contractFlattening capabilities without external plugin activation
joeizang Jan 31, 2023
a41b605
add fixes from @LianaHus & @Aniket-Engg
joeizang Jan 31, 2023
d8da3df
fix color inversion
joeizang Jan 31, 2023
3477c46
fix theme state not updating correctly
joeizang Jan 31, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion apps/remix-ide-e2e/src/tests/ballot.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,7 @@ module.exports = {
.waitForElementVisible('select[id="compilierLanguageSelector"]', 10000)
.click('select[id="compilierLanguageSelector"]')
.click('select[id="compilierLanguageSelector"] option[value=Yul]')
.waitForElementContainsText('[data-id="compiledContracts"]', 'Contract', 60000)
.waitForElementContainsText('[data-id="compiledContracts"]', 'Contract', 65000)
.clickLaunchIcon('udapp')
.click('*[data-id="Deploy - transact (not payable)"]')
.waitForElementPresent('*[data-id="universalDappUiContractActionWrapper"]', 60000)
Expand Down
12 changes: 11 additions & 1 deletion apps/remix-ide/src/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ import { Injected0ptimismProvider } from './app/tabs/injected-optimism-provider'
import { InjectedArbitrumOneProvider } from './app/tabs/injected-arbitrum-one-provider'
import { FileDecorator } from './app/plugins/file-decorator'
import { CodeFormat } from './app/plugins/code-format'
import { SolidityUmlGen } from './app/plugins/solidity-umlgen'
import { ContractFlattener } from './app/plugins/contractFlattener'

const isElectron = require('is-electron')

Expand Down Expand Up @@ -173,6 +175,12 @@ class AppComponent {
//----- search
const search = new SearchPlugin()

//---------------- Solidity UML Generator -------------------------
const solidityumlgen = new SolidityUmlGen(appManager)

// ----------------- ContractFlattener ----------------------------
const contractFlattener = new ContractFlattener()

// ----------------- import content service ------------------------
const contentImport = new CompilerImports()

Expand Down Expand Up @@ -265,7 +273,9 @@ class AppComponent {
injected0ptimismProvider,
injectedArbitrumOneProvider,
this.walkthroughService,
search
search,
solidityumlgen,
contractFlattener
])

// LAYOUT & SYSTEM VIEWS
Expand Down
7 changes: 5 additions & 2 deletions apps/remix-ide/src/app/files/fileManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import Registry from '../state/registry'
import { EventEmitter } from 'events'
import { fileChangedToastMsg, recursivePasteToastMsg, storageFullMessage } from '@remix-ui/helper'
import helper from '../../lib/helper.js'
import { RemixAppManager } from '../../remixAppManager'

/*
attach to files event (removed renamed)
Expand Down Expand Up @@ -40,7 +41,7 @@ class FileManager extends Plugin {
events: EventEmitter
editor: any
_components: any
appManager: any
appManager: RemixAppManager
_deps: any
getCurrentFile: () => any
getFile: (path: any) => Promise<unknown>
Expand Down Expand Up @@ -622,13 +623,15 @@ class FileManager extends Plugin {
file = resolved.file
await this.saveCurrentFile()
if (this.currentFile() === file) return

const provider = resolved.provider
this._deps.config.set('currentFile', file)
this.openedFiles[file] = file

let content = ''
try {
content = await provider.get(file)
content = await provider.get(file)

} catch (error) {
console.log(error)
throw error
Expand Down
2 changes: 1 addition & 1 deletion apps/remix-ide/src/app/panels/tab-proxy.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ export class TabProxy extends Plugin {

this.on('fileManager', 'filesAllClosed', () => {
this.call('manager', 'activatePlugin', 'home')
this.tabsApi.activateTab('home')
this.focus('home')
})

this.on('fileManager', 'fileRemoved', (name) => {
Expand Down
49 changes: 49 additions & 0 deletions apps/remix-ide/src/app/plugins/contractFlattener.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import React from 'react'
import { Plugin } from '@remixproject/engine'
import { customAction } from '@remixproject/plugin-api'
import { concatSourceFiles, getDependencyGraph } from '@remix-ui/solidity-compiler'

const profile = {
name: 'contractflattener',
displayName: 'Contract Flattener',
description: 'Flatten solidity contracts',
methods: ['flattenAContract'],
events: [],
}

export class ContractFlattener extends Plugin {
fileName: string
constructor() {
super(profile)
this.fileName = ''
}

onActivation(): void {
this.on('solidity', 'compilationFinished', async (file, source, languageVersion, data, input, version) => {
await this.flattenContract(source, this.fileName, data)
})
}

async flattenAContract(action: customAction) {
this.fileName = action.path[0]
this.call('solidity', 'compile', this.fileName)
}

/**
* Takes currently compiled contract that has a bunch of imports at the top
* and flattens them ready for UML creation. Takes the flattened result
* and assigns to a local property
* @returns {Promise<string>}
*/
async flattenContract (source: any, filePath: string, data: any) {
const ast = data.sources
const dependencyGraph = getDependencyGraph(ast, filePath)
const sorted = dependencyGraph.isEmpty()
? [filePath]
: dependencyGraph.sort().reverse()
const sources = source.sources
const result = concatSourceFiles(sorted, sources)
await this.call('fileManager', 'writeFile', `${filePath}_flattened.sol`, result)
return result
}
}
159 changes: 159 additions & 0 deletions apps/remix-ide/src/app/plugins/solidity-umlgen.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
/* eslint-disable @nrwl/nx/enforce-module-boundaries */
import { ViewPlugin } from '@remixproject/engine-web'
import React from 'react'
// eslint-disable-next-line @nrwl/nx/enforce-module-boundaries
import { RemixUiSolidityUmlGen } from '@remix-ui/solidity-uml-gen'
import { ISolidityUmlGen } from 'libs/remix-ui/solidity-uml-gen/src/types'
import { RemixAppManager } from 'libs/remix-ui/plugin-manager/src/types'
import { concatSourceFiles, getDependencyGraph } from 'libs/remix-ui/solidity-compiler/src/lib/logic/flattenerUtilities'
import { convertUmlClasses2Dot } from 'sol2uml/lib/converterClasses2Dot'
import { convertAST2UmlClasses } from 'sol2uml/lib/converterAST2Classes'
import vizRenderStringSync from '@aduh95/viz.js/sync'
import { PluginViewWrapper } from '@remix-ui/helper'
import { customAction } from '@remixproject/plugin-api'
const parser = (window as any).SolidityParser

const profile = {
name: 'solidityumlgen',
displayName: 'Solidity UML Generator',
description: 'Generate UML diagram in svg format from last compiled contract',
location: 'mainPanel',
methods: ['showUmlDiagram', 'generateUml', 'generateCustomAction'],
events: [],
}

export class SolidityUmlGen extends ViewPlugin implements ISolidityUmlGen {
element: HTMLDivElement
currentFile: string
svgPayload: string
updatedSvg: string
currentlySelectedTheme: string
loading: boolean

appManager: RemixAppManager
dispatch: React.Dispatch<any> = () => {}
constructor(appManager: RemixAppManager) {
super(profile)
this.currentFile = ''
this.svgPayload = ''
this.updatedSvg = ''
this.loading = false
this.currentlySelectedTheme = ''
this.appManager = appManager
this.element = document.createElement('div')
this.element.setAttribute('id', 'sol-uml-gen')
}

onActivation(): void {
if (this.currentFile.length < 1)
this.on('solidity', 'compilationFinished', async (file, source, languageVersion, data, input, version) => {
let result = ''
try {
if (data.sources && Object.keys(data.sources).length > 1) { // we should flatten first as there are multiple asts
result = await this.flattenContract(source, this.currentFile, data)
}
const ast = result.length > 1 ? parser.parse(result) : parser.parse(source.sources[this.currentFile].content)
const umlClasses = convertAST2UmlClasses(ast, this.currentFile)
const umlDot = convertUmlClasses2Dot(umlClasses)
const payload = vizRenderStringSync(umlDot)
const currentTheme = await this.call('theme', 'currentTheme')
this.currentlySelectedTheme = currentTheme.quality
this.updatedSvg = payload
this.renderComponent()
} catch (error) {
console.log({ error })
}
})
this.on('theme', 'themeChanged', (theme) => {
this.currentlySelectedTheme = theme.quality
this.renderComponent()
})
}

async mangleSvgPayload(svgPayload: string) : Promise<string> {
const parser = new DOMParser()
const themeQuality = await this.call('theme', 'currentTheme')
const parsedDocument = parser.parseFromString(svgPayload, 'image/svg+xml')
const res = parsedDocument.documentElement
parsedDocument.bgColor = '#cccabc'
res.style.filter = themeQuality.quality === 'dark' ? 'invert(1)' : 'invert(0)'
const stringifiedSvg = new XMLSerializer().serializeToString(parsedDocument)
console.log({ parsedDocument, themeQuality, stringifiedSvg })
return stringifiedSvg
}

onDeactivation(): void {
this.off('solidity', 'compilationFinished')
}

generateCustomAction = async (action: customAction) => {
this.currentFile = action.path[0]
await this.generateUml(action.path[0])
}

async generateUml(currentFile: string) {
await this.call('solidity', 'compile', currentFile)
await this.call('tabs', 'focus', 'solidityumlgen')
this.loading = true
this.renderComponent()
}

/**
* Takes currently compiled contract that has a bunch of imports at the top
* and flattens them ready for UML creation. Takes the flattened result
* and assigns to a local property
* @returns {Promise<string>}
*/
async flattenContract (source: any, filePath: string, data: any) {
const hold = { data, source, filePath }
const ast = data.sources
const dependencyGraph = getDependencyGraph(ast, filePath)
const sorted = dependencyGraph.isEmpty()
? [filePath]
: dependencyGraph.sort().reverse()
const sources = source.sources
const result = concatSourceFiles(sorted, sources)
await this.call('fileManager', 'writeFile', `${filePath}_flattened.sol`, result)
return result
}

async showUmlDiagram(svgPayload: string) {
this.updatedSvg = svgPayload
this.renderComponent()
}

hideSpinner() {
this.loading = false
this.renderComponent()
}

setDispatch (dispatch: React.Dispatch<any>) {
this.dispatch = dispatch
this.renderComponent()
}

render() {
return <div id='sol-uml-gen'>
<PluginViewWrapper plugin={this} />
</div>
}

renderComponent () {
this.dispatch({
...this,
updatedSvg: this.updatedSvg,
loading: this.loading,
themeSelected: this.currentlySelectedTheme
})
}

updateComponent(state: any) {
return <RemixUiSolidityUmlGen
plugin={state}
updatedSvg={state.updatedSvg}
loading={state.loading}
themeSelected={state.currentlySelectedTheme}
/>
}
}

4 changes: 4 additions & 0 deletions apps/remix-ide/src/app/tabs/locales/en/solidity.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@
"solidity.noFileSelected": "no file selected",
"solidity.compileAndRunScript": "Compile and Run script",
"solidity.publishOn": "Publish on",
"solidity.flatten": "Flatten contracts before UML generation.",
"solidity.generateUML": "Generate a UML diagram of your contract.",
"solidity.flattenLabel": "Flatten",
"solidity.generateUMLLabel": "Generate UML Diagram",
"solidity.Assembly": "Assembly opcodes describing the contract including corresponding solidity source code",
"solidity.Opcodes": "Assembly opcodes describing the contract",
"solidity.name": "Name of the compiled contract",
Expand Down
4 changes: 4 additions & 0 deletions apps/remix-ide/src/app/tabs/locales/zh/solidity.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@
"solidity.noFileSelected": "未选中文件",
"solidity.compileAndRunScript": "编译且执行脚本",
"solidity.publishOn": "发布到",
"solidity.flatten": "",
"solidity.generateUML": "",
"solidity.flattenLabel": "",
"solidity.generateUMLLabel": "",
"solidity.Assembly": "合约的汇编操作码,包含对应的solidity源程序",
"solidity.Opcodes": "合约的汇编操作码",
"solidity.name": "已编译合约的名称",
Expand Down
4 changes: 3 additions & 1 deletion apps/remix-ide/src/app/tabs/theme-module.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,9 @@ export class ThemeModule extends Plugin {
this.forced = !!queryTheme
}

/** Return the active theme */
/** Return the active theme
* @return {{ name: string, quality: string, url: string }} - The active theme
*/
currentTheme () {
return this.themes[this.active]
}
Expand Down
16 changes: 13 additions & 3 deletions apps/remix-ide/src/remixAppManager.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ const requiredModules = [ // services + layout views + system views
'filePanel', 'terminal', 'settings', 'pluginManager', 'tabs', 'udapp', 'dGitProvider', 'solidity', 'solidity-logic', 'gistHandler', 'layout',
'notification', 'permissionhandler', 'walkthrough', 'storage', 'restorebackupzip', 'link-libraries', 'deploy-libraries', 'openzeppelin-proxy',
'hardhat-provider', 'ganache-provider', 'foundry-provider', 'basic-http-provider', 'injected-optimism-provider', 'injected-arbitrum-one-provider',
'compileAndRun', 'search', 'recorder', 'fileDecorator', 'codeParser', 'codeFormatter']
'compileAndRun', 'search', 'recorder', 'fileDecorator', 'codeParser', 'codeFormatter', 'solidityumlgen', 'contractflattener']

// dependentModules shouldn't be manually activated (e.g hardhat is activated by remixd)
const dependentModules = ['foundry', 'hardhat', 'truffle', 'slither']
Expand Down Expand Up @@ -157,8 +157,8 @@ export class RemixAppManager extends PluginManager {

async registerContextMenuItems() {
await this.call('filePanel', 'registerContextMenuItem', {
id: 'flattener',
name: 'flattenFileCustomAction',
id: 'contractflattener',
name: 'flattenAContract',
label: 'Flatten',
type: [],
extension: ['.sol'],
Expand All @@ -176,6 +176,16 @@ export class RemixAppManager extends PluginManager {
pattern: [],
sticky: true
})
await this.call('filePanel', 'registerContextMenuItem', {
id: 'solidityumlgen',
name: 'generateCustomAction',
label: 'Generate UML',
type: [],
extension: ['.sol'],
path: [],
pattern: [],
sticky: true
})
}
}

Expand Down
2 changes: 1 addition & 1 deletion libs/remix-lib/src/types/ICompilerApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ export interface ICompilerApi {

resolveContentAndSave: (url: string) => Promise<string>
fileExists: (file: string) => Promise<boolean>
writeFile: (file: string, content: string) => Promise<void>
writeFile: (file: string, content: any) => Promise<void>
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this change necessary?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, when left as a string, It becomes difficult to write the pdf to file explorer. Even though deep in the recesses of the plugin engin, it takes a string. Making it any allows me to write the result from generating the pdf to fileexplorer.

readFile: (file: string) => Promise<string>
open: (file: string) => void
saveCurrentFile: () => void
Expand Down
1 change: 1 addition & 0 deletions libs/remix-ui/app/src/lib/remix-app/remix-app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ const RemixApp = (props: IRemixAppUi) => {
}

return (
//@ts-ignore
<IntlProvider locale={locale.code} messages={locale.messages}>
<AppProvider value={value}>
<OriginWarning></OriginWarning>
Expand Down
1 change: 1 addition & 0 deletions libs/remix-ui/solidity-compiler/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export * from './lib/solidity-compiler'
export * from './lib/logic'
export * from './lib/logic/flattenerUtilities'
Loading