sol2uml 2.5.9 → 2.5.11
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 +28 -26
- package/lib/diffContracts.d.ts +11 -10
- package/lib/diffContracts.js +107 -23
- package/lib/parserFiles.js +1 -1
- package/lib/sol2uml.js +24 -26
- package/lib/writerFiles.js +13 -9
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -68,25 +68,25 @@ Options:
|
|
|
68
68
|
-h, --help display help for command
|
|
69
69
|
|
|
70
70
|
Commands:
|
|
71
|
-
class [options] <fileFolderAddress>
|
|
72
|
-
storage [options] <fileFolderAddress>
|
|
71
|
+
class [options] <fileFolderAddress> Generates a UML class diagram from Solidity source code.
|
|
72
|
+
storage [options] <fileFolderAddress> Visually display a contract's storage slots.
|
|
73
73
|
|
|
74
|
-
|
|
75
|
-
flatten <contractAddress>
|
|
74
|
+
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.
|
|
75
|
+
flatten <contractAddress> Merges verified source files for a contract from a Blockchain explorer into one local Solidity file.
|
|
76
76
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
diff [options] <addressA> <
|
|
77
|
+
In order for the merged code to compile, the following is done:
|
|
78
|
+
1. pragma solidity is set using the compiler of the verified contract.
|
|
79
|
+
2. All pragma solidity lines in the source files are commented out.
|
|
80
|
+
3. File imports are commented out.
|
|
81
|
+
4. "SPDX-License-Identifier" is renamed to "SPDX--License-Identifier".
|
|
82
|
+
5. Contract dependencies are analysed so the files are merged in an order that will compile.
|
|
83
|
+
diff [options] <addressA> <addressB_folders> Compare verified Solidity code to another verified contract or local source files.
|
|
84
84
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
help [command]
|
|
85
|
+
The results show the comparison of contract A to B.
|
|
86
|
+
The green sections are additions to contract B that are not in contract A.
|
|
87
|
+
The red sections are removals from contract A that are not in contract B.
|
|
88
|
+
The line numbers are from contract B. There are no line numbers for the red sections as they are not in contract B.
|
|
89
|
+
help [command] display help for command
|
|
90
90
|
```
|
|
91
91
|
|
|
92
92
|
### Class usage
|
|
@@ -99,8 +99,8 @@ Generates a UML class diagram from Solidity source code.
|
|
|
99
99
|
Arguments:
|
|
100
100
|
fileFolderAddress file name, folder(s) or contract address.
|
|
101
101
|
When a folder is used, all *.sol files in that folder and all sub folders are used.
|
|
102
|
-
A comma-separated list of files and folders can also be used. For example
|
|
103
|
-
sol2uml contracts,node_modules
|
|
102
|
+
A comma-separated list of files and folders can also be used. For example,
|
|
103
|
+
sol2uml contracts,node_modules/@openzeppelin
|
|
104
104
|
If an Ethereum address with a 0x prefix is passed, the verified source code from Etherscan will be used. For example
|
|
105
105
|
sol2uml 0x79fEbF6B9F76853EDBcBc913e6aAE8232cFB9De9
|
|
106
106
|
|
|
@@ -180,9 +180,9 @@ Options:
|
|
|
180
180
|
### Diff usage
|
|
181
181
|
|
|
182
182
|
```
|
|
183
|
-
Usage: sol2uml diff [options] <addressA> <addressB>
|
|
183
|
+
Usage: sol2uml diff [options] <addressA> <addressB or comma-separated folders>
|
|
184
184
|
|
|
185
|
-
Compare verified Solidity code
|
|
185
|
+
Compare verified Solidity code to another verified contract or local source files.
|
|
186
186
|
|
|
187
187
|
The results show the comparison of contract A to B.
|
|
188
188
|
The green sections are additions to contract B that are not in contract A.
|
|
@@ -191,19 +191,21 @@ The line numbers are from contract B. There are no line numbers for the red sect
|
|
|
191
191
|
|
|
192
192
|
Arguments:
|
|
193
193
|
addressA Contract address in hexadecimal format with a 0x prefix of the first contract
|
|
194
|
-
|
|
194
|
+
addressB_folders Location of the contract source code to compare against. Can be a contract address or comma-separated list of local folders.
|
|
195
|
+
For example, 0x1091588Cc431275F99DC5Df311fd8E1Ab81c89F3 will get the verified source code from Etherscan
|
|
196
|
+
or ".,node_modules" will compare against local files in the current folder and the node_modules folder.
|
|
195
197
|
|
|
196
198
|
Options:
|
|
197
|
-
-
|
|
199
|
+
-s, --summary Only show a summary of the file differences (default: false)
|
|
198
200
|
-af --aFile <value> Contract A source code filename without the .sol extension (default: compares all source files)
|
|
199
201
|
-bf --bFile <value> Contract B source code filename without the .sol extension (default: aFile if specified)
|
|
200
|
-
-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: "mainnet",
|
|
201
|
-
"
|
|
202
|
+
-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: "mainnet", "goerli", "sepolia", "polygon", "arbitrum", "avalanche",
|
|
203
|
+
"bsc", "crono", "fantom", "moonbeam", "optimism", "gnosis", "celo")
|
|
202
204
|
-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)
|
|
203
205
|
-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)
|
|
204
|
-
|
|
205
|
-
--flatten Flatten into a single file before comparing (default: false)
|
|
206
|
+
--flatten Flatten into a single file before comparing. Only works when comparing two verified contracts, not to local files (default: false)
|
|
206
207
|
--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)
|
|
208
|
+
-l, --lineBuffer <value> Minimum number of lines before and after changes (default: 4)
|
|
207
209
|
-h, --help display help for command
|
|
208
210
|
```
|
|
209
211
|
|
package/lib/diffContracts.d.ts
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { EtherscanParser } from './parserEtherscan';
|
|
2
2
|
interface DiffOptions {
|
|
3
3
|
network: string;
|
|
4
|
+
bNetwork?: string;
|
|
4
5
|
lineBuffer: number;
|
|
6
|
+
summary?: boolean;
|
|
5
7
|
}
|
|
6
8
|
interface FlattenAndDiffOptions extends DiffOptions {
|
|
7
9
|
aFile?: string;
|
|
@@ -17,19 +19,18 @@ interface DiffFiles {
|
|
|
17
19
|
interface CompareContracts {
|
|
18
20
|
files: DiffFiles[];
|
|
19
21
|
contractNameA: string;
|
|
20
|
-
contractNameB
|
|
22
|
+
contractNameB?: string;
|
|
21
23
|
}
|
|
22
|
-
export declare const
|
|
23
|
-
export declare const
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
24
|
+
export declare const compareVerifiedContracts: (addressA: string, aEtherscanParser: EtherscanParser, addressB: string, bEtherscanParser: EtherscanParser, options: DiffOptions) => Promise<void>;
|
|
25
|
+
export declare const compareVerified2Local: (addressA: string, aEtherscanParser: EtherscanParser, localFolders: string[], options: DiffOptions) => Promise<void>;
|
|
26
|
+
export declare const compareFlattenContracts: (addressA: string, addressB: string, aEtherscanParser: EtherscanParser, bEtherscanParser: EtherscanParser, options: FlattenAndDiffOptions) => Promise<{
|
|
27
|
+
contractNameA: string;
|
|
28
|
+
contractNameB: string;
|
|
29
|
+
}>;
|
|
30
|
+
export declare const diffVerified2Local: (addressA: string, etherscanParserA: EtherscanParser, baseFolders: string[], ignoreFilesOrFolders?: string[]) => Promise<CompareContracts>;
|
|
31
|
+
export declare const diffVerifiedContracts: (addressA: string, addressB: string, etherscanParserA: EtherscanParser, etherscanParserB: EtherscanParser, options: DiffOptions) => Promise<CompareContracts>;
|
|
27
32
|
export declare const displayFileDiffSummary: (fileDiffs: DiffFiles[]) => void;
|
|
28
33
|
export declare const displayFileDiffs: (fileDiffs: DiffFiles[], options?: {
|
|
29
34
|
lineBuffer?: number;
|
|
30
35
|
}) => void;
|
|
31
|
-
export declare const flattenAndDiff: (addressA: string, addressB: string, aEtherscanParser: EtherscanParser, bEtherscanParser: EtherscanParser, options: FlattenAndDiffOptions) => Promise<{
|
|
32
|
-
contractNameA: string;
|
|
33
|
-
contractNameB: string;
|
|
34
|
-
}>;
|
|
35
36
|
export {};
|
package/lib/diffContracts.js
CHANGED
|
@@ -1,11 +1,114 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
4
|
-
const regEx_1 = require("./utils/regEx");
|
|
3
|
+
exports.displayFileDiffs = exports.displayFileDiffSummary = exports.diffVerifiedContracts = exports.diffVerified2Local = exports.compareFlattenContracts = exports.compareVerified2Local = exports.compareVerifiedContracts = void 0;
|
|
5
4
|
const clc = require('cli-color');
|
|
5
|
+
const fs_1 = require("fs");
|
|
6
|
+
const path_1 = require("path");
|
|
7
|
+
const parserFiles_1 = require("./parserFiles");
|
|
6
8
|
const writerFiles_1 = require("./writerFiles");
|
|
9
|
+
const regEx_1 = require("./utils/regEx");
|
|
7
10
|
const diff_1 = require("./utils/diff");
|
|
8
|
-
const
|
|
11
|
+
const debug = require('debug')('sol2uml');
|
|
12
|
+
const compareVerifiedContracts = async (addressA, aEtherscanParser, addressB, bEtherscanParser, options) => {
|
|
13
|
+
const { contractNameA, contractNameB, files } = await (0, exports.diffVerifiedContracts)(addressA, addressB, aEtherscanParser, bEtherscanParser, options);
|
|
14
|
+
if (!options.summary) {
|
|
15
|
+
(0, exports.displayFileDiffs)(files, options);
|
|
16
|
+
}
|
|
17
|
+
console.log(`Compared the "${contractNameA}" contract with address ${addressA} on ${options.network}`);
|
|
18
|
+
console.log(`to the "${contractNameB}" contract with address ${addressB} on ${options.bNetwork || options.network}\n`);
|
|
19
|
+
(0, exports.displayFileDiffSummary)(files);
|
|
20
|
+
};
|
|
21
|
+
exports.compareVerifiedContracts = compareVerifiedContracts;
|
|
22
|
+
const compareVerified2Local = async (addressA, aEtherscanParser, localFolders, options) => {
|
|
23
|
+
// compare verified contract to local files
|
|
24
|
+
const { contractNameA, files } = await (0, exports.diffVerified2Local)(addressA, aEtherscanParser, localFolders);
|
|
25
|
+
if (!options.summary) {
|
|
26
|
+
(0, exports.displayFileDiffs)(files, options);
|
|
27
|
+
}
|
|
28
|
+
console.log(`Compared the "${contractNameA}" contract with address ${addressA} on ${options.network}`);
|
|
29
|
+
console.log(`to local files under folders "${localFolders}"\n`);
|
|
30
|
+
(0, exports.displayFileDiffSummary)(files);
|
|
31
|
+
};
|
|
32
|
+
exports.compareVerified2Local = compareVerified2Local;
|
|
33
|
+
const compareFlattenContracts = async (addressA, addressB, aEtherscanParser, bEtherscanParser, options) => {
|
|
34
|
+
// Get verified Solidity code from Etherscan and flatten
|
|
35
|
+
const { solidityCode: codeA, contractName: contractNameA } = await aEtherscanParser.getSolidityCode(addressA, options.aFile);
|
|
36
|
+
const { solidityCode: codeB, contractName: contractNameB } = await bEtherscanParser.getSolidityCode(addressB, options.bFile || options.aFile);
|
|
37
|
+
(0, diff_1.diffCode)(codeA, codeB, options.lineBuffer);
|
|
38
|
+
if (options.saveFiles) {
|
|
39
|
+
await (0, writerFiles_1.writeSolidity)(codeA, addressA);
|
|
40
|
+
await (0, writerFiles_1.writeSolidity)(codeB, addressB);
|
|
41
|
+
}
|
|
42
|
+
console.log(`Compared the flattened "${contractNameA}" contract with address ${addressA} on ${options.network}`);
|
|
43
|
+
console.log(`to the flattened "${contractNameB}" contract with address ${addressB} on ${options.bNetwork || options.network}\n`);
|
|
44
|
+
return { contractNameA, contractNameB };
|
|
45
|
+
};
|
|
46
|
+
exports.compareFlattenContracts = compareFlattenContracts;
|
|
47
|
+
const diffVerified2Local = async (addressA, etherscanParserA, baseFolders, ignoreFilesOrFolders = []) => {
|
|
48
|
+
const files = [];
|
|
49
|
+
// Get all the source files for the verified contract from Etherscan
|
|
50
|
+
const { files: aFiles, contractName: contractNameA } = await etherscanParserA.getSourceCode(addressA);
|
|
51
|
+
const bFiles = await (0, parserFiles_1.getSolidityFilesFromFolderOrFiles)(baseFolders, ignoreFilesOrFolders);
|
|
52
|
+
// For each file in the A contract
|
|
53
|
+
for (const aFile of aFiles) {
|
|
54
|
+
// Look for A contract filename in local filesystem
|
|
55
|
+
let bFile;
|
|
56
|
+
// for each of the base folders
|
|
57
|
+
for (const baseFolder of baseFolders) {
|
|
58
|
+
bFile = bFiles.find((bFile) => {
|
|
59
|
+
const resolvedPath = (0, path_1.resolve)(process.cwd(), baseFolder, aFile.filename);
|
|
60
|
+
return bFile === resolvedPath;
|
|
61
|
+
});
|
|
62
|
+
if (bFile) {
|
|
63
|
+
break;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
if (bFile) {
|
|
67
|
+
try {
|
|
68
|
+
debug(`Matched verified file ${aFile.filename} to local file ${bFile}`);
|
|
69
|
+
// Try and read code from bFile
|
|
70
|
+
const bCode = (0, fs_1.readFileSync)(bFile, 'utf8');
|
|
71
|
+
// The A contract filename exists in the B contract
|
|
72
|
+
if (aFile.code !== bCode) {
|
|
73
|
+
// console.log(`${aFile.filename} ${clc.red('different')}:`)
|
|
74
|
+
files.push({
|
|
75
|
+
filename: aFile.filename,
|
|
76
|
+
aCode: aFile.code,
|
|
77
|
+
bCode,
|
|
78
|
+
result: 'changed',
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
else {
|
|
82
|
+
files.push({
|
|
83
|
+
filename: aFile.filename,
|
|
84
|
+
aCode: aFile.code,
|
|
85
|
+
bCode,
|
|
86
|
+
result: 'match',
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
catch (err) {
|
|
91
|
+
throw Error(`Failed to read local file ${bFile}`);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
else {
|
|
95
|
+
debug(`Failed to find local file for verified files ${aFile.filename}`);
|
|
96
|
+
// The A contract filename does not exist in the B contract
|
|
97
|
+
files.push({
|
|
98
|
+
filename: aFile.filename,
|
|
99
|
+
aCode: aFile.code,
|
|
100
|
+
result: 'removed',
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
// Sort by filename
|
|
105
|
+
return {
|
|
106
|
+
files: files.sort((a, b) => a.filename.localeCompare(b.filename)),
|
|
107
|
+
contractNameA,
|
|
108
|
+
};
|
|
109
|
+
};
|
|
110
|
+
exports.diffVerified2Local = diffVerified2Local;
|
|
111
|
+
const diffVerifiedContracts = async (addressA, addressB, etherscanParserA, etherscanParserB, options) => {
|
|
9
112
|
const files = [];
|
|
10
113
|
const { files: aFiles, contractName: contractNameA } = await etherscanParserA.getSourceCode(addressA);
|
|
11
114
|
const { files: bFiles, contractName: contractNameB } = await etherscanParserB.getSourceCode(addressB);
|
|
@@ -76,12 +179,7 @@ const compareContracts = async (addressA, addressB, etherscanParserA, etherscanP
|
|
|
76
179
|
contractNameB,
|
|
77
180
|
};
|
|
78
181
|
};
|
|
79
|
-
exports.
|
|
80
|
-
const displayContractNames = (addressA, addressB, contractNameA, contractNameB, options) => {
|
|
81
|
-
console.log(`Contract A: ${addressA} ${contractNameA} on ${options.network}`);
|
|
82
|
-
console.log(`Contract B: ${addressB} ${contractNameB} on ${options.bNetwork || options.network}\n`);
|
|
83
|
-
};
|
|
84
|
-
exports.displayContractNames = displayContractNames;
|
|
182
|
+
exports.diffVerifiedContracts = diffVerifiedContracts;
|
|
85
183
|
const displayFileDiffSummary = (fileDiffs) => {
|
|
86
184
|
for (const file of fileDiffs) {
|
|
87
185
|
switch (file.result) {
|
|
@@ -118,18 +216,4 @@ const displayFileDiffs = (fileDiffs, options = {}) => {
|
|
|
118
216
|
}
|
|
119
217
|
};
|
|
120
218
|
exports.displayFileDiffs = displayFileDiffs;
|
|
121
|
-
const flattenAndDiff = async (addressA, addressB, aEtherscanParser, bEtherscanParser, options) => {
|
|
122
|
-
// Get verified Solidity code from Etherscan and flatten
|
|
123
|
-
const { solidityCode: codeA, contractName: contractNameA } = await aEtherscanParser.getSolidityCode(addressA, options.aFile);
|
|
124
|
-
const { solidityCode: codeB, contractName: contractNameB } = await bEtherscanParser.getSolidityCode(addressB, options.bFile || options.aFile);
|
|
125
|
-
(0, exports.displayContractNames)(addressA, addressB, contractNameA, contractNameB, options);
|
|
126
|
-
(0, diff_1.diffCode)(codeA, codeB, options.lineBuffer);
|
|
127
|
-
if (options.saveFiles) {
|
|
128
|
-
await (0, writerFiles_1.writeSolidity)(codeA, addressA);
|
|
129
|
-
await (0, writerFiles_1.writeSolidity)(codeB, addressB);
|
|
130
|
-
}
|
|
131
|
-
(0, exports.displayContractNames)(addressA, addressB, contractNameA, contractNameB, options);
|
|
132
|
-
return { contractNameA, contractNameB };
|
|
133
|
-
};
|
|
134
|
-
exports.flattenAndDiff = flattenAndDiff;
|
|
135
219
|
//# sourceMappingURL=diffContracts.js.map
|
package/lib/parserFiles.js
CHANGED
|
@@ -57,7 +57,7 @@ function getSolidityFilesFromFolderOrFile(folderOrFilePath, ignoreFilesOrFolders
|
|
|
57
57
|
files.push(file.path);
|
|
58
58
|
})
|
|
59
59
|
.on('end', () => {
|
|
60
|
-
debug(`Got Solidity files to be parsed: ${files}`)
|
|
60
|
+
// debug(`Got Solidity files to be parsed: ${files}`)
|
|
61
61
|
resolve(files);
|
|
62
62
|
});
|
|
63
63
|
}
|
package/lib/sol2uml.js
CHANGED
|
@@ -47,8 +47,8 @@ const version = (0, path_1.basename)(__dirname) === 'lib'
|
|
|
47
47
|
program.version(version);
|
|
48
48
|
const argumentText = `file name, folder(s) or contract address.
|
|
49
49
|
\t\t\t\t When a folder is used, all *.sol files in that folder and all sub folders are used.
|
|
50
|
-
\t\t\t\t A comma-separated list of files and folders can also be used. For example
|
|
51
|
-
\t\t\t\t\tsol2uml contracts,node_modules
|
|
50
|
+
\t\t\t\t A comma-separated list of files and folders can also be used. For example,
|
|
51
|
+
\t\t\t\t\tsol2uml contracts,node_modules/@openzeppelin
|
|
52
52
|
\t\t\t\t If an Ethereum address with a 0x prefix is passed, the verified source code from Etherscan will be used. For example
|
|
53
53
|
\t\t\t\t\tsol2uml 0x79fEbF6B9F76853EDBcBc913e6aAE8232cFB9De9`;
|
|
54
54
|
program
|
|
@@ -218,50 +218,48 @@ In order for the merged code to compile, the following is done:
|
|
|
218
218
|
});
|
|
219
219
|
program
|
|
220
220
|
.command('diff')
|
|
221
|
-
.usage('[options] <addressA> <addressB>')
|
|
222
|
-
.description(`Compare verified Solidity code
|
|
221
|
+
.usage('[options] <addressA> <addressB or comma-separated folders>')
|
|
222
|
+
.description(`Compare verified Solidity code to another verified contract or local source files.
|
|
223
223
|
|
|
224
224
|
The results show the comparison of contract A to B.
|
|
225
225
|
The ${clc.green('green')} sections are additions to contract B that are not in contract A.
|
|
226
226
|
The ${clc.red('red')} sections are removals from contract A that are not in contract B.
|
|
227
227
|
The line numbers are from contract B. There are no line numbers for the red sections as they are not in contract B.\n`)
|
|
228
228
|
.argument('<addressA>', 'Contract address in hexadecimal format with a 0x prefix of the first contract', validators_1.validateAddress)
|
|
229
|
-
.argument('<
|
|
230
|
-
|
|
229
|
+
.argument('<addressB_folders>', `Location of the contract source code to compare against. Can be a contract address or comma-separated list of local folders.
|
|
230
|
+
For example, 0x1091588Cc431275F99DC5Df311fd8E1Ab81c89F3 will get the verified source code from Etherscan
|
|
231
|
+
or ".,node_modules" will compare against local files in the current folder and the node_modules folder.`)
|
|
232
|
+
.option('-s, --summary', 'Only show a summary of the file differences', false)
|
|
231
233
|
.option('-af --aFile <value>', 'Contract A source code filename without the .sol extension (default: compares all source files)')
|
|
232
234
|
.option('-bf --bFile <value>', 'Contract B source code filename without the .sol extension (default: aFile if specified)')
|
|
233
235
|
.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))
|
|
234
236
|
.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)')
|
|
235
237
|
.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)')
|
|
236
|
-
.option('
|
|
237
|
-
.option('--flatten', 'Flatten into a single file before comparing', false)
|
|
238
|
+
.option('--flatten', 'Flatten into a single file before comparing. Only works when comparing two verified contracts, not to local files', false)
|
|
238
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)
|
|
239
|
-
.
|
|
240
|
+
.option('-l, --lineBuffer <value>', 'Minimum number of lines before and after changes (default: 4)', validators_1.validateLineBuffer)
|
|
241
|
+
.action(async (addressA, addressB_folders, options, command) => {
|
|
240
242
|
try {
|
|
241
|
-
debug(`About to
|
|
243
|
+
debug(`About to compare ${addressA} to ${addressB_folders}`);
|
|
242
244
|
const combinedOptions = {
|
|
243
245
|
...command.parent._optionValues,
|
|
244
246
|
...options,
|
|
245
247
|
};
|
|
246
248
|
const aEtherscanParser = new parserEtherscan_1.EtherscanParser(combinedOptions.apiKey, combinedOptions.network, combinedOptions.explorerUrl);
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
249
|
+
if ((0, regEx_1.isAddress)(addressB_folders)) {
|
|
250
|
+
const addressB = addressB_folders;
|
|
251
|
+
const bEtherscanParser = new parserEtherscan_1.EtherscanParser(combinedOptions.bApiKey || combinedOptions.apiKey, combinedOptions.bNetwork || combinedOptions.network, combinedOptions.bExplorerUrl || combinedOptions.explorerUrl);
|
|
252
|
+
// If flattening or just comparing a single file
|
|
253
|
+
if (options.flatten || options.aFile) {
|
|
254
|
+
await (0, diffContracts_1.compareFlattenContracts)(addressA, addressB, aEtherscanParser, bEtherscanParser, combinedOptions);
|
|
255
|
+
}
|
|
256
|
+
else {
|
|
257
|
+
await (0, diffContracts_1.compareVerifiedContracts)(addressA, aEtherscanParser, addressB, bEtherscanParser, combinedOptions);
|
|
258
|
+
}
|
|
250
259
|
}
|
|
251
260
|
else {
|
|
252
|
-
const
|
|
253
|
-
(0, diffContracts_1.
|
|
254
|
-
(0, diffContracts_1.displayFileDiffSummary)(files);
|
|
255
|
-
if (!options.summary) {
|
|
256
|
-
// Just show the summary if all the files are the same
|
|
257
|
-
const diffFiles = files.filter((f) => f.result !== 'match');
|
|
258
|
-
if (diffFiles.length === 0)
|
|
259
|
-
return;
|
|
260
|
-
console.log();
|
|
261
|
-
(0, diffContracts_1.displayFileDiffs)(files, combinedOptions);
|
|
262
|
-
(0, diffContracts_1.displayContractNames)(addressA, addressB, contractNameA, contractNameB, combinedOptions);
|
|
263
|
-
(0, diffContracts_1.displayFileDiffSummary)(files);
|
|
264
|
-
}
|
|
261
|
+
const localFolders = addressB_folders.split(',');
|
|
262
|
+
await (0, diffContracts_1.compareVerified2Local)(addressA, aEtherscanParser, localFolders, combinedOptions);
|
|
265
263
|
}
|
|
266
264
|
}
|
|
267
265
|
catch (err) {
|
package/lib/writerFiles.js
CHANGED
|
@@ -81,15 +81,16 @@ function writeSolidity(code, filename = 'solidity') {
|
|
|
81
81
|
}
|
|
82
82
|
exports.writeSolidity = writeSolidity;
|
|
83
83
|
function writeDot(dot, filename) {
|
|
84
|
-
|
|
85
|
-
(
|
|
84
|
+
const dotFilename = changeFileExtension(filename, 'dot');
|
|
85
|
+
debug(`About to write Dot file to ${dotFilename}`);
|
|
86
|
+
(0, fs_1.writeFile)(dotFilename, dot, (err) => {
|
|
86
87
|
if (err) {
|
|
87
|
-
throw new Error(`Failed to write Dot file to ${
|
|
88
|
+
throw new Error(`Failed to write Dot file to ${dotFilename}`, {
|
|
88
89
|
cause: err,
|
|
89
90
|
});
|
|
90
91
|
}
|
|
91
92
|
else {
|
|
92
|
-
console.log(`Dot file written to ${
|
|
93
|
+
console.log(`Dot file written to ${dotFilename}`);
|
|
93
94
|
}
|
|
94
95
|
});
|
|
95
96
|
}
|
|
@@ -102,7 +103,7 @@ exports.writeDot = writeDot;
|
|
|
102
103
|
* @throws Error - If there is an error writing the SVG file.
|
|
103
104
|
*/
|
|
104
105
|
function writeSVG(svg, svgFilename = 'classDiagram.svg', outputFormats = 'png') {
|
|
105
|
-
debug(`About to write
|
|
106
|
+
debug(`About to write SVG file to ${svgFilename}`);
|
|
106
107
|
if (outputFormats === 'png') {
|
|
107
108
|
const parsedFile = path_1.default.parse(svgFilename);
|
|
108
109
|
if (!parsedFile.dir) {
|
|
@@ -134,10 +135,7 @@ exports.writeSVG = writeSVG;
|
|
|
134
135
|
* @throws Error - If there is an error converting or writing the PNG file.
|
|
135
136
|
*/
|
|
136
137
|
async function writePng(svg, filename) {
|
|
137
|
-
|
|
138
|
-
const parsedPngFile = path_1.default.parse(filename);
|
|
139
|
-
const pngDir = parsedPngFile.dir === '' ? '.' : path_1.default.resolve(parsedPngFile.dir);
|
|
140
|
-
const pngFilename = pngDir + '/' + parsedPngFile.name + '.png';
|
|
138
|
+
const pngFilename = changeFileExtension(filename, 'png');
|
|
141
139
|
debug(`About to write png file ${pngFilename}`);
|
|
142
140
|
try {
|
|
143
141
|
const png = await convert(svg, {
|
|
@@ -164,4 +162,10 @@ async function writePng(svg, filename) {
|
|
|
164
162
|
}
|
|
165
163
|
}
|
|
166
164
|
exports.writePng = writePng;
|
|
165
|
+
// put a new file extension on a filename
|
|
166
|
+
const changeFileExtension = (filename, extension) => {
|
|
167
|
+
const parsedFile = path_1.default.parse(filename);
|
|
168
|
+
const dir = parsedFile.dir === '' ? '.' : path_1.default.resolve(parsedFile.dir);
|
|
169
|
+
return dir + '/' + parsedFile.name + '.' + extension;
|
|
170
|
+
};
|
|
167
171
|
//# sourceMappingURL=writerFiles.js.map
|