add transalationslots. fix flatter logic

pull/3321/head^2
Joseph Izang 2 years ago committed by Aniket
parent e2ad65b424
commit 7a9206f459
  1. 4
      apps/remix-ide/src/app/tabs/locales/en/solidity.json
  2. 4
      apps/remix-ide/src/app/tabs/locales/zh/solidity.json
  3. 39
      libs/remix-ui/solidity-compiler/src/lib/contract-selection.tsx
  4. 169
      libs/remix-ui/solidity-compiler/src/lib/logic/flattenerUtilities.ts

@ -22,6 +22,10 @@
"solidity.noFileSelected": "no file selected",
"solidity.compileAndRunScript": "Compile and Run script",
"solidity.publishOn": "Publish on",
"solidity.flatten": "Flatten contracts with imports before UML generation.",
"solidity.generateUML": "Genrate 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",

@ -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": "已编译合约的名称",

@ -11,6 +11,7 @@ import vizRenderStringSync from '@aduh95/viz.js/sync'
import './css/style.css'
import { CustomTooltip } from '@remix-ui/helper'
import { concatSourceFiles, getDependencyGraph } from './logic/flattenerUtilities'
export const ContractSelection = (props: ContractSelectionProps) => {
const { api, compiledFileName, contractsDetails, contractList, compilerInput, modal } = props
@ -194,10 +195,11 @@ export const ContractSelection = (props: ContractSelectionProps) => {
return copyContractProperty('bytecode')
}
const generateUML = async () => {
let content4AST: string
const generateUML = () => {
try {
const currentFile = api.currentFile
const ast = parser.parse(api.getCompilationResult().source.sources[currentFile].content)
const ast = content4AST.length > 1 ? parser.parse(content4AST) : parser.parse(api.getCompilationResult().source.sources[currentFile].content)
const svgResult = vizRenderStringSync(convertUmlClasses2Dot(convertAST2UmlClasses(ast, currentFile)))
console.log({ svgResult })
} catch (error) {
@ -205,6 +207,17 @@ export const ContractSelection = (props: ContractSelectionProps) => {
}
}
const flattenContract = () => {
const filePath = api.getCompilationResult().source.target
const ast = api.getCompilationResult().data.sources
const dependencyGraph = getDependencyGraph(ast, filePath)
const sorted = dependencyGraph.isEmpty()
? [filePath]
: dependencyGraph.sort().reverse()
const sources = api.getCompilationResult().source.sources
content4AST = concatSourceFiles(sorted, sources)
}
return (
// define swarm logo
<>
@ -218,8 +231,26 @@ export const ContractSelection = (props: ContractSelectionProps) => {
</select>
</div>
<article className="mt-2 pb-0">
<button onClick={generateUML} className="btn btn-primary btn-block mt-2"> Flatten {api.currentFile}</button>
<button onClick={generateUML} className="btn btn-primary btn-block mt-2"> Generate UML Diagram</button>
<CustomTooltip
placement="right-start"
tooltipId="flattenContractTooltip"
tooltipClasses="text-nowrap"
tooltipText={`${intl.formatMessage({ id: 'solidity.flattenLabel' })}`}
>
<button id="contractFlattener" onClick={flattenContract} className="btn btn-secondary btn-block mt-2">
<FormattedMessage id='solidity.flattenLabel' />{api.currentFile}
</button>
</CustomTooltip>
<CustomTooltip
placement="right-start"
tooltipId="generateUMLTooltip"
tooltipClasses="text-nowrap"
tooltipText={`${intl.formatMessage({ id: 'solidity.generateUML' })}`}
>
<button id="generateUML" onClick={generateUML} className="btn btn-secondary btn-block mt-2">
<FormattedMessage id='solidity.generateUMLLabel' />
</button>
</CustomTooltip>
<button id="publishOnIpfs" className="btn btn-secondary btn-block" onClick={() => { handlePublishToStorage('ipfs') }}>
<CustomTooltip
placement="right-start"

@ -0,0 +1,169 @@
const IMPORT_SOLIDITY_REGEX = /^\s*import(\s+).*$/gm;
const SPDX_SOLIDITY_REGEX = /^\s*\/\/ SPDX-License-Identifier:.*$/gm;
export function getDependencyGraph(ast, target) {
const graph = tsort();
const visited = {};
visited[target] = 1;
_traverse(graph, visited, ast, target);
return graph;
}
export function concatSourceFiles(files, sources) {
let concat = '';
for (const file of files) {
const source = sources[file].content;
const sourceWithoutImport = source.replace(IMPORT_SOLIDITY_REGEX, '');
const sourceWithoutSPDX = sourceWithoutImport.replace(SPDX_SOLIDITY_REGEX, '');
concat += `\n// File: ${file}\n\n`;
concat += sourceWithoutSPDX;
}
return concat;
}
function _traverse(graph, visited, ast, name) {
const currentAst = ast[name].ast;
const dependencies = _getDependencies(currentAst);
for (const dependency of dependencies) {
const path = resolve(name, dependency);
if (path in visited) {
continue;
}
visited[path] = 1;
graph.add(name, path);
_traverse(graph, visited, ast, path);
}
}
function _getDependencies(ast) {
const dependencies = ast.nodes
.filter(node => node.nodeType === 'ImportDirective')
.map(node => node.file);
return dependencies;
}
// TSORT
function tsort(initial?: any) {
const graph = new Graph();
if (initial) {
initial.forEach(function (entry) {
Graph.prototype.add.apply(graph, entry);
});
}
return graph;
}
function Graph() {
this.nodes = {};
}
// Add sorted items to the graph
Graph.prototype.add = function () {
const self = this;
// eslint-disable-next-line prefer-rest-params
let items = [].slice.call(arguments);
if (items.length === 1 && Array.isArray(items[0]))
items = items[0];
items.forEach(function (item) {
if (!self.nodes[item]) {
self.nodes[item] = [];
}
});
for (let i = 1; i < items.length; i++) {
const from = items[i];
const to = items[i - 1];
self.nodes[from].push(to);
}
return self;
};
// Depth first search
// As given in http://en.wikipedia.org/wiki/Topological_sorting
Graph.prototype.sort = function () {
const self = this;
const nodes = Object.keys(this.nodes);
const sorted = [];
const marks = {};
for (let i = 0; i < nodes.length; i++) {
const node = nodes[i];
if (!marks[node]) {
visit(node);
}
}
return sorted;
function visit(node) {
if (marks[node] === 'temp')
throw new Error("There is a cycle in the graph. It is not possible to derive a topological sort.");
else if (marks[node])
return;
marks[node] = 'temp';
self.nodes[node].forEach(visit);
marks[node] = 'perm';
sorted.push(node);
}
};
Graph.prototype.isEmpty = function () {
const nodes = Object.keys(this.nodes);
return nodes.length === 0;
}
// PATH
function resolve(parentPath, childPath) {
if (_isAbsolute(childPath)) {
return childPath;
}
const path = parentPath + '/../' + childPath;
const pathParts = path.split('/');
const resolvedParts = _resolvePathArray(pathParts);
const resolvedPath = resolvedParts
.join('/')
.replace('http:/', 'http://')
.replace('https:/', 'https://');
return resolvedPath;
}
function _isAbsolute(path) {
return path[0] !== '.';
}
function _resolvePathArray(parts) {
const res = [];
for (let i = 0; i < parts.length; i++) {
const p = parts[i];
// ignore empty parts
if (!p || p === '.')
continue;
if (p === '..') {
if (res.length && res[res.length - 1] !== '..') {
res.pop();
}
} else {
res.push(p);
}
}
return res;
}
Loading…
Cancel
Save