@ic-reactor/candid 3.0.7-beta.2 → 3.0.8-beta.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.
- package/dist/display-reactor.d.ts +3 -2
- package/dist/display-reactor.d.ts.map +1 -1
- package/dist/display-reactor.js +6 -0
- package/dist/display-reactor.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/metadata-display-reactor.d.ts +73 -0
- package/dist/metadata-display-reactor.d.ts.map +1 -0
- package/dist/metadata-display-reactor.js +128 -0
- package/dist/metadata-display-reactor.js.map +1 -0
- package/dist/visitor/arguments/index.d.ts +69 -0
- package/dist/visitor/arguments/index.d.ts.map +1 -0
- package/dist/visitor/arguments/index.js +277 -0
- package/dist/visitor/arguments/index.js.map +1 -0
- package/dist/visitor/arguments/types.d.ts +92 -0
- package/dist/visitor/arguments/types.d.ts.map +1 -0
- package/dist/visitor/arguments/types.js +2 -0
- package/dist/visitor/arguments/types.js.map +1 -0
- package/dist/visitor/constants.d.ts +4 -0
- package/dist/visitor/constants.d.ts.map +1 -0
- package/dist/visitor/constants.js +61 -0
- package/dist/visitor/constants.js.map +1 -0
- package/dist/visitor/helpers.d.ts +30 -0
- package/dist/visitor/helpers.d.ts.map +1 -0
- package/dist/visitor/helpers.js +200 -0
- package/dist/visitor/helpers.js.map +1 -0
- package/dist/visitor/returns/index.d.ts +76 -0
- package/dist/visitor/returns/index.d.ts.map +1 -0
- package/dist/visitor/returns/index.js +426 -0
- package/dist/visitor/returns/index.js.map +1 -0
- package/dist/visitor/returns/types.d.ts +143 -0
- package/dist/visitor/returns/types.d.ts.map +1 -0
- package/dist/visitor/returns/types.js +2 -0
- package/dist/visitor/returns/types.js.map +1 -0
- package/dist/visitor/types.d.ts +6 -0
- package/dist/visitor/types.d.ts.map +1 -0
- package/dist/visitor/types.js +3 -0
- package/dist/visitor/types.js.map +1 -0
- package/package.json +3 -2
- package/src/display-reactor.ts +10 -2
- package/src/index.ts +1 -0
- package/src/metadata-display-reactor.ts +184 -0
- package/src/visitor/arguments/index.test.ts +882 -0
- package/src/visitor/arguments/index.ts +405 -0
- package/src/visitor/arguments/types.ts +168 -0
- package/src/visitor/constants.ts +62 -0
- package/src/visitor/helpers.ts +221 -0
- package/src/visitor/returns/index.test.ts +2027 -0
- package/src/visitor/returns/index.ts +553 -0
- package/src/visitor/returns/types.ts +272 -0
- package/src/visitor/types.ts +29 -0
|
@@ -0,0 +1,553 @@
|
|
|
1
|
+
import { isQuery } from "../helpers"
|
|
2
|
+
import { checkTextFormat, checkNumberFormat } from "../constants"
|
|
3
|
+
import { IDL } from "../types"
|
|
4
|
+
import type {
|
|
5
|
+
ResultField,
|
|
6
|
+
ResultFieldWithValue,
|
|
7
|
+
RecordResultField,
|
|
8
|
+
VariantResultField,
|
|
9
|
+
TupleResultField,
|
|
10
|
+
OptionalResultField,
|
|
11
|
+
VectorResultField,
|
|
12
|
+
BlobResultField,
|
|
13
|
+
RecursiveResultField,
|
|
14
|
+
PrincipalResultField,
|
|
15
|
+
NumberResultField,
|
|
16
|
+
TextResultField,
|
|
17
|
+
BooleanResultField,
|
|
18
|
+
NullResultField,
|
|
19
|
+
UnknownResultField,
|
|
20
|
+
MethodResultMeta,
|
|
21
|
+
ServiceResultMeta,
|
|
22
|
+
ResolvedMethodResult,
|
|
23
|
+
} from "./types"
|
|
24
|
+
import { DisplayCodecVisitor } from "@ic-reactor/core"
|
|
25
|
+
import type {
|
|
26
|
+
ActorMethodReturnType,
|
|
27
|
+
BaseActor,
|
|
28
|
+
FunctionName,
|
|
29
|
+
FunctionType,
|
|
30
|
+
} from "@ic-reactor/core"
|
|
31
|
+
|
|
32
|
+
export * from "./types"
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* ResultFieldVisitor generates metadata for displaying method results from Candid IDL types.
|
|
36
|
+
*
|
|
37
|
+
* ## Design Principles
|
|
38
|
+
*
|
|
39
|
+
* 1. **Works with raw IDL types BEFORE transformation** - generates metadata at initialization
|
|
40
|
+
* 2. **No value dependencies** - metadata describes structure, not specific values
|
|
41
|
+
* 3. **Describes display format** - includes hints for how values will appear after transformation
|
|
42
|
+
* 4. **Efficient** - single traversal, reusable metadata
|
|
43
|
+
* 5. **Resolvable** - metadata can be combined with values at runtime via .resolve(val)
|
|
44
|
+
*
|
|
45
|
+
* ## Key Insight: Metadata vs Values
|
|
46
|
+
*
|
|
47
|
+
* The visitor generates a "schema" that describes:
|
|
48
|
+
* - What type each field is in Candid (nat, Principal, opt, etc.)
|
|
49
|
+
* - What it becomes after display transformation (string, null, etc.)
|
|
50
|
+
* - How it should be formatted (timestamp, cycle, hex, etc.)
|
|
51
|
+
*
|
|
52
|
+
* Values are NOT passed during traversal. Instead, the generated schema
|
|
53
|
+
* is used at render time to properly display transformed values.
|
|
54
|
+
*
|
|
55
|
+
* ## Display Transformations (applied by DisplayCodecVisitor)
|
|
56
|
+
*
|
|
57
|
+
* | Candid Type | Display Type | Notes |
|
|
58
|
+
* |-------------|--------------|-------|
|
|
59
|
+
* | nat, int, nat64, int64 | string | BigInt → string |
|
|
60
|
+
* | Principal | string | Principal.toText() |
|
|
61
|
+
* | opt T | T \| null | [value] → value, [] → null |
|
|
62
|
+
* | vec nat8 (blob) | string | Uint8Array → hex string |
|
|
63
|
+
* | variant { Ok, Err } | unwrapped | { Ok: val } → val (or throws on Err) |
|
|
64
|
+
*
|
|
65
|
+
* @example
|
|
66
|
+
* ```typescript
|
|
67
|
+
* const visitor = new ResultFieldVisitor()
|
|
68
|
+
* const serviceMeta = service.accept(visitor, null)
|
|
69
|
+
*
|
|
70
|
+
* // Get method result metadata
|
|
71
|
+
* const methodMeta = serviceMeta["icrc1_balance_of"]
|
|
72
|
+
* // methodMeta.resultFields[0] = {
|
|
73
|
+
* // type: "number",
|
|
74
|
+
* // candidType: "nat",
|
|
75
|
+
* // displayType: "string",
|
|
76
|
+
* // numberFormat: "normal"
|
|
77
|
+
* // }
|
|
78
|
+
*
|
|
79
|
+
* // At render time, apply to transformed value:
|
|
80
|
+
* const transformedResult = "1000000000" // Already transformed by DisplayCodec
|
|
81
|
+
* renderField(methodMeta.resultFields[0], transformedResult)
|
|
82
|
+
* ```
|
|
83
|
+
*/
|
|
84
|
+
export class ResultFieldVisitor<A = BaseActor> extends IDL.Visitor<
|
|
85
|
+
string,
|
|
86
|
+
ResultField | MethodResultMeta<A> | ServiceResultMeta<A>
|
|
87
|
+
> {
|
|
88
|
+
private displayVisitor = new DisplayCodecVisitor()
|
|
89
|
+
|
|
90
|
+
// ════════════════════════════════════════════════════════════════════════
|
|
91
|
+
// Service & Function Level
|
|
92
|
+
// ════════════════════════════════════════════════════════════════════════
|
|
93
|
+
|
|
94
|
+
public visitService(t: IDL.ServiceClass): ServiceResultMeta<A> {
|
|
95
|
+
const result = {} as ServiceResultMeta<A>
|
|
96
|
+
|
|
97
|
+
for (const [functionName, func] of t._fields) {
|
|
98
|
+
result[functionName as FunctionName<A>] = func.accept(
|
|
99
|
+
this,
|
|
100
|
+
functionName
|
|
101
|
+
) as MethodResultMeta<A>
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
return result
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
public visitFunc(
|
|
108
|
+
t: IDL.FuncClass,
|
|
109
|
+
functionName: FunctionName<A>
|
|
110
|
+
): MethodResultMeta<A> {
|
|
111
|
+
const functionType: FunctionType = isQuery(t) ? "query" : "update"
|
|
112
|
+
|
|
113
|
+
const resultFields = t.retTypes.map((retType, index) =>
|
|
114
|
+
retType.accept(this, `__ret${index}`)
|
|
115
|
+
) as ResultField[]
|
|
116
|
+
|
|
117
|
+
const generateMetadata = (
|
|
118
|
+
data: ActorMethodReturnType<A[FunctionName<A>]>
|
|
119
|
+
): ResolvedMethodResult<A> => {
|
|
120
|
+
const dataArray: unknown[] =
|
|
121
|
+
resultFields.length === 0
|
|
122
|
+
? []
|
|
123
|
+
: resultFields.length === 1
|
|
124
|
+
? [data]
|
|
125
|
+
: (data as unknown[])
|
|
126
|
+
|
|
127
|
+
const results = resultFields.map((field, index) =>
|
|
128
|
+
field.resolve(dataArray[index])
|
|
129
|
+
)
|
|
130
|
+
|
|
131
|
+
return {
|
|
132
|
+
functionType,
|
|
133
|
+
functionName,
|
|
134
|
+
results,
|
|
135
|
+
raw: data,
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
return {
|
|
140
|
+
functionType,
|
|
141
|
+
functionName,
|
|
142
|
+
resultFields,
|
|
143
|
+
returnCount: t.retTypes.length,
|
|
144
|
+
generateMetadata,
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// ════════════════════════════════════════════════════════════════════════
|
|
149
|
+
// Compound Types
|
|
150
|
+
// ════════════════════════════════════════════════════════════════════════
|
|
151
|
+
|
|
152
|
+
public visitRecord(
|
|
153
|
+
_t: IDL.RecordClass,
|
|
154
|
+
fields_: Array<[string, IDL.Type]>,
|
|
155
|
+
label: string
|
|
156
|
+
): RecordResultField {
|
|
157
|
+
const fields = fields_.map(
|
|
158
|
+
([key, type]) => type.accept(this, key) as ResultField
|
|
159
|
+
)
|
|
160
|
+
|
|
161
|
+
const field: RecordResultField = {
|
|
162
|
+
type: "record",
|
|
163
|
+
label,
|
|
164
|
+
candidType: "record",
|
|
165
|
+
displayType: "object",
|
|
166
|
+
fields,
|
|
167
|
+
resolve(value: unknown): ResultFieldWithValue {
|
|
168
|
+
const record = value as Record<string, unknown> | null | undefined
|
|
169
|
+
if (record == null) {
|
|
170
|
+
return { field, value: null, raw: value }
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
const resolvedFields: Record<string, ResultFieldWithValue> = {}
|
|
174
|
+
for (const f of fields) {
|
|
175
|
+
resolvedFields[f.label] = f.resolve(record[f.label])
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
return { field, value: resolvedFields, raw: value }
|
|
179
|
+
},
|
|
180
|
+
}
|
|
181
|
+
return field
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
public visitVariant(
|
|
185
|
+
_t: IDL.VariantClass,
|
|
186
|
+
fields_: Array<[string, IDL.Type]>,
|
|
187
|
+
label: string
|
|
188
|
+
): VariantResultField {
|
|
189
|
+
const options: string[] = []
|
|
190
|
+
const optionFields: ResultField[] = []
|
|
191
|
+
|
|
192
|
+
for (const [key, type] of fields_) {
|
|
193
|
+
options.push(key)
|
|
194
|
+
optionFields.push(type.accept(this, key) as ResultField)
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
// Detect if this is a Result type (has Ok and Err options)
|
|
198
|
+
const isResult = options.includes("Ok") && options.includes("Err")
|
|
199
|
+
const displayType = isResult ? "result" : "variant"
|
|
200
|
+
|
|
201
|
+
const field: VariantResultField = {
|
|
202
|
+
type: "variant",
|
|
203
|
+
label,
|
|
204
|
+
candidType: "variant",
|
|
205
|
+
displayType,
|
|
206
|
+
options,
|
|
207
|
+
optionFields,
|
|
208
|
+
resolve(value: unknown): ResultFieldWithValue {
|
|
209
|
+
if (value == null) {
|
|
210
|
+
return { field, value: null, raw: value }
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
const variant = value as Record<string, unknown>
|
|
214
|
+
const optionsInValue = Object.keys(variant)
|
|
215
|
+
const activeOption = optionsInValue.find((opt) => options.includes(opt))
|
|
216
|
+
|
|
217
|
+
if (!activeOption) {
|
|
218
|
+
return { field, value: null, raw: value }
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
const activeValue = variant[activeOption]
|
|
222
|
+
const optionIndex = options.indexOf(activeOption)
|
|
223
|
+
const optionField = optionFields[optionIndex]
|
|
224
|
+
|
|
225
|
+
const specificField: VariantResultField = {
|
|
226
|
+
...field,
|
|
227
|
+
options,
|
|
228
|
+
optionFields: [optionField],
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
return {
|
|
232
|
+
field: specificField,
|
|
233
|
+
value: {
|
|
234
|
+
option: activeOption,
|
|
235
|
+
value: optionField?.resolve(activeValue) ?? {
|
|
236
|
+
field: optionField,
|
|
237
|
+
value: activeValue,
|
|
238
|
+
raw: activeValue,
|
|
239
|
+
},
|
|
240
|
+
},
|
|
241
|
+
raw: value,
|
|
242
|
+
}
|
|
243
|
+
},
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
return field
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
public visitTuple<T extends IDL.Type[]>(
|
|
250
|
+
_t: IDL.TupleClass<T>,
|
|
251
|
+
components: IDL.Type[],
|
|
252
|
+
label: string
|
|
253
|
+
): TupleResultField {
|
|
254
|
+
const fields = components.map(
|
|
255
|
+
(type, index) => type.accept(this, `_${index}`) as ResultField
|
|
256
|
+
)
|
|
257
|
+
|
|
258
|
+
const field: TupleResultField = {
|
|
259
|
+
type: "tuple",
|
|
260
|
+
label,
|
|
261
|
+
candidType: "tuple",
|
|
262
|
+
displayType: "array",
|
|
263
|
+
fields,
|
|
264
|
+
resolve(value: unknown): ResultFieldWithValue {
|
|
265
|
+
const tuple = value as unknown[] | null | undefined
|
|
266
|
+
if (tuple == null) {
|
|
267
|
+
return { field, value: null, raw: value }
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
const resolvedItems = fields.map((f, index) => f.resolve(tuple[index]))
|
|
271
|
+
return { field, value: resolvedItems, raw: value }
|
|
272
|
+
},
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
return field
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
public visitOpt<T>(
|
|
279
|
+
_t: IDL.OptClass<T>,
|
|
280
|
+
ty: IDL.Type<T>,
|
|
281
|
+
label: string
|
|
282
|
+
): OptionalResultField {
|
|
283
|
+
const innerField = ty.accept(this, label) as ResultField
|
|
284
|
+
|
|
285
|
+
const field: OptionalResultField = {
|
|
286
|
+
type: "optional",
|
|
287
|
+
label,
|
|
288
|
+
candidType: "opt",
|
|
289
|
+
displayType: "nullable",
|
|
290
|
+
innerField,
|
|
291
|
+
resolve(value: unknown): ResultFieldWithValue {
|
|
292
|
+
const opt = value as [unknown] | [] | null | undefined
|
|
293
|
+
if (opt == null || opt.length === 0) {
|
|
294
|
+
return { field, value: null, raw: value }
|
|
295
|
+
}
|
|
296
|
+
return { field, value: innerField.resolve(opt[0]), raw: value }
|
|
297
|
+
},
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
return field
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
public visitVec<T>(
|
|
304
|
+
_t: IDL.VecClass<T>,
|
|
305
|
+
ty: IDL.Type<T>,
|
|
306
|
+
label: string
|
|
307
|
+
): VectorResultField | BlobResultField {
|
|
308
|
+
// Check if it's blob (vec nat8)
|
|
309
|
+
if (ty instanceof IDL.FixedNatClass && ty._bits === 8) {
|
|
310
|
+
const codec = _t.accept(this.displayVisitor, null) as any
|
|
311
|
+
const blobField: BlobResultField = {
|
|
312
|
+
type: "blob",
|
|
313
|
+
label,
|
|
314
|
+
candidType: "blob",
|
|
315
|
+
displayType: "string", // Transformed to hex string
|
|
316
|
+
displayHint: "hex",
|
|
317
|
+
resolve(value: unknown): ResultFieldWithValue {
|
|
318
|
+
return {
|
|
319
|
+
field: blobField,
|
|
320
|
+
value: codec.decode(value),
|
|
321
|
+
raw: value,
|
|
322
|
+
}
|
|
323
|
+
},
|
|
324
|
+
}
|
|
325
|
+
return blobField
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
const itemField = ty.accept(this, "item") as ResultField
|
|
329
|
+
|
|
330
|
+
const field: VectorResultField = {
|
|
331
|
+
type: "vector",
|
|
332
|
+
label,
|
|
333
|
+
candidType: "vec",
|
|
334
|
+
displayType: "array",
|
|
335
|
+
itemField,
|
|
336
|
+
resolve(value: unknown): ResultFieldWithValue {
|
|
337
|
+
const vec = value as unknown[] | null | undefined
|
|
338
|
+
if (vec == null) {
|
|
339
|
+
return { field, value: null, raw: value }
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
const resolvedItems = vec.map((item) => itemField.resolve(item))
|
|
343
|
+
return { field, value: resolvedItems, raw: value }
|
|
344
|
+
},
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
return field
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
public visitRec<T>(
|
|
351
|
+
t: IDL.RecClass<T>,
|
|
352
|
+
ty: IDL.ConstructType<T>,
|
|
353
|
+
label: string
|
|
354
|
+
): RecursiveResultField {
|
|
355
|
+
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
|
356
|
+
const self = this
|
|
357
|
+
|
|
358
|
+
const field: RecursiveResultField = {
|
|
359
|
+
type: "recursive",
|
|
360
|
+
label,
|
|
361
|
+
candidType: "rec",
|
|
362
|
+
displayType: "recursive",
|
|
363
|
+
typeName: t.name,
|
|
364
|
+
// Lazy extraction to prevent infinite loops
|
|
365
|
+
extract: () => ty.accept(self, label) as ResultField,
|
|
366
|
+
resolve(value: unknown): ResultFieldWithValue {
|
|
367
|
+
// Extract the inner field and resolve with it
|
|
368
|
+
const innerField = field.extract()
|
|
369
|
+
return innerField.resolve(value)
|
|
370
|
+
},
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
return field
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
// ════════════════════════════════════════════════════════════════════════
|
|
377
|
+
// Primitive Types
|
|
378
|
+
// ════════════════════════════════════════════════════════════════════════
|
|
379
|
+
|
|
380
|
+
public visitPrincipal(
|
|
381
|
+
t: IDL.PrincipalClass,
|
|
382
|
+
label: string
|
|
383
|
+
): PrincipalResultField {
|
|
384
|
+
const codec = t.accept(this.displayVisitor, null) as any
|
|
385
|
+
const field: PrincipalResultField = {
|
|
386
|
+
type: "principal",
|
|
387
|
+
label,
|
|
388
|
+
candidType: "principal",
|
|
389
|
+
displayType: "string", // Principal.toText()
|
|
390
|
+
textFormat: checkTextFormat(label),
|
|
391
|
+
resolve(value: unknown): ResultFieldWithValue {
|
|
392
|
+
return {
|
|
393
|
+
field,
|
|
394
|
+
value: codec.decode(value),
|
|
395
|
+
raw: value,
|
|
396
|
+
}
|
|
397
|
+
},
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
return field
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
public visitText(t: IDL.TextClass, label: string): TextResultField {
|
|
404
|
+
const codec = t.accept(this.displayVisitor, null) as any
|
|
405
|
+
const field: TextResultField = {
|
|
406
|
+
type: "text",
|
|
407
|
+
label,
|
|
408
|
+
candidType: "text",
|
|
409
|
+
displayType: "string",
|
|
410
|
+
textFormat: checkTextFormat(label),
|
|
411
|
+
resolve(value: unknown): ResultFieldWithValue {
|
|
412
|
+
return { field, value: codec.decode(value), raw: value }
|
|
413
|
+
},
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
return field
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
public visitBool(t: IDL.BoolClass, label: string): BooleanResultField {
|
|
420
|
+
const codec = t.accept(this.displayVisitor, null) as any
|
|
421
|
+
const field: BooleanResultField = {
|
|
422
|
+
type: "boolean",
|
|
423
|
+
label,
|
|
424
|
+
candidType: "bool",
|
|
425
|
+
displayType: "boolean",
|
|
426
|
+
resolve(value: unknown): ResultFieldWithValue {
|
|
427
|
+
return { field, value: codec.decode(value), raw: value }
|
|
428
|
+
},
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
return field
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
public visitNull(t: IDL.NullClass, label: string): NullResultField {
|
|
435
|
+
const codec = t.accept(this.displayVisitor, null) as any
|
|
436
|
+
const field: NullResultField = {
|
|
437
|
+
type: "null",
|
|
438
|
+
label,
|
|
439
|
+
candidType: "null",
|
|
440
|
+
displayType: "null",
|
|
441
|
+
resolve(value: unknown): ResultFieldWithValue {
|
|
442
|
+
return { field, value: codec.decode(value), raw: value }
|
|
443
|
+
},
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
return field
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
// Numbers
|
|
450
|
+
public visitInt(t: IDL.IntClass, label: string): NumberResultField {
|
|
451
|
+
const codec = t.accept(this.displayVisitor, null) as any
|
|
452
|
+
const field: NumberResultField = {
|
|
453
|
+
type: "number",
|
|
454
|
+
label,
|
|
455
|
+
candidType: "int",
|
|
456
|
+
displayType: "string", // BigInt → string
|
|
457
|
+
numberFormat: checkNumberFormat(label),
|
|
458
|
+
resolve(value: unknown): ResultFieldWithValue {
|
|
459
|
+
return { field, value: codec.decode(value), raw: value }
|
|
460
|
+
},
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
return field
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
public visitNat(t: IDL.NatClass, label: string): NumberResultField {
|
|
467
|
+
const codec = t.accept(this.displayVisitor, null) as any
|
|
468
|
+
const field: NumberResultField = {
|
|
469
|
+
type: "number",
|
|
470
|
+
label,
|
|
471
|
+
candidType: "nat",
|
|
472
|
+
displayType: "string", // BigInt → string
|
|
473
|
+
numberFormat: checkNumberFormat(label),
|
|
474
|
+
resolve(value: unknown): ResultFieldWithValue {
|
|
475
|
+
return { field, value: codec.decode(value), raw: value }
|
|
476
|
+
},
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
return field
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
public visitFloat(t: IDL.FloatClass, label: string): NumberResultField {
|
|
483
|
+
const codec = t.accept(this.displayVisitor, null) as any
|
|
484
|
+
const field: NumberResultField = {
|
|
485
|
+
type: "number",
|
|
486
|
+
label,
|
|
487
|
+
candidType: `float${t._bits}`,
|
|
488
|
+
displayType: "number", // Floats stay as numbers
|
|
489
|
+
numberFormat: checkNumberFormat(label),
|
|
490
|
+
resolve(value: unknown): ResultFieldWithValue {
|
|
491
|
+
return { field, value: codec.decode(value), raw: value }
|
|
492
|
+
},
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
return field
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
public visitFixedInt(t: IDL.FixedIntClass, label: string): NumberResultField {
|
|
499
|
+
const bits = t._bits
|
|
500
|
+
const codec = t.accept(this.displayVisitor, null) as any
|
|
501
|
+
const field: NumberResultField = {
|
|
502
|
+
type: "number",
|
|
503
|
+
label,
|
|
504
|
+
candidType: `int${bits}`,
|
|
505
|
+
displayType: bits <= 32 ? "number" : "string", // int64 → string
|
|
506
|
+
numberFormat: checkNumberFormat(label),
|
|
507
|
+
resolve(value: unknown): ResultFieldWithValue {
|
|
508
|
+
return {
|
|
509
|
+
field,
|
|
510
|
+
value: codec.decode(value),
|
|
511
|
+
raw: value,
|
|
512
|
+
}
|
|
513
|
+
},
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
return field
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
public visitFixedNat(t: IDL.FixedNatClass, label: string): NumberResultField {
|
|
520
|
+
const bits = t._bits
|
|
521
|
+
const codec = t.accept(this.displayVisitor, null) as any
|
|
522
|
+
const field: NumberResultField = {
|
|
523
|
+
type: "number",
|
|
524
|
+
label,
|
|
525
|
+
candidType: `nat${bits}`,
|
|
526
|
+
displayType: bits <= 32 ? "number" : "string", // nat64 → string
|
|
527
|
+
numberFormat: checkNumberFormat(label),
|
|
528
|
+
resolve(value: unknown): ResultFieldWithValue {
|
|
529
|
+
return {
|
|
530
|
+
field,
|
|
531
|
+
value: codec.decode(value),
|
|
532
|
+
raw: value,
|
|
533
|
+
}
|
|
534
|
+
},
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
return field
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
public visitType<T>(_t: IDL.Type<T>, label: string): UnknownResultField {
|
|
541
|
+
const field: UnknownResultField = {
|
|
542
|
+
type: "unknown",
|
|
543
|
+
label,
|
|
544
|
+
candidType: "unknown",
|
|
545
|
+
displayType: "unknown",
|
|
546
|
+
resolve(value: unknown): ResultFieldWithValue {
|
|
547
|
+
return { field, value, raw: value }
|
|
548
|
+
},
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
return field
|
|
552
|
+
}
|
|
553
|
+
}
|