sol2uml 2.1.7 → 2.2.0
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 +2 -0
- package/lib/associations.d.ts +1 -1
- package/lib/associations.js +11 -4
- package/lib/converterAST2Classes.js +1 -0
- package/lib/converterClass2Dot.d.ts +2 -0
- package/lib/converterClass2Dot.js +13 -5
- package/lib/converterClasses2Storage.js +3 -3
- package/lib/parserFiles.js +6 -1
- package/lib/sol2uml.js +6 -0
- package/lib/umlClass.d.ts +1 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -97,6 +97,8 @@ 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
|
+
-hm, --hideModifiers hide modifier functions from contracts (default: false)
|
|
101
|
+
-ht, --hideEvents hide events from contracts, interfaces and libraries (default: false)
|
|
100
102
|
-hc, --hideConstants hide file level constants (default: false)
|
|
101
103
|
-he, --hideEnums hide enum types (default: false)
|
|
102
104
|
-hs, --hideStructs hide data structures (default: false)
|
package/lib/associations.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import { Association, UmlClass } from './umlClass';
|
|
2
|
-
export declare const findAssociatedClass: (association: Association, sourceUmlClass: UmlClass, umlClasses: UmlClass[]) => UmlClass | undefined;
|
|
2
|
+
export declare const findAssociatedClass: (association: Association, sourceUmlClass: UmlClass, umlClasses: UmlClass[], searchedAbsolutePaths?: string[]) => UmlClass | undefined;
|
package/lib/associations.js
CHANGED
|
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.findAssociatedClass = void 0;
|
|
4
4
|
const umlClass_1 = require("./umlClass");
|
|
5
5
|
// Find the UML class linked to the association
|
|
6
|
-
const findAssociatedClass = (association, sourceUmlClass, umlClasses) => {
|
|
6
|
+
const findAssociatedClass = (association, sourceUmlClass, umlClasses, searchedAbsolutePaths = []) => {
|
|
7
7
|
let umlClass = umlClasses.find((targetUmlClass) => {
|
|
8
8
|
// is the source class link via the association to the target class?
|
|
9
9
|
if (isAssociated(association, sourceUmlClass, targetUmlClass))
|
|
@@ -28,7 +28,9 @@ const findAssociatedClass = (association, sourceUmlClass, umlClasses) => {
|
|
|
28
28
|
if (umlClass)
|
|
29
29
|
return umlClass;
|
|
30
30
|
// Could not find a link so now need to recursively look at imports of imports
|
|
31
|
-
|
|
31
|
+
// add to already recursively processed files to avoid getting stuck in circular imports
|
|
32
|
+
searchedAbsolutePaths.push(sourceUmlClass.absolutePath);
|
|
33
|
+
return findImplicitImport(association, sourceUmlClass, umlClasses, searchedAbsolutePaths);
|
|
32
34
|
};
|
|
33
35
|
exports.findAssociatedClass = findAssociatedClass;
|
|
34
36
|
// Tests if source class can be linked to the target class via an association
|
|
@@ -54,7 +56,7 @@ const isAssociated = (association, sourceUmlClass, targetUmlClass) => {
|
|
|
54
56
|
importedClass.alias &&
|
|
55
57
|
importedClass.className === targetUmlClass.name))));
|
|
56
58
|
};
|
|
57
|
-
const findImplicitImport = (association, sourceUmlClass, umlClasses) => {
|
|
59
|
+
const findImplicitImport = (association, sourceUmlClass, umlClasses, searchedRelativePaths) => {
|
|
58
60
|
// Get all implicit imports. That is, imports that do not explicitly import contracts or interfaces.
|
|
59
61
|
const implicitImports = sourceUmlClass.imports.filter((i) => i.classNames.length === 0);
|
|
60
62
|
// For each implicit import
|
|
@@ -65,8 +67,13 @@ const findImplicitImport = (association, sourceUmlClass, umlClasses) => {
|
|
|
65
67
|
// Could not find a class in the import file so just move onto the next loop
|
|
66
68
|
continue;
|
|
67
69
|
}
|
|
70
|
+
// Avoid circular imports
|
|
71
|
+
if (searchedRelativePaths.includes(newSourceUmlClass.absolutePath)) {
|
|
72
|
+
// Have already recursively looked for imports of imports in this file
|
|
73
|
+
continue;
|
|
74
|
+
}
|
|
68
75
|
// TODO need to handle imports that use aliases as the association will not be found
|
|
69
|
-
const umlClass = (0, exports.findAssociatedClass)(association, newSourceUmlClass, umlClasses);
|
|
76
|
+
const umlClass = (0, exports.findAssociatedClass)(association, newSourceUmlClass, umlClasses, searchedRelativePaths);
|
|
70
77
|
if (umlClass)
|
|
71
78
|
return umlClass;
|
|
72
79
|
}
|
|
@@ -265,6 +265,7 @@ function parseContractDefinition(umlClass, node) {
|
|
|
265
265
|
stereotype,
|
|
266
266
|
parameters: parseParameters(subNode.parameters),
|
|
267
267
|
returnParameters: parseParameters(subNode.returnParameters),
|
|
268
|
+
modifiers: subNode.modifiers.map((m) => m.name),
|
|
268
269
|
});
|
|
269
270
|
}
|
|
270
271
|
// Recursively parse function parameters for associations
|
|
@@ -62,7 +62,7 @@ const dotClassTitle = (umlClass, options = {}) => {
|
|
|
62
62
|
}
|
|
63
63
|
return `\\<\\<${stereoName}\\>\\>\\n${umlClass.name}${relativePath}`;
|
|
64
64
|
};
|
|
65
|
-
const dotAttributeVisibilities = (umlClass, options
|
|
65
|
+
const dotAttributeVisibilities = (umlClass, options) => {
|
|
66
66
|
if (umlClass.attributes.length === 0)
|
|
67
67
|
return '';
|
|
68
68
|
let dotString = '| ';
|
|
@@ -115,7 +115,7 @@ const dotAttributes = (attributes, vizGroup, indent = true) => {
|
|
|
115
115
|
});
|
|
116
116
|
return dotString;
|
|
117
117
|
};
|
|
118
|
-
const dotOperatorVisibilities = (umlClass, options
|
|
118
|
+
const dotOperatorVisibilities = (umlClass, options) => {
|
|
119
119
|
if (umlClass.operators.length === 0)
|
|
120
120
|
return '';
|
|
121
121
|
let dotString = '| ';
|
|
@@ -146,11 +146,11 @@ const dotOperatorVisibilities = (umlClass, options = {}) => {
|
|
|
146
146
|
operators.push(operator);
|
|
147
147
|
}
|
|
148
148
|
}
|
|
149
|
-
dotString += dotOperators(umlClass, vizGroup, operators);
|
|
149
|
+
dotString += dotOperators(umlClass, vizGroup, operators, options);
|
|
150
150
|
}
|
|
151
151
|
return dotString;
|
|
152
152
|
};
|
|
153
|
-
const dotOperators = (umlClass, vizGroup, operators) => {
|
|
153
|
+
const dotOperators = (umlClass, vizGroup, operators, options) => {
|
|
154
154
|
// Skip if there are no operators
|
|
155
155
|
if (!operators || operators.length === 0) {
|
|
156
156
|
return '';
|
|
@@ -160,7 +160,12 @@ const dotOperators = (umlClass, vizGroup, operators) => {
|
|
|
160
160
|
const operatorsSortedByStereotype = operators.sort((a, b) => {
|
|
161
161
|
return b.stereotype - a.stereotype;
|
|
162
162
|
});
|
|
163
|
-
|
|
163
|
+
// Filter out any modifiers or events if options are flagged to hide them
|
|
164
|
+
let operatorsFiltered = operatorsSortedByStereotype.filter((o) => !((options.hideModifiers === true &&
|
|
165
|
+
o.stereotype === umlClass_1.OperatorStereotype.Modifier) ||
|
|
166
|
+
(options.hideEvents === true &&
|
|
167
|
+
o.stereotype === umlClass_1.OperatorStereotype.Event)));
|
|
168
|
+
for (const operator of operatorsFiltered) {
|
|
164
169
|
dotString += '\\ \\ \\ \\ ';
|
|
165
170
|
if (operator.stereotype > 0) {
|
|
166
171
|
dotString += dotOperatorStereotype(umlClass, operator.stereotype);
|
|
@@ -170,6 +175,9 @@ const dotOperators = (umlClass, vizGroup, operators) => {
|
|
|
170
175
|
if (operator.returnParameters?.length > 0) {
|
|
171
176
|
dotString += ': ' + dotParameters(operator.returnParameters, true);
|
|
172
177
|
}
|
|
178
|
+
if (options.hideModifiers === false && operator.modifiers?.length > 0) {
|
|
179
|
+
dotString += ` \\<\\<${operator.modifiers.join(', ')}\\>\\>`;
|
|
180
|
+
}
|
|
173
181
|
dotString += '\\l';
|
|
174
182
|
}
|
|
175
183
|
return dotString;
|
|
@@ -29,8 +29,8 @@ const addStorageValues = async (url, contractAddress, storage, blockTag) => {
|
|
|
29
29
|
const valueVariables = storage.variables.filter((s) => !s.noValue);
|
|
30
30
|
const slots = valueVariables.map((s) => s.fromSlot);
|
|
31
31
|
const values = await (0, slotValues_1.getStorageValues)(url, contractAddress, slots, blockTag);
|
|
32
|
-
valueVariables.forEach((
|
|
33
|
-
|
|
32
|
+
valueVariables.forEach((valueVariable, i) => {
|
|
33
|
+
valueVariable.value = values[i];
|
|
34
34
|
});
|
|
35
35
|
};
|
|
36
36
|
exports.addStorageValues = addStorageValues;
|
|
@@ -49,7 +49,7 @@ const convertClasses2Storages = (contractName, umlClasses, contractFilename) =>
|
|
|
49
49
|
const contractFilenameError = contractFilename
|
|
50
50
|
? ` in filename "${contractFilename}"`
|
|
51
51
|
: '';
|
|
52
|
-
throw Error(`Failed to find contract with name "${contractName}"${contractFilenameError}
|
|
52
|
+
throw Error(`Failed to find contract with name "${contractName}"${contractFilenameError}.\nIs the \`-c --contract <name>\` option correct?`);
|
|
53
53
|
}
|
|
54
54
|
debug(`Found contract "${contractName}" in ${umlClass.absolutePath}`);
|
|
55
55
|
const storages = [];
|
package/lib/parserFiles.js
CHANGED
|
@@ -48,7 +48,12 @@ function getSolidityFilesFromFolderOrFile(folderOrFilePath, ignoreFilesOrFolders
|
|
|
48
48
|
preserveSymlinks: true,
|
|
49
49
|
})
|
|
50
50
|
.on('data', (file) => {
|
|
51
|
-
if (
|
|
51
|
+
if (
|
|
52
|
+
// If file has sol extension
|
|
53
|
+
(0, path_1.extname)(file.path) === '.sol' &&
|
|
54
|
+
// and file and not a folder
|
|
55
|
+
// Note Foundry's forge outputs folders with the same name as the source file
|
|
56
|
+
file.stats.isFile())
|
|
52
57
|
files.push(file.path);
|
|
53
58
|
})
|
|
54
59
|
.on('end', () => {
|
package/lib/sol2uml.js
CHANGED
|
@@ -60,6 +60,8 @@ 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('-hm, --hideModifiers', 'hide modifier functions from contracts', false)
|
|
64
|
+
.option('-ht, --hideEvents', 'hide events from contracts, interfaces and libraries', false)
|
|
63
65
|
.option('-hc, --hideConstants', 'hide file level constants', false)
|
|
64
66
|
.option('-he, --hideEnums', 'hide enum types', false)
|
|
65
67
|
.option('-hs, --hideStructs', 'hide data structures', false)
|
|
@@ -110,6 +112,10 @@ WARNING: sol2uml does not use the Solidity compiler so may differ with solc. A k
|
|
|
110
112
|
...command.parent._optionValues,
|
|
111
113
|
...options,
|
|
112
114
|
};
|
|
115
|
+
// If not an address and the contractName option has not been specified
|
|
116
|
+
if (!(0, regEx_1.isAddress)(fileFolderAddress) && !combinedOptions.contract) {
|
|
117
|
+
throw Error(`Must use the \`-c, --contract <name>\` option to specify the contract to draw the storage diagram for when sourcing from local files.\nThis option is not needed when sourcing from a blockchain explorer with a contract address.`);
|
|
118
|
+
}
|
|
113
119
|
let { umlClasses, contractName } = await (0, parserGeneral_1.parserUmlClasses)(fileFolderAddress, combinedOptions);
|
|
114
120
|
contractName = combinedOptions.contract || contractName;
|
|
115
121
|
const storages = (0, converterClasses2Storage_1.convertClasses2Storages)(contractName, umlClasses, combinedOptions.contractFile);
|
package/lib/umlClass.d.ts
CHANGED