import * as fs from 'fs' import * as path from 'path' import AbiManager from '../utils/abi_manager' class GenManager { private static contracts = ['Daos', 'Organization', 'OrgToken'] static gen() { this.contracts.forEach(name => { new Generator(name).gen() }) this.genAbiData() } private static genAbiData() { let r = {} let p = path.join(__dirname, '../../release/contracts') let cs = fs.readdirSync(p) as string[] cs.forEach(c => { let n = path.basename(c) let fns = fs.readdirSync(path.join(p, n)) as string[] let vs: number[] = [] fns.forEach(fn => { let n = path.basename(fn) if (/^(\d+)\..+$/.test(n)) { vs.push(parseInt(RegExp.$1)) } }) vs = vs.sort() let rv = {} vs.forEach(v => { rv[v] = JSON.parse(fs.readFileSync(path.join(p, n, `${v}.json`), 'utf8')) }) r[n] = rv }) fs.writeFileSync(path.join(__dirname, '../utils/abi-data.ts'), `export default ${JSON.stringify(r, null, 2)}`) } } class Generator { name: string abi: any private contractTemplate: string private constructorTemplate: string private viewFunctionTemplate: string private notViewFunctionTemplate: string constructor(name: string) { this.name = name this.abi = AbiManager.getAbiAndBytecode(name).abi this.contractTemplate = String(fs.readFileSync(path.join(__dirname, 'resources/contract_template.txt'))) this.constructorTemplate = String(fs.readFileSync(path.join(__dirname, 'resources/function_constructor_template.txt'))) this.viewFunctionTemplate = String(fs.readFileSync(path.join(__dirname, 'resources/function_view_template.txt'))) this.notViewFunctionTemplate = String(fs.readFileSync(path.join(__dirname, 'resources/function_not_view_template.txt'))) } private get content(): string { return this.contractTemplate .replace(/@contract/ig, this.name) .replace(/@constructor/ig, this.constructorCode) .replace('@functions', this.functions) } private get constructorCode(): string { let ele: any = null for (let i = 0; i < this.abi.length; ++i) { let e = this.abi[i] if (e['type'] == 'constructor') { ele = e break } } if (!ele) { return this.constructorTemplate .replace(/@contract/ig, this.name) .replace('@params_def', '') .replace('@params_list', '') } return this.constructorTemplate .replace(/@contract/ig, this.name) .replace('@params_def', this.paramsDef(ele) + ', ') .replace('@params_list', this.paramsList(ele)) } private get functions(): string { let s = '' this.abi.forEach(ele => { if (ele.type == 'function') { if (ele.stateMutability == 'view') { s += '\n' + this.genViewFunction(ele) } else { s += '\n' + this.genNotViewFunction(ele) } } }) return s } private genViewFunction(ele) { return this.viewFunctionTemplate .replace(/@function/ig, ele.name) .replace('@params_def', this.paramsDef(ele)) .replace('@params_list', this.paramsList(ele)) } private genNotViewFunction(ele) { let n = ele.name.substr(0, 1).toUpperCase() + ele.name.substr(1) return this.notViewFunctionTemplate .replace(/@function_name/ig, n) .replace(/@function/ig, ele.name) .replace('@params_def', this.paramsDef(ele)) .replace('@params_list', this.paramsList(ele)) } private paramsDef(ele) { let r = [] let ai = 0 ele.inputs.forEach(i => { let n = i.name if (n.length == 0) { n = 'arg' + (ai++) } if (i.type.endsWith('[]')) { r.push(n + ': string[]') } else { r.push(n + ': string') } }) return r.join(', ') } private paramsList(ele) { let r = [] let ai = 0 ele.inputs.forEach(i => { let n = i.name if (n.length == 0) { n = 'arg' + (ai++) } r.push(n) }) return r.join(', ') } private get fileName(): string { let a = this.name.match(/[A-Z]+?[^A-Z]*/g) let r = [] a.forEach(w => { r.push(w.toLocaleLowerCase()) }) return r.join('_') } gen() { let p = path.join(__dirname, '../', this.fileName + '.ts') fs.writeFileSync(p, this.content) } } export default GenManager