harsta
Version:
Harsta is a contract development tool based on Hardhat, designed to streamline the development, testing, and referencing of contracts, addresses, ABIs, and contract instances.
121 lines (106 loc) • 3.85 kB
text/typescript
import path from 'pathe'
import fs from 'fs-extra'
import { absolutePaths, packRoot, relativePaths, userRoot } from '../../constants'
import { findsFilePaths, resolveFileConflicts } from '../../utils'
export interface ContractFragment {
path: string
input: {
import: string
relative: string
typechains: string
factory: string
exports: string[]
file: string
}
outfile: {
dirname: string
file: string
name: string
}
}
export async function resolveUserAddresses() {
const userAddressesPath = path.resolve(userRoot, './config/addresses.ts')
const addrFile = path.resolve(userRoot, './config/addresses.ts')
const jsonFile = path.resolve(userRoot, './config/addresses.json')
if (fs.existsSync(jsonFile))
return `export default ${await fs.readFile(jsonFile, 'utf-8')}`
if (fs.existsSync(addrFile))
return fs.readFile(addrFile, 'utf-8')
const defaultFileContent = 'export default {\n\n}\n'
await fs.ensureDir(path.dirname(userAddressesPath))
await fs.writeFile(userAddressesPath, defaultFileContent)
return defaultFileContent
}
export function resolveFragmentsPaths() {
const generateRoot = path.resolve(packRoot, './generated')
const fragmentsFactoriesPaths = resolveFileConflicts(findsFilePaths(absolutePaths.generateFactoriesFragments))
const fragmentsContractsPaths = resolveFileConflicts(findsFilePaths(absolutePaths.generateContractsFragments))
return {
factories: generateFragmentData(
fragmentsFactoriesPaths,
generateRoot,
relativePaths.generateFactories,
relativePaths.generateFactoriesTypechain,
) as ContractFragment[],
contracts: generateFragmentData(
fragmentsContractsPaths,
generateRoot,
relativePaths.generateContracts,
relativePaths.generateContractsTypechain,
) as ContractFragment[],
}
}
function generateFragmentData(fragments: string[], generateRoot: string, contractsDir: string, typechainsDir: string) {
return fragments.map((fPath: string) => {
const outDir = path.resolve(generateRoot, contractsDir)
const outfile_ = outfile(fPath, outDir)
const typechainsPath = path.resolve(generateRoot, typechainsDir)
return {
path: fPath,
input: input(fPath, typechainsPath, outfile_),
outfile: outfile_,
}
})
}
function input(p: string, typechainsPath: string, outfile: any) {
const relativeFile = getRelativeFilePath(p, typechainsPath)
const file = `${path.resolve(typechainsPath, relativeFile)}.ts`
const importPath = `${path.relative(outfile.dirname, typechainsPath)}/${relativeFile}`
const factoryPath = `${typechainsPath}/factories/${relativeFile}__factory.ts`
const content = fs.readFileSync(file, 'utf-8')
const exports = extractExports(content, outfile.name)
return {
import: importPath,
relative: relativeFile,
typechains: typechainsPath,
factory: factoryPath,
exports,
file,
}
}
function getRelativeFilePath(p: string, typechainsPath: string) {
if (p.includes('.sol')) {
const file = path.resolve(typechainsPath, `${p.split('.sol')[0]}.sol`)
return fs.existsSync(file) ? p.split('.json')[0] : p.split('.sol')[0]
}
return p.split('.json')[0]
}
function extractExports(content: string, outfileName: string) {
const regExps = [
/export declare namespace (.*?) \{/gs,
/export interface (.*?) extends Interface \{/gs,
/export namespace (.*?) \{/gs,
]
const exports = regExps
.flatMap(reg => [...content.matchAll(reg)].map(mat => mat[1]))
if (!exports.includes(outfileName)) {
exports.push(outfileName)
}
return exports
}
function outfile(p: string, outdir: string) {
const name = path.basename(p).replace('.json', '')
const file = path.resolve(outdir, p).replace('.json', '.ts')
const dirname = path.dirname(file)
return { dirname, file, name }
}