sol2uml 2.1.3 → 2.1.6
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 +11 -10
- package/lib/converterAST2Classes.js +18 -8
- package/lib/converterClasses2Storage.d.ts +1 -1
- package/lib/converterClasses2Storage.js +19 -4
- package/lib/parserEtherscan.d.ts +1 -1
- package/lib/parserEtherscan.js +59 -7
- package/lib/sol2uml.js +19 -21
- package/package.json +10 -9
package/README.md
CHANGED
|
@@ -58,8 +58,8 @@ Options:
|
|
|
58
58
|
-f, --outputFormat <value> output file format. (choices: "svg", "png", "dot", "all", default: "svg")
|
|
59
59
|
-o, --outputFileName <value> output file name
|
|
60
60
|
-i, --ignoreFilesOrFolders <filesOrFolders> comma separated list of files or folders to ignore
|
|
61
|
-
-n, --network <network> Ethereum network (choices: "mainnet", "polygon", "
|
|
62
|
-
-k, --apiKey <key> Etherscan,
|
|
61
|
+
-n, --network <network> Ethereum network (choices: "mainnet", "ropsten", "kovan", "rinkeby", "goerli", "sepolia", "polygon", "testnet.polygon", "arbitrum", "testnet.arbitrum", "avalanche", "testnet.avalanche", "bsc", "testnet.bsc", "crono", "fantom", "testnet.fantom", "moonbeam", "optimistic", "kovan-optimistic", default: "mainnet", env: ETH_NETWORK)
|
|
62
|
+
-k, --apiKey <key> Blockchain explorer API key. eg Etherscan, Arbiscan, BscScan, CronoScan, FTMScan, PolygonScan or SnowTrace API key (env: SCAN_API_KEY)
|
|
63
63
|
-v, --verbose run with debugging statements (default: false)
|
|
64
64
|
-h, --help display help for command
|
|
65
65
|
|
|
@@ -77,9 +77,9 @@ Usage: sol2uml class <fileFolderAddress> [options]
|
|
|
77
77
|
|
|
78
78
|
Generates UML diagrams from Solidity source code.
|
|
79
79
|
|
|
80
|
-
If no file, folder or address is
|
|
80
|
+
If no file, folder or address is passed as the first argument, the working folder is used.
|
|
81
81
|
When a folder is used, all *.sol files are found in that folder and all sub folders.
|
|
82
|
-
A comma separated list of files and folders can also used. For example
|
|
82
|
+
A comma separated list of files and folders can also be used. For example
|
|
83
83
|
sol2uml contracts,node_modules/openzeppelin-solidity
|
|
84
84
|
|
|
85
85
|
If an Ethereum address with a 0x prefix is passed, the verified source code from Etherscan will be used. For example
|
|
@@ -119,12 +119,13 @@ Arguments:
|
|
|
119
119
|
fileFolderAddress file name, base folder or contract address
|
|
120
120
|
|
|
121
121
|
Options:
|
|
122
|
-
-c, --contract <name>
|
|
123
|
-
-
|
|
124
|
-
-
|
|
125
|
-
-
|
|
126
|
-
-
|
|
127
|
-
-
|
|
122
|
+
-c, --contract <name> Contract name in the local Solidity files. Not needed when using an address as the first argument as the contract name can be derived from Etherscan.
|
|
123
|
+
-cf, --contractFile <filename> Filename the contract is located in. This can include the relative path to the desired file.
|
|
124
|
+
-d, --data Gets the values in the storage slots from an Ethereum node. (default: false)
|
|
125
|
+
-s, --storage <address> The address of the contract with the storage values. This will be different from the contract with the code if a proxy contract is used. This is not needed if `fileFolderAddress` is an address and the contract is not proxied.
|
|
126
|
+
-u, --url <url> URL of the Ethereum node to get storage values if the `data` option is used. (default: "http://localhost:8545", env: NODE_URL)
|
|
127
|
+
-bn, --block <number> Block number to get the contract storage values from. (default: "latest")
|
|
128
|
+
-h, --help display help for command
|
|
128
129
|
```
|
|
129
130
|
|
|
130
131
|
### Flatten usage
|
|
@@ -25,6 +25,7 @@ var __importStar = (this && this.__importStar) || function (mod) {
|
|
|
25
25
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
26
|
exports.convertAST2UmlClasses = void 0;
|
|
27
27
|
const path = __importStar(require("path"));
|
|
28
|
+
const path_1 = require("path");
|
|
28
29
|
const umlClass_1 = require("./umlClass");
|
|
29
30
|
const typeGuards_1 = require("./typeGuards");
|
|
30
31
|
const debug = require('debug')('sol2uml');
|
|
@@ -35,7 +36,6 @@ function convertAST2UmlClasses(node, relativePath, filesystem = false) {
|
|
|
35
36
|
if (node.type === 'SourceUnit') {
|
|
36
37
|
node.children.forEach((childNode) => {
|
|
37
38
|
if (childNode.type === 'ContractDefinition') {
|
|
38
|
-
debug(`Adding contract ${childNode.name}`);
|
|
39
39
|
let umlClass = new umlClass_1.UmlClass({
|
|
40
40
|
name: childNode.name,
|
|
41
41
|
absolutePath: filesystem
|
|
@@ -44,6 +44,7 @@ function convertAST2UmlClasses(node, relativePath, filesystem = false) {
|
|
|
44
44
|
relativePath,
|
|
45
45
|
});
|
|
46
46
|
umlClass = parseContractDefinition(umlClass, childNode);
|
|
47
|
+
debug(`Added contract ${childNode.name}`);
|
|
47
48
|
umlClasses.push(umlClass);
|
|
48
49
|
}
|
|
49
50
|
else if (childNode.type === 'StructDefinition') {
|
|
@@ -57,6 +58,7 @@ function convertAST2UmlClasses(node, relativePath, filesystem = false) {
|
|
|
57
58
|
relativePath,
|
|
58
59
|
});
|
|
59
60
|
umlClass = parseStructDefinition(umlClass, childNode);
|
|
61
|
+
debug(`Added struct ${umlClass.name}`);
|
|
60
62
|
umlClasses.push(umlClass);
|
|
61
63
|
}
|
|
62
64
|
else if (childNode.type === 'EnumDefinition') {
|
|
@@ -69,6 +71,7 @@ function convertAST2UmlClasses(node, relativePath, filesystem = false) {
|
|
|
69
71
|
: relativePath,
|
|
70
72
|
relativePath,
|
|
71
73
|
});
|
|
74
|
+
debug(`Added enum ${umlClass.name}`);
|
|
72
75
|
umlClass = parseEnumDefinition(umlClass, childNode);
|
|
73
76
|
umlClasses.push(umlClass);
|
|
74
77
|
}
|
|
@@ -80,7 +83,7 @@ function convertAST2UmlClasses(node, relativePath, filesystem = false) {
|
|
|
80
83
|
const importPath = require.resolve(childNode.path, {
|
|
81
84
|
paths: [codeFolder],
|
|
82
85
|
});
|
|
83
|
-
|
|
86
|
+
const newImport = {
|
|
84
87
|
absolutePath: importPath,
|
|
85
88
|
classNames: childNode.symbolAliases
|
|
86
89
|
? childNode.symbolAliases.map((alias) => {
|
|
@@ -90,7 +93,9 @@ function convertAST2UmlClasses(node, relativePath, filesystem = false) {
|
|
|
90
93
|
};
|
|
91
94
|
})
|
|
92
95
|
: [],
|
|
93
|
-
}
|
|
96
|
+
};
|
|
97
|
+
debug(`Added filesystem import ${newImport.absolutePath} with class names ${newImport.classNames}`);
|
|
98
|
+
imports.push(newImport);
|
|
94
99
|
}
|
|
95
100
|
catch (err) {
|
|
96
101
|
debug(`Failed to resolve import ${childNode.path} from file ${relativePath}`);
|
|
@@ -98,10 +103,12 @@ function convertAST2UmlClasses(node, relativePath, filesystem = false) {
|
|
|
98
103
|
}
|
|
99
104
|
else {
|
|
100
105
|
// this has come from Etherscan
|
|
101
|
-
const importPath = childNode.path[0] === '
|
|
102
|
-
?
|
|
103
|
-
|
|
104
|
-
|
|
106
|
+
const importPath = childNode.path[0] === '.'
|
|
107
|
+
? // Use Linux paths, not Windows paths, to resolve Etherscan files
|
|
108
|
+
path_1.posix.join(codeFolder.toString(), childNode.path)
|
|
109
|
+
: childNode.path;
|
|
110
|
+
debug(`codeFolder ${codeFolder} childNode.path ${childNode.path}`);
|
|
111
|
+
const newImport = {
|
|
105
112
|
absolutePath: importPath,
|
|
106
113
|
classNames: childNode.symbolAliases
|
|
107
114
|
? childNode.symbolAliases.map((alias) => {
|
|
@@ -111,9 +118,12 @@ function convertAST2UmlClasses(node, relativePath, filesystem = false) {
|
|
|
111
118
|
};
|
|
112
119
|
})
|
|
113
120
|
: [],
|
|
114
|
-
}
|
|
121
|
+
};
|
|
122
|
+
debug(`Added Etherscan import ${newImport.absolutePath} with class names: ${newImport.classNames}`);
|
|
123
|
+
imports.push(newImport);
|
|
115
124
|
}
|
|
116
125
|
}
|
|
126
|
+
// TODO add file level constants
|
|
117
127
|
});
|
|
118
128
|
}
|
|
119
129
|
else {
|
|
@@ -36,7 +36,7 @@ export interface Storage {
|
|
|
36
36
|
* @param storage is mutated with the storage values
|
|
37
37
|
*/
|
|
38
38
|
export declare const addStorageValues: (url: string, contractAddress: string, storage: Storage, blockTag: string) => Promise<void>;
|
|
39
|
-
export declare const convertClasses2Storages: (contractName: string, umlClasses: UmlClass[]) => Storage[];
|
|
39
|
+
export declare const convertClasses2Storages: (contractName: string, umlClasses: UmlClass[], contractFilename?: string) => Storage[];
|
|
40
40
|
export declare const parseReferenceStorage: (attribute: Attribute, umlClass: UmlClass, otherClasses: UmlClass[], storages: Storage[]) => Storage | undefined;
|
|
41
41
|
export declare const calcStorageByteSize: (attribute: Attribute, umlClass: UmlClass, otherClasses: UmlClass[]) => {
|
|
42
42
|
size: number;
|
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
2
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
6
|
exports.findDimensionLength = exports.offsetStorageSlots = exports.calcSlotKey = exports.isElementary = exports.calcStorageByteSize = exports.parseReferenceStorage = exports.convertClasses2Storages = exports.addStorageValues = exports.StorageType = void 0;
|
|
4
7
|
const umlClass_1 = require("./umlClass");
|
|
@@ -6,6 +9,8 @@ const associations_1 = require("./associations");
|
|
|
6
9
|
const slotValues_1 = require("./slotValues");
|
|
7
10
|
const utils_1 = require("ethers/lib/utils");
|
|
8
11
|
const ethers_1 = require("ethers");
|
|
12
|
+
const path_1 = __importDefault(require("path"));
|
|
13
|
+
const debug = require('debug')('sol2uml');
|
|
9
14
|
var StorageType;
|
|
10
15
|
(function (StorageType) {
|
|
11
16
|
StorageType["Contract"] = "Contract";
|
|
@@ -29,14 +34,24 @@ const addStorageValues = async (url, contractAddress, storage, blockTag) => {
|
|
|
29
34
|
});
|
|
30
35
|
};
|
|
31
36
|
exports.addStorageValues = addStorageValues;
|
|
32
|
-
const convertClasses2Storages = (contractName, umlClasses) => {
|
|
37
|
+
const convertClasses2Storages = (contractName, umlClasses, contractFilename) => {
|
|
33
38
|
// Find the base UML Class from the base contract name
|
|
34
|
-
const umlClass = umlClasses.find(({ name }) => {
|
|
35
|
-
|
|
39
|
+
const umlClass = umlClasses.find(({ name, relativePath }) => {
|
|
40
|
+
if (!contractFilename) {
|
|
41
|
+
return name === contractName;
|
|
42
|
+
}
|
|
43
|
+
return (name === contractName &&
|
|
44
|
+
(relativePath == path_1.default.normalize(contractFilename) ||
|
|
45
|
+
path_1.default.basename(relativePath) ===
|
|
46
|
+
path_1.default.normalize(contractFilename)));
|
|
36
47
|
});
|
|
37
48
|
if (!umlClass) {
|
|
38
|
-
|
|
49
|
+
const contractFilenameError = contractFilename
|
|
50
|
+
? ` in filename "${contractFilename}"`
|
|
51
|
+
: '';
|
|
52
|
+
throw Error(`Failed to find contract with name "${contractName}"${contractFilenameError}`);
|
|
39
53
|
}
|
|
54
|
+
debug(`Found contract "${contractName}" in ${umlClass.absolutePath}`);
|
|
40
55
|
const storages = [];
|
|
41
56
|
const variables = parseVariables(umlClass, umlClasses, [], storages, []);
|
|
42
57
|
storages.unshift({
|
package/lib/parserEtherscan.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ASTNode } from '@solidity-parser/parser/dist/src/ast-types';
|
|
2
2
|
import { UmlClass } from './umlClass';
|
|
3
|
-
declare const networks: readonly ["mainnet", "ropsten", "kovan", "rinkeby", "goerli", "sepolia", "polygon", "
|
|
3
|
+
export declare const networks: readonly ["mainnet", "ropsten", "kovan", "rinkeby", "goerli", "sepolia", "polygon", "testnet.polygon", "arbitrum", "testnet.arbitrum", "avalanche", "testnet.avalanche", "bsc", "testnet.bsc", "crono", "fantom", "testnet.fantom", "moonbeam", "optimistic", "kovan-optimistic"];
|
|
4
4
|
declare type Network = typeof networks[number];
|
|
5
5
|
export declare class EtherscanParser {
|
|
6
6
|
protected apikey: string;
|
package/lib/parserEtherscan.js
CHANGED
|
@@ -3,13 +3,13 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.EtherscanParser = void 0;
|
|
6
|
+
exports.EtherscanParser = exports.networks = void 0;
|
|
7
7
|
const axios_1 = __importDefault(require("axios"));
|
|
8
8
|
const parser_1 = require("@solidity-parser/parser");
|
|
9
9
|
const converterAST2Classes_1 = require("./converterAST2Classes");
|
|
10
10
|
const filterClasses_1 = require("./filterClasses");
|
|
11
11
|
const debug = require('debug')('sol2uml');
|
|
12
|
-
|
|
12
|
+
exports.networks = [
|
|
13
13
|
'mainnet',
|
|
14
14
|
'ropsten',
|
|
15
15
|
'kovan',
|
|
@@ -17,15 +17,26 @@ const networks = [
|
|
|
17
17
|
'goerli',
|
|
18
18
|
'sepolia',
|
|
19
19
|
'polygon',
|
|
20
|
-
'
|
|
20
|
+
'testnet.polygon',
|
|
21
21
|
'arbitrum',
|
|
22
|
+
'testnet.arbitrum',
|
|
23
|
+
'avalanche',
|
|
24
|
+
'testnet.avalanche',
|
|
25
|
+
'bsc',
|
|
26
|
+
'testnet.bsc',
|
|
27
|
+
'crono',
|
|
28
|
+
'fantom',
|
|
29
|
+
'testnet.fantom',
|
|
30
|
+
'moonbeam',
|
|
31
|
+
'optimistic',
|
|
32
|
+
'kovan-optimistic',
|
|
22
33
|
];
|
|
23
34
|
class EtherscanParser {
|
|
24
35
|
constructor(apikey = 'ZAD4UI2RCXCQTP38EXS3UY2MPHFU5H9KB1', network = 'mainnet') {
|
|
25
36
|
this.apikey = apikey;
|
|
26
37
|
this.network = network;
|
|
27
|
-
if (!networks.includes(network)) {
|
|
28
|
-
throw new Error(`Invalid network "${network}". Must be one of ${networks}`);
|
|
38
|
+
if (!exports.networks.includes(network)) {
|
|
39
|
+
throw new Error(`Invalid network "${network}". Must be one of ${exports.networks}`);
|
|
29
40
|
}
|
|
30
41
|
else if (network === 'mainnet') {
|
|
31
42
|
this.url = 'https://api.etherscan.io/api';
|
|
@@ -34,12 +45,52 @@ class EtherscanParser {
|
|
|
34
45
|
this.url = 'https://api.polygonscan.com/api';
|
|
35
46
|
this.apikey = 'AMHGNTV5A7XYGX2M781JB3RC1DZFVRWQEB';
|
|
36
47
|
}
|
|
48
|
+
else if (network === 'testnet.polygon') {
|
|
49
|
+
this.url = 'https://api-testnet.polygonscan.com/api';
|
|
50
|
+
this.apikey = 'AMHGNTV5A7XYGX2M781JB3RC1DZFVRWQEB';
|
|
51
|
+
}
|
|
52
|
+
else if (network === 'arbitrum') {
|
|
53
|
+
this.url = 'https://api.arbiscan.io/api';
|
|
54
|
+
this.apikey = 'ZGTK2TAGWMAB6IAC12BMK8YYPNCPIM8VDQ';
|
|
55
|
+
}
|
|
56
|
+
else if (network === 'testnet.arbitrum') {
|
|
57
|
+
this.url = 'https://api-testnet.arbiscan.io/api';
|
|
58
|
+
this.apikey = 'ZGTK2TAGWMAB6IAC12BMK8YYPNCPIM8VDQ';
|
|
59
|
+
}
|
|
60
|
+
else if (network === 'avalanche') {
|
|
61
|
+
this.url = 'https://api.snowtrace.io/api';
|
|
62
|
+
this.apikey = 'U5FAN98S5XNH5VI83TI4H35R9I4TDCKEJY';
|
|
63
|
+
}
|
|
64
|
+
else if (network === 'testnet.avalanche') {
|
|
65
|
+
this.url = 'https://api-testnet.snowtrace.io/api';
|
|
66
|
+
this.apikey = 'U5FAN98S5XNH5VI83TI4H35R9I4TDCKEJY';
|
|
67
|
+
}
|
|
37
68
|
else if (network === 'bsc') {
|
|
38
69
|
this.url = 'https://api.bscscan.com/api';
|
|
70
|
+
}
|
|
71
|
+
else if (network === 'testnet.bsc') {
|
|
72
|
+
this.url = 'https://api-testnet.bscscan.com/api';
|
|
73
|
+
}
|
|
74
|
+
else if (network === 'crono') {
|
|
75
|
+
this.url = 'https://api.cronoscan.com/api';
|
|
76
|
+
this.apikey = '76A3RG5WHTPMMR66E9SFI2EIDT6MP976W2';
|
|
39
77
|
this.apikey = 'APYH49FXVY9UA3KTDI6F4WP3KPIC86NITN';
|
|
40
78
|
}
|
|
41
|
-
else if (network === '
|
|
42
|
-
this.url = 'https://api.
|
|
79
|
+
else if (network === 'fantom') {
|
|
80
|
+
this.url = 'https://api.ftmscan.com/api';
|
|
81
|
+
this.apikey = '71KRX13XPZMGR3D1Q85W78G2DSZ4JPMAEX';
|
|
82
|
+
}
|
|
83
|
+
else if (network === 'testnet.fantom') {
|
|
84
|
+
this.url = 'https://api-testnet.ftmscan.com/api';
|
|
85
|
+
this.apikey = '71KRX13XPZMGR3D1Q85W78G2DSZ4JPMAEX';
|
|
86
|
+
}
|
|
87
|
+
else if (network === 'optimistic' || network === 'kovan-optimistic') {
|
|
88
|
+
this.url = `https://api-${network}.etherscan.io/api`;
|
|
89
|
+
this.apikey = 'FEXS1HXVA4Y2RNTMEA8V1UTK21S4JWHH9U';
|
|
90
|
+
}
|
|
91
|
+
else if (network === 'moonbeam') {
|
|
92
|
+
this.url = 'https://api-moonbeam.moonscan.io/api';
|
|
93
|
+
this.apikey = '5EUFXW6TDC16VERF3D9SCWRRU6AEMTBHNJ';
|
|
43
94
|
}
|
|
44
95
|
else {
|
|
45
96
|
this.url = `https://api-${network}.etherscan.io/api`;
|
|
@@ -54,6 +105,7 @@ class EtherscanParser {
|
|
|
54
105
|
const { files, contractName } = await this.getSourceCode(contractAddress);
|
|
55
106
|
let umlClasses = [];
|
|
56
107
|
for (const file of files) {
|
|
108
|
+
debug(`Parsing source file ${file.filename}`);
|
|
57
109
|
const node = await this.parseSourceCode(file.code);
|
|
58
110
|
const umlClass = (0, converterAST2Classes_1.convertAST2UmlClasses)(node, file.filename);
|
|
59
111
|
umlClasses = umlClasses.concat(umlClass);
|
package/lib/sol2uml.js
CHANGED
|
@@ -10,8 +10,12 @@ const converterClasses2Storage_1 = require("./converterClasses2Storage");
|
|
|
10
10
|
const converterStorage2Dot_1 = require("./converterStorage2Dot");
|
|
11
11
|
const regEx_1 = require("./utils/regEx");
|
|
12
12
|
const writerFiles_1 = require("./writerFiles");
|
|
13
|
+
const path_1 = require("path");
|
|
13
14
|
const program = new commander_1.Command();
|
|
14
|
-
|
|
15
|
+
const version = (0, path_1.basename)(__dirname) === 'lib'
|
|
16
|
+
? require('../package.json').version // used when run from compile js in /lib
|
|
17
|
+
: require('../../package.json').version; // used when run from TypeScript source files under src/ts via ts-node
|
|
18
|
+
program.version(version);
|
|
15
19
|
const debugControl = require('debug');
|
|
16
20
|
const debug = require('debug')('sol2uml');
|
|
17
21
|
program
|
|
@@ -30,20 +34,10 @@ The Solidity code can be pulled from verified source code on Blockchain explorer
|
|
|
30
34
|
.option('-o, --outputFileName <value>', 'output file name')
|
|
31
35
|
.option('-i, --ignoreFilesOrFolders <filesOrFolders>', 'comma separated list of files or folders to ignore')
|
|
32
36
|
.addOption(new commander_1.Option('-n, --network <network>', 'Ethereum network')
|
|
33
|
-
.choices(
|
|
34
|
-
'mainnet',
|
|
35
|
-
'polygon',
|
|
36
|
-
'bsc',
|
|
37
|
-
'arbitrum',
|
|
38
|
-
'ropsten',
|
|
39
|
-
'kovan',
|
|
40
|
-
'rinkeby',
|
|
41
|
-
'goerli',
|
|
42
|
-
'sepolia',
|
|
43
|
-
])
|
|
37
|
+
.choices(parserEtherscan_1.networks)
|
|
44
38
|
.default('mainnet')
|
|
45
39
|
.env('ETH_NETWORK'))
|
|
46
|
-
.addOption(new commander_1.Option('-k, --apiKey <key>', 'Etherscan,
|
|
40
|
+
.addOption(new commander_1.Option('-k, --apiKey <key>', 'Blockchain explorer API key. eg Etherscan, Arbiscan, BscScan, CronoScan, FTMScan, PolygonScan or SnowTrace API key').env('SCAN_API_KEY'))
|
|
47
41
|
.option('-v, --verbose', 'run with debugging statements', false);
|
|
48
42
|
program
|
|
49
43
|
.command('class', { isDefault: true })
|
|
@@ -52,9 +46,9 @@ program
|
|
|
52
46
|
|
|
53
47
|
Generates UML diagrams from Solidity source code.
|
|
54
48
|
|
|
55
|
-
If no file, folder or address is
|
|
49
|
+
If no file, folder or address is passed as the first argument, the working folder is used.
|
|
56
50
|
When a folder is used, all *.sol files are found in that folder and all sub folders.
|
|
57
|
-
A comma separated list of files and folders can also used. For example
|
|
51
|
+
A comma separated list of files and folders can also be used. For example
|
|
58
52
|
sol2uml contracts,node_modules/openzeppelin-solidity
|
|
59
53
|
|
|
60
54
|
If an Ethereum address with a 0x prefix is passed, the verified source code from Etherscan will be used. For example
|
|
@@ -90,7 +84,8 @@ If an Ethereum address with a 0x prefix is passed, the verified source code from
|
|
|
90
84
|
debug(`Finished generating UML`);
|
|
91
85
|
}
|
|
92
86
|
catch (err) {
|
|
93
|
-
console.error(
|
|
87
|
+
console.error(err);
|
|
88
|
+
process.exit(2);
|
|
94
89
|
}
|
|
95
90
|
});
|
|
96
91
|
program
|
|
@@ -100,7 +95,8 @@ program
|
|
|
100
95
|
|
|
101
96
|
WARNING: sol2uml does not use the Solidity compiler so may differ with solc. A known example is fixed-sized arrays declared with an expression will fail to be sized.`)
|
|
102
97
|
.argument('<fileFolderAddress>', 'file name, base folder or contract address')
|
|
103
|
-
.option('-c, --contract <name>', 'Contract name in local Solidity files. Not needed when using an address as the first argument as the contract name can be derived from Etherscan.')
|
|
98
|
+
.option('-c, --contract <name>', 'Contract name in the local Solidity files. Not needed when using an address as the first argument as the contract name can be derived from Etherscan.')
|
|
99
|
+
.option('-cf, --contractFile <filename>', 'Filename the contract is located in. This can include the relative path to the desired file.')
|
|
104
100
|
.option('-d, --data', 'Gets the values in the storage slots from an Ethereum node.', false)
|
|
105
101
|
.option('-s, --storage <address>', 'The address of the contract with the storage values. This will be different from the contract with the code if a proxy contract is used. This is not needed if `fileFolderAddress` is an address and the contract is not proxied.')
|
|
106
102
|
.addOption(new commander_1.Option('-u, --url <url>', 'URL of the Ethereum node to get storage values if the `data` option is used.')
|
|
@@ -115,7 +111,7 @@ WARNING: sol2uml does not use the Solidity compiler so may differ with solc. A k
|
|
|
115
111
|
};
|
|
116
112
|
let { umlClasses, contractName } = await (0, parserGeneral_1.parserUmlClasses)(fileFolderAddress, combinedOptions);
|
|
117
113
|
contractName = combinedOptions.contract || contractName;
|
|
118
|
-
const storages = (0, converterClasses2Storage_1.convertClasses2Storages)(contractName, umlClasses);
|
|
114
|
+
const storages = (0, converterClasses2Storage_1.convertClasses2Storages)(contractName, umlClasses, combinedOptions.contractFile);
|
|
119
115
|
if ((0, regEx_1.isAddress)(fileFolderAddress)) {
|
|
120
116
|
// The first storage is the contract
|
|
121
117
|
storages[0].address = fileFolderAddress;
|
|
@@ -130,7 +126,7 @@ WARNING: sol2uml does not use the Solidity compiler so may differ with solc. A k
|
|
|
130
126
|
}
|
|
131
127
|
else {
|
|
132
128
|
if (!(0, regEx_1.isAddress)(fileFolderAddress)) {
|
|
133
|
-
throw Error(`Can not get storage slot values if first param is not an address and the \`
|
|
129
|
+
throw Error(`Can not get storage slot values if first param is not an address and the \`--storage\` option is not used.`);
|
|
134
130
|
}
|
|
135
131
|
storageAddress = fileFolderAddress;
|
|
136
132
|
}
|
|
@@ -143,7 +139,8 @@ WARNING: sol2uml does not use the Solidity compiler so may differ with solc. A k
|
|
|
143
139
|
await (0, writerFiles_1.writeOutputFiles)(dotString, fileFolderAddress, contractName || 'storageDiagram', combinedOptions.outputFormat, combinedOptions.outputFileName);
|
|
144
140
|
}
|
|
145
141
|
catch (err) {
|
|
146
|
-
console.error(
|
|
142
|
+
console.error(err.stack);
|
|
143
|
+
process.exit(2);
|
|
147
144
|
}
|
|
148
145
|
});
|
|
149
146
|
program
|
|
@@ -170,7 +167,8 @@ In order for the merged code to compile, the following is done:
|
|
|
170
167
|
await (0, writerFiles_1.writeSolidity)(solidityCode, outputFilename);
|
|
171
168
|
}
|
|
172
169
|
catch (err) {
|
|
173
|
-
console.error(
|
|
170
|
+
console.error(err);
|
|
171
|
+
process.exit(2);
|
|
174
172
|
}
|
|
175
173
|
});
|
|
176
174
|
program.on('option:verbose', () => {
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sol2uml",
|
|
3
|
-
"version": "2.1.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "2.1.6",
|
|
4
|
+
"description": "Solidity contract visualisation tool.",
|
|
5
5
|
"main": "./lib/index.js",
|
|
6
6
|
"types": "./lib/index.d.ts",
|
|
7
7
|
"scripts": {
|
|
@@ -54,14 +54,15 @@
|
|
|
54
54
|
"UML",
|
|
55
55
|
"Solidity",
|
|
56
56
|
"Ethereum",
|
|
57
|
-
"Class diagram",
|
|
58
|
-
"Class",
|
|
59
57
|
"diagram",
|
|
60
|
-
"
|
|
61
|
-
"
|
|
62
|
-
"
|
|
63
|
-
"SVG",
|
|
58
|
+
"class",
|
|
59
|
+
"diagram",
|
|
60
|
+
"contract",
|
|
64
61
|
"Blockchain",
|
|
65
|
-
"
|
|
62
|
+
"storage",
|
|
63
|
+
"flatten",
|
|
64
|
+
"visual",
|
|
65
|
+
"tool",
|
|
66
|
+
"cli"
|
|
66
67
|
]
|
|
67
68
|
}
|