@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/src/types.ts ADDED
@@ -0,0 +1,251 @@
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 class TypeDescriptor<T = any> {
12
+ qname: string
13
+ reference: boolean
14
+ mutable: boolean
15
+ typeArgs: TypeDescriptor[]
16
+
17
+ constructor(symbol: string, typeParams?: TypeDescriptor[]) {
18
+ this.qname = symbol
19
+ this.reference = false
20
+ this.mutable = false
21
+ this.typeArgs = typeParams || []
22
+ }
23
+
24
+ apply(...typeArgs: TypeDescriptor[]): TypeDescriptor {
25
+ const newObj = this.clone()
26
+ newObj.typeArgs = typeArgs
27
+ return newObj
28
+ }
29
+
30
+ clone(): this {
31
+ const newObj = new TypeDescriptor(this.qname, this.typeArgs)
32
+ newObj.reference = this.reference
33
+ newObj.mutable = this.mutable
34
+ return newObj as any
35
+ }
36
+
37
+ // compare qname without consider case for system type
38
+ compareQname(t: TypeDescriptor): boolean {
39
+ let t1 = this.qname
40
+ if (BUILTIN_TYPES_SET.has(this.qname.toLowerCase())) {
41
+ t1 = this.qname.toLowerCase()
42
+ }
43
+ let t2 = t.qname
44
+ if (BUILTIN_TYPES_SET.has(t.qname.toLowerCase())) {
45
+ t2 = t.qname
46
+ }
47
+ return t1 === t2
48
+ }
49
+
50
+ getSignature(): string {
51
+ if (this.typeArgs.length > 0) {
52
+ return (
53
+ this.qname +
54
+ '<' +
55
+ this.typeArgs.map((t) => t.getSignature()).join(', ') +
56
+ '>'
57
+ )
58
+ }
59
+ return this.qname
60
+ }
61
+
62
+ // Replace T0, T1 with more concrete type
63
+ applyTypeArgs(ctx: Map<string, TypeDescriptor>): TypeDescriptor {
64
+ const replace = ctx.get(this.qname)
65
+ if (replace) {
66
+ return replace
67
+ }
68
+ if (ctx.size === 0 || this.typeArgs.length === 0) {
69
+ return this
70
+ }
71
+
72
+ const typeArgs: TypeDescriptor[] = []
73
+ for (const arg of this.typeArgs) {
74
+ const replace = ctx.get(arg.qname)
75
+ if (replace) {
76
+ typeArgs.push(replace)
77
+ } else {
78
+ typeArgs.push(arg.applyTypeArgs(ctx))
79
+ }
80
+ }
81
+ return new TypeDescriptor(this.qname, typeArgs)
82
+ }
83
+
84
+ // all depended types including itself, not include system type
85
+ dependedTypes(): string[] {
86
+ if (this.qname.startsWith('&')) {
87
+ console.error('Not expected &')
88
+ return []
89
+ }
90
+
91
+ if (this.qname.toLowerCase() === VECTOR_STR) {
92
+ return this.typeArgs[0].dependedTypes()
93
+ }
94
+
95
+ if (BUILTIN_TYPES_SET.has(this.qname.toLowerCase())) {
96
+ return []
97
+ }
98
+ switch (this.qname) {
99
+ case 'signer':
100
+ case '0x1::string::String':
101
+ return []
102
+ }
103
+
104
+ // Type parameters are not depended
105
+ if (this.qname.indexOf(SPLITTER) == -1) {
106
+ if (this.qname.startsWith('T')) {
107
+ return []
108
+ }
109
+ }
110
+
111
+ const types = new Set<string>()
112
+ for (const param of this.typeArgs) {
113
+ param.dependedTypes().forEach((t) => types.add(t))
114
+ }
115
+
116
+ types.add(this.qname)
117
+
118
+ return Array.from(types)
119
+ }
120
+ }
121
+
122
+ export function parseMoveType(type: string): TypeDescriptor {
123
+ const stack: TypeDescriptor[] = [new TypeDescriptor('')]
124
+ let buffer = []
125
+
126
+ // xxx:asdf<g1<a,<c,d>>, b, g2<a,b>, e>
127
+ for (let i = 0; i < type.length; i++) {
128
+ const ch = type[i]
129
+ if (ch === ' ') {
130
+ continue
131
+ }
132
+ if (ch === '<') {
133
+ // const symbol = type.slice(symbolStart, i)
134
+ // symbolStart =
135
+ const symbol = buffer.join('')
136
+ buffer = []
137
+ stack[stack.length - 1].qname = symbol
138
+ adjustType(stack[stack.length - 1])
139
+ stack.push(new TypeDescriptor(''))
140
+ continue
141
+ }
142
+ if (ch === '>' || ch === ',') {
143
+ const typeParam = stack.pop()
144
+ if (!typeParam) {
145
+ throw Error('Unexpected stack size')
146
+ }
147
+ if (buffer.length > 0) {
148
+ typeParam.qname = buffer.join('')
149
+ buffer = []
150
+ }
151
+ adjustType(typeParam)
152
+ stack[stack.length - 1].typeArgs.push(typeParam)
153
+ if (ch === ',') {
154
+ stack.push(new TypeDescriptor(''))
155
+ }
156
+ continue
157
+ }
158
+ buffer.push(ch)
159
+ }
160
+
161
+ if (buffer.length > 0) {
162
+ stack[stack.length - 1].qname = buffer.join('')
163
+ }
164
+ adjustType(stack[stack.length - 1])
165
+
166
+ const res = stack.pop()
167
+ if (!res || stack.length > 0) {
168
+ throw Error('Unexpected stack size')
169
+ }
170
+ return res
171
+ }
172
+
173
+ function adjustType(type: TypeDescriptor) {
174
+ if (type.qname.startsWith('&')) {
175
+ type.reference = true
176
+ type.qname = type.qname.slice(1)
177
+ }
178
+ if (type.qname.startsWith('mut')) {
179
+ type.mutable = true
180
+ type.qname = type.qname.slice(3)
181
+ }
182
+ const parts = type.qname.split(SPLITTER)
183
+ if (parts.length > 1) {
184
+ const [account, module, name] = parts
185
+ type.qname = [accountTypeString(account), module, name].join(SPLITTER)
186
+ }
187
+ }
188
+
189
+ export const ANY_TYPE = new TypeDescriptor<any>('any')
190
+
191
+ export function vectorType<T>(
192
+ t: TypeDescriptor<T> = ANY_TYPE
193
+ ): TypeDescriptor<T[]> {
194
+ return BUILTIN_TYPES.VECTOR_TYPE_ANY.apply(t)
195
+ }
196
+
197
+ export const BUILTIN_TYPES = {
198
+ ADDRESS_TYPE: new TypeDescriptor<string>('address'),
199
+ // export const Address = new TypeDescriptor<string>("Address")
200
+
201
+ VECTOR_TYPE_ANY: new TypeDescriptor<any[]>('vector'),
202
+ VECTOR_TYPE: vectorType,
203
+
204
+ BOOL_TYPE: new TypeDescriptor<number>('bool'),
205
+
206
+ U8_TYPE: new TypeDescriptor<number>('u8'),
207
+ // export const U8 = new TypeDescriptor<number>("U8")
208
+ U16_TYPE: new TypeDescriptor<number>('u16'),
209
+ // export const U16 = new TypeDescriptor<number>("U16")
210
+ U32_TYPE: new TypeDescriptor<number>('u32'),
211
+ // export const U32 = new TypeDescriptor<number>("U32")
212
+ U64_TYPE: new TypeDescriptor<number>('u64'),
213
+ // export const U64 = new TypeDescriptor<number>("U64")
214
+ U128_TYPE: new TypeDescriptor<number>('u128'),
215
+ // export const U128 = new TypeDescriptor<number>("U128")
216
+ U256_TYPE: new TypeDescriptor<number>('u256'),
217
+ // export const U256 = new TypeDescriptor<number>("U256")
218
+ }
219
+
220
+ const BUILTIN_TYPES_SET = new Set(
221
+ Object.values(BUILTIN_TYPES).flatMap((t) => {
222
+ if (typeof t === 'object') {
223
+ return [t.qname.toLowerCase()]
224
+ }
225
+ return []
226
+ })
227
+ )
228
+
229
+ /**
230
+ *
231
+ * @param matcher
232
+ * @param type
233
+ */
234
+ export function matchType(
235
+ matcher: TypeDescriptor,
236
+ type: TypeDescriptor
237
+ ): boolean {
238
+ if (matcher.qname === 'any') {
239
+ return true
240
+ }
241
+ if (!matcher.compareQname(type)) {
242
+ return false
243
+ }
244
+ for (const [idx, matcherTarg] of matcher.typeArgs.entries()) {
245
+ const targ = type.typeArgs[idx]
246
+ if (!matchType(matcherTarg, targ)) {
247
+ return false
248
+ }
249
+ }
250
+ return true
251
+ }
package/src/utils.ts ADDED
@@ -0,0 +1,83 @@
1
+ import { InternalMoveModule, InternalMoveStruct } from './internal-models.js'
2
+
3
+ export const SPLITTER = '::'
4
+
5
+ export const VECTOR_STR = 'vector'
6
+
7
+ export function isFrameworkAccount(account: string) {
8
+ const n = parseInt(account, 16)
9
+ if (Number.isNaN(n)) {
10
+ return false
11
+ }
12
+ return n >= 0 && n < 16
13
+ }
14
+
15
+ // strip any lead 0
16
+ export function accountTypeString(account: string): string {
17
+ const withoutPrefix = account.toLowerCase().replace(/^(0x)/, '')
18
+ return '0x' + withoutPrefix.replace(/^0*/, '')
19
+ }
20
+
21
+ const MOVE_ADDRESS_LENGTH = 32
22
+
23
+ function isHex(value: string): boolean {
24
+ return /^(0x|0X)?[a-fA-F0-9]+$/.test(value)
25
+ }
26
+
27
+ function getHexByteLength(value: string): number {
28
+ return /^(0x|0X)/.test(value) ? (value.length - 2) / 2 : value.length / 2
29
+ }
30
+
31
+ export function isValidMoveAddress(value: string): boolean {
32
+ return isHex(value) && getHexByteLength(value) <= MOVE_ADDRESS_LENGTH
33
+ }
34
+
35
+ // Get full address with 32 bytes
36
+ export function accountAddressString(account: string): string {
37
+ if (!isValidMoveAddress(account)) {
38
+ throw Error('Not valid move address')
39
+ }
40
+
41
+ const address = account.toLowerCase().replace(/^(0x)/, '')
42
+ return `0x${address.padStart(MOVE_ADDRESS_LENGTH * 2, '0')}`
43
+ }
44
+
45
+ const KEYWORDS = new Set([
46
+ 'package',
47
+ 'namespace',
48
+ 'volatile',
49
+ 'object',
50
+ 'string',
51
+ 'number',
52
+ 'bigint',
53
+ 'any',
54
+ ])
55
+
56
+ export function normalizeToJSName(name: string) {
57
+ if (KEYWORDS.has(name)) {
58
+ return name + '_'
59
+ }
60
+ return name
61
+ }
62
+
63
+ export function moduleQnameForType(type: string): [string, string] {
64
+ const parts = type.split(SPLITTER).slice(0, 2)
65
+ return [parts[0], parts[1]]
66
+ }
67
+
68
+ export function moduleQname(module: { address: string; name: string }): string {
69
+ return accountTypeString(module.address) + SPLITTER + module.name
70
+ }
71
+
72
+ export function structQname(
73
+ module: InternalMoveModule,
74
+ struct: InternalMoveStruct
75
+ ): string {
76
+ return [accountTypeString(module.address), module.name, struct.name].join(
77
+ SPLITTER
78
+ )
79
+ }
80
+
81
+ export function upperFirst(str: string): string {
82
+ return str.charAt(0).toUpperCase() + str.slice(1)
83
+ }