parent
1350699582
commit
d5ee50dfd0
|
@ -10,18 +10,26 @@ const _DOT = '.'
|
|||
const _DIRTY_PATH = '/./'
|
||||
const _DIRTY_PATH_2 = '/../'
|
||||
const _SOL = '/**/*.sol'
|
||||
const _LICENSE_PREFIX_1 = "// SPDX-License-Identifier"
|
||||
const _LICENSE_PREFIX_2 = "//SPDX-License-Identifier"
|
||||
const _SOL_VERSION_PREFIX = "pragma solidity"
|
||||
const _SOL_EXP_HEADER_PREFIX = "pragma experimental"
|
||||
|
||||
module.exports = {
|
||||
UTF8: _UTF8,
|
||||
EMPTY: _EMPTY,
|
||||
AS: _AS,
|
||||
SEMICOLON: _SEMICOLON,
|
||||
SLASH: _SLASH,
|
||||
IS: _IS,
|
||||
IMPORT: _IMPORT,
|
||||
CONTRACT: _CONTRACT,
|
||||
DOT: _DOT,
|
||||
SOL: _SOL,
|
||||
DIRTY_PATH: _DIRTY_PATH,
|
||||
DIRTY_PATH_2: _DIRTY_PATH_2
|
||||
}
|
||||
UTF8: _UTF8,
|
||||
EMPTY: _EMPTY,
|
||||
AS: _AS,
|
||||
SEMICOLON: _SEMICOLON,
|
||||
SLASH: _SLASH,
|
||||
IS: _IS,
|
||||
IMPORT: _IMPORT,
|
||||
CONTRACT: _CONTRACT,
|
||||
DOT: _DOT,
|
||||
SOL: _SOL,
|
||||
DIRTY_PATH: _DIRTY_PATH,
|
||||
DIRTY_PATH_2: _DIRTY_PATH_2,
|
||||
LICENSE_PREFIX_1: _LICENSE_PREFIX_1,
|
||||
LICENSE_PREFIX_2: _LICENSE_PREFIX_2,
|
||||
SOL_VERSION_PREFIX: _SOL_VERSION_PREFIX,
|
||||
SOL_EXP_HEADER_PREFIX: _SOL_EXP_HEADER_PREFIX,
|
||||
}
|
||||
|
|
|
@ -0,0 +1,60 @@
|
|||
const os = require('os');
|
||||
const constants = require('./constants')
|
||||
|
||||
function deduplicateSolidityVersoins(content) {
|
||||
return deduplicateLines(content, [constants.SOL_VERSION_PREFIX]);
|
||||
}
|
||||
|
||||
function deduplicateSolidityExpHeaders(content) {
|
||||
return deduplicateLines(content, [constants.SOL_EXP_HEADER_PREFIX]);
|
||||
}
|
||||
|
||||
function deduplicateLicenses(content) {
|
||||
return deduplicateLines(content, [constants.LICENSE_PREFIX_1, constants.LICENSE_PREFIX_2]);
|
||||
}
|
||||
|
||||
function deduplicateLines(content, linePrefixes) {
|
||||
const isTargetLine = (line) => {
|
||||
const lineTrimed = line.trim()
|
||||
for(const linePrefix of linePrefixes) {
|
||||
if (lineTrimed.indexOf(linePrefix) >= 0) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
const cleanTargetLine = (line) => {
|
||||
for(const linePrefix of linePrefixes) {
|
||||
const idx = line.indexOf(linePrefix)
|
||||
if (idx >= 0) {
|
||||
return line.substr(0, idx)
|
||||
}
|
||||
}
|
||||
return line;
|
||||
}
|
||||
|
||||
const lines = content.split(os.EOL)
|
||||
let isFirst = true
|
||||
let newContent = ""
|
||||
for (const line of lines) {
|
||||
if (isTargetLine(line)) {
|
||||
if (isFirst) {
|
||||
newContent += line + os.EOL
|
||||
isFirst = false
|
||||
} else {
|
||||
newContent += cleanTargetLine(line) + os.EOL
|
||||
}
|
||||
} else {
|
||||
newContent += line + os.EOL
|
||||
}
|
||||
}
|
||||
|
||||
return newContent
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
deduplicateLicenses,
|
||||
deduplicateSolidityVersoins,
|
||||
deduplicateSolidityExpHeaders
|
||||
}
|
|
@ -1,37 +0,0 @@
|
|||
const { SEMICOLON, EMPTY } = require('./constants')
|
||||
const pragmaSubstr = 'pragma solidity'
|
||||
|
||||
/*
|
||||
* Removes all pragma solidity instruction
|
||||
*/
|
||||
function removeDoubledSolidityVersion(content) {
|
||||
//1st pragma solidity declaration
|
||||
const { firstIndex, lastIndex } = getFirstPragma(content)
|
||||
const contentPart = content.substr(lastIndex)
|
||||
let contentFiltered = contentPart
|
||||
//remove other pragma solidity declarations
|
||||
const regex = new RegExp(pragmaSubstr,'gi')
|
||||
let result
|
||||
while ( (result = regex.exec(contentPart)) ) {
|
||||
const start = result.index
|
||||
const end = start + contentPart.substr(start).indexOf(SEMICOLON) + 1
|
||||
if (start != firstIndex) contentFiltered = contentFiltered.replace(contentPart.substring(start, end), EMPTY)
|
||||
}
|
||||
|
||||
return contentFiltered
|
||||
}
|
||||
|
||||
/*
|
||||
* Gets 1st pragma solidity instruction from content
|
||||
*/
|
||||
function getFirstPragma(content) {
|
||||
const firstIndex = content.indexOf(pragmaSubstr)
|
||||
const lastIndex = firstIndex + content.substr(firstIndex).indexOf(SEMICOLON) + 1
|
||||
const pragma = content.substr(0, lastIndex)
|
||||
return { pragma, firstIndex, lastIndex}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
removeDoubledSolidityVersion,
|
||||
getFirstPragma,
|
||||
}
|
|
@ -1,40 +0,0 @@
|
|||
const { SEMICOLON, EMPTY } = require('./constants')
|
||||
const pragmaExperimentalstr = 'pragma experimental'
|
||||
|
||||
/*
|
||||
* Removes all pragma solidity instruction
|
||||
*/
|
||||
function removeDuplicatedExpHeaders(content) {
|
||||
//1st pragma solidity declaration
|
||||
const { firstIndex, lastIndex } = getFirstPragmaExp(content)
|
||||
if (firstIndex >= 0 && lastIndex > 0) {
|
||||
const contentPart = content.substr(lastIndex)
|
||||
let contentFiltered = contentPart
|
||||
//remove other pragma solidity declarations
|
||||
const regex = new RegExp(pragmaExperimentalstr,'gi')
|
||||
let result
|
||||
while ( (result = regex.exec(contentPart)) ) {
|
||||
const start = result.index
|
||||
const end = start + contentPart.substr(start).indexOf(SEMICOLON) + 1
|
||||
if (start != firstIndex) contentFiltered = contentFiltered.replace(contentPart.substring(start, end), EMPTY)
|
||||
}
|
||||
return contentFiltered
|
||||
} else {
|
||||
return content
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Gets 1st pragma solidity instruction from content
|
||||
*/
|
||||
function getFirstPragmaExp(content) {
|
||||
const firstIndex = content.indexOf(pragmaExperimentalstr)
|
||||
const lastIndex = firstIndex + content.substr(firstIndex).indexOf(SEMICOLON) + 1
|
||||
const pragmaExp = content.substr(0, lastIndex)
|
||||
return { pragmaExp, firstIndex, lastIndex}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
removeDuplicatedExpHeaders,
|
||||
getFirstPragmaExp,
|
||||
}
|
|
@ -1,4 +1,5 @@
|
|||
const fs = require('fs')
|
||||
const os = require('os')
|
||||
const path = require('path')
|
||||
const variables = require('./variables')
|
||||
const constants = require('./constants')
|
||||
|
@ -9,68 +10,68 @@ const cleanPath = require('./clean-path')
|
|||
const log = require('./logger')
|
||||
|
||||
async function replaceAllImportsInCurrentLayer(i, importObjs, updatedFileContent, dir) {
|
||||
return new Promise(async (resolve) => {
|
||||
await replaceAllImportsInCurrentLayerInner(i, importObjs, updatedFileContent, dir, resolve)
|
||||
})
|
||||
return new Promise(async (resolve) => {
|
||||
await replaceAllImportsInCurrentLayerInner(i, importObjs, updatedFileContent, dir, resolve)
|
||||
})
|
||||
}
|
||||
|
||||
async function replaceAllImportsInCurrentLayerInner(i, importObjs, updatedFileContent, dir, resolve) {
|
||||
if (i >= importObjs.length) {
|
||||
return resolve(updatedFileContent)
|
||||
}
|
||||
if (i >= importObjs.length) {
|
||||
return resolve(updatedFileContent)
|
||||
}
|
||||
|
||||
let importObj = importObjs[i]
|
||||
const { importedSrcFiles } = variables
|
||||
let _updatedFileContent
|
||||
let importObj = importObjs[i]
|
||||
const { importedSrcFiles } = variables
|
||||
let _updatedFileContent
|
||||
|
||||
//replace contracts aliases
|
||||
if (importObj.contractName) {
|
||||
_updatedFileContent = updatedFileContent.replace(importObj.alias + constants.DOT, importObj.contractName + constants.DOT)
|
||||
} else {
|
||||
_updatedFileContent = updatedFileContent
|
||||
}
|
||||
//replace contracts aliases
|
||||
if (importObj.contractName) {
|
||||
_updatedFileContent = updatedFileContent.replace(importObj.alias + constants.DOT, importObj.contractName + constants.DOT)
|
||||
} else {
|
||||
_updatedFileContent = updatedFileContent
|
||||
}
|
||||
|
||||
let { dependencyPath } = importObj
|
||||
dependencyPath = cleanPath(dependencyPath)
|
||||
let isAbsolutePath = !dependencyPath.startsWith(constants.DOT)
|
||||
let filePath = isAbsolutePath ? dependencyPath : (dir + dependencyPath)
|
||||
filePath = cleanPath(filePath)
|
||||
let { dependencyPath } = importObj
|
||||
dependencyPath = cleanPath(dependencyPath)
|
||||
let isAbsolutePath = !dependencyPath.startsWith(constants.DOT)
|
||||
let filePath = isAbsolutePath ? dependencyPath : (dir + dependencyPath)
|
||||
filePath = cleanPath(filePath)
|
||||
|
||||
importObj = updateImportObjectLocationInTarget(importObj, _updatedFileContent)
|
||||
const importStatement = _updatedFileContent.substring(importObj.startIndex, importObj.endIndex)
|
||||
const fileBaseName = path.basename(filePath)
|
||||
const fileExists = fs.existsSync(filePath, fs.F_OK)
|
||||
if (fileExists) {
|
||||
log.info(`${filePath} SOURCE FILE WAS FOUND`)
|
||||
const importedFileContentUpdated = await changeRelativePathToAbsolute(filePath)
|
||||
if (!importedSrcFiles.hasOwnProperty(fileBaseName)) {
|
||||
importedSrcFiles[fileBaseName] = importedFileContentUpdated
|
||||
if (importedFileContentUpdated.includes(constants.IS)) {
|
||||
_updatedFileContent = _updatedFileContent.replace(importStatement, importedFileContentUpdated)
|
||||
} else {
|
||||
_updatedFileContent = importedFileContentUpdated + _updatedFileContent.replace(importStatement, constants.EMPTY)
|
||||
}
|
||||
} else {
|
||||
_updatedFileContent = _updatedFileContent.replace(importStatement, constants.EMPTY)
|
||||
//issue #1.
|
||||
if (_updatedFileContent.includes(importedSrcFiles[fileBaseName]) && _updatedFileContent.includes(constants.IMPORT)) {
|
||||
_updatedFileContent = importedFileContentUpdated + _updatedFileContent.replace(importedSrcFiles[fileBaseName], constants.EMPTY)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (!importedSrcFiles.hasOwnProperty(fileBaseName)) {
|
||||
log.warn(`!!! ${filePath} SOURCE FILE WAS NOT FOUND. I'M TRYING TO FIND IT RECURSIVELY !!!`)
|
||||
const directorySeperator = process.platform === 'win32' ? '\\' : constants.SLASH
|
||||
const dirNew = dir.substring(0, dir.lastIndexOf(directorySeperator))
|
||||
_updatedFileContent = await findFile.byNameAndReplace(dirNew, dependencyPath, _updatedFileContent, importStatement)
|
||||
log.info(`${filePath} SOURCE FILE WAS FOUND`)
|
||||
} else {
|
||||
_updatedFileContent = _updatedFileContent.replace(importStatement, constants.EMPTY)
|
||||
}
|
||||
}
|
||||
importObj = updateImportObjectLocationInTarget(importObj, _updatedFileContent)
|
||||
const importStatement = _updatedFileContent.substring(importObj.startIndex, importObj.endIndex)
|
||||
const fileBaseName = path.basename(filePath)
|
||||
const fileExists = fs.existsSync(filePath, fs.F_OK)
|
||||
if (fileExists) {
|
||||
log.info(`${filePath} SOURCE FILE WAS FOUND`)
|
||||
const importedFileContentUpdated = await changeRelativePathToAbsolute(filePath)
|
||||
if (!importedSrcFiles.hasOwnProperty(fileBaseName)) {
|
||||
importedSrcFiles[fileBaseName] = importedFileContentUpdated
|
||||
if (importedFileContentUpdated.includes(constants.IS)) {
|
||||
_updatedFileContent = _updatedFileContent.replace(importStatement, importedFileContentUpdated)
|
||||
} else {
|
||||
_updatedFileContent = importedFileContentUpdated + _updatedFileContent.replace(importStatement, constants.EMPTY)
|
||||
}
|
||||
} else {
|
||||
_updatedFileContent = _updatedFileContent.replace(importStatement, constants.EMPTY)
|
||||
//issue #1.
|
||||
if (_updatedFileContent.includes(importedSrcFiles[fileBaseName]) && _updatedFileContent.includes(constants.IMPORT)) {
|
||||
_updatedFileContent = importedFileContentUpdated + _updatedFileContent.replace(importedSrcFiles[fileBaseName], constants.EMPTY)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (!importedSrcFiles.hasOwnProperty(fileBaseName)) {
|
||||
log.warn(`!!! ${filePath} SOURCE FILE WAS NOT FOUND. I'M TRYING TO FIND IT RECURSIVELY !!!`)
|
||||
const directorySeperator = process.platform === 'win32' ? '\\' : constants.SLASH
|
||||
const dirNew = dir.substring(0, dir.lastIndexOf(directorySeperator))
|
||||
_updatedFileContent = await findFile.byNameAndReplace(dirNew, dependencyPath, _updatedFileContent, importStatement)
|
||||
log.info(`${filePath} SOURCE FILE WAS FOUND`)
|
||||
} else {
|
||||
_updatedFileContent = _updatedFileContent.replace(importStatement, constants.EMPTY)
|
||||
}
|
||||
}
|
||||
|
||||
i++
|
||||
replaceAllImportsInCurrentLayerInner(i, importObjs, _updatedFileContent, dir, resolve)
|
||||
i++
|
||||
replaceAllImportsInCurrentLayerInner(i, importObjs, _updatedFileContent, dir, resolve)
|
||||
}
|
||||
|
||||
module.exports = replaceAllImportsInCurrentLayer
|
||||
|
|
|
@ -5,19 +5,19 @@ const replaceAllImportsInCurrentLayer = require('./replace-all-imports-in-curren
|
|||
* Recursively replaces all imports
|
||||
*/
|
||||
async function replaceAllImportsRecursively(fileContent, dir) {
|
||||
return new Promise(async (resolve) => {
|
||||
await replaceAllImportsRecursivelyInner(fileContent, dir, resolve)
|
||||
})
|
||||
return new Promise(async (resolve) => {
|
||||
await replaceAllImportsRecursivelyInner(fileContent, dir, resolve)
|
||||
})
|
||||
}
|
||||
|
||||
async function replaceAllImportsRecursivelyInner(fileContent, dir, resolve) {
|
||||
const importObjs = await findAllImportPaths(dir, fileContent)
|
||||
if (!importObjs || importObjs.length == 0) {
|
||||
return resolve(fileContent)
|
||||
}
|
||||
const importObjs = await findAllImportPaths(dir, fileContent)
|
||||
if (!importObjs || importObjs.length == 0) {
|
||||
return resolve(fileContent)
|
||||
}
|
||||
|
||||
const updatedFileContent = await replaceAllImportsInCurrentLayer(0, importObjs, fileContent, dir)
|
||||
replaceAllImportsRecursivelyInner(updatedFileContent, dir, resolve)
|
||||
const updatedFileContent = await replaceAllImportsInCurrentLayer(0, importObjs, fileContent, dir)
|
||||
replaceAllImportsRecursivelyInner(updatedFileContent, dir, resolve)
|
||||
}
|
||||
|
||||
module.exports = replaceAllImportsRecursively
|
||||
module.exports = replaceAllImportsRecursively
|
||||
|
|
58
index.js
58
index.js
|
@ -5,42 +5,48 @@ const variables = require('./helpers/variables')
|
|||
const log = require('./helpers/logger')
|
||||
const constants = require('./helpers/constants')
|
||||
const cleanPath = require('./helpers/clean-path')
|
||||
const { removeDoubledSolidityVersion, getFirstPragma } = require('./helpers/remove-doubled-solidity-version')
|
||||
const { removeDuplicatedExpHeaders, getFirstPragmaExp } = require('./helpers/remove-duplicated-experimental-headers')
|
||||
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)
|
||||
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 getSourceFiles(dir, path) {
|
||||
return await glob(path)
|
||||
return await glob(path)
|
||||
}
|
||||
|
||||
async function replaceImports(inputFileContent, dir) {
|
||||
const { pragma: firstPragma } = getFirstPragma(inputFileContent)
|
||||
let { pragmaExp: firstPragmaExp } = getFirstPragmaExp(inputFileContent)
|
||||
let outputFileContent = await replaceAllImportsRecursively(inputFileContent, dir)
|
||||
|
||||
let outputFileContent = await replaceAllImportsRecursively(inputFileContent, dir)
|
||||
outputFileContent = removeDoubledSolidityVersion(outputFileContent)
|
||||
outputFileContent = removeDuplicatedExpHeaders(outputFileContent)
|
||||
firstPragmaExp = removeDoubledSolidityVersion(firstPragmaExp)
|
||||
outputFileContent = firstPragma + firstPragmaExp + 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`)
|
||||
// outputFileContent = outputFileContent.toString()
|
||||
// // console.log('outputFileContent:', outputFileContent);
|
||||
|
||||
outputFileContent = deduplicateLicenses(outputFileContent)
|
||||
outputFileContent = deduplicateSolidityVersoins(outputFileContent)
|
||||
outputFileContent = deduplicateSolidityExpHeaders(outputFileContent)
|
||||
|
||||
// console.log('outputFileContent type:', Object.prototype.toString.call(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`)
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue