sol2uml 2.1.4 → 2.1.7
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 +10 -8
- package/lib/converterAST2Classes.js +64 -16
- package/lib/converterClass2Dot.d.ts +1 -0
- package/lib/converterClass2Dot.js +9 -3
- package/lib/converterClasses2Dot.js +4 -2
- package/lib/converterClasses2Storage.d.ts +1 -1
- package/lib/converterClasses2Storage.js +30 -11
- package/lib/parserEtherscan.js +1 -0
- package/lib/sol2uml.js +7 -5
- package/lib/umlClass.d.ts +2 -1
- package/lib/umlClass.js +1 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -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
|
|
@@ -97,6 +97,7 @@ Options:
|
|
|
97
97
|
-hv, --hideVariables hide variables from contracts, interfaces, structs and enums (default: false)
|
|
98
98
|
-hf, --hideFunctions hide functions from contracts, interfaces and libraries (default: false)
|
|
99
99
|
-hp, --hidePrivates hide private and internal attributes and operators (default: false)
|
|
100
|
+
-hc, --hideConstants hide file level constants (default: false)
|
|
100
101
|
-he, --hideEnums hide enum types (default: false)
|
|
101
102
|
-hs, --hideStructs hide data structures (default: false)
|
|
102
103
|
-hl, --hideLibraries hide libraries (default: false)
|
|
@@ -119,12 +120,13 @@ Arguments:
|
|
|
119
120
|
fileFolderAddress file name, base folder or contract address
|
|
120
121
|
|
|
121
122
|
Options:
|
|
122
|
-
-c, --contract <name>
|
|
123
|
-
-
|
|
124
|
-
-
|
|
125
|
-
-
|
|
126
|
-
-
|
|
127
|
-
-
|
|
123
|
+
-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.
|
|
124
|
+
-cf, --contractFile <filename> Filename the contract is located in. This can include the relative path to the desired file.
|
|
125
|
+
-d, --data Gets the values in the storage slots from an Ethereum node. (default: false)
|
|
126
|
+
-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.
|
|
127
|
+
-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)
|
|
128
|
+
-bn, --block <number> Block number to get the contract storage values from. (default: "latest")
|
|
129
|
+
-h, --help display help for command
|
|
128
130
|
```
|
|
129
131
|
|
|
130
132
|
### 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,10 +44,11 @@ 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') {
|
|
50
|
-
debug(`Adding struct ${childNode.name}`);
|
|
51
|
+
debug(`Adding file level struct ${childNode.name}`);
|
|
51
52
|
let umlClass = new umlClass_1.UmlClass({
|
|
52
53
|
name: childNode.name,
|
|
53
54
|
stereotype: umlClass_1.ClassStereotype.Struct,
|
|
@@ -57,10 +58,11 @@ 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') {
|
|
63
|
-
debug(`Adding enum ${childNode.name}`);
|
|
65
|
+
debug(`Adding file level enum ${childNode.name}`);
|
|
64
66
|
let umlClass = new umlClass_1.UmlClass({
|
|
65
67
|
name: childNode.name,
|
|
66
68
|
stereotype: umlClass_1.ClassStereotype.Enum,
|
|
@@ -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,8 +118,40 @@ function convertAST2UmlClasses(node, relativePath, filesystem = false) {
|
|
|
111
118
|
};
|
|
112
119
|
})
|
|
113
120
|
: [],
|
|
121
|
+
};
|
|
122
|
+
debug(`Added Etherscan import ${newImport.absolutePath} with class names: ${newImport.classNames}`);
|
|
123
|
+
imports.push(newImport);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
else if (childNode.type === 'FileLevelConstant') {
|
|
127
|
+
debug(`Adding file level constant ${childNode.name}`);
|
|
128
|
+
const [type, attributeType] = parseTypeName(childNode.typeName);
|
|
129
|
+
const umlClass = new umlClass_1.UmlClass({
|
|
130
|
+
name: childNode.name,
|
|
131
|
+
stereotype: umlClass_1.ClassStereotype.Constant,
|
|
132
|
+
absolutePath: filesystem
|
|
133
|
+
? path.resolve(relativePath) // resolve the absolute path
|
|
134
|
+
: relativePath,
|
|
135
|
+
relativePath,
|
|
136
|
+
attributes: [
|
|
137
|
+
{
|
|
138
|
+
name: childNode.name,
|
|
139
|
+
type,
|
|
140
|
+
attributeType,
|
|
141
|
+
},
|
|
142
|
+
],
|
|
143
|
+
});
|
|
144
|
+
if (childNode?.initialValue?.type === 'NumberLiteral') {
|
|
145
|
+
umlClass.constants.push({
|
|
146
|
+
name: childNode.name,
|
|
147
|
+
value: parseInt(childNode.initialValue.number),
|
|
114
148
|
});
|
|
115
149
|
}
|
|
150
|
+
// TODO handle expressions. eg N_COINS * 2
|
|
151
|
+
umlClasses.push(umlClass);
|
|
152
|
+
}
|
|
153
|
+
else if (childNode.type !== 'PragmaDirective') {
|
|
154
|
+
debug(`node type "${childNode.type}" not parsed in ${relativePath}`);
|
|
116
155
|
}
|
|
117
156
|
});
|
|
118
157
|
}
|
|
@@ -337,13 +376,22 @@ function addAssociations(nodes, umlClass) {
|
|
|
337
376
|
], umlClass);
|
|
338
377
|
// Array of user defined types
|
|
339
378
|
}
|
|
340
|
-
else if (node.typeName.type == 'ArrayTypeName'
|
|
341
|
-
node.typeName.baseTypeName.type ===
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
379
|
+
else if (node.typeName.type == 'ArrayTypeName') {
|
|
380
|
+
if (node.typeName.baseTypeName.type ===
|
|
381
|
+
'UserDefinedTypeName') {
|
|
382
|
+
const { umlClassName } = parseClassName(node.typeName.baseTypeName.namePath);
|
|
383
|
+
umlClass.addAssociation({
|
|
384
|
+
referenceType,
|
|
385
|
+
targetUmlClassName: umlClassName,
|
|
386
|
+
});
|
|
387
|
+
}
|
|
388
|
+
else if (node.typeName.length?.type === 'Identifier') {
|
|
389
|
+
const { umlClassName } = parseClassName(node.typeName.length.name);
|
|
390
|
+
umlClass.addAssociation({
|
|
391
|
+
referenceType,
|
|
392
|
+
targetUmlClassName: umlClassName,
|
|
393
|
+
});
|
|
394
|
+
}
|
|
347
395
|
}
|
|
348
396
|
break;
|
|
349
397
|
case 'UserDefinedTypeName':
|
|
@@ -14,7 +14,9 @@ const convertClass2Dot = (umlClass, options = {}) => {
|
|
|
14
14
|
umlClass.stereotype === umlClass_1.ClassStereotype.Abstract) ||
|
|
15
15
|
(options.hideStructs &&
|
|
16
16
|
umlClass.stereotype === umlClass_1.ClassStereotype.Struct) ||
|
|
17
|
-
(options.hideEnums && umlClass.stereotype === umlClass_1.ClassStereotype.Enum)
|
|
17
|
+
(options.hideEnums && umlClass.stereotype === umlClass_1.ClassStereotype.Enum) ||
|
|
18
|
+
(options.hideConstants &&
|
|
19
|
+
umlClass.stereotype === umlClass_1.ClassStereotype.Constant)) {
|
|
18
20
|
return '';
|
|
19
21
|
}
|
|
20
22
|
let dotString = `\n${umlClass.id} [label="{${dotClassTitle(umlClass, options)}`;
|
|
@@ -51,6 +53,9 @@ const dotClassTitle = (umlClass, options = {}) => {
|
|
|
51
53
|
case umlClass_1.ClassStereotype.Enum:
|
|
52
54
|
stereoName = 'Enum';
|
|
53
55
|
break;
|
|
56
|
+
case umlClass_1.ClassStereotype.Constant:
|
|
57
|
+
stereoName = 'Constant';
|
|
58
|
+
break;
|
|
54
59
|
default:
|
|
55
60
|
// Contract or undefined stereotype will just return the UmlClass name
|
|
56
61
|
return `${umlClass.name}${relativePath}`;
|
|
@@ -61,9 +66,10 @@ const dotAttributeVisibilities = (umlClass, options = {}) => {
|
|
|
61
66
|
if (umlClass.attributes.length === 0)
|
|
62
67
|
return '';
|
|
63
68
|
let dotString = '| ';
|
|
64
|
-
// if a struct or
|
|
69
|
+
// if a struct, enum or constant then no visibility group
|
|
65
70
|
if (umlClass.stereotype === umlClass_1.ClassStereotype.Struct ||
|
|
66
|
-
umlClass.stereotype === umlClass_1.ClassStereotype.Enum
|
|
71
|
+
umlClass.stereotype === umlClass_1.ClassStereotype.Enum ||
|
|
72
|
+
umlClass.stereotype === umlClass_1.ClassStereotype.Constant) {
|
|
67
73
|
return dotString + dotAttributes(umlClass.attributes, undefined, false);
|
|
68
74
|
}
|
|
69
75
|
// For each visibility group
|
|
@@ -90,7 +90,7 @@ function addAssociationsToDot(umlClasses, classOptions = {}) {
|
|
|
90
90
|
exports.addAssociationsToDot = addAssociationsToDot;
|
|
91
91
|
function addAssociationToDot(sourceUmlClass, targetUmlClass, association, classOptions = {}) {
|
|
92
92
|
// do not include library or interface associations if hidden
|
|
93
|
-
// Or associations to Structs or
|
|
93
|
+
// Or associations to Structs, Enums or Constants if they are hidden
|
|
94
94
|
if ((classOptions.hideLibraries &&
|
|
95
95
|
(sourceUmlClass.stereotype === umlClass_1.ClassStereotype.Library ||
|
|
96
96
|
targetUmlClass.stereotype === umlClass_1.ClassStereotype.Library)) ||
|
|
@@ -103,7 +103,9 @@ function addAssociationToDot(sourceUmlClass, targetUmlClass, association, classO
|
|
|
103
103
|
(classOptions.hideStructs &&
|
|
104
104
|
targetUmlClass.stereotype === umlClass_1.ClassStereotype.Struct) ||
|
|
105
105
|
(classOptions.hideEnums &&
|
|
106
|
-
targetUmlClass.stereotype === umlClass_1.ClassStereotype.Enum)
|
|
106
|
+
targetUmlClass.stereotype === umlClass_1.ClassStereotype.Enum) ||
|
|
107
|
+
(classOptions.hideConstants &&
|
|
108
|
+
targetUmlClass.stereotype === umlClass_1.ClassStereotype.Constant)) {
|
|
107
109
|
return '';
|
|
108
110
|
}
|
|
109
111
|
let dotString = `\n${sourceUmlClass.id} -> ${targetUmlClass.id} [`;
|
|
@@ -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({
|
|
@@ -162,25 +177,29 @@ const parseReferenceStorage = (attribute, umlClass, otherClasses, storages) => {
|
|
|
162
177
|
attributeType: baseAttributeType,
|
|
163
178
|
};
|
|
164
179
|
const { size: arrayItemSize } = (0, exports.calcStorageByteSize)(baseAttribute, umlClass, otherClasses);
|
|
165
|
-
const
|
|
180
|
+
const arraySlotSize = arrayItemSize > 16
|
|
181
|
+
? 32 * Math.ceil(arrayItemSize / 32)
|
|
182
|
+
: arrayItemSize;
|
|
183
|
+
const variables = [];
|
|
184
|
+
variables[0] = {
|
|
166
185
|
id: variableId++,
|
|
167
186
|
fromSlot: 0,
|
|
168
|
-
toSlot: Math.floor((
|
|
187
|
+
toSlot: Math.floor((arraySlotSize - 1) / 32),
|
|
169
188
|
byteSize: arrayItemSize,
|
|
170
189
|
byteOffset: 0,
|
|
171
190
|
type: baseType,
|
|
172
191
|
dynamic,
|
|
173
192
|
noValue: false,
|
|
174
193
|
};
|
|
175
|
-
const variables = [firstVariable];
|
|
176
194
|
if (arrayLength > 1) {
|
|
195
|
+
// For fixed length arrays. Dynamic arrays will have undefined arrayLength
|
|
177
196
|
for (let i = 1; i < arrayLength; i++) {
|
|
178
197
|
variables.push({
|
|
179
198
|
id: variableId++,
|
|
180
|
-
fromSlot: Math.floor((i *
|
|
181
|
-
toSlot: Math.floor(((i + 1) *
|
|
199
|
+
fromSlot: Math.floor((i * arraySlotSize) / 32),
|
|
200
|
+
toSlot: Math.floor(((i + 1) * arraySlotSize - 1) / 32),
|
|
182
201
|
byteSize: arrayItemSize,
|
|
183
|
-
byteOffset: (i *
|
|
202
|
+
byteOffset: (i * arraySlotSize) % 32,
|
|
184
203
|
type: baseType,
|
|
185
204
|
dynamic,
|
|
186
205
|
noValue: false,
|
|
@@ -190,7 +209,7 @@ const parseReferenceStorage = (attribute, umlClass, otherClasses, storages) => {
|
|
|
190
209
|
// recursively add storage
|
|
191
210
|
if (baseAttributeType !== umlClass_1.AttributeType.Elementary) {
|
|
192
211
|
const referenceStorage = (0, exports.parseReferenceStorage)(baseAttribute, umlClass, otherClasses, storages);
|
|
193
|
-
|
|
212
|
+
variables[0].referenceStorageId = referenceStorage?.id;
|
|
194
213
|
}
|
|
195
214
|
const newStorage = {
|
|
196
215
|
id: storageId++,
|
package/lib/parserEtherscan.js
CHANGED
|
@@ -105,6 +105,7 @@ class EtherscanParser {
|
|
|
105
105
|
const { files, contractName } = await this.getSourceCode(contractAddress);
|
|
106
106
|
let umlClasses = [];
|
|
107
107
|
for (const file of files) {
|
|
108
|
+
debug(`Parsing source file ${file.filename}`);
|
|
108
109
|
const node = await this.parseSourceCode(file.code);
|
|
109
110
|
const umlClass = (0, converterAST2Classes_1.convertAST2UmlClasses)(node, file.filename);
|
|
110
111
|
umlClasses = umlClasses.concat(umlClass);
|
package/lib/sol2uml.js
CHANGED
|
@@ -46,9 +46,9 @@ program
|
|
|
46
46
|
|
|
47
47
|
Generates UML diagrams from Solidity source code.
|
|
48
48
|
|
|
49
|
-
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.
|
|
50
50
|
When a folder is used, all *.sol files are found in that folder and all sub folders.
|
|
51
|
-
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
|
|
52
52
|
sol2uml contracts,node_modules/openzeppelin-solidity
|
|
53
53
|
|
|
54
54
|
If an Ethereum address with a 0x prefix is passed, the verified source code from Etherscan will be used. For example
|
|
@@ -60,6 +60,7 @@ If an Ethereum address with a 0x prefix is passed, the verified source code from
|
|
|
60
60
|
.option('-hv, --hideVariables', 'hide variables from contracts, interfaces, structs and enums', false)
|
|
61
61
|
.option('-hf, --hideFunctions', 'hide functions from contracts, interfaces and libraries', false)
|
|
62
62
|
.option('-hp, --hidePrivates', 'hide private and internal attributes and operators', false)
|
|
63
|
+
.option('-hc, --hideConstants', 'hide file level constants', false)
|
|
63
64
|
.option('-he, --hideEnums', 'hide enum types', false)
|
|
64
65
|
.option('-hs, --hideStructs', 'hide data structures', false)
|
|
65
66
|
.option('-hl, --hideLibraries', 'hide libraries', false)
|
|
@@ -95,7 +96,8 @@ program
|
|
|
95
96
|
|
|
96
97
|
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.`)
|
|
97
98
|
.argument('<fileFolderAddress>', 'file name, base folder or contract address')
|
|
98
|
-
.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.')
|
|
99
|
+
.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.')
|
|
100
|
+
.option('-cf, --contractFile <filename>', 'Filename the contract is located in. This can include the relative path to the desired file.')
|
|
99
101
|
.option('-d, --data', 'Gets the values in the storage slots from an Ethereum node.', false)
|
|
100
102
|
.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.')
|
|
101
103
|
.addOption(new commander_1.Option('-u, --url <url>', 'URL of the Ethereum node to get storage values if the `data` option is used.')
|
|
@@ -110,7 +112,7 @@ WARNING: sol2uml does not use the Solidity compiler so may differ with solc. A k
|
|
|
110
112
|
};
|
|
111
113
|
let { umlClasses, contractName } = await (0, parserGeneral_1.parserUmlClasses)(fileFolderAddress, combinedOptions);
|
|
112
114
|
contractName = combinedOptions.contract || contractName;
|
|
113
|
-
const storages = (0, converterClasses2Storage_1.convertClasses2Storages)(contractName, umlClasses);
|
|
115
|
+
const storages = (0, converterClasses2Storage_1.convertClasses2Storages)(contractName, umlClasses, combinedOptions.contractFile);
|
|
114
116
|
if ((0, regEx_1.isAddress)(fileFolderAddress)) {
|
|
115
117
|
// The first storage is the contract
|
|
116
118
|
storages[0].address = fileFolderAddress;
|
|
@@ -125,7 +127,7 @@ WARNING: sol2uml does not use the Solidity compiler so may differ with solc. A k
|
|
|
125
127
|
}
|
|
126
128
|
else {
|
|
127
129
|
if (!(0, regEx_1.isAddress)(fileFolderAddress)) {
|
|
128
|
-
throw Error(`Can not get storage slot values if first param is not an address and the \`
|
|
130
|
+
throw Error(`Can not get storage slot values if first param is not an address and the \`--storage\` option is not used.`);
|
|
129
131
|
}
|
|
130
132
|
storageAddress = fileFolderAddress;
|
|
131
133
|
}
|
package/lib/umlClass.d.ts
CHANGED
package/lib/umlClass.js
CHANGED
|
@@ -18,6 +18,7 @@ var ClassStereotype;
|
|
|
18
18
|
ClassStereotype[ClassStereotype["Contract"] = 4] = "Contract";
|
|
19
19
|
ClassStereotype[ClassStereotype["Struct"] = 5] = "Struct";
|
|
20
20
|
ClassStereotype[ClassStereotype["Enum"] = 6] = "Enum";
|
|
21
|
+
ClassStereotype[ClassStereotype["Constant"] = 7] = "Constant";
|
|
21
22
|
})(ClassStereotype = exports.ClassStereotype || (exports.ClassStereotype = {}));
|
|
22
23
|
var OperatorStereotype;
|
|
23
24
|
(function (OperatorStereotype) {
|