sol2uml 2.5.3 → 2.5.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +23 -1
- package/lib/converterAST2Classes.js +1 -1
- package/lib/filterClasses.js +1 -1
- package/lib/parserEtherscan.d.ts +4 -3
- package/lib/parserEtherscan.js +20 -5
- package/lib/sol2uml.js +4 -2
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -55,7 +55,8 @@ Options:
|
|
|
55
55
|
-f, --outputFormat <value> output file format. (choices: "svg", "png", "dot", "all", default: "svg")
|
|
56
56
|
-o, --outputFileName <value> output file name
|
|
57
57
|
-i, --ignoreFilesOrFolders <filesOrFolders> comma separated list of files or folders to ignore
|
|
58
|
-
-n, --network <network> Ethereum network (choices: "mainnet", "goerli", "sepolia", "polygon", "arbitrum", "avalanche", "bsc", "crono", "fantom", "moonbeam",
|
|
58
|
+
-n, --network <network> Ethereum network (choices: "mainnet", "goerli", "sepolia", "polygon", "arbitrum", "avalanche", "bsc", "crono", "fantom", "moonbeam",
|
|
59
|
+
"optimism", "gnosis", "celo", default: "mainnet", env: ETH_NETWORK)
|
|
59
60
|
-k, --apiKey <key> Blockchain explorer API key. eg Etherscan, Arbiscan, Optimism, BscScan, CronoScan, FTMScan, PolygonScan or SnowTrace API key (env: SCAN_API_KEY)
|
|
60
61
|
-bc, --backColor <color> Canvas background color. "none" will use a transparent canvas. (default: "white")
|
|
61
62
|
-sc, --shapeColor <color> Basic drawing color for graphics, not text (default: "black")
|
|
@@ -192,6 +193,8 @@ Arguments:
|
|
|
192
193
|
|
|
193
194
|
Options:
|
|
194
195
|
-l, --lineBuffer <value> Minimum number of lines before and after changes (default: "4")
|
|
196
|
+
--aFile <value> Contract A source code filename without the .sol extension. (default: compares all source files)
|
|
197
|
+
--bFile <value> Contract B source code filename without the .sol extension. (default: aFile if specified)
|
|
195
198
|
-s, --saveFiles Save the flattened contract code to the filesystem. The file names will be the contract address with a .sol extension. (default: false)
|
|
196
199
|
-h, --help display help for command
|
|
197
200
|
```
|
|
@@ -329,6 +332,25 @@ To access your local changes on your machine globally.
|
|
|
329
332
|
|
|
330
333
|
`npm link`
|
|
331
334
|
|
|
335
|
+
# Publish
|
|
336
|
+
|
|
337
|
+
Commands to publish a new package version.
|
|
338
|
+
|
|
339
|
+
```bash
|
|
340
|
+
npm run prettier
|
|
341
|
+
npm run clean
|
|
342
|
+
npm run package-lock
|
|
343
|
+
npm run build
|
|
344
|
+
npm run permit
|
|
345
|
+
# make tx2uml globally available for local testing
|
|
346
|
+
npm link
|
|
347
|
+
# check all the files are included in the npm package
|
|
348
|
+
npm pack --dry-run
|
|
349
|
+
npm publish
|
|
350
|
+
```
|
|
351
|
+
|
|
352
|
+
Then create a new release on GitHub https://github.com/naddison36/sol2uml/releases
|
|
353
|
+
|
|
332
354
|
# About
|
|
333
355
|
|
|
334
356
|
This is a rewrite of the Richard Ramos's [solidity-diagram-gen](https://github.com/richard-ramos/solidity-diagram-gen) tool which no longer works as it uses [solidity-parser](https://www.npmjs.com/package/solidity-parser/v/0.4.0) which cannot handle newer Solidity syntax like `constructor`.
|
|
@@ -102,7 +102,7 @@ function convertAST2UmlClasses(node, relativePath, remappings, filesystem = fals
|
|
|
102
102
|
})
|
|
103
103
|
: [],
|
|
104
104
|
};
|
|
105
|
-
debug(`Added filesystem import ${newImport.absolutePath} with class names ${newImport.classNames}`);
|
|
105
|
+
debug(`Added filesystem import ${newImport.absolutePath} with class names ${newImport.classNames.map((i) => i.className)}`);
|
|
106
106
|
imports.push(newImport);
|
|
107
107
|
}
|
|
108
108
|
catch (err) {
|
package/lib/filterClasses.js
CHANGED
|
@@ -87,7 +87,7 @@ function loadWeightedDirectedGraph(umlClasses) {
|
|
|
87
87
|
continue;
|
|
88
88
|
}
|
|
89
89
|
const isTarget = umlClasses.find((u) => u.id === targetUmlClass.id);
|
|
90
|
-
debug(`isTarget ${isTarget} Adding edge from ${sourceUmlClass.name} with id ${sourceUmlClass.id} to ${targetUmlClass.name} with id ${targetUmlClass.id} and type ${targetUmlClass.stereotype}`);
|
|
90
|
+
debug(`isTarget ${!!isTarget}: Adding edge from ${sourceUmlClass.name} with id ${sourceUmlClass.id} to ${targetUmlClass.name} with id ${targetUmlClass.id} and type ${targetUmlClass.stereotype}`);
|
|
91
91
|
weightedDirectedGraph.addEdge(new js_graph_algorithms_1.Edge(sourceUmlClass.id, targetUmlClass.id, 1));
|
|
92
92
|
}
|
|
93
93
|
}
|
package/lib/parserEtherscan.d.ts
CHANGED
|
@@ -4,7 +4,7 @@ export interface Remapping {
|
|
|
4
4
|
from: RegExp;
|
|
5
5
|
to: string;
|
|
6
6
|
}
|
|
7
|
-
export declare const networks: readonly ["mainnet", "goerli", "sepolia", "polygon", "arbitrum", "avalanche", "bsc", "crono", "fantom", "moonbeam", "optimism", "gnosis"];
|
|
7
|
+
export declare const networks: readonly ["mainnet", "goerli", "sepolia", "polygon", "arbitrum", "avalanche", "bsc", "crono", "fantom", "moonbeam", "optimism", "gnosis", "celo"];
|
|
8
8
|
export type Network = (typeof networks)[number];
|
|
9
9
|
export declare class EtherscanParser {
|
|
10
10
|
protected apikey: string;
|
|
@@ -26,7 +26,7 @@ export declare class EtherscanParser {
|
|
|
26
26
|
* @param contractAddress Ethereum contract address with a 0x prefix
|
|
27
27
|
* @return Promise string of Solidity code
|
|
28
28
|
*/
|
|
29
|
-
getSolidityCode(contractAddress: string): Promise<{
|
|
29
|
+
getSolidityCode(contractAddress: string, filename?: string): Promise<{
|
|
30
30
|
solidityCode: string;
|
|
31
31
|
contractName: string;
|
|
32
32
|
}>;
|
|
@@ -39,8 +39,9 @@ export declare class EtherscanParser {
|
|
|
39
39
|
/**
|
|
40
40
|
* Calls Etherscan to get the verified source code for the specified contract address
|
|
41
41
|
* @param contractAddress Ethereum contract address with a 0x prefix
|
|
42
|
+
* @oaram filename optional, case-sensitive name of the source file without the .sol
|
|
42
43
|
*/
|
|
43
|
-
getSourceCode(contractAddress: string): Promise<{
|
|
44
|
+
getSourceCode(contractAddress: string, filename?: string): Promise<{
|
|
44
45
|
files: readonly {
|
|
45
46
|
code: string;
|
|
46
47
|
filename: string;
|
package/lib/parserEtherscan.js
CHANGED
|
@@ -9,6 +9,7 @@ const parser_1 = require("@solidity-parser/parser");
|
|
|
9
9
|
const converterAST2Classes_1 = require("./converterAST2Classes");
|
|
10
10
|
const filterClasses_1 = require("./filterClasses");
|
|
11
11
|
const regEx_1 = require("./utils/regEx");
|
|
12
|
+
const path_1 = __importDefault(require("path"));
|
|
12
13
|
require('axios-debug-log');
|
|
13
14
|
const debug = require('debug')('sol2uml');
|
|
14
15
|
exports.networks = [
|
|
@@ -24,6 +25,7 @@ exports.networks = [
|
|
|
24
25
|
'moonbeam',
|
|
25
26
|
'optimism',
|
|
26
27
|
'gnosis',
|
|
28
|
+
'celo',
|
|
27
29
|
];
|
|
28
30
|
class EtherscanParser {
|
|
29
31
|
constructor(apikey = 'ZAD4UI2RCXCQTP38EXS3UY2MPHFU5H9KB1', network = 'mainnet') {
|
|
@@ -71,6 +73,10 @@ class EtherscanParser {
|
|
|
71
73
|
this.url = 'https://api.gnosisscan.io/api';
|
|
72
74
|
this.apikey = '2RWGXIWK538EJ8XSP9DE2JUINSCG7UCSJB';
|
|
73
75
|
}
|
|
76
|
+
else if (network === 'celo') {
|
|
77
|
+
this.url = 'https://api.celoscan.io/api';
|
|
78
|
+
this.apikey = 'JBV78T5KP15W7WKKKD6KC4J8RX2F4PK8AF';
|
|
79
|
+
}
|
|
74
80
|
else {
|
|
75
81
|
this.url = `https://api-${network}.etherscan.io/api`;
|
|
76
82
|
}
|
|
@@ -100,8 +106,8 @@ class EtherscanParser {
|
|
|
100
106
|
* @param contractAddress Ethereum contract address with a 0x prefix
|
|
101
107
|
* @return Promise string of Solidity code
|
|
102
108
|
*/
|
|
103
|
-
async getSolidityCode(contractAddress) {
|
|
104
|
-
const { files, contractName, compilerVersion, remappings } = await this.getSourceCode(contractAddress);
|
|
109
|
+
async getSolidityCode(contractAddress, filename) {
|
|
110
|
+
const { files, contractName, compilerVersion, remappings } = await this.getSourceCode(contractAddress, filename);
|
|
105
111
|
// Parse the UmlClasses from the Solidity code in each file
|
|
106
112
|
let umlClasses = [];
|
|
107
113
|
for (const file of files) {
|
|
@@ -137,7 +143,7 @@ class EtherscanParser {
|
|
|
137
143
|
// match whitespace before import
|
|
138
144
|
// and characters after import up to ;
|
|
139
145
|
// replace all in file and match across multiple lines
|
|
140
|
-
const removedImports = removedPragmaSolidity.replace(
|
|
146
|
+
const removedImports = removedPragmaSolidity.replace(/^\s*?(import.*?;)/gms, '/* $1 */');
|
|
141
147
|
// Rename SPDX-License-Identifier to SPDX--License-Identifier so the merged file will compile
|
|
142
148
|
const removedSPDX = removedImports.replace(/SPDX-/, 'SPDX--');
|
|
143
149
|
solidityCode += removedSPDX;
|
|
@@ -164,8 +170,9 @@ class EtherscanParser {
|
|
|
164
170
|
/**
|
|
165
171
|
* Calls Etherscan to get the verified source code for the specified contract address
|
|
166
172
|
* @param contractAddress Ethereum contract address with a 0x prefix
|
|
173
|
+
* @oaram filename optional, case-sensitive name of the source file without the .sol
|
|
167
174
|
*/
|
|
168
|
-
async getSourceCode(contractAddress) {
|
|
175
|
+
async getSourceCode(contractAddress, filename) {
|
|
169
176
|
const description = `get verified source code for address ${contractAddress} from Etherscan API.`;
|
|
170
177
|
try {
|
|
171
178
|
debug(`About to get Solidity source code for ${contractAddress} from ${this.url}`);
|
|
@@ -226,8 +233,16 @@ class EtherscanParser {
|
|
|
226
233
|
filename: contractAddress,
|
|
227
234
|
};
|
|
228
235
|
});
|
|
236
|
+
let files = results.flat(1);
|
|
237
|
+
const filenameWithExt = filename + '.sol';
|
|
238
|
+
if (filename) {
|
|
239
|
+
files = files.filter((r) => path_1.default.parse(r.filename).base == filenameWithExt);
|
|
240
|
+
if (!files?.length) {
|
|
241
|
+
throw new Error(`Failed to find source file "${filename}" for contract ${contractAddress}`);
|
|
242
|
+
}
|
|
243
|
+
}
|
|
229
244
|
return {
|
|
230
|
-
files
|
|
245
|
+
files,
|
|
231
246
|
contractName: response.data.result[0].ContractName,
|
|
232
247
|
compilerVersion: response.data.result[0].CompilerVersion,
|
|
233
248
|
remappings,
|
package/lib/sol2uml.js
CHANGED
|
@@ -225,6 +225,8 @@ The line numbers are from contract B. There are no line numbers for the red sect
|
|
|
225
225
|
.argument('<addressA>', 'Contract address in hexadecimal format with a 0x prefix of the first contract.')
|
|
226
226
|
.argument('<addressB>', 'Contract address in hexadecimal format with a 0x prefix of the second contract.')
|
|
227
227
|
.addOption(new commander_1.Option('-l, --lineBuffer <value>', 'Minimum number of lines before and after changes').default('4'))
|
|
228
|
+
.addOption(new commander_1.Option('-af --aFile <value>', 'Contract A source code filename without the .sol extension. (default: compares all source files)'))
|
|
229
|
+
.addOption(new commander_1.Option('-bf --bFile <value>', 'Contract B source code filename without the .sol extension. (default: aFile if specified)'))
|
|
228
230
|
.option('-s, --saveFiles', 'Save the flattened contract code to the filesystem. The file names will be the contract address with a .sol extension.', false)
|
|
229
231
|
.action(async (addressA, addressB, options, command) => {
|
|
230
232
|
try {
|
|
@@ -239,8 +241,8 @@ The line numbers are from contract B. There are no line numbers for the red sect
|
|
|
239
241
|
throw Error(`Invalid line buffer "${options.lineBuffer}". Must be a number`);
|
|
240
242
|
const etherscanParser = new parserEtherscan_1.EtherscanParser(combinedOptions.apiKey, combinedOptions.network);
|
|
241
243
|
// Get verified Solidity code from Etherscan and flatten
|
|
242
|
-
const { solidityCode: codeA, contractName: contractNameA } = await etherscanParser.getSolidityCode(addressA);
|
|
243
|
-
const { solidityCode: codeB, contractName: contractNameB } = await etherscanParser.getSolidityCode(addressB);
|
|
244
|
+
const { solidityCode: codeA, contractName: contractNameA } = await etherscanParser.getSolidityCode(addressA, combinedOptions.aFile);
|
|
245
|
+
const { solidityCode: codeB, contractName: contractNameB } = await etherscanParser.getSolidityCode(addressB, combinedOptions.bFile || combinedOptions.aFile);
|
|
244
246
|
console.log(`Difference between`);
|
|
245
247
|
console.log(`A. ${addressA} ${contractNameA} on ${combinedOptions.network}`);
|
|
246
248
|
console.log(`B. ${addressB} ${contractNameB} on ${combinedOptions.network}\n`);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sol2uml",
|
|
3
|
-
"version": "2.5.
|
|
3
|
+
"version": "2.5.5",
|
|
4
4
|
"description": "Solidity contract visualisation tool.",
|
|
5
5
|
"main": "./lib/index.js",
|
|
6
6
|
"types": "./lib/index.d.ts",
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
"klaw": "^4.1.0"
|
|
37
37
|
},
|
|
38
38
|
"devDependencies": {
|
|
39
|
-
"@openzeppelin/contracts": "4.8.
|
|
39
|
+
"@openzeppelin/contracts": "^4.8.2",
|
|
40
40
|
"@types/diff-match-patch": "^1.0.32",
|
|
41
41
|
"@types/jest": "^29.4.0",
|
|
42
42
|
"@types/klaw": "^3.0.3",
|