sol2uml 2.5.21 → 2.5.22
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 +8 -9
- package/lib/associations.js +75 -45
- package/lib/converterAST2Classes.js +24 -14
- package/lib/converterClasses2Dot.js +2 -3
- package/lib/converterStorage2Dot.js +2 -2
- package/lib/parserEtherscan.d.ts +4 -3
- package/lib/parserEtherscan.js +68 -71
- package/lib/parserFiles.js +4 -4
- package/lib/parserGeneral.js +1 -1
- package/lib/slotValues.d.ts +2 -2
- package/lib/sol2uml.js +5 -7
- package/lib/squashClasses.js +17 -7
- package/lib/utils/diff.js +17 -7
- package/lib/writerFiles.js +6 -6
- package/package.json +15 -15
package/README.md
CHANGED
|
@@ -57,9 +57,9 @@ Options:
|
|
|
57
57
|
-f, --outputFormat <value> output file format. (choices: "svg", "png", "dot", "all", default: "svg")
|
|
58
58
|
-o, --outputFileName <value> output file name
|
|
59
59
|
-i, --ignoreFilesOrFolders <names> comma-separated list of files or folders to ignore
|
|
60
|
-
-n, --network <network>
|
|
60
|
+
-n, --network <network> Name or chain id of the blockchain explorer. A name like `ethereum` or `base` will map to a chain id, eg 1 or 8453. Alternatively, use an integer of the chain id. Supported names: ethereum, sepolia, holesky, hoodi, arbitrum, optimism, polygon, avalanche, base, bsc, crono, fantom, sonic, gnosis, moonbeam, celo, scroll, linea, blast, berachain, zksync (default: "ethereum", env: ETH_NETWORK)
|
|
61
61
|
-e, --explorerUrl <url> Override the `network` option with a custom blockchain explorer API URL. eg Polygon Mumbai testnet https://api-testnet.polygonscan.com/api (env: EXPLORER_URL)
|
|
62
|
-
-k, --apiKey <key> Blockchain explorer API key.
|
|
62
|
+
-k, --apiKey <key> Blockchain explorer API key. (env: SCAN_API_KEY)
|
|
63
63
|
-bc, --backColor <color> Canvas background color. "none" will use a transparent canvas. (default: "white")
|
|
64
64
|
-sc, --shapeColor <color> Basic drawing color for graphics, not text (default: "black")
|
|
65
65
|
-fc, --fillColor <color> Color used to fill the background of a node (default: "gray95")
|
|
@@ -81,7 +81,7 @@ Commands:
|
|
|
81
81
|
3. File imports are commented out.
|
|
82
82
|
4. "SPDX-License-Identifier" is renamed to "SPDX--License-Identifier".
|
|
83
83
|
5. Contract dependencies are analysed so the files are merged in an order that will compile.
|
|
84
|
-
diff [options] <addressA> <fileFoldersAddress> Compare verified
|
|
84
|
+
diff [options] <addressA> <fileFoldersAddress> Compare verified contract code on Etherscan-like explorers to another verified contract, a local file or multiple local files.
|
|
85
85
|
|
|
86
86
|
The results show the comparison of contract A to B.
|
|
87
87
|
The green sections are additions to contract B that are not in contract A.
|
|
@@ -106,7 +106,7 @@ Arguments:
|
|
|
106
106
|
sol2uml 0x79fEbF6B9F76853EDBcBc913e6aAE8232cFB9De9
|
|
107
107
|
|
|
108
108
|
Options:
|
|
109
|
-
-b, --baseContractNames <names> only output contracts connected to these comma
|
|
109
|
+
-b, --baseContractNames <names> only output contracts connected to these comma-separated base contract names
|
|
110
110
|
-d, --depth <value> depth of connected classes to the base contracts. 1 will only show directly connected contracts, interfaces, libraries, structs and enums. (default: all)
|
|
111
111
|
-c, --clusterFolders cluster contracts into source folders (default: false)
|
|
112
112
|
-hv, --hideVariables hide variables from contracts, interfaces, structs and enums (default: false)
|
|
@@ -139,8 +139,8 @@ WARNING: sol2uml does not use the Solidity compiler so may differ with solc. A k
|
|
|
139
139
|
Arguments:
|
|
140
140
|
fileFolderAddress file name, folder(s) or contract address.
|
|
141
141
|
When a folder is used, all *.sol files in that folder and all sub folders are used.
|
|
142
|
-
A comma-separated list of files and folders can also be used. For example
|
|
143
|
-
sol2uml contracts,node_modules
|
|
142
|
+
A comma-separated list of files and folders can also be used. For example,
|
|
143
|
+
sol2uml contracts,node_modules/@openzeppelin
|
|
144
144
|
If an Ethereum address with a 0x prefix is passed, the verified source code from Etherscan will be used. For example
|
|
145
145
|
sol2uml 0x79fEbF6B9F76853EDBcBc913e6aAE8232cFB9De9
|
|
146
146
|
|
|
@@ -203,13 +203,12 @@ Options:
|
|
|
203
203
|
-s, --summary Only show a summary of the file differences (default: false)
|
|
204
204
|
-af --aFile <value> Limit code compare to contract A source file with the full path and extension as displayed in the file summary (default: compares all source files)
|
|
205
205
|
-bf --bFile <value> Contract B source file with the full path and extension as displayed in the file summary. Used if aFile is specified and the source file has been renamed (default: aFile if specified)
|
|
206
|
-
-bn, --bNetwork <network> Ethereum network which maps to a blockchain explorer for contract B if on a different blockchain to contract A. Contract A uses the `network` option (default: value of `network` option) (choices: "
|
|
207
|
-
-be, --bExplorerUrl <url> Override the `bNetwork` option with custom blockchain explorer API URL for contract B if on a different blockchain to contract A. Contract A uses the `explorerUrl` (default: value of `explorerUrl` option)
|
|
208
|
-
-bk, --bApiKey <key> Blockchain explorer API key for contract B if on a different blockchain to contract A. Contract A uses the `apiKey` option (default: value of `apiKey` option)
|
|
206
|
+
-bn, --bNetwork <network> Ethereum network which maps to a blockchain explorer for contract B if on a different blockchain to contract A. Contract A uses the `network` option (default: value of `network` option) (choices: "ethereum", "sepolia", "holesky", "hoodi", "arbitrum", "optimism", "polygon", "avalanche", "base", "bsc", "crono", "fantom", "sonic", "gnosis", "moonbeam", "celo", "scroll", "linea", "blast", "berachain", "zksync")
|
|
209
207
|
--flatten Flatten into a single file before comparing. Only works when comparing two verified contracts, not to local files (default: false)
|
|
210
208
|
--saveFiles Save the flattened contract code to the filesystem when using the `flatten` option. The file names will be the contract address with a .sol extension (default: false)
|
|
211
209
|
-l, --lineBuffer <value> Minimum number of lines before and after changes (default: 4)
|
|
212
210
|
-h, --help display help for command
|
|
211
|
+
|
|
213
212
|
```
|
|
214
213
|
|
|
215
214
|
## UML Class diagram examples
|
package/lib/associations.js
CHANGED
|
@@ -13,16 +13,23 @@ const findAssociatedClass = (association, sourceUmlClass, umlClasses, searchedAb
|
|
|
13
13
|
// If a link was found
|
|
14
14
|
if (umlClass)
|
|
15
15
|
return umlClass;
|
|
16
|
-
// Could not find association so now need to recursively look at imports of imports
|
|
17
|
-
// add to already recursively processed files to avoid getting stuck in circular imports
|
|
18
|
-
searchedAbsolutePaths.push(sourceUmlClass.absolutePath)
|
|
19
|
-
const importedType = findChainedImport(
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
//
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
16
|
+
// // Could not find association so now need to recursively look at imports of imports
|
|
17
|
+
// // add to already recursively processed files to avoid getting stuck in circular imports
|
|
18
|
+
// searchedAbsolutePaths.push(sourceUmlClass.absolutePath)
|
|
19
|
+
// const importedType = findChainedImport(
|
|
20
|
+
// association,
|
|
21
|
+
// sourceUmlClass,
|
|
22
|
+
// umlClasses,
|
|
23
|
+
// searchedAbsolutePaths,
|
|
24
|
+
// )
|
|
25
|
+
// if (importedType) return importedType
|
|
26
|
+
// // Still could not find association so now need to recursively look for inherited types
|
|
27
|
+
// const inheritedType = findInheritedType(
|
|
28
|
+
// association,
|
|
29
|
+
// sourceUmlClass,
|
|
30
|
+
// umlClasses,
|
|
31
|
+
// )
|
|
32
|
+
// if (inheritedType) return inheritedType
|
|
26
33
|
return undefined;
|
|
27
34
|
};
|
|
28
35
|
exports.findAssociatedClass = findAssociatedClass;
|
|
@@ -109,39 +116,62 @@ const findInheritedType = (association, sourceUmlClass, umlClasses) => {
|
|
|
109
116
|
}
|
|
110
117
|
return undefined;
|
|
111
118
|
};
|
|
112
|
-
const findChainedImport = (
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
119
|
+
// const findChainedImport = (
|
|
120
|
+
// association: Association,
|
|
121
|
+
// sourceUmlClass: UmlClass,
|
|
122
|
+
// umlClasses: readonly UmlClass[],
|
|
123
|
+
// searchedRelativePaths: string[],
|
|
124
|
+
// ): UmlClass | undefined => {
|
|
125
|
+
// // Get all valid imports. That is, imports that do not explicitly import contracts or interfaces
|
|
126
|
+
// // or explicitly import the source class
|
|
127
|
+
// const imports = sourceUmlClass.imports.filter(
|
|
128
|
+
// (i) =>
|
|
129
|
+
// i.classNames.length === 0 ||
|
|
130
|
+
// i.classNames.some(
|
|
131
|
+
// (cn) =>
|
|
132
|
+
// (association.targetUmlClassName === cn.className &&
|
|
133
|
+
// !cn.alias) ||
|
|
134
|
+
// association.targetUmlClassName === cn.alias,
|
|
135
|
+
// ),
|
|
136
|
+
// )
|
|
137
|
+
// // For each import
|
|
138
|
+
// for (const importDetail of imports) {
|
|
139
|
+
// // Find a class with the same absolute path as the import so we can get the new imports
|
|
140
|
+
// const newSourceUmlClass = umlClasses.find(
|
|
141
|
+
// (c) => c.absolutePath === importDetail.absolutePath,
|
|
142
|
+
// )
|
|
143
|
+
// if (!newSourceUmlClass) {
|
|
144
|
+
// // Could not find a class in the import file so just move onto the next loop
|
|
145
|
+
// continue
|
|
146
|
+
// }
|
|
147
|
+
// // Avoid circular imports
|
|
148
|
+
// if (searchedRelativePaths.includes(newSourceUmlClass.absolutePath)) {
|
|
149
|
+
// // Have already recursively looked for imports of imports in this file
|
|
150
|
+
// continue
|
|
151
|
+
// }
|
|
152
|
+
//
|
|
153
|
+
// // find class linked to the association without aliased imports
|
|
154
|
+
// const umlClass = findAssociatedClass(
|
|
155
|
+
// association,
|
|
156
|
+
// newSourceUmlClass,
|
|
157
|
+
// umlClasses,
|
|
158
|
+
// searchedRelativePaths,
|
|
159
|
+
// )
|
|
160
|
+
// if (umlClass) return umlClass
|
|
161
|
+
//
|
|
162
|
+
// // find all aliased imports
|
|
163
|
+
// const aliasedImports = importDetail.classNames.filter((cn) => cn.alias)
|
|
164
|
+
// // For each aliased import
|
|
165
|
+
// for (const aliasedImport of aliasedImports) {
|
|
166
|
+
// const umlClass = findAssociatedClass(
|
|
167
|
+
// { ...association, targetUmlClassName: aliasedImport.className },
|
|
168
|
+
// newSourceUmlClass,
|
|
169
|
+
// umlClasses,
|
|
170
|
+
// searchedRelativePaths,
|
|
171
|
+
// )
|
|
172
|
+
// if (umlClass) return umlClass
|
|
173
|
+
// }
|
|
174
|
+
// }
|
|
175
|
+
// return undefined
|
|
176
|
+
// }
|
|
147
177
|
//# sourceMappingURL=associations.js.map
|
|
@@ -15,15 +15,26 @@ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (
|
|
|
15
15
|
}) : function(o, v) {
|
|
16
16
|
o["default"] = v;
|
|
17
17
|
});
|
|
18
|
-
var __importStar = (this && this.__importStar) || function (
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
};
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
25
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
|
-
exports.renameFile =
|
|
36
|
+
exports.renameFile = void 0;
|
|
37
|
+
exports.convertAST2UmlClasses = convertAST2UmlClasses;
|
|
27
38
|
const path = __importStar(require("path"));
|
|
28
39
|
const path_1 = require("path");
|
|
29
40
|
const umlClass_1 = require("./umlClass");
|
|
@@ -48,7 +59,7 @@ function convertAST2UmlClasses(node, relativePath, remappings, filesystem = fals
|
|
|
48
59
|
name: childNode.name,
|
|
49
60
|
absolutePath: filesystem
|
|
50
61
|
? path.resolve(relativePath) // resolve the absolute path
|
|
51
|
-
: relativePath,
|
|
62
|
+
: relativePath, // from Etherscan so don't resolve
|
|
52
63
|
relativePath,
|
|
53
64
|
});
|
|
54
65
|
umlClasses.push(umlClass);
|
|
@@ -62,7 +73,7 @@ function convertAST2UmlClasses(node, relativePath, remappings, filesystem = fals
|
|
|
62
73
|
stereotype: umlClass_1.ClassStereotype.Struct,
|
|
63
74
|
absolutePath: filesystem
|
|
64
75
|
? path.resolve(relativePath) // resolve the absolute path
|
|
65
|
-
: relativePath,
|
|
76
|
+
: relativePath, // from Etherscan so don't resolve
|
|
66
77
|
relativePath,
|
|
67
78
|
});
|
|
68
79
|
parseStructDefinition(childNode, umlClass);
|
|
@@ -76,7 +87,7 @@ function convertAST2UmlClasses(node, relativePath, remappings, filesystem = fals
|
|
|
76
87
|
stereotype: umlClass_1.ClassStereotype.Enum,
|
|
77
88
|
absolutePath: filesystem
|
|
78
89
|
? path.resolve(relativePath) // resolve the absolute path
|
|
79
|
-
: relativePath,
|
|
90
|
+
: relativePath, // from Etherscan so don't resolve
|
|
80
91
|
relativePath,
|
|
81
92
|
});
|
|
82
93
|
debug(`Added enum ${umlClass.name}`);
|
|
@@ -143,7 +154,7 @@ function convertAST2UmlClasses(node, relativePath, remappings, filesystem = fals
|
|
|
143
154
|
stereotype: umlClass_1.ClassStereotype.Constant,
|
|
144
155
|
absolutePath: filesystem
|
|
145
156
|
? path.resolve(relativePath) // resolve the absolute path
|
|
146
|
-
: relativePath,
|
|
157
|
+
: relativePath, // from Etherscan so don't resolve
|
|
147
158
|
relativePath,
|
|
148
159
|
attributes: [
|
|
149
160
|
{
|
|
@@ -181,7 +192,7 @@ function convertAST2UmlClasses(node, relativePath, remappings, filesystem = fals
|
|
|
181
192
|
stereotype: umlClass_1.ClassStereotype.Import,
|
|
182
193
|
absolutePath: filesystem
|
|
183
194
|
? path.resolve(relativePath) // resolve the absolute path
|
|
184
|
-
: relativePath,
|
|
195
|
+
: relativePath, // from Etherscan so don't resolve
|
|
185
196
|
relativePath,
|
|
186
197
|
});
|
|
187
198
|
importUmlClass.imports = imports;
|
|
@@ -189,7 +200,6 @@ function convertAST2UmlClasses(node, relativePath, remappings, filesystem = fals
|
|
|
189
200
|
}
|
|
190
201
|
return umlClasses;
|
|
191
202
|
}
|
|
192
|
-
exports.convertAST2UmlClasses = convertAST2UmlClasses;
|
|
193
203
|
/**
|
|
194
204
|
* Parse struct definition for UML attributes and associations.
|
|
195
205
|
* @param node defined in ASTNode as `StructDefinition`
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
3
|
+
exports.convertUmlClasses2Dot = convertUmlClasses2Dot;
|
|
4
|
+
exports.addAssociationsToDot = addAssociationsToDot;
|
|
4
5
|
const path_1 = require("path");
|
|
5
6
|
const converterClass2Dot_1 = require("./converterClass2Dot");
|
|
6
7
|
const umlClass_1 = require("./umlClass");
|
|
@@ -49,7 +50,6 @@ label="${codeFolder}"`;
|
|
|
49
50
|
debug(dotString);
|
|
50
51
|
return dotString;
|
|
51
52
|
}
|
|
52
|
-
exports.convertUmlClasses2Dot = convertUmlClasses2Dot;
|
|
53
53
|
let subGraphCount = 0;
|
|
54
54
|
function getSubGraphName(clusterFolders = false) {
|
|
55
55
|
if (clusterFolders) {
|
|
@@ -104,7 +104,6 @@ function addAssociationsToDot(umlClasses, classOptions = {}) {
|
|
|
104
104
|
}
|
|
105
105
|
return dotString;
|
|
106
106
|
}
|
|
107
|
-
exports.addAssociationsToDot = addAssociationsToDot;
|
|
108
107
|
function addAssociationToDot(sourceUmlClass, targetUmlClass, association, classOptions = {}) {
|
|
109
108
|
// do not include library or interface associations if hidden
|
|
110
109
|
// Or associations to Structs, Enums or Constants if they are hidden
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
3
|
+
exports.convertStorages2Dot = void 0;
|
|
4
|
+
exports.convertStorage2Dot = convertStorage2Dot;
|
|
4
5
|
const converterClasses2Storage_1 = require("./converterClasses2Storage");
|
|
5
6
|
const umlClass_1 = require("./umlClass");
|
|
6
7
|
const formatters_1 = require("./utils/formatters");
|
|
@@ -113,7 +114,6 @@ function convertStorage2Dot(storageSection, dotString, options) {
|
|
|
113
114
|
dotString += '}}"]\n';
|
|
114
115
|
return dotString;
|
|
115
116
|
}
|
|
116
|
-
exports.convertStorage2Dot = convertStorage2Dot;
|
|
117
117
|
const dotVariable = (variable, contractName) => {
|
|
118
118
|
const port = variable.referenceSectionId !== undefined ? `<${variable.id}>` : '';
|
|
119
119
|
const contractNamePrefix = variable.contractName !== contractName
|
package/lib/parserEtherscan.d.ts
CHANGED
|
@@ -4,13 +4,14 @@ export interface Remapping {
|
|
|
4
4
|
from: RegExp;
|
|
5
5
|
to: string;
|
|
6
6
|
}
|
|
7
|
-
export declare const networks: readonly ["
|
|
7
|
+
export declare const networks: readonly ["ethereum", "sepolia", "holesky", "hoodi", "arbitrum", "optimism", "polygon", "avalanche", "base", "bsc", "crono", "fantom", "sonic", "gnosis", "moonbeam", "celo", "scroll", "linea", "blast", "berachain", "zksync"];
|
|
8
8
|
export type Network = (typeof networks)[number];
|
|
9
|
+
export declare const setChainId: (network: string) => number;
|
|
9
10
|
export declare class EtherscanParser {
|
|
10
|
-
protected
|
|
11
|
+
protected apiKey?: string;
|
|
11
12
|
network: Network;
|
|
12
13
|
readonly url: string;
|
|
13
|
-
constructor(
|
|
14
|
+
constructor(apiKey?: string, network?: Network, url?: string);
|
|
14
15
|
/**
|
|
15
16
|
* Parses the verified source code files from Etherscan
|
|
16
17
|
* @param contractAddress Ethereum contract address with a 0x prefix
|
package/lib/parserEtherscan.js
CHANGED
|
@@ -3,7 +3,7 @@ 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.parseRemapping = exports.parseRemappings = exports.EtherscanParser = exports.networks = void 0;
|
|
6
|
+
exports.parseRemapping = exports.parseRemappings = exports.EtherscanParser = exports.setChainId = 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");
|
|
@@ -13,92 +13,89 @@ const path_1 = __importDefault(require("path"));
|
|
|
13
13
|
require('axios-debug-log');
|
|
14
14
|
const debug = require('debug')('sol2uml');
|
|
15
15
|
exports.networks = [
|
|
16
|
-
'
|
|
17
|
-
'holesky',
|
|
16
|
+
'ethereum',
|
|
18
17
|
'sepolia',
|
|
19
|
-
'
|
|
18
|
+
'holesky',
|
|
19
|
+
'hoodi',
|
|
20
20
|
'arbitrum',
|
|
21
|
+
'optimism',
|
|
22
|
+
'polygon',
|
|
21
23
|
'avalanche',
|
|
24
|
+
'base',
|
|
22
25
|
'bsc',
|
|
23
26
|
'crono',
|
|
24
27
|
'fantom',
|
|
25
|
-
'
|
|
26
|
-
'optimism',
|
|
28
|
+
'sonic',
|
|
27
29
|
'gnosis',
|
|
30
|
+
'moonbeam',
|
|
28
31
|
'celo',
|
|
29
32
|
'scroll',
|
|
30
|
-
'
|
|
31
|
-
'
|
|
33
|
+
'linea',
|
|
34
|
+
'blast',
|
|
35
|
+
'berachain',
|
|
36
|
+
'zksync',
|
|
32
37
|
];
|
|
38
|
+
const setChainId = (network) =>
|
|
39
|
+
// If an integer is passed, return it as is
|
|
40
|
+
/^-?(0|[1-9]\d*)$/.test(network)
|
|
41
|
+
? parseInt(network)
|
|
42
|
+
: network === 'sepolia'
|
|
43
|
+
? 11155111
|
|
44
|
+
: network === 'holesky'
|
|
45
|
+
? 17000
|
|
46
|
+
: network === 'hoodi'
|
|
47
|
+
? 560048
|
|
48
|
+
: network === 'arbitrum'
|
|
49
|
+
? 42161
|
|
50
|
+
: network === 'optimism'
|
|
51
|
+
? 10
|
|
52
|
+
: network === 'polygon'
|
|
53
|
+
? 137
|
|
54
|
+
: network === 'avalanche'
|
|
55
|
+
? 43114
|
|
56
|
+
: network === 'base'
|
|
57
|
+
? 8453
|
|
58
|
+
: network === 'bsc'
|
|
59
|
+
? 56
|
|
60
|
+
: network === 'crono'
|
|
61
|
+
? 25
|
|
62
|
+
: network === 'fantom'
|
|
63
|
+
? 250
|
|
64
|
+
: network === 'sonic'
|
|
65
|
+
? 146
|
|
66
|
+
: network === 'gnosis'
|
|
67
|
+
? 100
|
|
68
|
+
: network === 'moonbeam'
|
|
69
|
+
? 1284
|
|
70
|
+
: network === 'celo'
|
|
71
|
+
? 42220
|
|
72
|
+
: network === 'scroll'
|
|
73
|
+
? 534352
|
|
74
|
+
: network === 'linea'
|
|
75
|
+
? 59144
|
|
76
|
+
: network === 'blast'
|
|
77
|
+
? 81457
|
|
78
|
+
: network === 'berachain'
|
|
79
|
+
? 80094
|
|
80
|
+
: network === 'zksync'
|
|
81
|
+
? 324
|
|
82
|
+
: 1;
|
|
83
|
+
exports.setChainId = setChainId;
|
|
33
84
|
class EtherscanParser {
|
|
34
|
-
constructor(
|
|
35
|
-
this.
|
|
85
|
+
constructor(apiKey, network = 'ethereum', url) {
|
|
86
|
+
this.apiKey = apiKey;
|
|
36
87
|
this.network = network;
|
|
37
88
|
if (url) {
|
|
38
89
|
this.url = url;
|
|
39
90
|
return;
|
|
40
91
|
}
|
|
41
|
-
if (!
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
else if (network === 'mainnet') {
|
|
45
|
-
this.url = 'https://api.etherscan.io/api';
|
|
46
|
-
}
|
|
47
|
-
else if (network === 'polygon') {
|
|
48
|
-
this.url = 'https://api.polygonscan.com/api';
|
|
49
|
-
this.apikey = 'AMHGNTV5A7XYGX2M781JB3RC1DZFVRWQEB';
|
|
50
|
-
}
|
|
51
|
-
else if (network === 'arbitrum') {
|
|
52
|
-
this.url = 'https://api.arbiscan.io/api';
|
|
53
|
-
this.apikey = 'ZGTK2TAGWMAB6IAC12BMK8YYPNCPIM8VDQ';
|
|
54
|
-
}
|
|
55
|
-
else if (network === 'avalanche') {
|
|
56
|
-
this.url = 'https://api.snowtrace.io/api';
|
|
57
|
-
this.apikey = 'U5FAN98S5XNH5VI83TI4H35R9I4TDCKEJY';
|
|
58
|
-
}
|
|
59
|
-
else if (network === 'bsc') {
|
|
60
|
-
this.url = 'https://api.bscscan.com/api';
|
|
61
|
-
this.apikey = 'APYH49FXVY9UA3KTDI6F4WP3KPIC86NITN';
|
|
62
|
-
}
|
|
63
|
-
else if (network === 'crono') {
|
|
64
|
-
this.url = 'https://api.cronoscan.com/api';
|
|
65
|
-
this.apikey = '76A3RG5WHTPMMR66E9SFI2EIDT6MP976W2';
|
|
66
|
-
}
|
|
67
|
-
else if (network === 'fantom') {
|
|
68
|
-
this.url = 'https://api.ftmscan.com/api';
|
|
69
|
-
this.apikey = '71KRX13XPZMGR3D1Q85W78G2DSZ4JPMAEX';
|
|
70
|
-
}
|
|
71
|
-
else if (network === 'optimism') {
|
|
72
|
-
this.url = `https://api-optimistic.etherscan.io/api`;
|
|
73
|
-
this.apikey = 'FEXS1HXVA4Y2RNTMEA8V1UTK21S4JWHH9U';
|
|
74
|
-
}
|
|
75
|
-
else if (network === 'moonbeam') {
|
|
76
|
-
this.url = 'https://api-moonbeam.moonscan.io/api';
|
|
77
|
-
this.apikey = '5EUFXW6TDC16VERF3D9SCWRRU6AEMTBHNJ';
|
|
78
|
-
}
|
|
79
|
-
else if (network === 'gnosis') {
|
|
80
|
-
this.url = 'https://api.gnosisscan.io/api';
|
|
81
|
-
this.apikey = '2RWGXIWK538EJ8XSP9DE2JUINSCG7UCSJB';
|
|
82
|
-
}
|
|
83
|
-
else if (network === 'scroll') {
|
|
84
|
-
this.url = 'https://api.scrollscan.com/api';
|
|
85
|
-
this.apikey = '4V37ZJFIN9AURJSU9YG1RP3MSVTPH6D6Z4';
|
|
86
|
-
}
|
|
87
|
-
else if (network === 'celo') {
|
|
88
|
-
this.url = 'https://api.celoscan.io/api';
|
|
89
|
-
this.apikey = 'JBV78T5KP15W7WKKKD6KC4J8RX2F4PK8AF';
|
|
90
|
-
}
|
|
91
|
-
else if (network === 'base') {
|
|
92
|
-
this.url = 'https://api.basescan.org/api';
|
|
93
|
-
this.apikey = '9I5HUJHPD4ZNXJ4M8TZJ1HD2QBVP1U3M3J';
|
|
94
|
-
}
|
|
95
|
-
else if (network === 'sonic') {
|
|
96
|
-
this.url = 'https://api.sonicscan.org/api';
|
|
97
|
-
this.apikey = 'STCM7CPYP341C66C4IVV1IFMWDYRUTI1QY';
|
|
98
|
-
}
|
|
99
|
-
else {
|
|
100
|
-
this.url = `https://api-${network}.etherscan.io/api`;
|
|
92
|
+
if (!apiKey) {
|
|
93
|
+
console.error(`The apiKey option must be set when getting verified source code from an Etherscan like explorer`);
|
|
94
|
+
process.exit(1);
|
|
101
95
|
}
|
|
96
|
+
const chainId = (0, exports.setChainId)(network);
|
|
97
|
+
debug(`Chain id ${chainId} for network ${network}`);
|
|
98
|
+
this.url = `https://api.etherscan.io/v2/api?chainid=${chainId}`;
|
|
102
99
|
}
|
|
103
100
|
/**
|
|
104
101
|
* Parses the verified source code files from Etherscan
|
|
@@ -200,7 +197,7 @@ class EtherscanParser {
|
|
|
200
197
|
module: 'contract',
|
|
201
198
|
action: 'getsourcecode',
|
|
202
199
|
address: contractAddress,
|
|
203
|
-
apikey: this.
|
|
200
|
+
apikey: this.apiKey,
|
|
204
201
|
},
|
|
205
202
|
});
|
|
206
203
|
if (!Array.isArray(response?.data?.result)) {
|
package/lib/parserFiles.js
CHANGED
|
@@ -3,7 +3,10 @@ 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.isFolder = exports.isFile = exports.readFile = exports.
|
|
6
|
+
exports.isFolder = exports.isFile = exports.readFile = exports.parseUmlClassesFromFiles = void 0;
|
|
7
|
+
exports.getSolidityFilesFromFolderOrFiles = getSolidityFilesFromFolderOrFiles;
|
|
8
|
+
exports.getSolidityFilesFromFolderOrFile = getSolidityFilesFromFolderOrFile;
|
|
9
|
+
exports.parseSolidityFile = parseSolidityFile;
|
|
7
10
|
const fs_1 = require("fs");
|
|
8
11
|
const path_1 = require("path");
|
|
9
12
|
const klaw_1 = __importDefault(require("klaw"));
|
|
@@ -30,7 +33,6 @@ async function getSolidityFilesFromFolderOrFiles(folderOrFilePaths, ignoreFilesO
|
|
|
30
33
|
}
|
|
31
34
|
return files;
|
|
32
35
|
}
|
|
33
|
-
exports.getSolidityFilesFromFolderOrFiles = getSolidityFilesFromFolderOrFiles;
|
|
34
36
|
function getSolidityFilesFromFolderOrFile(folderOrFilePath, ignoreFilesOrFolders = [], depthLimit = -1) {
|
|
35
37
|
debug(`About to get Solidity files under ${folderOrFilePath}`);
|
|
36
38
|
return new Promise((resolve, reject) => {
|
|
@@ -87,7 +89,6 @@ function getSolidityFilesFromFolderOrFile(folderOrFilePath, ignoreFilesOrFolders
|
|
|
87
89
|
}
|
|
88
90
|
});
|
|
89
91
|
}
|
|
90
|
-
exports.getSolidityFilesFromFolderOrFile = getSolidityFilesFromFolderOrFile;
|
|
91
92
|
function parseSolidityFile(fileName) {
|
|
92
93
|
const solidityCode = (0, exports.readFile)(fileName);
|
|
93
94
|
try {
|
|
@@ -99,7 +100,6 @@ function parseSolidityFile(fileName) {
|
|
|
99
100
|
});
|
|
100
101
|
}
|
|
101
102
|
}
|
|
102
|
-
exports.parseSolidityFile = parseSolidityFile;
|
|
103
103
|
const readFile = (fileName, extension) => {
|
|
104
104
|
try {
|
|
105
105
|
// try to read file with no extension
|
package/lib/parserGeneral.js
CHANGED
|
@@ -16,7 +16,7 @@ const parserUmlClasses = async (fileFolderAddress, options) => {
|
|
|
16
16
|
};
|
|
17
17
|
if ((0, regEx_1.isAddress)(fileFolderAddress)) {
|
|
18
18
|
debug(`argument ${fileFolderAddress} is an Ethereum address so checking Etherscan for the verified source code`);
|
|
19
|
-
const etherscanApiKey = options.apiKey
|
|
19
|
+
const etherscanApiKey = options.apiKey;
|
|
20
20
|
const etherscanParser = new parserEtherscan_1.EtherscanParser(etherscanApiKey, options.network, options.explorerUrl);
|
|
21
21
|
result = await etherscanParser.getUmlClasses(fileFolderAddress);
|
|
22
22
|
}
|
package/lib/slotValues.d.ts
CHANGED
|
@@ -22,7 +22,7 @@ export declare const parseValue: (variable: Variable) => string;
|
|
|
22
22
|
* @param blockTag block number or `latest`
|
|
23
23
|
* @return slotValues array of 32 byte slot values as hexadecimal strings
|
|
24
24
|
*/
|
|
25
|
-
export declare const getSlotValues: (url: string, contractAddress: string, slotKeys: readonly BigNumberish[], blockTag?: BigNumberish |
|
|
25
|
+
export declare const getSlotValues: (url: string, contractAddress: string, slotKeys: readonly BigNumberish[], blockTag?: BigNumberish | "latest") => Promise<string[]>;
|
|
26
26
|
/**
|
|
27
27
|
* Get storage slot values from JSON-RPC API provider.
|
|
28
28
|
* @param url of Ethereum JSON-RPC API provider. eg Infura or Alchemy
|
|
@@ -32,7 +32,7 @@ export declare const getSlotValues: (url: string, contractAddress: string, slotK
|
|
|
32
32
|
* @param blockTag block number or `latest`
|
|
33
33
|
* @return slotValue 32 byte slot value as hexadecimal string
|
|
34
34
|
*/
|
|
35
|
-
export declare const getSlotValue: (url: string, contractAddress: string, slotKey: BigNumberish, blockTag: BigNumberish |
|
|
35
|
+
export declare const getSlotValue: (url: string, contractAddress: string, slotKey: BigNumberish, blockTag: BigNumberish | "latest") => Promise<string>;
|
|
36
36
|
/**
|
|
37
37
|
* Calculates the number of string characters or bytes of a string or bytes type.
|
|
38
38
|
* See the following for how string and bytes are stored in storage slots
|
package/lib/sol2uml.js
CHANGED
|
@@ -30,12 +30,12 @@ Can also flatten or compare verified source files on Etherscan-like explorers.`)
|
|
|
30
30
|
.default('svg'))
|
|
31
31
|
.option('-o, --outputFileName <value>', 'output file name')
|
|
32
32
|
.option('-i, --ignoreFilesOrFolders <names>', 'comma-separated list of files or folders to ignore', validators_1.validateNames)
|
|
33
|
-
.addOption(new commander_1.Option('-n, --network <network>', '
|
|
34
|
-
|
|
35
|
-
.default('
|
|
33
|
+
.addOption(new commander_1.Option('-n, --network <network>', 'Name or chain id of the blockchain explorer. A name like `ethereum` or `base` will map to a chain id, eg 1 or 8453. Alternatively, use an integer of the chain id. Supported names: ' +
|
|
34
|
+
parserEtherscan_1.networks.join(', '))
|
|
35
|
+
.default('ethereum')
|
|
36
36
|
.env('ETH_NETWORK'))
|
|
37
37
|
.addOption(new commander_1.Option('-e, --explorerUrl <url>', 'Override the `network` option with a custom blockchain explorer API URL. eg Polygon Mumbai testnet https://api-testnet.polygonscan.com/api').env('EXPLORER_URL'))
|
|
38
|
-
.addOption(new commander_1.Option('-k, --apiKey <key>', 'Blockchain explorer API key.
|
|
38
|
+
.addOption(new commander_1.Option('-k, --apiKey <key>', 'Blockchain explorer API key.').env('SCAN_API_KEY'))
|
|
39
39
|
.option('-bc, --backColor <color>', 'Canvas background color. "none" will use a transparent canvas.', 'white')
|
|
40
40
|
.option('-sc, --shapeColor <color>', 'Basic drawing color for graphics, not text', 'black')
|
|
41
41
|
.option('-fc, --fillColor <color>', 'Color used to fill the background of a node', 'gray95')
|
|
@@ -235,8 +235,6 @@ The line numbers are from contract B. There are no line numbers for the red sect
|
|
|
235
235
|
.option('-af --aFile <value>', 'Limit code compare to contract A source file with the full path and extension as displayed in the file summary (default: compares all source files)')
|
|
236
236
|
.option('-bf --bFile <value>', 'Contract B source file with the full path and extension as displayed in the file summary. Used if aFile is specified and the source file has been renamed (default: aFile if specified)')
|
|
237
237
|
.addOption(new commander_1.Option('-bn, --bNetwork <network>', 'Ethereum network which maps to a blockchain explorer for contract B if on a different blockchain to contract A. Contract A uses the `network` option (default: value of `network` option)').choices(parserEtherscan_1.networks))
|
|
238
|
-
.option('-be, --bExplorerUrl <url>', 'Override the `bNetwork` option with custom blockchain explorer API URL for contract B if on a different blockchain to contract A. Contract A uses the `explorerUrl` (default: value of `explorerUrl` option)')
|
|
239
|
-
.option('-bk, --bApiKey <key>', 'Blockchain explorer API key for contract B if on a different blockchain to contract A. Contract A uses the `apiKey` option (default: value of `apiKey` option)')
|
|
240
238
|
.option('--flatten', 'Flatten into a single file before comparing. Only works when comparing two verified contracts, not to local files', false)
|
|
241
239
|
.option('--saveFiles', 'Save the flattened contract code to the filesystem when using the `flatten` option. The file names will be the contract address with a .sol extension', false)
|
|
242
240
|
.option('-l, --lineBuffer <value>', 'Minimum number of lines before and after changes (default: 4)', validators_1.validateLineBuffer)
|
|
@@ -250,7 +248,7 @@ The line numbers are from contract B. There are no line numbers for the red sect
|
|
|
250
248
|
const aEtherscanParser = new parserEtherscan_1.EtherscanParser(combinedOptions.apiKey, combinedOptions.network, combinedOptions.explorerUrl);
|
|
251
249
|
if ((0, regEx_1.isAddress)(fileFoldersAddress)) {
|
|
252
250
|
const addressB = fileFoldersAddress;
|
|
253
|
-
const bEtherscanParser = new parserEtherscan_1.EtherscanParser(combinedOptions.
|
|
251
|
+
const bEtherscanParser = new parserEtherscan_1.EtherscanParser(combinedOptions.apiKey, combinedOptions.bNetwork || combinedOptions.network, combinedOptions.explorerUrl);
|
|
254
252
|
// If flattening
|
|
255
253
|
if (options.flatten) {
|
|
256
254
|
await (0, diffContracts_1.compareFlattenContracts)(addressA, addressB, aEtherscanParser, bEtherscanParser, combinedOptions);
|
package/lib/squashClasses.js
CHANGED
|
@@ -15,13 +15,23 @@ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (
|
|
|
15
15
|
}) : function(o, v) {
|
|
16
16
|
o["default"] = v;
|
|
17
17
|
});
|
|
18
|
-
var __importStar = (this && this.__importStar) || function (
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
};
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
25
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
36
|
exports.squashUmlClasses = void 0;
|
|
27
37
|
const umlClass_1 = require("./umlClass");
|
package/lib/utils/diff.js
CHANGED
|
@@ -15,13 +15,23 @@ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (
|
|
|
15
15
|
}) : function(o, v) {
|
|
16
16
|
o["default"] = v;
|
|
17
17
|
});
|
|
18
|
-
var __importStar = (this && this.__importStar) || function (
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
};
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
25
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
36
|
exports.diffCode = void 0;
|
|
27
37
|
const diff_match_patch_1 = __importStar(require("diff-match-patch"));
|
package/lib/writerFiles.js
CHANGED
|
@@ -3,7 +3,12 @@ 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.
|
|
6
|
+
exports.writeOutputFiles = void 0;
|
|
7
|
+
exports.convertDot2Svg = convertDot2Svg;
|
|
8
|
+
exports.writeSourceCode = writeSourceCode;
|
|
9
|
+
exports.writeDot = writeDot;
|
|
10
|
+
exports.writeSVG = writeSVG;
|
|
11
|
+
exports.writePng = writePng;
|
|
7
12
|
const fs_1 = require("fs");
|
|
8
13
|
const path_1 = __importDefault(require("path"));
|
|
9
14
|
const sync_1 = __importDefault(require("@aduh95/viz.js/sync"));
|
|
@@ -63,7 +68,6 @@ function convertDot2Svg(dot) {
|
|
|
63
68
|
throw new Error(`Failed to parse dot string`, { cause: err });
|
|
64
69
|
}
|
|
65
70
|
}
|
|
66
|
-
exports.convertDot2Svg = convertDot2Svg;
|
|
67
71
|
function writeSourceCode(code, filename = 'source', extension = '.sol') {
|
|
68
72
|
const fileExtension = path_1.default.extname(filename);
|
|
69
73
|
const outputFile = fileExtension === extension ? filename : filename + extension;
|
|
@@ -79,7 +83,6 @@ function writeSourceCode(code, filename = 'source', extension = '.sol') {
|
|
|
79
83
|
}
|
|
80
84
|
});
|
|
81
85
|
}
|
|
82
|
-
exports.writeSourceCode = writeSourceCode;
|
|
83
86
|
function writeDot(dot, filename) {
|
|
84
87
|
const dotFilename = changeFileExtension(filename, 'dot');
|
|
85
88
|
debug(`About to write Dot file to ${dotFilename}`);
|
|
@@ -94,7 +97,6 @@ function writeDot(dot, filename) {
|
|
|
94
97
|
}
|
|
95
98
|
});
|
|
96
99
|
}
|
|
97
|
-
exports.writeDot = writeDot;
|
|
98
100
|
/**
|
|
99
101
|
* Writes an SVG file to the file system.
|
|
100
102
|
* @param svg The SVG input to be written to the file system.
|
|
@@ -127,7 +129,6 @@ function writeSVG(svg, svgFilename = 'classDiagram.svg', outputFormats = 'png')
|
|
|
127
129
|
});
|
|
128
130
|
});
|
|
129
131
|
}
|
|
130
|
-
exports.writeSVG = writeSVG;
|
|
131
132
|
/**
|
|
132
133
|
* Asynchronously writes a PNG file to the file system from an SVG input.
|
|
133
134
|
* @param svg - The SVG input to be converted to a PNG file.
|
|
@@ -161,7 +162,6 @@ async function writePng(svg, filename) {
|
|
|
161
162
|
});
|
|
162
163
|
}
|
|
163
164
|
}
|
|
164
|
-
exports.writePng = writePng;
|
|
165
165
|
// put a new file extension on a filename
|
|
166
166
|
const changeFileExtension = (filename, extension) => {
|
|
167
167
|
const parsedFile = path_1.default.parse(filename);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sol2uml",
|
|
3
|
-
"version": "2.5.
|
|
3
|
+
"version": "2.5.22",
|
|
4
4
|
"description": "Solidity contract visualisation tool.",
|
|
5
5
|
"main": "./lib/index.js",
|
|
6
6
|
"types": "./lib/index.d.ts",
|
|
@@ -23,28 +23,28 @@
|
|
|
23
23
|
"license": "MIT",
|
|
24
24
|
"dependencies": {
|
|
25
25
|
"@aduh95/viz.js": "^3.7.0",
|
|
26
|
-
"@solidity-parser/parser": "^0.
|
|
27
|
-
"axios": "^1.
|
|
26
|
+
"@solidity-parser/parser": "^0.20.1",
|
|
27
|
+
"axios": "^1.10.0",
|
|
28
28
|
"axios-debug-log": "^1.0.0",
|
|
29
|
-
"cli-color": "^2.0.
|
|
30
|
-
"commander": "^
|
|
29
|
+
"cli-color": "^2.0.4",
|
|
30
|
+
"commander": "^12.1.0",
|
|
31
31
|
"convert-svg-to-png": "^0.6.4",
|
|
32
|
-
"debug": "^4.
|
|
32
|
+
"debug": "^4.4.1",
|
|
33
33
|
"diff-match-patch": "^1.0.5",
|
|
34
|
-
"ethers": "^5.
|
|
34
|
+
"ethers": "^5.8.0",
|
|
35
35
|
"js-graph-algorithms": "^1.0.18",
|
|
36
36
|
"klaw": "^4.1.0"
|
|
37
37
|
},
|
|
38
38
|
"devDependencies": {
|
|
39
39
|
"@openzeppelin/contracts": "^4.9.3",
|
|
40
|
-
"@types/diff-match-patch": "^1.0.
|
|
41
|
-
"@types/jest": "^29.5.
|
|
42
|
-
"@types/klaw": "^3.0.
|
|
43
|
-
"jest": "^
|
|
44
|
-
"prettier": "^3.
|
|
45
|
-
"ts-jest": "^29.
|
|
46
|
-
"ts-node": "^10.9.
|
|
47
|
-
"typescript": "^5.
|
|
40
|
+
"@types/diff-match-patch": "^1.0.36",
|
|
41
|
+
"@types/jest": "^29.5.14",
|
|
42
|
+
"@types/klaw": "^3.0.7",
|
|
43
|
+
"jest": "^30.0.0",
|
|
44
|
+
"prettier": "^3.5.3",
|
|
45
|
+
"ts-jest": "^29.4.0",
|
|
46
|
+
"ts-node": "^10.9.2",
|
|
47
|
+
"typescript": "^5.8.3"
|
|
48
48
|
},
|
|
49
49
|
"files": [
|
|
50
50
|
"lib/*.js",
|