@typemove/move 2.0.0 → 2.0.1-rc.1

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.
Files changed (46) hide show
  1. package/dist/esm/abstract-move-coder.d.ts +30 -0
  2. package/dist/esm/abstract-move-coder.d.ts.map +1 -0
  3. package/dist/esm/abstract-move-coder.js +308 -0
  4. package/dist/esm/abstract-move-coder.js.map +1 -0
  5. package/dist/esm/account.d.ts +16 -0
  6. package/dist/esm/account.d.ts.map +1 -0
  7. package/dist/esm/account.js +71 -0
  8. package/dist/esm/account.js.map +1 -0
  9. package/dist/esm/chain-adapter.d.ts +13 -0
  10. package/dist/esm/chain-adapter.d.ts.map +1 -0
  11. package/dist/esm/chain-adapter.js +3 -0
  12. package/dist/esm/chain-adapter.js.map +1 -0
  13. package/dist/esm/codegen/abstract-codegen.d.ts +50 -0
  14. package/dist/esm/codegen/abstract-codegen.d.ts.map +1 -0
  15. package/dist/esm/codegen/abstract-codegen.js +463 -0
  16. package/dist/esm/codegen/abstract-codegen.js.map +1 -0
  17. package/dist/esm/codegen/index.d.ts +2 -0
  18. package/dist/esm/codegen/index.d.ts.map +1 -0
  19. package/dist/esm/codegen/index.js +2 -0
  20. package/dist/esm/codegen/index.js.map +1 -0
  21. package/dist/esm/index.d.ts +7 -0
  22. package/dist/esm/index.d.ts.map +1 -0
  23. package/dist/esm/index.js +7 -0
  24. package/dist/esm/index.js.map +1 -0
  25. package/dist/esm/internal-models.d.ts +46 -0
  26. package/dist/esm/internal-models.d.ts.map +1 -0
  27. package/dist/esm/internal-models.js +7 -0
  28. package/dist/esm/internal-models.js.map +1 -0
  29. package/dist/esm/types.d.ts +52 -0
  30. package/dist/esm/types.d.ts.map +1 -0
  31. package/dist/esm/types.js +317 -0
  32. package/dist/esm/types.js.map +1 -0
  33. package/dist/esm/utils.d.ts +17 -0
  34. package/dist/esm/utils.d.ts.map +1 -0
  35. package/dist/esm/utils.js +127 -0
  36. package/dist/esm/utils.js.map +1 -0
  37. package/package.json +5 -5
  38. package/src/abstract-move-coder.ts +347 -0
  39. package/src/account.ts +81 -0
  40. package/src/chain-adapter.ts +26 -0
  41. package/src/codegen/abstract-codegen.ts +574 -0
  42. package/src/codegen/index.ts +1 -0
  43. package/src/index.ts +6 -0
  44. package/src/internal-models.ts +52 -0
  45. package/src/types.ts +362 -0
  46. package/src/utils.ts +144 -0
package/src/types.ts ADDED
@@ -0,0 +1,362 @@
1
+ import { accountTypeString, SPLITTER, VECTOR_STR } from './utils.js'
2
+
3
+ export type DecodedStruct<B, T> = B & {
4
+ /**
5
+ * decoded data using ABI, undefined if there is decoding error, usually because the ABI/data mismatch
6
+ */
7
+ data_decoded: T
8
+ type_arguments: string[]
9
+ }
10
+
11
+ export type NestedDecodedStruct<A, B extends { data: A }, T> = B & {
12
+ data: DecodedStruct<A, T>
13
+ }
14
+
15
+ export class TypeDescriptor<T = any> {
16
+ qname: string
17
+ reference: boolean
18
+ mutable: boolean
19
+ typeArgs: TypeDescriptor[]
20
+
21
+ constructor(symbol: string, typeParams?: TypeDescriptor[]) {
22
+ this.qname = symbol
23
+ this.reference = false
24
+ this.mutable = false
25
+ this.typeArgs = typeParams || []
26
+ }
27
+
28
+ apply(...typeArgs: TypeDescriptor[]): TypeDescriptor {
29
+ const newObj = this.clone()
30
+ newObj.typeArgs = typeArgs
31
+ return newObj
32
+ }
33
+
34
+ clone(): this {
35
+ const newObj = new TypeDescriptor(this.qname, this.typeArgs)
36
+ newObj.reference = this.reference
37
+ newObj.mutable = this.mutable
38
+ return newObj as any
39
+ }
40
+
41
+ // compare qname without consider case for system type
42
+ compareQname(t: TypeDescriptor): boolean {
43
+ let t1 = this.qname
44
+ if (BUILTIN_TYPES_SET.has(this.qname.toLowerCase())) {
45
+ t1 = this.qname.toLowerCase()
46
+ }
47
+ let t2 = t.qname
48
+ if (BUILTIN_TYPES_SET.has(t.qname.toLowerCase())) {
49
+ t2 = t.qname
50
+ }
51
+ return t1 === t2
52
+ }
53
+
54
+ getSignature(): string {
55
+ if (this.typeArgs.length > 0) {
56
+ return this.qname + '<' + this.typeArgs.map((t) => t.getSignature()).join(', ') + '>'
57
+ }
58
+ return this.qname
59
+ }
60
+
61
+ // Make U8, U16, etc => u8, u16
62
+ getNormalizedSignature(): string {
63
+ let qname = this.qname
64
+ switch (qname) {
65
+ case 'U8':
66
+ case 'U16':
67
+ case 'U32':
68
+ case 'U64':
69
+ case 'U128':
70
+ case 'U256':
71
+ case 'Vector':
72
+ case 'Bool':
73
+ case 'Address':
74
+ qname = qname.toLowerCase()
75
+ }
76
+
77
+ if (this.typeArgs.length > 0) {
78
+ return qname + '<' + this.typeArgs.map((t) => t.getNormalizedSignature()).join(', ') + '>'
79
+ }
80
+ return qname
81
+ }
82
+
83
+ // Replace T0, T1 with more concrete type
84
+ applyTypeArgs(ctx: Map<string, TypeDescriptor>): TypeDescriptor {
85
+ const replace = ctx.get(this.qname)
86
+ if (replace) {
87
+ return replace
88
+ }
89
+ if (ctx.size === 0 || this.typeArgs.length === 0) {
90
+ return this
91
+ }
92
+
93
+ const typeArgs: TypeDescriptor[] = []
94
+ for (const arg of this.typeArgs) {
95
+ const replace = ctx.get(arg.qname)
96
+ if (replace) {
97
+ typeArgs.push(replace)
98
+ } else {
99
+ typeArgs.push(arg.applyTypeArgs(ctx))
100
+ }
101
+ }
102
+ return new TypeDescriptor(this.qname, typeArgs)
103
+ }
104
+
105
+ // all depended types including itself, not include system type
106
+ dependedTypes(): string[] {
107
+ if (this.qname.startsWith('&')) {
108
+ console.error('Not expected &')
109
+ return []
110
+ }
111
+
112
+ // Handle closure/lambda types: |&mut T1|T2 or |T1, T2|T3
113
+ if (this.qname.startsWith('|')) {
114
+ // Closure types are function types, not module dependencies
115
+ // The actual type dependencies are in the typeArgs if any
116
+ const types = new Set<string>()
117
+ for (const param of this.typeArgs) {
118
+ param.dependedTypes().forEach((t) => types.add(t))
119
+ }
120
+ return Array.from(types)
121
+ }
122
+
123
+ if (this.isVector()) {
124
+ return this.typeArgs[0].dependedTypes()
125
+ }
126
+
127
+ if (BUILTIN_TYPES_SET.has(this.qname.toLowerCase())) {
128
+ return []
129
+ }
130
+ switch (this.qname) {
131
+ case 'signer':
132
+ case '0x1::string::String':
133
+ return []
134
+ }
135
+
136
+ // Type parameters are not depended
137
+ if (this.qname.indexOf(SPLITTER) == -1) {
138
+ if (this.qname.startsWith('T')) {
139
+ return []
140
+ }
141
+ }
142
+
143
+ const types = new Set<string>()
144
+ for (const param of this.typeArgs) {
145
+ param.dependedTypes().forEach((t) => types.add(t))
146
+ }
147
+
148
+ types.add(this.qname)
149
+
150
+ return Array.from(types)
151
+ }
152
+
153
+ isVector(): boolean {
154
+ return this.qname.toLowerCase() === VECTOR_STR
155
+ }
156
+
157
+ existAnyType(): boolean {
158
+ if (this.qname === 'any') {
159
+ return true
160
+ }
161
+ for (const param of this.typeArgs) {
162
+ if (param.existAnyType()) {
163
+ return true
164
+ }
165
+ }
166
+ return false
167
+ }
168
+
169
+ name(): string {
170
+ const parts = this.qname.split(SPLITTER)
171
+ return parts[parts.length - 1]
172
+ }
173
+
174
+ module(): string {
175
+ const parts = this.qname.split(SPLITTER)
176
+ return parts[parts.length - 2]
177
+ }
178
+ }
179
+
180
+ export function parseMoveType(type: string): TypeDescriptor {
181
+ if (type === undefined) {
182
+ console.log('')
183
+ }
184
+
185
+ // Aptos SDK 7+ exposes Move closure / function-value types in ABIs as
186
+ // `|param1, param2, ...| ret`. Parse them specially — the inner params and
187
+ // return type are nested and recursively parsed; the descriptor's qname is
188
+ // the sentinel `|fn|` (other code in this file branches on qname.startsWith('|')).
189
+ const closure = tryParseClosure(type)
190
+ if (closure) {
191
+ return closure
192
+ }
193
+
194
+ const stack: TypeDescriptor[] = [new TypeDescriptor('')]
195
+ let buffer = []
196
+
197
+ // xxx:asdf<g1<a,<c,d>>, b, g2<a,b>, e>
198
+ for (let i = 0; i < type.length; i++) {
199
+ const ch = type[i]
200
+ if (ch === ' ') {
201
+ continue
202
+ }
203
+ if (ch === '<') {
204
+ // const symbol = type.slice(symbolStart, i)
205
+ // symbolStart =
206
+ const symbol = buffer.join('')
207
+ buffer = []
208
+ stack[stack.length - 1].qname = symbol
209
+ adjustType(stack[stack.length - 1])
210
+ stack.push(new TypeDescriptor(''))
211
+ continue
212
+ }
213
+ if (ch === '>' || ch === ',') {
214
+ const typeParam = stack.pop()
215
+ if (!typeParam) {
216
+ throw Error('Unexpected stack size')
217
+ }
218
+ if (buffer.length > 0) {
219
+ typeParam.qname = buffer.join('')
220
+ buffer = []
221
+ }
222
+ adjustType(typeParam)
223
+ stack[stack.length - 1].typeArgs.push(typeParam)
224
+ if (ch === ',') {
225
+ stack.push(new TypeDescriptor(''))
226
+ }
227
+ continue
228
+ }
229
+ buffer.push(ch)
230
+ }
231
+
232
+ if (buffer.length > 0) {
233
+ stack[stack.length - 1].qname = buffer.join('')
234
+ }
235
+ adjustType(stack[stack.length - 1])
236
+
237
+ const res = stack.pop()
238
+ if (!res || stack.length > 0) {
239
+ throw Error('Unexpected stack size')
240
+ }
241
+ return res
242
+ }
243
+
244
+ // Parse `|param1, param2, ...| return_type` (Aptos Move closure / function-value
245
+ // types exposed by SDK 7+). Returns undefined if the input is not a closure.
246
+ // Commas and the closing `|` are matched at angle-bracket depth 0.
247
+ function tryParseClosure(type: string): TypeDescriptor | undefined {
248
+ let i = 0
249
+ while (i < type.length && type[i] === ' ') i++
250
+ if (type[i] !== '|') return undefined
251
+
252
+ let depth = 0
253
+ let close = -1
254
+ for (let j = i + 1; j < type.length; j++) {
255
+ const ch = type[j]
256
+ if (ch === '<') depth++
257
+ else if (ch === '>') depth--
258
+ else if (ch === '|' && depth === 0) {
259
+ close = j
260
+ break
261
+ }
262
+ }
263
+ if (close < 0) return undefined
264
+
265
+ const inner = type.slice(i + 1, close)
266
+ const ret = type.slice(close + 1).trim()
267
+
268
+ const paramTypes: TypeDescriptor[] = []
269
+ if (inner.trim().length > 0) {
270
+ let depth2 = 0
271
+ let start = 0
272
+ for (let k = 0; k <= inner.length; k++) {
273
+ const ch = inner[k]
274
+ if (k === inner.length || (ch === ',' && depth2 === 0)) {
275
+ const piece = inner.slice(start, k).trim()
276
+ if (piece.length > 0) paramTypes.push(parseMoveType(piece))
277
+ start = k + 1
278
+ } else if (ch === '<') depth2++
279
+ else if (ch === '>') depth2--
280
+ }
281
+ }
282
+
283
+ const typeArgs = paramTypes.slice()
284
+ if (ret.length > 0) typeArgs.push(parseMoveType(ret))
285
+
286
+ return new TypeDescriptor('|fn|', typeArgs)
287
+ }
288
+
289
+ function adjustType(type: TypeDescriptor) {
290
+ if (type.qname.startsWith('&')) {
291
+ type.reference = true
292
+ type.qname = type.qname.slice(1)
293
+ }
294
+ if (type.qname.startsWith('mut')) {
295
+ type.mutable = true
296
+ type.qname = type.qname.slice(3)
297
+ }
298
+ const parts = type.qname.split(SPLITTER)
299
+ if (parts.length > 1) {
300
+ const [account, module, name] = parts
301
+ type.qname = [accountTypeString(account), module, name].join(SPLITTER)
302
+ }
303
+ }
304
+
305
+ export const ANY_TYPE = new TypeDescriptor<any>('any')
306
+
307
+ export function vectorType<T>(t: TypeDescriptor<T> = ANY_TYPE): TypeDescriptor<T[]> {
308
+ return BUILTIN_TYPES.VECTOR_TYPE_ANY.apply(t)
309
+ }
310
+
311
+ export const BUILTIN_TYPES = {
312
+ ADDRESS_TYPE: new TypeDescriptor<string>('address'),
313
+ // export const Address = new TypeDescriptor<string>("Address")
314
+
315
+ VECTOR_TYPE_ANY: new TypeDescriptor<any[]>('vector'),
316
+ VECTOR_TYPE: vectorType,
317
+
318
+ BOOL_TYPE: new TypeDescriptor<number>('bool'),
319
+
320
+ U8_TYPE: new TypeDescriptor<number>('u8'),
321
+ // export const U8 = new TypeDescriptor<number>("U8")
322
+ U16_TYPE: new TypeDescriptor<number>('u16'),
323
+ // export const U16 = new TypeDescriptor<number>("U16")
324
+ U32_TYPE: new TypeDescriptor<number>('u32'),
325
+ // export const U32 = new TypeDescriptor<number>("U32")
326
+ U64_TYPE: new TypeDescriptor<number>('u64'),
327
+ // export const U64 = new TypeDescriptor<number>("U64")
328
+ U128_TYPE: new TypeDescriptor<number>('u128'),
329
+ // export const U128 = new TypeDescriptor<number>("U128")
330
+ U256_TYPE: new TypeDescriptor<number>('u256')
331
+ // export const U256 = new TypeDescriptor<number>("U256")
332
+ }
333
+
334
+ const BUILTIN_TYPES_SET = new Set(
335
+ Object.values(BUILTIN_TYPES).flatMap((t) => {
336
+ if (typeof t === 'object') {
337
+ return [t.qname.toLowerCase()]
338
+ }
339
+ return []
340
+ })
341
+ )
342
+
343
+ /**
344
+ *
345
+ * @param matcher
346
+ * @param type
347
+ */
348
+ export function matchType(matcher: TypeDescriptor, type: TypeDescriptor): boolean {
349
+ if (matcher.qname === 'any') {
350
+ return true
351
+ }
352
+ if (!matcher.compareQname(type)) {
353
+ return false
354
+ }
355
+ for (const [idx, matcherTarg] of matcher.typeArgs.entries()) {
356
+ const targ = type.typeArgs[idx]
357
+ if (!matchType(matcherTarg, targ)) {
358
+ return false
359
+ }
360
+ }
361
+ return true
362
+ }
package/src/utils.ts ADDED
@@ -0,0 +1,144 @@
1
+ import { InternalMoveModule, InternalMoveStruct } from './internal-models.js'
2
+ import { camel as camelRadash } from 'radash'
3
+
4
+ export const SPLITTER = '::'
5
+
6
+ export const VECTOR_STR = 'vector'
7
+
8
+ export function isFrameworkAccount(account: string) {
9
+ const n = parseInt(account, 16)
10
+ if (Number.isNaN(n)) {
11
+ return false
12
+ }
13
+ return n >= 0 && n < 16
14
+ }
15
+
16
+ // strip any lead 0
17
+ export function accountTypeString(account: string): string {
18
+ const withoutPrefix = account.toLowerCase().replace(/^(0x)/, '')
19
+ return '0x' + withoutPrefix.replace(/^0*/, '')
20
+ }
21
+
22
+ const MOVE_ADDRESS_LENGTH = 32
23
+
24
+ function isHex(value: string): boolean {
25
+ return /^(0x|0X)?[a-fA-F0-9]+$/.test(value)
26
+ }
27
+
28
+ function getHexByteLength(value: string): number {
29
+ return /^(0x|0X)/.test(value) ? (value.length - 2) / 2 : value.length / 2
30
+ }
31
+
32
+ export function isValidMoveAddress(value: string): boolean {
33
+ return isHex(value) && getHexByteLength(value) <= MOVE_ADDRESS_LENGTH
34
+ }
35
+
36
+ // Get full address with 32 bytes
37
+ export function accountAddressString(account: string): string {
38
+ if (!isValidMoveAddress(account)) {
39
+ throw Error('Not valid move address')
40
+ }
41
+
42
+ const address = account.toLowerCase().replace(/^(0x)/, '')
43
+ return `0x${address.padStart(MOVE_ADDRESS_LENGTH * 2, '0')}`
44
+ }
45
+
46
+ // https://github.com/microsoft/TypeScript/issues/2536
47
+ const KEYWORDS = new Set([
48
+ 'break',
49
+ 'case',
50
+ 'catch',
51
+ 'class',
52
+ 'const',
53
+ 'continue',
54
+ 'debugger',
55
+ 'default',
56
+ 'delete',
57
+ 'do',
58
+ 'else',
59
+ 'enum',
60
+ 'export',
61
+ 'extends',
62
+ 'false',
63
+ 'finally',
64
+ 'for',
65
+ 'function',
66
+ 'if',
67
+ 'import',
68
+ 'in',
69
+ 'instanceof',
70
+ 'new',
71
+ 'null',
72
+ 'return',
73
+ 'super',
74
+ 'switch',
75
+ 'this',
76
+ 'throw',
77
+ 'true',
78
+ 'try',
79
+ 'typeof',
80
+ 'var',
81
+ 'void',
82
+ 'while',
83
+ 'with',
84
+ 'as',
85
+ 'implements',
86
+ 'interface',
87
+ 'let',
88
+ 'package',
89
+ 'private',
90
+ 'protected',
91
+ 'public',
92
+ 'static',
93
+ 'yield',
94
+ 'any',
95
+ 'boolean',
96
+ 'constructor',
97
+ 'declare',
98
+ // 'get',
99
+ 'module',
100
+ // 'require',
101
+ 'number',
102
+ // 'set',
103
+ 'string',
104
+ 'symbol',
105
+ 'type',
106
+ 'from',
107
+ // 'of',
108
+ 'async',
109
+ 'await',
110
+ 'bigint',
111
+ 'object',
112
+ 'volatile',
113
+ 'namespace',
114
+ 'arguments'
115
+ ])
116
+
117
+ export function normalizeToJSName(name: string) {
118
+ if (KEYWORDS.has(name)) {
119
+ return name + '$'
120
+ }
121
+ return name
122
+ }
123
+
124
+ export function moduleQnameForType(type: string): [string, string] {
125
+ const parts = type.split(SPLITTER).slice(0, 2)
126
+ return [parts[0], parts[1]]
127
+ }
128
+
129
+ export function moduleQname(module: { address: string; name: string }): string {
130
+ return accountTypeString(module.address) + SPLITTER + module.name
131
+ }
132
+
133
+ export function structQname(module: InternalMoveModule, struct: InternalMoveStruct): string {
134
+ return [accountTypeString(module.address), module.name, struct.name].join(SPLITTER)
135
+ }
136
+
137
+ export function upperFirst(str: string): string {
138
+ return str.charAt(0).toUpperCase() + str.slice(1)
139
+ }
140
+
141
+ export function camel(str: string): string {
142
+ const base = camelRadash(str)
143
+ return str.endsWith('_') ? base + '_' : base
144
+ }