Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Changes for programmatic usage #2

Merged
merged 2 commits into from
Sep 17, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
86 changes: 63 additions & 23 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,55 +8,95 @@

### Installation from npm

`npm i @poanet/solidity-flattener`
```bash
npm install https://github.com/vulcanize/solidity-flattener.git
```

### Usage
#### Usage

`./node_modules/.bin/poa-solidity-flattener ./contracts/example.sol`
* CLI:

It will save flattened source of Solidity smart-contract into `./out` directory
```bash
npm run solidity-flattener [input-file-path] [output-file-path]
```

* `input-file-path`: Input contract file path.
* `output-file-path`: Flattened contract output file path (default: appends `-flat` to input filename).

### Installation from source
Arguments are taken from `config.json` if not provided.

Example:

```bash
npm run solidity-flattener ./contracts/ERC20/ERC20.sol ./out/ERC20-flat.sol
```

* As a package:

Example:

```
const { flatten } = require('@poanet/solidity-flattener')

const inputFile = './contracts/ERC20/ERC20.sol'
const flatContract = flatten(inputFile)
console.log(flatContract)
```

### Installation from source

```
git clone https://github.com/poanetwork/solidity-flattener
git clone https://github.com/vulcanize/solidity-flattener
cd solidity-flattener
npm install
```

You can start script either
#### Usage

You can start the script with:

```
npm start "path_to_not_flat_contract_definition_file.sol"
npm start [input-file-path] [output-file-path]
```

or without paramaters (path to input file will be extracted from `./config.json`)
* `input-file-path`: Input contract file path.
* `output-file-path`: Flattened contract output file path (default: appends `-flat` to input filename).

Arguments are taken from `config.json` if not provided.

Examples:

```
npm start
# Saves the flattened contract at the provided output-file-path.
npm start ./contracts/ERC20/ERC20.sol ./out/ERC20-flat.sol
```

```
# Saves the flattened contract at the provided output-file-path in config.json.
npm start
```


Expected result:
If there is no `output-file-path` in `config.json`:

```
Success! Flat file ORIGINAL_FILE_NAME_flat.sol is generated to ./out directory
# Saves the flattened contract at `./Oracles-flat.sol`
npm start ./demo/src/Oracles.sol
```

`./flatContract.sol` - flat .sol file is created in output directory (`./out/` by default)

**Note:** *utility doesn't support aliases at import statements*
**Note:** *Utility doesn't support aliases at import statements.*

## Config

path `./config.json`
* Path: `./config.json`
* Fields:
* `input-file-path`: Input contract file path.
* `output-file-path`: Flattened contract output file path.

```
{
"inputFilePath": "./demo/src/Oracles.sol",
"outputDir": "./out"
}
```
* Example:

```
{
"inputFilePath": "./demo/src/Oracles.sol",
"outputFilePath": "./demo/out/Oracles-flat.sol"
}
```
6 changes: 6 additions & 0 deletions bin/solidity-flattener
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#! /usr/bin/env node

const { main } = require('../index.js')

const args = process.argv.slice(2)
main(args)
4 changes: 2 additions & 2 deletions config.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{
"inputFilePath": "./demo/src/Oracles.sol",
"outputDir": "./out"
}
"outputFilePath": "./demo/out/Oracles-flat.sol"
}
4 changes: 2 additions & 2 deletions helpers/find-file.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
const fs = require('fs')
const glob = require('glob-promise')
const path = require('path')
const variables = require('./variables')
const { processVariables } = require('./variables')
const constants = require('./constants')
const changeRelativePathToAbsolute = require('./change-relative-path-to-absolute')

Expand Down Expand Up @@ -60,7 +60,7 @@ async function byNameAndReplaceInnerRecursivelyInner(importStatement, updatedFil

let isAbsolutePath = !dependencyPath.startsWith(constants.DOT)
const filePath = srcFiles[j]
const { importedSrcFiles } = variables
const { importedSrcFiles } = processVariables(process.argv.slice(2))
if (isAbsolutePath && filePath.includes(dependencyPath)) {
let flattenFileContent = constants.EMPTY
if (!importedSrcFiles.hasOwnProperty(path.basename(filePath)) || fs.existsSync(dependencyPath)) {
Expand Down
9 changes: 7 additions & 2 deletions helpers/logger.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
let bunyan = require('bunyan')
let log = bunyan.createLogger({name: 'solidity-flattener'})

module.exports = log
const level = process.env.DEBUG_LEVEL || 'error'
let log = bunyan.createLogger({
name: 'solidity-flattener',
level
})

module.exports = log
4 changes: 2 additions & 2 deletions helpers/replace-all-imports-in-current-layer.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
const fs = require('fs')
const path = require('path')
const variables = require('./variables')
const { processVariables } = require('./variables')
const constants = require('./constants')
const findFile = require('./find-file')
const updateImportObjectLocationInTarget = require('./update-import-object-location-in-target')
Expand All @@ -20,7 +20,7 @@ async function replaceAllImportsInCurrentLayerInner(i, importObjs, updatedFileCo
}

let importObj = importObjs[i]
const { importedSrcFiles } = variables
const { importedSrcFiles } = processVariables(process.argv.slice(2))
let _updatedFileContent

//replace contracts aliases
Expand Down
55 changes: 27 additions & 28 deletions helpers/variables.js
Original file line number Diff line number Diff line change
@@ -1,39 +1,38 @@
const path = require('path')
const fs = require('fs')

const constants = require('./constants')

const configPath = './config.json'
let configExists = fs.existsSync(configPath, fs.F_OK)
let config
if (configExists) {
config = JSON.parse(fs.readFileSync(configPath, constants.UTF8))
}
function processVariables(args) {

//Input solidity file path
let args = process.argv.slice(2)
let inputFilePath = args.length > 0 ? args[0] : config ? config.inputFilePath : constants.EMPTY
const configPath = './config.json'
let configExists = fs.existsSync(configPath, fs.F_OK)
let config
if (configExists) {
config = JSON.parse(fs.readFileSync(configPath, constants.UTF8))
}

//Input solidity file dir name
let inputFileDir = path.dirname(inputFilePath)
// Get file paths. Resolution order: Command line args, config, defaults.
const inputFilePath = args.length > 0 ? args[0] : config ? config.inputFilePath : constants.EMPTY
const outputFilePath = args.length > 1 ? args[1] : config ? config.outputFilePath : constants.EMPTY

//Input parent dir
let parentDir = inputFileDir
// Output directory to store flat combined solidity file.
const outputDir = path.dirname(outputFilePath)

//Output directory to store flat combined solidity file
let outDir = args.length > 1 ? args[1] : config ? config.outputDir : './out'
let flatContractPrefix = args.length > 2 ? args[2] : path.basename(inputFilePath, '.sol')
// Extracting filename for output file if outputFilePath not given.
const flatContractPrefix = path.basename(inputFilePath, '.sol')

let allSrcFiles = []
let importedSrcFiles = {}
const importedSrcFiles = {}

const variables = {
inputFilePath,
outputFilePath,
outputDir,
importedSrcFiles,
flatContractPrefix
}

return variables
}

module.exports = {
args,
inputFilePath,
inputFileDir,
parentDir,
outDir,
allSrcFiles,
importedSrcFiles,
flatContractPrefix
}
module.exports = { processVariables }
52 changes: 28 additions & 24 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,35 +1,41 @@
#! /usr/bin/env node

const path = require('path')
const fs = require('fs')
const glob = require('glob-promise')
const variables = require('./helpers/variables')

const { processVariables } = require('./helpers/variables')
const log = require('./helpers/logger')
const constants = require('./helpers/constants')
const cleanPath = require('./helpers/clean-path')
const replaceAllImportsRecursively = require('./helpers/replace-all-imports-recursively')
const {
deduplicateSolidityVersoins,
deduplicateSolidityExpHeaders,
deduplicateLicenses
} = require('./helpers/deduplicate-lines')

flatten()

async function flatten() {
const inputFileContent = await fs.readFileSync(variables.inputFilePath, 'utf8')
let dir = variables.parentDir + constants.SLASH
const isAbsolutePath = !dir.startsWith(constants.DOT)
if (!isAbsolutePath) {
dir = __dirname + constants.SLASH + dir
}
dir = cleanPath(dir)
const path = variables.parentDir + constants.SOL
const srcFiles = await getSourceFiles(dir, path)
variables.srcFiles = srcFiles
await replaceImports(inputFileContent, dir)
async function main(args) {
// Get the processed variables.
const variables = processVariables(args)

// Flatten the contract.
const outputFileContent = await flatten(variables.inputFilePath)

// Store the output file at the required destination.
if (!fs.existsSync(variables.outputDir)) fs.mkdirSync(variables.outputDir, { recursive: true })
const fileName = variables.outputFilePath ? path.basename(variables.outputFilePath) : `${variables.flatContractPrefix}-flat.sol`
const filePath = `${variables.outputDir}/${fileName}`
fs.writeFileSync(filePath, outputFileContent)
log.info(`Success! Flat file ${fileName} is generated to ${variables.outputDir} directory.`)
}

async function getSourceFiles(dir, path) {
return await glob(path)
async function flatten(inputFilePath) {
inputFilePath = path.resolve(inputFilePath)

const inputFileContent = fs.readFileSync(inputFilePath, 'utf8')

let dir = path.dirname(inputFilePath) + constants.SLASH

return await replaceImports(inputFileContent, dir)
}

async function replaceImports(inputFileContent, dir) {
Expand All @@ -39,9 +45,7 @@ async function replaceImports(inputFileContent, dir) {
outputFileContent = deduplicateSolidityVersoins(outputFileContent)
outputFileContent = deduplicateSolidityExpHeaders(outputFileContent)

if (!fs.existsSync(variables.outDir)) fs.mkdirSync(variables.outDir)
const fileName = `${variables.flatContractPrefix}_flat.sol`
const filePath = `${variables.outDir}/${fileName}`
fs.writeFileSync(filePath, outputFileContent)
log.info(`Success! Flat file ${fileName} is generated to ${variables.outDir} directory`)
return outputFileContent
}

module.exports = { flatten, main }
Loading