Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

sol2uml

Package Overview
Dependencies
Maintainers
1
Versions
84
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

sol2uml - npm Package Compare versions

Comparing version 1.1.29 to 2.0.0-beta.1

lib/converterAST2Classes.d.ts

12

lib/index.d.ts

@@ -1,4 +0,10 @@

export * from './converter';
export * from './etherscanParser';
export * from './fileParser';
export * from './converterAST2Classes';
export * from './converterClass2Dot';
export * from './converterClasses2Dot';
export * from './converterClasses2Storage';
export * from './parserEtherscan';
export * from './parserFiles';
export * from './parserGeneral';
export * from './typeGuards';
export * from './umlClass';
export * from './writerFiles';

@@ -13,6 +13,12 @@ "use strict";

Object.defineProperty(exports, "__esModule", { value: true });
__exportStar(require("./converter"), exports);
__exportStar(require("./etherscanParser"), exports);
__exportStar(require("./fileParser"), exports);
__exportStar(require("./converterAST2Classes"), exports);
__exportStar(require("./converterClass2Dot"), exports);
__exportStar(require("./converterClasses2Dot"), exports);
__exportStar(require("./converterClasses2Storage"), exports);
__exportStar(require("./parserEtherscan"), exports);
__exportStar(require("./parserFiles"), exports);
__exportStar(require("./parserGeneral"), exports);
__exportStar(require("./typeGuards"), exports);
__exportStar(require("./umlClass"), exports);
__exportStar(require("./writerFiles"), exports);
//# sourceMappingURL=index.js.map
#! /usr/bin/env node
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const etherscanParser_1 = require("./etherscanParser");
const fileParser_1 = require("./fileParser");
const contractFilter_1 = require("./contractFilter");
const converterClasses2Dot_1 = require("./converterClasses2Dot");
const parserGeneral_1 = require("./parserGeneral");
const parserEtherscan_1 = require("./parserEtherscan");
const filterClasses_1 = require("./filterClasses");
const commander_1 = require("commander");
const converterClasses2Storage_1 = require("./converterClasses2Storage");
const converterStorage2Dot_1 = require("./converterStorage2Dot");
const regEx_1 = require("./utils/regEx");
const writerFiles_1 = require("./writerFiles");
const program = new commander_1.Command();
const debugControl = require('debug');
const debug = require('debug')('sol2uml');
const commander_1 = require("commander");
const program = new commander_1.Command();
program
.usage(`[subcommand] <options>
The three subcommands:
* class: Generates a UML class diagram from Solidity source code. default
* storage: Generates a diagram of a contract's storage slots.
* flatten: Pulls verified source files from a Blockchain explorer into one, flat, local Solidity file.
The Solidity code can be pulled from verified source code on Blockchain explorers like Etherscan or from local Solidity files.`)
.addOption(new commander_1.Option('-sf, --subfolders <value>', 'number of subfolders that will be recursively searched for Solidity files.').default('-1', 'all'))
.addOption(new commander_1.Option('-f, --outputFormat <value>', 'output file format.')
.choices(['svg', 'png', 'dot', 'all'])
.default('svg'))
.option('-o, --outputFileName <value>', 'output file name')
.option('-i, --ignoreFilesOrFolders <filesOrFolders>', 'comma separated list of files or folders to ignore')
.addOption(new commander_1.Option('-n, --network <network>', 'Ethereum network')
.choices([
'mainnet',
'polygon',
'bsc',
'arbitrum',
'ropsten',
'kovan',
'rinkeby',
'goerli',
])
.default('mainnet'))
.option('-k, --apiKey <key>', 'Etherscan, Polygonscan, BscScan or Arbiscan API key')
.option('-v, --verbose', 'run with debugging statements', false);
program
.command('class', { isDefault: true })
.description('Generates a UML class diagram from Solidity source code.')
.usage(`<fileFolderAddress> [options]

@@ -23,82 +58,86 @@

sol2uml 0x79fEbF6B9F76853EDBcBc913e6aAE8232cFB9De9`)
.argument('[fileFolderAddress]', 'file name, base folder or contract address', process.cwd())
.option('-b, --baseContractNames <value>', 'only output contracts connected to these comma separated base contract names')
.option('-f, --outputFormat <value>', 'output file format: svg, png, sol, dot or all', 'svg')
.option('-o, --outputFileName <value>', 'output file name')
.option('-d, --depthLimit <depth>', 'number of sub folders that will be recursively searched for Solidity files. Default -1 is unlimited', '-1')
.option('-i, --ignoreFilesOrFolders <filesOrFolders>', 'comma separated list of files or folders to ignore')
.option('-n, --network <network>', 'mainnet, polygon, bsc, ropsten, kovan, rinkeby or goerli', 'mainnet')
.option('-a, --hideAttributes', 'hide class and interface attributes')
.option('-p, --hideOperators', 'hide class and interface operators/functions')
.option('-e, --hideEnums', 'hide enum types')
.option('-s, --hideStructs ', 'hide data structures')
.option('-l, --hideLibraries ', 'hide libraries')
.option('-t, --hideInterfaces ', 'hide interfaces')
.option('-r, --hideInternals', 'hide private and internal attributes and operators')
.option('-k, --etherscanApiKey <key>', 'Etherscan API Key')
.option('-c, --clusterFolders', 'cluster contracts into source folders')
.option('-v, --verbose', 'run with debugging statements')
.parse(process.argv);
const options = program.opts();
if (options.verbose) {
debugControl.enable('sol2uml');
}
// This function needs to be loaded after the DEBUG env variable has been set
const converter_1 = require("./converter");
async function sol2uml() {
let fileFolderAddress;
if (program.args.length === 0) {
fileFolderAddress = process.cwd();
.addOption(new commander_1.Option('-d, --depth <value>', 'depth of connected classes to the base contracts. 1 will only show directly connected contracts, interfaces, libraries, structs and enums.').default('100', 'all'))
.option('-c, --clusterFolders', 'cluster contracts into source folders', false)
.option('-hv, --hideVariables', 'hide variables from contracts, interfaces, structs and enums', false)
.option('-hf, --hideFunctions', 'hide functions from contracts, interfaces and libraries', false)
.option('-hp, --hidePrivates', 'hide private and internal attributes and operators', false)
.option('-he, --hideEnums', 'hide enum types', false)
.option('-hs, --hideStructs', 'hide data structures', false)
.option('-hl, --hideLibraries', 'hide libraries', false)
.option('-hi, --hideInterfaces', 'hide interfaces', false)
.option('-ha, --hideAbstracts', 'hide abstract contracts', false)
.option('-hn, --hideFilename', 'hide relative path and file name', false)
.action(async (fileFolderAddress, options, command) => {
try {
const combinedOptions = {
...command.parent._optionValues,
...options,
};
const { umlClasses } = await parserGeneral_1.parserUmlClasses(fileFolderAddress, combinedOptions);
let filteredUmlClasses = umlClasses;
if (options.baseContractNames) {
const baseContractNames = options.baseContractNames.split(',');
filteredUmlClasses = filterClasses_1.classesConnectedToBaseContracts(umlClasses, baseContractNames, options.depth);
}
const dotString = converterClasses2Dot_1.convertUmlClasses2Dot(filteredUmlClasses, combinedOptions.clusterFolders, combinedOptions);
await writerFiles_1.writeOutputFiles(dotString, fileFolderAddress, combinedOptions.outputFormat, combinedOptions.outputFileName);
debug(`Finished generating UML`);
}
else {
fileFolderAddress = program.args[0];
catch (err) {
console.error(`Failed to generate UML diagram ${err.message}`);
}
let umlClasses;
if (fileFolderAddress.match(/^0x([A-Fa-f0-9]{40})$/)) {
debug(`argument ${fileFolderAddress} is an Ethereum address so checking Etherscan for the verified source code`);
const etherscanApiKey = options.etherscanApiKey || 'ZAD4UI2RCXCQTP38EXS3UY2MPHFU5H9KB1';
const etherscanParser = new etherscanParser_1.EtherscanParser(etherscanApiKey, options.network);
// If output is Solidity code
if (options.outputFormat === 'sol') {
const solidityCode = await etherscanParser.getSolidityCode(fileFolderAddress);
// Write Solidity to the contract address
converter_1.writeSolidity(solidityCode, fileFolderAddress);
return;
});
program
.command('storage')
.description('output a contracts storage slots')
.argument('<fileFolderAddress>', 'file name, base folder or contract address')
.option('-c, --contractName <value>', 'Contract name in local Solidity files. Not needed when using an address as the first argument.')
// .option('-d, --data', 'gets the data in the storage slots')
.action(async (fileFolderAddress, options, command) => {
try {
const combinedOptions = {
...command.parent._optionValues,
...options,
};
const { umlClasses, contractName } = await parserGeneral_1.parserUmlClasses(fileFolderAddress, combinedOptions);
const filteredUmlClasses = filterClasses_1.classesConnectedToBaseContracts(umlClasses, [combinedOptions.contractName || contractName]);
const storageObjects = converterClasses2Storage_1.convertClasses2StorageObjects(combinedOptions.contractName || contractName, filteredUmlClasses);
if (regEx_1.isAddress(fileFolderAddress)) {
// The first object is the contract
storageObjects[0].address = fileFolderAddress;
}
umlClasses = await etherscanParser.getUmlClasses(fileFolderAddress);
debug(storageObjects);
const dotString = converterStorage2Dot_1.convertStorage2Dot(storageObjects);
await writerFiles_1.writeOutputFiles(dotString, fileFolderAddress, combinedOptions.outputFormat, combinedOptions.outputFileName);
}
else {
const depthLimit = parseInt(options.depthLimit);
if (isNaN(depthLimit)) {
console.error(`depthLimit option must be an integer. Not ${options.depthLimit}`);
process.exit(1);
}
const filesFolders = fileFolderAddress.split(',');
let ignoreFilesFolders = options.ignoreFilesOrFolders
? options.ignoreFilesOrFolders.split(',')
: [];
umlClasses = await fileParser_1.parseUmlClassesFromFiles(filesFolders, ignoreFilesFolders, depthLimit);
catch (err) {
console.error(`Failed to generate storage diagram ${err.message}`);
}
let filteredUmlClasses = umlClasses;
if (options.baseContractNames) {
const baseContractNames = options.baseContractNames.split(',');
filteredUmlClasses = contractFilter_1.classesConnectedToBaseContracts(umlClasses, baseContractNames);
}
converter_1.generateFilesFromUmlClasses(filteredUmlClasses, fileFolderAddress, options.outputFormat, options.outputFileName, options.clusterFolders, {
hideAttributes: options.hideAttributes,
hideOperators: options.hideOperators,
hideEnums: options.hideEnums,
hideStructs: options.hideStructs,
hideLibraries: options.hideLibraries,
hideInterfaces: options.hideInterfaces,
hideInternals: options.hideInternals,
}).then(() => {
debug(`Finished`);
});
}
try {
sol2uml();
}
catch (err) {
console.error(`Failed to generate UML diagram ${err.message}`);
}
});
program
.command('flatten')
.description('get all verified source code for a contract from the Blockchain explorer into one local file')
.argument('<contractAddress>', 'Contract address')
.action(async (contractAddress, options, command) => {
debug(`About to flatten ${contractAddress}`);
const combinedOptions = {
...command.parent._optionValues,
...options,
};
const etherscanParser = new parserEtherscan_1.EtherscanParser(combinedOptions.apiKey, combinedOptions.network);
const { solidityCode, contractName } = await etherscanParser.getSolidityCode(contractAddress);
// Write Solidity to the contract address
const outputFilename = combinedOptions.outputFileName || contractName;
await writerFiles_1.writeSolidity(solidityCode, outputFilename);
});
program.on('option:verbose', () => {
debugControl.enable('sol2uml');
debug('verbose on');
});
const main = async () => {
await program.parseAsync(process.argv);
};
main();
//# sourceMappingURL=sol2uml.js.map

@@ -25,5 +25,8 @@ export declare enum Visibility {

}
export interface Parameter {
name?: string;
type: string;
export declare enum AttributeType {
Elementary = 0,
UserDefined = 1,
Function = 2,
Array = 3,
Mapping = 4
}

@@ -34,3 +37,9 @@ export interface Attribute {

type?: string;
attributeType?: AttributeType;
compiled?: boolean;
}
export interface Parameter {
name?: string;
type: string;
}
export interface Operator extends Attribute {

@@ -58,5 +67,4 @@ stereotype?: OperatorStereotype;

stereotype?: ClassStereotype;
enums?: {
[name: string]: string[];
};
enums?: number[];
structs?: number[];
attributes?: Attribute[];

@@ -78,8 +86,4 @@ operators?: Operator[];

operators: Operator[];
enums: {
[name: string]: string[];
};
structs: {
[name: string]: Parameter[];
};
enums: number[];
structs: number[];
associations: {

@@ -90,2 +94,7 @@ [name: string]: Association;

addAssociation(association: Association): void;
/**
* Gets the immediate parent contracts this class inherits from.
* Does not include any grand parent associations. That has to be done recursively.
*/
getParentContracts(): Association[];
}
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.UmlClass = exports.ReferenceType = exports.OperatorStereotype = exports.ClassStereotype = exports.Visibility = void 0;
exports.UmlClass = exports.ReferenceType = exports.AttributeType = exports.OperatorStereotype = exports.ClassStereotype = exports.Visibility = void 0;
var Visibility;

@@ -31,2 +31,10 @@ (function (Visibility) {

})(OperatorStereotype = exports.OperatorStereotype || (exports.OperatorStereotype = {}));
var AttributeType;
(function (AttributeType) {
AttributeType[AttributeType["Elementary"] = 0] = "Elementary";
AttributeType[AttributeType["UserDefined"] = 1] = "UserDefined";
AttributeType[AttributeType["Function"] = 2] = "Function";
AttributeType[AttributeType["Array"] = 3] = "Array";
AttributeType[AttributeType["Mapping"] = 4] = "Mapping";
})(AttributeType = exports.AttributeType || (exports.AttributeType = {}));
var ReferenceType;

@@ -41,4 +49,4 @@ (function (ReferenceType) {

this.operators = [];
this.enums = {};
this.structs = {};
this.enums = [];
this.structs = [];
this.associations = {};

@@ -72,2 +80,11 @@ if (!properties || !properties.name) {

}
/**
* Gets the immediate parent contracts this class inherits from.
* Does not include any grand parent associations. That has to be done recursively.
*/
getParentContracts() {
return Object.values(this.associations).filter((association) => association.realization &&
association.targetUmlClassStereotype !==
ClassStereotype.Interface);
}
}

@@ -74,0 +91,0 @@ exports.UmlClass = UmlClass;

{
"name": "sol2uml",
"version": "1.1.29",
"version": "2.0.0-beta.1",
"description": "Unified Modeling Language (UML) class diagram generator for Solidity contracts",

@@ -39,4 +39,4 @@ "main": "./lib/index.js",

"prettier": "^2.3.2",
"ts-jest": "^27.0.4",
"ts-node": "^10.1.0",
"ts-jest": "^27.0.5",
"ts-node": "^10.2.1",
"typescript": "^4.3.5"

@@ -43,0 +43,0 @@ },

@@ -36,8 +36,37 @@ # Solidity 2 UML

To see the usage options
```
$ sol2uml -h
Usage: sol2uml <fileFolderAddress> [options]
$ sol2uml --help
Usage: sol2uml [subcommand] <options>
The three subcommands:
* class: Generates a UML class diagram from Solidity source code. default
* storage: Generates a diagram of a contract's storage slots.
* flatten: Pulls verified source files from a Blockchain explorer into one, flat, local Solidity file.
The Solidity code can be pulled from verified source code on Blockchain explorers like Etherscan or from local Solidity files.
Options:
-sf, --subfolders <value> number of subfolders that will be recursively searched for Solidity files. (default: all)
-f, --outputFormat <value> output file format. (choices: "svg", "png", "dot", "all", default: "svg")
-o, --outputFileName <value> output file name
-i, --ignoreFilesOrFolders <filesOrFolders> comma separated list of files or folders to ignore
-n, --network <network> Ethereum network (choices: "mainnet", "polygon", "bsc", "arbitrum", "ropsten", "kovan", "rinkeby", "goerli", default: "mainnet")
-k, --apiKey <key> Etherscan, Polygonscan or BscScan API key
-v, --verbose run with debugging statements (default: false)
-h, --help display help for command
Commands:
class [options] [fileFolderAddress] Generates a UML class diagram from Solidity source code.
storage [options] <fileFolderAddress> output a contracts storage slots
flatten <contractAddress> get all verified source code for a contract from the Blockchain explorer into one local file
help [command] display help for command
```
### Class usage
```
$sol2uml class --help
Usage: sol2uml class <fileFolderAddress> [options]
Generates UML diagrams from Solidity source code.
If no file, folder or address is passes as the first argument, the working folder is used.

@@ -51,25 +80,60 @@ When a folder is used, all *.sol files are found in that folder and all sub folders.

Generates a UML class diagram from Solidity source code.
Arguments:
fileFolderAddress file name, base folder or contract address (default: "/Users/nicholasaddison/Documents/workspaces/sol2uml")
Options:
-b, --baseContractNames <value> only output contracts connected to these comma separated base contract names
-f, --outputFormat <value> output file format: svg, png, sol, dot or all (default: "svg")
-o, --outputFileName <value> output file name
-d, --depthLimit <depth> number of sub folders that will be recursively searched for Solidity files. Default -1 is unlimited (default: -1)
-i, --ignoreFilesOrFolders <filesOrFolders> comma separated list of files or folders to ignore
-n, --network <network> mainnet, polygon, bsc, ropsten, kovan, rinkeby or goerli (default: "mainnet")
-a, --hideAttributes hide class and interface attributes
-p, --hideOperators hide class and interface operators/functions
-e, --hideEnums hide enum types
-s, --hideStructs hide data structures
-l, --hideLibraries hide libraries
-t, --hideInterfaces hide interfaces
-r, --hideInternals hide private and internal attributes and operators
-k, --etherscanApiKey <key> Etherscan API Key
-c, --clusterFolders cluster contracts into source folders
-v, --verbose run with debugging statements
-h, --help output usage information
-b, --baseContractNames <value> only output contracts connected to these comma separated base contract names
-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)
-c, --clusterFolders cluster contracts into source folders (default: false)
-hv, --hideVariables hide variables from contracts, interfaces, structs and enums (default: false)
-hf, --hideFunctions hide functions from contracts, interfaces and libraries (default: false)
-hp, --hidePrivates hide private and internal attributes and operators (default: false)
-he, --hideEnums hide enum types (default: false)
-hs, --hideStructs hide data structures (default: false)
-hl, --hideLibraries hide libraries (default: false)
-hi, --hideInterfaces hide interfaces (default: false)
-ha, --hideAbstracts hide abstract contracts (default: false)
-hn, --hideFilename hide relative path and file name (default: false)
-h, --help display help for command
```
### Storage usage
```
Usage: sol2uml storage [options] <fileFolderAddress>
output a contracts storage slots
Arguments:
fileFolderAddress file name, base folder or contract address
Options:
-c, --contractName <value> Contract name in local Solidity files. Not needed when using an address as the first argument.
-h, --help display help for command
```
### Flatten usage
```
$sol2uml flatten --help
Usage: sol2uml flatten [options] <contractAddress>
get all verified source code for a contract from the Blockchain explorer into one local file
Arguments:
contractAddress Contract address
Options:
-h, --help display help for command
```
## UML Class diagram examples
To generate a diagram of all contracts under the contracts folder and its sub folders
```bash
sol2uml ./contracts
sol2uml class ./contracts
```

@@ -79,3 +143,3 @@

```bash
sol2uml 0x8d12A197cB00D4747a1fe03395095ce2A5CC6819
sol2uml class 0x8d12A197cB00D4747a1fe03395095ce2A5CC6819
```

@@ -85,3 +149,3 @@

```bash
sol2uml 0xa19833bd291b66aB0E17b9C6d46D2Ec5fEC15190 -n ropsten
sol2uml class 0xa19833bd291b66aB0E17b9C6d46D2Ec5fEC15190 -n ropsten
```

@@ -91,3 +155,3 @@

```bash
sol2uml path/to/contracts/root/folder -o ./outputFile.svg
sol2uml class path/to/contracts/root/folder -o ./outputFile.svg
```

@@ -97,3 +161,3 @@

```bash
sol2uml path/to/contracts/root/folder/solidity/file.sol -f png -o ./someFile.png
sol2uml class path/to/contracts/root/folder/solidity/file.sol -f png -o ./someFile.png
```

@@ -103,3 +167,3 @@

```bash
sol2uml ./contracts,node_modules/openzeppelin-solidity -f all -v
sol2uml class ./contracts,node_modules/openzeppelin-solidity -f all -v
```

@@ -109,29 +173,7 @@

```bash
sol2uml -i solparse,@solidity-parser,ethlint
sol2uml class -i solparse,@solidity-parser,ethlint
```
## Application Programming Interface (API)
# UML Class Diagram Syntax
The main function that parses Solidity source code from files or files in folders is [parseUmlClassesFromFiles](./lib/fileParser.d.ts#L3). This returns an array of UML class objects.
[EtherscanParser](./lib/etherscanParser.d.ts#L5) is a class that parses Etherscan's verified Solidity source code for a contract. For example
```ts
import { convertUmlClassesToSvg, EtherscanParser } from 'sol2uml'
async function generateSvg() {
const etherscanParser = new EtherscanParser()
// get the verified source code from Etherscan for the contract address and
// parse Solidity into UML class objects
const umlClasses = await etherscanParser.getUmlClasses('0xf5dce57282a584d2746faf1593d3121fcac444dc')
// Convert UML classes to a svg string
const svg = await convertUmlClassesToSvg(umlClasses)
}
```
[generateFilesFromUmlClasses](./lib/converter.d.ts#L3) is used to write the dot, svg and png files from an array of UML class objects.
# UML Syntax
Good online resources for learning UML

@@ -165,5 +207,5 @@ * [UML 2 Class Diagramming Guidelines](http://www.agilemodeling.com/style/classDiagram.htm)

- Solid lines for
- link the contract types of storage (state) variables. This can be linked to contracts, interfaces or libraries.
- link the contract types of storage (state) variables. This can be linked to contracts, interfaces, libraries or file level structs and enums.
- generalisations of contracts and abstract contracts.
- aggregated structs and enums
- aggregated contract level structs and enums.
- Dashed lines for

@@ -176,4 +218,10 @@ - generalisations of interfaces.

- An open arrow head for storage or memory variable dependencies
- A diamond tail for aggregations of structs and enums
- A diamond tail for aggregations of contract level structs and enums
# Version 2.x changes
The biggest change with 2.x is the introduction of subcommands as sol2uml can now draw contract storage diagrams.
See [version 2.x](./version2.md) for a list of changes from 1.x.
# Contribution

@@ -180,0 +228,0 @@

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc