import './type-extensions' ; import fsExtra from 'fs-extra' ; import { TASK_CLEAN , TASK_COMPILE , TASK_COMPILE_SOLIDITY_COMPILE_JOBS } from 'hardhat/builtin-tasks/task-names' ; import { extendConfig , subtask , task , types } from 'hardhat/config' ; import { getFullyQualifiedName } from 'hardhat/utils/contract-names' ; import _ , { uniq } from 'lodash' ; import { glob , PublicConfig as RunTypeChainConfig , runTypeChain } from 'typechain' ; import { getDefaultTypechainConfig } from './config' ; import { TASK_TYPECHAIN , TASK_TYPECHAIN_GENERATE_TYPES } from './constants' ; const taskArgsStore = { noTypechain : false , fullRebuild : false } ; extendConfig ( ( config ) => { config . typechain = getDefaultTypechainConfig ( config ) ; } ) ; task ( TASK_COMPILE , 'Compiles the entire project, building all artifacts' ) . addFlag ( 'noTypechain' , 'Skip Typechain compilation' ) . setAction ( async ( { noTypechain } , _ , runSuper ) => { taskArgsStore . noTypechain = noTypechain ! ! ; await runSuper ( ) ; } ) ; subtask ( TASK_COMPILE_SOLIDITY_COMPILE_JOBS , 'Compiles the entire project, building all artifacts' ) . setAction ( async ( taskArgs , { run } , runSuper ) => { const compileSolOutput = await runSuper ( taskArgs ) ; await run ( TASK_TYPECHAIN_GENERATE_TYPES , { compileSolOutput } ) ; return compileSolOutput ; } ) ; subtask ( TASK_TYPECHAIN_GENERATE_TYPES ) . addParam ( 'compileSolOutput' , 'Solidity compilation output' , { } , types . any ) . setAction ( async ( { compileSolOutput } , { config , artifacts } ) => { const artifactFQNs = getFQNamesFromCompilationOutput ( compileSolOutput ) ; const artifactPaths = uniq ( artifactFQNs . map ( ( fqn ) => ( artifacts as any ) . _getArtifactPathFromFullyQualifiedName ( fqn ) ) ) ; if ( taskArgsStore . noTypechain ) { return compileSolOutput ; } const typechainCfg = config . typechain ; if ( artifactPaths . length === 0 && ! taskArgsStore . fullRebuild && ! typechainCfg . externalArtifacts ) { console . log ( 'No need to generate any newer typings.' ) ; return compileSolOutput ; } const needsFullRebuild = taskArgsStore . fullRebuild || typechainCfg . target !== 'ethers-v5' ; console . log ( `Generating typings for: ${ artifactPaths . length } artifacts in dir: ${ typechainCfg . outDir } for target: ${ typechainCfg . target }` ) ; const cwd = config . paths . root ; const allFiles = glob ( cwd , [ `${ config . paths . artifacts }/!(build-info)/**/+([a-zA-Z0-9_]).json` ] ) ; if ( typechainCfg . externalArtifacts ) { allFiles . push ( ... glob ( cwd , typechainCfg . externalArtifacts , false ) ) ; } const typechainOptions = { cwd , allFiles , outDir : typechainCfg . outDir , target : typechainCfg . target , flags : { alwaysGenerateOverloads : typechainCfg . alwaysGenerateOverloads , tsNocheck : typechainCfg . tsNocheck , environment : 'hardhat' , } , } ; const result = await runTypeChain ( { ... typechainOptions , filesToProcess : needsFullRebuild ? allFiles : glob ( cwd , artifactPaths ) , } ) ; console . log ( `Successfully generated ${ result . filesGenerated } typings!` ) ; if ( ! needsFullRebuild && typechainCfg . externalArtifacts ) { const result = await runTypeChain ( { ... typechainOptions , filesToProcess : glob ( cwd , typechainCfg . externalArtifacts ! , false ) , } ) ; console . log ( `Successfully generated ${ result . filesGenerated } typings for external artifacts!` ) ; } } ) ; task ( TASK_TYPECHAIN , 'Generate Typechain typings for compiled contracts' ) . setAction ( async ( _ , { run } ) => { taskArgsStore . fullRebuild = true ; await run ( TASK_COMPILE , { quiet : true } ) ; } ) ; task ( TASK_CLEAN , 'Clears the cache and deletes all artifacts' , async ( { global } , { config } , runSuper ) => { if ( global ) { return ; } if ( await fsExtra . pathExists ( config . typechain . outDir ) ) { await fsExtra . remove ( config . typechain . outDir ) ; } await runSuper ( ) ; } ) ; function getFQNamesFromCompilationOutput ( compileSolOutput ) { const allFQNNamesNested = compileSolOutput . artifactsEmittedPerJob . map ( ( a ) => { return a . artifactsEmittedPerFile . map ( ( artifactPerFile ) => { return artifactPerFile . artifactsEmitted . map ( ( artifactName ) => { return getFullyQualifiedName ( artifactPerFile . file . sourceName , artifactName ) ; } ) ; } ) ; } ) ; return _ ( allFQNNamesNested ) . flatten ( ) . flatten ( ) . value ( ) ; }