fix issue #43 & #46

This commit is contained in:
kongliangzhong 2020-08-25 15:05:15 +08:00
parent 1350699582
commit d5ee50dfd0
7 changed files with 178 additions and 180 deletions

View File

@ -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,
}

View File

@ -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
}

View File

@ -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,
}

View File

@ -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,
}

View File

@ -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

View File

@ -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

View File

@ -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`)
}