@typemove/move 1.0.0-rc.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +201 -0
- package/package.json +20 -0
- package/src/abstract-codegen.ts +684 -0
- package/src/abstract-move-coder.ts +394 -0
- package/src/account.ts +93 -0
- package/src/chain-adapter.ts +30 -0
- package/src/index.ts +4 -0
- package/src/internal-models.ts +40 -0
- package/src/types.ts +251 -0
- package/src/utils.ts +83 -0
|
@@ -0,0 +1,684 @@
|
|
|
1
|
+
import {
|
|
2
|
+
InternalMoveFunction,
|
|
3
|
+
InternalMoveFunctionVisibility,
|
|
4
|
+
InternalMoveModule,
|
|
5
|
+
InternalMoveStruct,
|
|
6
|
+
} from './internal-models.js'
|
|
7
|
+
import path from 'path'
|
|
8
|
+
import fs from 'fs'
|
|
9
|
+
import { AccountModulesImportInfo, AccountRegister } from './account.js'
|
|
10
|
+
import chalk from 'chalk'
|
|
11
|
+
import { format } from 'prettier'
|
|
12
|
+
import {
|
|
13
|
+
isFrameworkAccount,
|
|
14
|
+
moduleQname,
|
|
15
|
+
normalizeToJSName,
|
|
16
|
+
SPLITTER,
|
|
17
|
+
upperFirst,
|
|
18
|
+
VECTOR_STR,
|
|
19
|
+
} from './utils.js'
|
|
20
|
+
import { camel } from 'radash'
|
|
21
|
+
import { TypeDescriptor } from './types.js'
|
|
22
|
+
import { ChainAdapter } from './chain-adapter.js'
|
|
23
|
+
|
|
24
|
+
interface OutputFile {
|
|
25
|
+
fileName: string
|
|
26
|
+
fileContent: string
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
interface Config<NetworkType> {
|
|
30
|
+
fileName: string
|
|
31
|
+
outputDir: string
|
|
32
|
+
network: NetworkType
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// TODO be able to generate cjs
|
|
36
|
+
export abstract class AbstractCodegen<NetworkType, ModuleTypes, StructType> {
|
|
37
|
+
TEST_NET: NetworkType
|
|
38
|
+
MAIN_NET: NetworkType
|
|
39
|
+
ADDRESS_TYPE: string
|
|
40
|
+
PREFIX: string
|
|
41
|
+
STRUCT_FIELD_NAME: string = 'data'
|
|
42
|
+
GENERATE_CLIENT = false
|
|
43
|
+
GENERATE_ON_ENTRY = true
|
|
44
|
+
PAYLOAD_OPTIONAL = false
|
|
45
|
+
SYSTEM_MODULES = new Set(['0x1', '0x2', '0x3'])
|
|
46
|
+
ESM = true
|
|
47
|
+
|
|
48
|
+
chainAdapter: ChainAdapter<NetworkType, ModuleTypes, StructType>
|
|
49
|
+
|
|
50
|
+
protected constructor(
|
|
51
|
+
chainAdapter: ChainAdapter<NetworkType, ModuleTypes, StructType>
|
|
52
|
+
) {
|
|
53
|
+
this.chainAdapter = chainAdapter
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
public maybeEsmPrefix() {
|
|
57
|
+
return this.ESM ? '.js' : ''
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
readModulesFile(fullPath: string) {
|
|
61
|
+
return JSON.parse(fs.readFileSync(fullPath, 'utf-8'))
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
async generate(
|
|
65
|
+
srcDir: string,
|
|
66
|
+
outputDir: string,
|
|
67
|
+
builtin = false
|
|
68
|
+
): Promise<number> {
|
|
69
|
+
const num1 = await this.generateForNetwork(
|
|
70
|
+
srcDir,
|
|
71
|
+
outputDir,
|
|
72
|
+
this.MAIN_NET,
|
|
73
|
+
builtin
|
|
74
|
+
)
|
|
75
|
+
const num2 = await this.generateForNetwork(
|
|
76
|
+
path.join(srcDir, 'testnet'),
|
|
77
|
+
path.join(outputDir, 'testnet'),
|
|
78
|
+
this.TEST_NET,
|
|
79
|
+
builtin
|
|
80
|
+
)
|
|
81
|
+
return num1 + num2
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
async generateForNetwork(
|
|
85
|
+
srcDir: string,
|
|
86
|
+
outputDir: string,
|
|
87
|
+
network: NetworkType,
|
|
88
|
+
builtin = false
|
|
89
|
+
) {
|
|
90
|
+
if (!fs.existsSync(srcDir)) {
|
|
91
|
+
return 0
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
const files = fs.readdirSync(srcDir)
|
|
95
|
+
outputDir = path.resolve(outputDir)
|
|
96
|
+
const outputs: OutputFile[] = []
|
|
97
|
+
|
|
98
|
+
fs.mkdirSync(outputDir, { recursive: true })
|
|
99
|
+
|
|
100
|
+
const loader = new AccountRegister()
|
|
101
|
+
|
|
102
|
+
// when generating user code, don't need to generate framework account
|
|
103
|
+
for (const sysModule of this.SYSTEM_MODULES) {
|
|
104
|
+
loader.accountImports.set(
|
|
105
|
+
sysModule,
|
|
106
|
+
new AccountModulesImportInfo(sysModule, sysModule)
|
|
107
|
+
)
|
|
108
|
+
}
|
|
109
|
+
// const client = getRpcClient(network)
|
|
110
|
+
|
|
111
|
+
for (const file of files) {
|
|
112
|
+
if (!file.endsWith('.json')) {
|
|
113
|
+
continue
|
|
114
|
+
}
|
|
115
|
+
const fullPath = path.resolve(srcDir, file)
|
|
116
|
+
const abi = this.readModulesFile(fullPath)
|
|
117
|
+
const modules = this.chainAdapter.toInternalModules(abi)
|
|
118
|
+
|
|
119
|
+
for (const module of modules) {
|
|
120
|
+
loader.register(module, path.basename(file, '.json'))
|
|
121
|
+
}
|
|
122
|
+
const codeGen = new AccountCodegen(this, loader, abi, modules, {
|
|
123
|
+
fileName: path.basename(file, '.json'),
|
|
124
|
+
outputDir: outputDir,
|
|
125
|
+
network,
|
|
126
|
+
})
|
|
127
|
+
|
|
128
|
+
outputs.push(...codeGen.generate())
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
while (loader.pendingAccounts.size > 0) {
|
|
132
|
+
for (const account of loader.pendingAccounts) {
|
|
133
|
+
console.log(
|
|
134
|
+
`download dependent module for account ${account} at ${network}`
|
|
135
|
+
)
|
|
136
|
+
|
|
137
|
+
try {
|
|
138
|
+
const rawModules = await this.chainAdapter.fetchModules(
|
|
139
|
+
account,
|
|
140
|
+
network
|
|
141
|
+
)
|
|
142
|
+
const modules = this.chainAdapter.toInternalModules(rawModules)
|
|
143
|
+
|
|
144
|
+
fs.writeFileSync(
|
|
145
|
+
path.resolve(srcDir, account + '.json'),
|
|
146
|
+
JSON.stringify(rawModules, null, '\t')
|
|
147
|
+
)
|
|
148
|
+
for (const module of modules) {
|
|
149
|
+
loader.register(module, account)
|
|
150
|
+
}
|
|
151
|
+
const codeGen = new AccountCodegen(
|
|
152
|
+
this,
|
|
153
|
+
loader,
|
|
154
|
+
rawModules,
|
|
155
|
+
modules,
|
|
156
|
+
{
|
|
157
|
+
fileName: account,
|
|
158
|
+
outputDir: outputDir,
|
|
159
|
+
network,
|
|
160
|
+
}
|
|
161
|
+
)
|
|
162
|
+
|
|
163
|
+
outputs.push(...codeGen.generate())
|
|
164
|
+
} catch (e) {
|
|
165
|
+
console.error(
|
|
166
|
+
chalk.red(
|
|
167
|
+
'Error downloading account module, check if you choose the right network,or download account modules manually into your director'
|
|
168
|
+
)
|
|
169
|
+
)
|
|
170
|
+
console.error(e)
|
|
171
|
+
process.exit(1)
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
for (const output of outputs) {
|
|
177
|
+
// const content = output.fileContent
|
|
178
|
+
const content = format(output.fileContent, { parser: 'typescript' })
|
|
179
|
+
fs.writeFileSync(path.join(outputDir, output.fileName), content)
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
const rootFile = path.join(outputDir, 'index.ts')
|
|
183
|
+
let rootFileContent = `/* Autogenerated file. Do not edit manually. */
|
|
184
|
+
/* tslint:disable */
|
|
185
|
+
/* eslint-disable */
|
|
186
|
+
`
|
|
187
|
+
for (const output of outputs) {
|
|
188
|
+
const parsed = path.parse(output.fileName)
|
|
189
|
+
rootFileContent += `export * as _${parsed.name.replaceAll(
|
|
190
|
+
'-',
|
|
191
|
+
'_'
|
|
192
|
+
)} from './${parsed.name}${this.maybeEsmPrefix()}\n`
|
|
193
|
+
}
|
|
194
|
+
fs.writeFileSync(rootFile, rootFileContent)
|
|
195
|
+
|
|
196
|
+
return outputs.length + 1
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
generateNetworkOption(network: NetworkType) {
|
|
200
|
+
switch (network) {
|
|
201
|
+
case this.TEST_NET:
|
|
202
|
+
return 'TEST_NET'
|
|
203
|
+
}
|
|
204
|
+
return 'MAIN_NET'
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
generateModule(
|
|
208
|
+
module: InternalMoveModule,
|
|
209
|
+
allEventStructs: Map<string, InternalMoveStruct>,
|
|
210
|
+
network: NetworkType
|
|
211
|
+
) {
|
|
212
|
+
const qname = moduleQname(module)
|
|
213
|
+
const functions = this.GENERATE_ON_ENTRY
|
|
214
|
+
? module.exposedFunctions
|
|
215
|
+
.map((f) => this.generateForEntryFunctions(module, f))
|
|
216
|
+
.filter((s) => s !== '')
|
|
217
|
+
: []
|
|
218
|
+
const clientFunctions = this.GENERATE_CLIENT
|
|
219
|
+
? module.exposedFunctions
|
|
220
|
+
.map((f) => this.generateClientFunctions(module, f))
|
|
221
|
+
.filter((s) => s !== '')
|
|
222
|
+
: []
|
|
223
|
+
const eventStructs = new Map<string, InternalMoveStruct>()
|
|
224
|
+
for (const [type, struct] of allEventStructs.entries()) {
|
|
225
|
+
if (type.startsWith(qname + SPLITTER)) {
|
|
226
|
+
eventStructs.set(type, struct)
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
const eventTypes = new Set(eventStructs.keys())
|
|
231
|
+
const events = Array.from(eventStructs.values())
|
|
232
|
+
.map((e) => this.generateForEvents(module, e))
|
|
233
|
+
.filter((s) => s !== '')
|
|
234
|
+
const structs = module.structs.map((s) =>
|
|
235
|
+
this.generateStructs(module, s, eventTypes)
|
|
236
|
+
)
|
|
237
|
+
const callArgs = module.exposedFunctions.map((f) =>
|
|
238
|
+
this.generateCallArgsStructs(module, f)
|
|
239
|
+
)
|
|
240
|
+
|
|
241
|
+
const moduleName = normalizeToJSName(module.name)
|
|
242
|
+
let processor = ''
|
|
243
|
+
let client = ''
|
|
244
|
+
|
|
245
|
+
if (clientFunctions.length > 0) {
|
|
246
|
+
client = `
|
|
247
|
+
export class ${moduleName}_client extends ModuleClient {
|
|
248
|
+
${clientFunctions.join('\n')}
|
|
249
|
+
}
|
|
250
|
+
`
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
if (functions.length > 0 || events.length > 0) {
|
|
254
|
+
processor = `export class ${moduleName} extends ${
|
|
255
|
+
this.PREFIX
|
|
256
|
+
}BaseProcessor {
|
|
257
|
+
|
|
258
|
+
constructor(options: ${this.PREFIX}BindOptions) {
|
|
259
|
+
super("${module.name}", options)
|
|
260
|
+
}
|
|
261
|
+
static DEFAULT_OPTIONS: ${this.PREFIX}BindOptions = {
|
|
262
|
+
address: "${module.address}",
|
|
263
|
+
network: ${this.PREFIX}Network.${this.generateNetworkOption(network)}
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
static bind(options: Partial<${
|
|
267
|
+
this.PREFIX
|
|
268
|
+
}BindOptions> = {}): ${moduleName} {
|
|
269
|
+
return new ${moduleName}({ ...${moduleName}.DEFAULT_OPTIONS, ...options })
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
${functions.join('\n')}
|
|
273
|
+
|
|
274
|
+
${events.join('\n')}
|
|
275
|
+
}
|
|
276
|
+
`
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
return `
|
|
280
|
+
${client}
|
|
281
|
+
|
|
282
|
+
${processor}
|
|
283
|
+
|
|
284
|
+
export namespace ${moduleName} {
|
|
285
|
+
${structs.join('\n')}
|
|
286
|
+
|
|
287
|
+
${callArgs.join('\n')}
|
|
288
|
+
}
|
|
289
|
+
`
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
generateStructs(
|
|
293
|
+
module: InternalMoveModule,
|
|
294
|
+
struct: InternalMoveStruct,
|
|
295
|
+
events: Set<string>,
|
|
296
|
+
typeOnly = false
|
|
297
|
+
) {
|
|
298
|
+
const typeParams = struct.typeParams || []
|
|
299
|
+
const genericString = this.generateStructTypeParameters(struct)
|
|
300
|
+
const genericStringAny = this.generateStructTypeParameters(struct, true)
|
|
301
|
+
|
|
302
|
+
const structName = normalizeToJSName(struct.name)
|
|
303
|
+
|
|
304
|
+
const fields = struct.fields.map((field) => {
|
|
305
|
+
const type = this.generateTypeForDescriptor(field.type, module.address)
|
|
306
|
+
return `${field.name}: ${type}`
|
|
307
|
+
})
|
|
308
|
+
|
|
309
|
+
const typeParamApplyArg = typeParams
|
|
310
|
+
.map((v, idx) => {
|
|
311
|
+
return `arg${idx}: TypeDescriptor<T${idx}> = ANY_TYPE`
|
|
312
|
+
})
|
|
313
|
+
.join(',')
|
|
314
|
+
const typeParamApply = typeParams
|
|
315
|
+
.map((v, idx) => {
|
|
316
|
+
return `arg${idx}`
|
|
317
|
+
})
|
|
318
|
+
.join(',')
|
|
319
|
+
|
|
320
|
+
const typeDescriptor = `
|
|
321
|
+
export namespace ${structName}{
|
|
322
|
+
export const TYPE_QNAME = '${module.address}::${module.name}::${struct.name}'
|
|
323
|
+
|
|
324
|
+
const TYPE = new TypeDescriptor<${structName}${genericStringAny}>(${structName}.TYPE_QNAME)
|
|
325
|
+
|
|
326
|
+
export function type${genericString}(${typeParamApplyArg}): TypeDescriptor<${structName}${genericString}> {
|
|
327
|
+
return TYPE.apply(${typeParamApply})
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
`
|
|
331
|
+
if (typeOnly) {
|
|
332
|
+
return typeDescriptor
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
let eventPayload = ''
|
|
336
|
+
if (events.has(moduleQname(module) + SPLITTER + struct.name)) {
|
|
337
|
+
eventPayload = `
|
|
338
|
+
export interface ${structName}Instance extends
|
|
339
|
+
TypedEventInstance<${structName}${genericStringAny}> {
|
|
340
|
+
${this.STRUCT_FIELD_NAME}_decoded: ${structName}${genericStringAny}
|
|
341
|
+
type_arguments: [${struct.typeParams.map((_) => 'string').join(', ')}]
|
|
342
|
+
}
|
|
343
|
+
`
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
return `
|
|
347
|
+
export interface ${structName}${genericString} {
|
|
348
|
+
${fields.join('\n')}
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
${typeDescriptor}
|
|
352
|
+
|
|
353
|
+
${eventPayload}
|
|
354
|
+
`
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
generateFunctionTypeParameters(func: InternalMoveFunction) {
|
|
358
|
+
let genericString = ''
|
|
359
|
+
if (func.typeParams && func.typeParams.length > 0) {
|
|
360
|
+
const params = func.typeParams
|
|
361
|
+
.map((v, idx) => {
|
|
362
|
+
return `T${idx}=any`
|
|
363
|
+
})
|
|
364
|
+
.join(',')
|
|
365
|
+
genericString = `<${params}>`
|
|
366
|
+
}
|
|
367
|
+
return genericString
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
generateStructTypeParameters(struct: InternalMoveStruct, useAny = false) {
|
|
371
|
+
let genericString = ''
|
|
372
|
+
|
|
373
|
+
if (struct.typeParams && struct.typeParams.length > 0) {
|
|
374
|
+
const params = struct.typeParams
|
|
375
|
+
.map((v, idx) => {
|
|
376
|
+
return useAny ? 'any' : 'T' + idx
|
|
377
|
+
})
|
|
378
|
+
.join(',')
|
|
379
|
+
genericString = `<${params}>`
|
|
380
|
+
}
|
|
381
|
+
return genericString
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
generateCallArgsStructs(
|
|
385
|
+
module: InternalMoveModule,
|
|
386
|
+
func: InternalMoveFunction
|
|
387
|
+
) {
|
|
388
|
+
if (!func.isEntry) {
|
|
389
|
+
return
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
const fields = this.chainAdapter
|
|
393
|
+
.getMeaningfulFunctionParams(func.params)
|
|
394
|
+
.map((param) => {
|
|
395
|
+
return (
|
|
396
|
+
this.generateTypeForDescriptor(param, module.address) +
|
|
397
|
+
(this.PAYLOAD_OPTIONAL ? ' | undefined' : '')
|
|
398
|
+
)
|
|
399
|
+
})
|
|
400
|
+
|
|
401
|
+
const camelFuncName = upperFirst(camel(func.name))
|
|
402
|
+
|
|
403
|
+
const genericString = this.generateFunctionTypeParameters(func)
|
|
404
|
+
return `
|
|
405
|
+
export interface ${camelFuncName}Payload${genericString}
|
|
406
|
+
extends TypedFunctionPayload<[${fields.join(',')}]> {
|
|
407
|
+
arguments_decoded: [${fields.join(',')}],
|
|
408
|
+
type_arguments: [${func.typeParams.map((_) => 'string').join(', ')}]
|
|
409
|
+
}
|
|
410
|
+
`
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
generateClientFunctions(
|
|
414
|
+
module: InternalMoveModule,
|
|
415
|
+
func: InternalMoveFunction
|
|
416
|
+
) {
|
|
417
|
+
if (func.visibility === InternalMoveFunctionVisibility.PRIVATE) {
|
|
418
|
+
return ''
|
|
419
|
+
}
|
|
420
|
+
if (func.isEntry) {
|
|
421
|
+
return ''
|
|
422
|
+
}
|
|
423
|
+
// const moduleName = normalizeToJSName(module.name)
|
|
424
|
+
const funcName = camel(func.name)
|
|
425
|
+
const fields = this.chainAdapter
|
|
426
|
+
.getMeaningfulFunctionParams(func.params)
|
|
427
|
+
.map((param) => {
|
|
428
|
+
return this.generateTypeForDescriptor(param, module.address)
|
|
429
|
+
})
|
|
430
|
+
const genericString = this.generateFunctionTypeParameters(func)
|
|
431
|
+
|
|
432
|
+
const returns = func.return.map((param) => {
|
|
433
|
+
return this.generateTypeForDescriptor(param, module.address)
|
|
434
|
+
})
|
|
435
|
+
|
|
436
|
+
const source = `
|
|
437
|
+
${funcName}${genericString}(type_arguments: [${func.typeParams
|
|
438
|
+
.map((_) => 'string')
|
|
439
|
+
.join(', ')}], args: [${fields.join(
|
|
440
|
+
','
|
|
441
|
+
)}], version?: bigint): Promise<[${returns.join(',')}]> {
|
|
442
|
+
return this.viewDecoded('${module.address}::${module.name}::${
|
|
443
|
+
func.name
|
|
444
|
+
}', type_arguments, args, version) as any
|
|
445
|
+
}`
|
|
446
|
+
return source
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
generateForEntryFunctions(
|
|
450
|
+
module: InternalMoveModule,
|
|
451
|
+
func: InternalMoveFunction
|
|
452
|
+
) {
|
|
453
|
+
return ''
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
generateForEvents(
|
|
457
|
+
module: InternalMoveModule,
|
|
458
|
+
struct: InternalMoveStruct
|
|
459
|
+
): string {
|
|
460
|
+
return ''
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
generateTypeForDescriptor(
|
|
464
|
+
type: TypeDescriptor,
|
|
465
|
+
currentAddress: string
|
|
466
|
+
): string {
|
|
467
|
+
if (type.reference) {
|
|
468
|
+
return this.ADDRESS_TYPE
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
switch (type.qname) {
|
|
472
|
+
case 'signer': // TODO check this
|
|
473
|
+
case 'address':
|
|
474
|
+
case 'Address':
|
|
475
|
+
return this.ADDRESS_TYPE
|
|
476
|
+
case '0x1::string::String':
|
|
477
|
+
return 'string'
|
|
478
|
+
case 'bool':
|
|
479
|
+
case 'Bool':
|
|
480
|
+
return 'Boolean'
|
|
481
|
+
case 'u8':
|
|
482
|
+
case 'U8':
|
|
483
|
+
case 'u16':
|
|
484
|
+
case 'U16':
|
|
485
|
+
case 'u32':
|
|
486
|
+
case 'U32':
|
|
487
|
+
return 'number'
|
|
488
|
+
case 'u64':
|
|
489
|
+
case 'U64':
|
|
490
|
+
case 'u128':
|
|
491
|
+
case 'U128':
|
|
492
|
+
case 'u256':
|
|
493
|
+
case 'U256':
|
|
494
|
+
return 'bigint'
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
if (type.qname.toLowerCase() === VECTOR_STR) {
|
|
498
|
+
// vector<u8> as hex string
|
|
499
|
+
const elementTypeQname = type.typeArgs[0].qname
|
|
500
|
+
if (elementTypeQname === 'u8') {
|
|
501
|
+
// only for aptos
|
|
502
|
+
return 'string'
|
|
503
|
+
}
|
|
504
|
+
if (
|
|
505
|
+
elementTypeQname.startsWith('T') &&
|
|
506
|
+
!elementTypeQname.includes(SPLITTER)
|
|
507
|
+
) {
|
|
508
|
+
return `${elementTypeQname}[] | string`
|
|
509
|
+
}
|
|
510
|
+
return (
|
|
511
|
+
this.generateTypeForDescriptor(type.typeArgs[0], currentAddress) + '[]'
|
|
512
|
+
)
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
const simpleName = this.generateSimpleType(type.qname, currentAddress)
|
|
516
|
+
if (simpleName.length === 0) {
|
|
517
|
+
console.error('unexpected error')
|
|
518
|
+
}
|
|
519
|
+
if (
|
|
520
|
+
simpleName.toLowerCase() === VECTOR_STR ||
|
|
521
|
+
simpleName.toLowerCase().startsWith(VECTOR_STR + SPLITTER)
|
|
522
|
+
) {
|
|
523
|
+
console.error('unexpected vector type error')
|
|
524
|
+
}
|
|
525
|
+
if (type.typeArgs.length > 0) {
|
|
526
|
+
// return simpleName
|
|
527
|
+
return (
|
|
528
|
+
simpleName +
|
|
529
|
+
'<' +
|
|
530
|
+
type.typeArgs
|
|
531
|
+
.map((t) => this.generateTypeForDescriptor(t, currentAddress))
|
|
532
|
+
.join(',') +
|
|
533
|
+
'>'
|
|
534
|
+
)
|
|
535
|
+
}
|
|
536
|
+
return simpleName
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
generateSimpleType(type: string, currentAddress: string): string {
|
|
540
|
+
const parts = type.split(SPLITTER)
|
|
541
|
+
|
|
542
|
+
for (let i = 0; i < parts.length; i++) {
|
|
543
|
+
parts[i] = normalizeToJSName(parts[i])
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
if (parts.length < 2) {
|
|
547
|
+
return parts[0]
|
|
548
|
+
}
|
|
549
|
+
if (parts[0] === currentAddress) {
|
|
550
|
+
return parts.slice(1).join('.')
|
|
551
|
+
}
|
|
552
|
+
return '_' + parts.join('.')
|
|
553
|
+
}
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
export class AccountCodegen<NetworkType, ModuleType, StructType> {
|
|
557
|
+
modules: InternalMoveModule[]
|
|
558
|
+
config: Config<NetworkType>
|
|
559
|
+
abi: ModuleType[]
|
|
560
|
+
loader: AccountRegister
|
|
561
|
+
moduleGen: AbstractCodegen<NetworkType, ModuleType, StructType>
|
|
562
|
+
|
|
563
|
+
constructor(
|
|
564
|
+
moduleGen: AbstractCodegen<NetworkType, ModuleType, StructType>,
|
|
565
|
+
loader: AccountRegister,
|
|
566
|
+
abi: ModuleType[],
|
|
567
|
+
modules: InternalMoveModule[],
|
|
568
|
+
config: Config<NetworkType>
|
|
569
|
+
) {
|
|
570
|
+
// const json = fs.readFileSync(config.srcFile, 'utf-8')
|
|
571
|
+
this.moduleGen = moduleGen
|
|
572
|
+
this.abi = abi
|
|
573
|
+
this.modules = modules
|
|
574
|
+
this.config = config
|
|
575
|
+
this.loader = loader
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
generate(): OutputFile[] {
|
|
579
|
+
if (!this.modules) {
|
|
580
|
+
return []
|
|
581
|
+
}
|
|
582
|
+
// const baseName = path.basename(this.config.fileName, '.json')
|
|
583
|
+
|
|
584
|
+
let address: string | undefined
|
|
585
|
+
for (const module of this.modules) {
|
|
586
|
+
address = module.address
|
|
587
|
+
}
|
|
588
|
+
if (!address) {
|
|
589
|
+
return []
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
const dependedAccounts: string[] = []
|
|
593
|
+
|
|
594
|
+
const moduleImports: string[] = []
|
|
595
|
+
|
|
596
|
+
const info = this.loader.accountImports.get(address)
|
|
597
|
+
|
|
598
|
+
if (info) {
|
|
599
|
+
for (const [account] of info.imports.entries()) {
|
|
600
|
+
// Remap to user's filename if possible, TODO codepath not well tested
|
|
601
|
+
const tsAccountModule =
|
|
602
|
+
'./' +
|
|
603
|
+
(this.loader.accountImports.get(account)?.moduleName || account)
|
|
604
|
+
if (isFrameworkAccount(account) && !isFrameworkAccount(address)) {
|
|
605
|
+
// Decide where to find runtime library
|
|
606
|
+
moduleImports.push(
|
|
607
|
+
`import { _${account} } from "@typemove/${this.moduleGen.PREFIX.toLowerCase()}"`
|
|
608
|
+
)
|
|
609
|
+
} else {
|
|
610
|
+
moduleImports.push(
|
|
611
|
+
`import * as _${account} from "${tsAccountModule}${this.moduleGen.maybeEsmPrefix()}"`
|
|
612
|
+
)
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
dependedAccounts.push(account)
|
|
616
|
+
}
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
let loadAllTypes = `loadAllTypes(defaultMoveCoder(${
|
|
620
|
+
this.moduleGen.PREFIX
|
|
621
|
+
}Network.${this.moduleGen.generateNetworkOption(this.config.network)}))`
|
|
622
|
+
|
|
623
|
+
if (this.moduleGen.SYSTEM_MODULES.has(address)) {
|
|
624
|
+
loadAllTypes = `
|
|
625
|
+
loadAllTypes(defaultMoveCoder(${this.moduleGen.PREFIX}Network.MAIN_NET))
|
|
626
|
+
loadAllTypes(defaultMoveCoder(${this.moduleGen.PREFIX}Network.TEST_NET))
|
|
627
|
+
`
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
const eventsMap: Map<string, InternalMoveStruct> =
|
|
631
|
+
this.moduleGen.chainAdapter.getAllEventStructs(this.modules)
|
|
632
|
+
|
|
633
|
+
const source = `
|
|
634
|
+
/* Autogenerated file. Do not edit manually. */
|
|
635
|
+
/* tslint:disable */
|
|
636
|
+
/* eslint-disable */
|
|
637
|
+
|
|
638
|
+
/* Generated modules for account ${address} */
|
|
639
|
+
|
|
640
|
+
${this.generateImports()}
|
|
641
|
+
|
|
642
|
+
${moduleImports.join('\n')}
|
|
643
|
+
|
|
644
|
+
${this.modules
|
|
645
|
+
.map((m) =>
|
|
646
|
+
this.moduleGen.generateModule(m, eventsMap, this.config.network)
|
|
647
|
+
)
|
|
648
|
+
.join('\n')}
|
|
649
|
+
|
|
650
|
+
const MODULES = JSON.parse('${JSON.stringify(this.abi)}')
|
|
651
|
+
|
|
652
|
+
export function loadAllTypes(coder: MoveCoder) {
|
|
653
|
+
${dependedAccounts.map((a) => `_${a}.loadAllTypes(coder)`).join('\n')}
|
|
654
|
+
for (const m of Object.values(MODULES)) {
|
|
655
|
+
coder.load(m as any)
|
|
656
|
+
}
|
|
657
|
+
}
|
|
658
|
+
|
|
659
|
+
${loadAllTypes}
|
|
660
|
+
` // source
|
|
661
|
+
|
|
662
|
+
return [
|
|
663
|
+
{
|
|
664
|
+
fileName: this.config.fileName + '.ts',
|
|
665
|
+
fileContent: source,
|
|
666
|
+
},
|
|
667
|
+
]
|
|
668
|
+
}
|
|
669
|
+
|
|
670
|
+
generateImports() {
|
|
671
|
+
const imports = `
|
|
672
|
+
import { TypeDescriptor, ANY_TYPE } from "@typemove/move"
|
|
673
|
+
import {
|
|
674
|
+
MoveCoder, defaultMoveCoder, ${
|
|
675
|
+
this.moduleGen.PREFIX
|
|
676
|
+
}Network } from "@typemove/${this.moduleGen.PREFIX.toLowerCase()}"
|
|
677
|
+
import { ${
|
|
678
|
+
this.moduleGen.ADDRESS_TYPE
|
|
679
|
+
}, ModuleClient } from "@typemove/${this.moduleGen.PREFIX.toLowerCase()}"
|
|
680
|
+
`
|
|
681
|
+
|
|
682
|
+
return imports
|
|
683
|
+
}
|
|
684
|
+
}
|