UNPKG

@graphprotocol/graph-cli

Version:

CLI for building for and deploying to The Graph

195 lines (181 loc) • 5.84 kB
const fs = require('fs-extra') const path = require('path') const prettier = require('prettier') const ABI = require('./abi') const { step, withSpinner } = require('../../command-helpers/spinner') const { GENERATED_FILE_NOTE } = require('../../codegen/typescript') const { displayPath } = require('../../command-helpers/fs') module.exports = class EthereumTypeGenerator { constructor(options = {}) { this.sourceDir = options.sourceDir this.outputDir = options.outputDir } async loadABIs(subgraph) { return await withSpinner( 'Load contract ABIs', 'Failed to load contract ABIs', `Warnings while loading contract ABIs`, async spinner => { try { return subgraph .get('dataSources') .reduce( (abis, dataSource) => dataSource.mapping?.abis.reduce( (abis, abi) => abis.push( this._loadABI( dataSource, abi.get('name'), abi.get('file'), spinner, ), ), abis, ), [], ) } catch (e) { throw Error(`Failed to load contract ABIs: ${e.message}`) } }, ) } _loadABI(dataSource, name, maybeRelativePath, spinner) { try { if (this.sourceDir) { let absolutePath = path.resolve(this.sourceDir, maybeRelativePath) step(spinner, `Load contract ABI from`, displayPath(absolutePath)) return { dataSource: dataSource, abi: ABI.load(name, absolutePath) } } else { return { dataSource: dataSource, abi: ABI.load(name, maybeRelativePath) } } } catch (e) { throw Error(`Failed to load contract ABI: ${e.message}`) } } async loadDataSourceTemplateABIs(subgraph) { return await withSpinner( `Load data source template ABIs`, `Failed to load data source template ABIs`, `Warnings while loading data source template ABIs`, async spinner => { let abis = [] for (let template of subgraph.get('templates', [])) { for (let abi of template.mapping?.abis) { abis.push( this._loadDataSourceTemplateABI( template, abi.get('name'), abi.get('file'), spinner, ), ) } } return abis }, ) } _loadDataSourceTemplateABI(template, name, maybeRelativePath, spinner) { try { if (this.sourceDir) { let absolutePath = path.resolve(this.sourceDir, maybeRelativePath) step(spinner, `Load data source template ABI from`, displayPath(absolutePath)) return { template, abi: ABI.load(name, absolutePath) } } else { return { template, abi: ABI.load(name, maybeRelativePath) } } } catch (e) { throw Error(`Failed to load data source template ABI: ${e.message}`) } } generateTypesForABIs(abis) { return withSpinner( `Generate types for contract ABIs`, `Failed to generate types for contract ABIs`, `Warnings while generating types for contract ABIs`, async spinner => { return await Promise.all( abis.map(async (abi, name) => await this._generateTypesForABI(abi, spinner)), ) }, ) } async _generateTypesForABI(abi, spinner) { try { step( spinner, `Generate types for contract ABI:`, `${abi.abi.name} (${displayPath(abi.abi.file)})`, ) let codeGenerator = abi.abi.codeGenerator() let code = prettier.format( [ GENERATED_FILE_NOTE, ...codeGenerator.generateModuleImports(), ...codeGenerator.generateTypes(), ].join('\n'), { parser: 'typescript', }, ) let outputFile = path.join( this.outputDir, abi.dataSource.get('name'), `${abi.abi.name}.ts`, ) step(spinner, `Write types to`, displayPath(outputFile)) await fs.mkdirs(path.dirname(outputFile)) await fs.writeFile(outputFile, code) } catch (e) { throw Error(`Failed to generate types for contract ABI: ${e.message}`) } } async generateTypesForDataSourceTemplateABIs(abis) { return await withSpinner( `Generate types for data source template ABIs`, `Failed to generate types for data source template ABIs`, `Warnings while generating types for data source template ABIs`, async spinner => { return await Promise.all( abis.map( async (abi, name) => await this._generateTypesForDataSourceTemplateABI(abi, spinner), ), ) }, ) } async _generateTypesForDataSourceTemplateABI(abi, spinner) { try { step( spinner, `Generate types for data source template ABI:`, `${abi.template.get('name')} > ${abi.abi.name} (${displayPath(abi.abi.file)})`, ) let codeGenerator = abi.abi.codeGenerator() let code = prettier.format( [ GENERATED_FILE_NOTE, ...codeGenerator.generateModuleImports(), ...codeGenerator.generateTypes(), ].join('\n'), { parser: 'typescript', }, ) let outputFile = path.join( this.outputDir, 'templates', abi.template.get('name'), `${abi.abi.name}.ts`, ) step(spinner, `Write types to`, displayPath(outputFile)) await fs.mkdirs(path.dirname(outputFile)) await fs.writeFile(outputFile, code) } catch (e) { throw Error(`Failed to generate types for data source template ABI: ${e.message}`) } } }