gen-typescript-from-tolk-dev 0.2.1 → 0.2.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/dist/dynamic-ctx.d.ts +17 -0
- package/dist/dynamic-ctx.js +39 -0
- package/dist/dynamic-debug-print.d.ts +9 -0
- package/dist/dynamic-debug-print.js +183 -0
- package/dist/dynamic-get-methods.d.ts +43 -0
- package/dist/dynamic-get-methods.js +451 -0
- package/dist/dynamic-serialization.d.ts +22 -0
- package/dist/dynamic-serialization.js +453 -0
- package/dist/dynamic-validation.d.ts +8 -0
- package/dist/dynamic-validation.js +56 -0
- package/dist/index.d.ts +9 -3
- package/dist/index.js +25 -1
- package/package.json +1 -1
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import * as c from '@ton/core';
|
|
2
|
+
import { SymTable } from './codegen-ctx';
|
|
3
|
+
import { ABIGetMethod, ContractABI } from './abi';
|
|
4
|
+
type CustomPackToBuilderFn<T> = (self: T, b: c.Builder) => void;
|
|
5
|
+
type CustomUnpackFromSliceFn<T> = (s: c.Slice) => T;
|
|
6
|
+
export declare class DynamicCtx {
|
|
7
|
+
readonly contractName: string;
|
|
8
|
+
readonly getMethods: ABIGetMethod[];
|
|
9
|
+
readonly symbols: SymTable;
|
|
10
|
+
private customSerializersRegistry;
|
|
11
|
+
constructor(contract: ContractABI);
|
|
12
|
+
registerCustomPackUnpack<T>(typeName: string, packToBuilderFn: CustomPackToBuilderFn<T> | null, unpackFromSliceFn: CustomUnpackFromSliceFn<T> | null): void;
|
|
13
|
+
getCustomPackFnOrThrow(typeName: string, fieldPath: string): CustomPackToBuilderFn<any>;
|
|
14
|
+
getCustomUnpackFnOrThrow(typeName: string, fieldPath: string): CustomUnpackFromSliceFn<any>;
|
|
15
|
+
findGetMethod(getMethodName: string): ABIGetMethod | undefined;
|
|
16
|
+
}
|
|
17
|
+
export {};
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.DynamicCtx = void 0;
|
|
4
|
+
const codegen_ctx_1 = require("./codegen-ctx");
|
|
5
|
+
const unsupported_errors_1 = require("./unsupported-errors");
|
|
6
|
+
class DynamicCtx {
|
|
7
|
+
constructor(contract) {
|
|
8
|
+
this.customSerializersRegistry = new Map;
|
|
9
|
+
this.contractName = contract.contract_name;
|
|
10
|
+
this.getMethods = contract.get_methods;
|
|
11
|
+
this.symbols = new codegen_ctx_1.SymTable(contract.declarations);
|
|
12
|
+
}
|
|
13
|
+
registerCustomPackUnpack(typeName, packToBuilderFn, unpackFromSliceFn) {
|
|
14
|
+
if (this.customSerializersRegistry.has(typeName)) {
|
|
15
|
+
throw new Error(`Custom pack/unpack for '${typeName}' already registered`);
|
|
16
|
+
}
|
|
17
|
+
this.customSerializersRegistry.set(typeName, [packToBuilderFn, unpackFromSliceFn]);
|
|
18
|
+
}
|
|
19
|
+
getCustomPackFnOrThrow(typeName, fieldPath) {
|
|
20
|
+
let packUnpack = this.customSerializersRegistry.get(typeName);
|
|
21
|
+
let packFn = packUnpack ? packUnpack[0] : null;
|
|
22
|
+
if (!packFn) {
|
|
23
|
+
throw new unsupported_errors_1.CantPackDynamic(fieldPath, `custom packToBuilder was not registered for '${typeName}'`);
|
|
24
|
+
}
|
|
25
|
+
return packFn;
|
|
26
|
+
}
|
|
27
|
+
getCustomUnpackFnOrThrow(typeName, fieldPath) {
|
|
28
|
+
let packUnpack = this.customSerializersRegistry.get(typeName);
|
|
29
|
+
let unpackFn = packUnpack ? packUnpack[1] : null;
|
|
30
|
+
if (!unpackFn) {
|
|
31
|
+
throw new unsupported_errors_1.CantUnpackDynamic(fieldPath, `custom unpackFromSlice was not registered for '${typeName}'`);
|
|
32
|
+
}
|
|
33
|
+
return unpackFn;
|
|
34
|
+
}
|
|
35
|
+
findGetMethod(getMethodName) {
|
|
36
|
+
return this.getMethods.find(m => m.name === getMethodName);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
exports.DynamicCtx = DynamicCtx;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { DynamicCtx } from './dynamic-ctx';
|
|
2
|
+
import { Ty } from './abi-types';
|
|
3
|
+
import { StackReader } from './dynamic-get-methods';
|
|
4
|
+
/**
|
|
5
|
+
* Read a value of type `ty` from the TVM stack `tuple` and return a human-readable string.
|
|
6
|
+
* Consumes `calcWidthOnStack(ty)` elements from the beginning of the array.
|
|
7
|
+
* Example: given `Point { x: int, y: int }` and stack `[10n, 20n]`, returns "Point { x: 10, y: 20 }".
|
|
8
|
+
*/
|
|
9
|
+
export declare function debugPrintFromStack(ctx: DynamicCtx, r: StackReader, ty: Ty): string;
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.debugPrintFromStack = debugPrintFromStack;
|
|
4
|
+
const dynamic_get_methods_1 = require("./dynamic-get-methods");
|
|
5
|
+
const dynamic_serialization_1 = require("./dynamic-serialization");
|
|
6
|
+
const types_kernel_1 = require("./types-kernel");
|
|
7
|
+
/*
|
|
8
|
+
Debug printing from the TVM stack.
|
|
9
|
+
Given TupleItem[] of a type Ty, and an ABI (via DynamicCtx),
|
|
10
|
+
produce a human-readable string representation.
|
|
11
|
+
This is used for debugging / println / explorers —
|
|
12
|
+
to show the value of a variable or a get method result in a readable format.
|
|
13
|
+
*/
|
|
14
|
+
function printRawCellContents(c) {
|
|
15
|
+
return c.toString();
|
|
16
|
+
}
|
|
17
|
+
// Read `ty` from a stack and return formatted human-readable representation.
|
|
18
|
+
// Throws if a stack is too small or failed to deserialize a value (inside `Cell<T>` or a map, for example).
|
|
19
|
+
function debugFormat(ctx, r, fieldPath, ty, unTupleIfW = false) {
|
|
20
|
+
if (unTupleIfW) {
|
|
21
|
+
let wOnStack = (0, types_kernel_1.calcWidthOnStack)(ctx.symbols, ty);
|
|
22
|
+
if (wOnStack !== 1) {
|
|
23
|
+
return r.readTuple(wOnStack, (r) => debugFormat(ctx, r, fieldPath, ty, false));
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
switch (ty.kind) {
|
|
27
|
+
case 'int':
|
|
28
|
+
case 'intN':
|
|
29
|
+
case 'uintN':
|
|
30
|
+
case 'varintN':
|
|
31
|
+
case 'varuintN':
|
|
32
|
+
case 'coins': return r.readBigInt().toString();
|
|
33
|
+
case 'bool': return r.readBoolean() ? 'true' : 'false';
|
|
34
|
+
case 'cell': return `cell{${printRawCellContents(r.readCell())}}`;
|
|
35
|
+
case 'builder': return `builder{${printRawCellContents(r.readBuilder().endCell())}}`;
|
|
36
|
+
case 'slice':
|
|
37
|
+
case 'bitsN':
|
|
38
|
+
case 'remaining': return `slice{${printRawCellContents(r.readSlice().asCell())}}`;
|
|
39
|
+
case 'string': return `"${r.readSnakeString()}"`;
|
|
40
|
+
case 'address': return r.readSlice().loadAddress().toString();
|
|
41
|
+
case 'addressOpt': return debugFormat(ctx, r, fieldPath, { kind: 'nullable', inner: { kind: 'address' } });
|
|
42
|
+
case 'addressExt': return r.readSlice().loadExternalAddress().toString();
|
|
43
|
+
case 'addressAny': {
|
|
44
|
+
let addr = (0, dynamic_serialization_1.dynamicUnpack)(ctx, fieldPath, ty, r.readSlice());
|
|
45
|
+
return addr === 'none' ? 'addr_none' : addr.toString();
|
|
46
|
+
}
|
|
47
|
+
case 'nullLiteral': return r.readNullLiteral() ?? 'null';
|
|
48
|
+
case 'void': return '(void)';
|
|
49
|
+
case 'unknown': return debugPrintUnknown(r.readUnknown());
|
|
50
|
+
case 'nullable': {
|
|
51
|
+
if (ty.stack_type_id) {
|
|
52
|
+
return r.readWideNullable(ty.stack_width, (r) => debugFormat(ctx, r, fieldPath, ty.inner)) ?? 'null';
|
|
53
|
+
}
|
|
54
|
+
return r.readNullable((r) => debugFormat(ctx, r, fieldPath, ty.inner)) ?? 'null';
|
|
55
|
+
}
|
|
56
|
+
case 'cellOf': {
|
|
57
|
+
let innerStr = r.readCellRef((s) => {
|
|
58
|
+
const deserialized = (0, dynamic_serialization_1.dynamicUnpack)(ctx, fieldPath, ty.inner, s);
|
|
59
|
+
return debugFormatValue(ctx, fieldPath, ty.inner, deserialized);
|
|
60
|
+
});
|
|
61
|
+
return `ref{${innerStr.ref}}`;
|
|
62
|
+
}
|
|
63
|
+
case 'arrayOf': {
|
|
64
|
+
let items = r.readArrayOf((r) => debugFormat(ctx, r, fieldPath, ty.inner, true));
|
|
65
|
+
return `[${items.join(', ')}]`;
|
|
66
|
+
}
|
|
67
|
+
case 'lispListOf': {
|
|
68
|
+
let items = r.readLispListOf((r) => debugFormat(ctx, r, fieldPath, ty.inner, true));
|
|
69
|
+
return `[${items.join(', ')}]`;
|
|
70
|
+
}
|
|
71
|
+
case 'tensor': {
|
|
72
|
+
let parts = [];
|
|
73
|
+
for (let i = 0; i < ty.items.length; ++i) {
|
|
74
|
+
parts.push(debugFormat(ctx, r, `${fieldPath}[${i}]`, ty.items[i]));
|
|
75
|
+
}
|
|
76
|
+
return `(${parts.join(', ')})`;
|
|
77
|
+
}
|
|
78
|
+
case 'shapedTuple': {
|
|
79
|
+
return r.readTuple(ty.items.length, (r) => {
|
|
80
|
+
let parts = [];
|
|
81
|
+
for (let i = 0; i < ty.items.length; ++i) {
|
|
82
|
+
parts.push(debugFormat(ctx, r, `${fieldPath}[${i}]`, ty.items[i], true));
|
|
83
|
+
}
|
|
84
|
+
return `[${parts.join(', ')}]`;
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
case 'mapKV': {
|
|
88
|
+
let dictKey = (0, dynamic_serialization_1.createTonCoreDictionaryKey)(fieldPath, ty.k);
|
|
89
|
+
let dictValue = (0, dynamic_serialization_1.createTonCoreDictionaryValue)(ctx, fieldPath, ty.v);
|
|
90
|
+
let entries = [];
|
|
91
|
+
for (let [k, v] of r.readDictionary(dictKey, dictValue)) {
|
|
92
|
+
let kStr = debugFormatValue(ctx, fieldPath, ty.k, k);
|
|
93
|
+
let vStr = debugFormatValue(ctx, `${fieldPath}[${kStr}]`, ty.v, v);
|
|
94
|
+
entries.push(`${kStr}: ${vStr}`);
|
|
95
|
+
}
|
|
96
|
+
if (entries.length === 0) {
|
|
97
|
+
return 'map{}';
|
|
98
|
+
}
|
|
99
|
+
return `map{${entries.join(', ')}}`;
|
|
100
|
+
}
|
|
101
|
+
case 'EnumRef': {
|
|
102
|
+
let value = r.readBigInt();
|
|
103
|
+
let enumRef = ctx.symbols.getEnum(ty.enum_name);
|
|
104
|
+
let member = enumRef.members.find(m => BigInt(m.value) === value);
|
|
105
|
+
if (member) {
|
|
106
|
+
return `${ty.enum_name}.${member.name}`;
|
|
107
|
+
}
|
|
108
|
+
return `${ty.enum_name}(${value})`;
|
|
109
|
+
}
|
|
110
|
+
case 'StructRef': {
|
|
111
|
+
const structRef = ctx.symbols.getStruct(ty.struct_name);
|
|
112
|
+
if (structRef.fields.length === 0) {
|
|
113
|
+
return `${ty.struct_name} {}`;
|
|
114
|
+
}
|
|
115
|
+
const fieldStrs = [];
|
|
116
|
+
for (const f of structRef.fields) {
|
|
117
|
+
const fTy = ty.type_args ? (0, types_kernel_1.instantiateGenerics)(f.ty, structRef.type_params, ty.type_args) : f.ty;
|
|
118
|
+
fieldStrs.push(`${f.name}: ${debugFormat(ctx, r, `${fieldPath}.${f.name}`, fTy)}`);
|
|
119
|
+
}
|
|
120
|
+
return `${ty.struct_name} { ${fieldStrs.join(', ')} }`;
|
|
121
|
+
}
|
|
122
|
+
case 'AliasRef': {
|
|
123
|
+
const aliasRef = ctx.symbols.getAlias(ty.alias_name);
|
|
124
|
+
const targetTy = ty.type_args ? (0, types_kernel_1.instantiateGenerics)(aliasRef.target_ty, aliasRef.type_params, ty.type_args) : aliasRef.target_ty;
|
|
125
|
+
return debugFormat(ctx, r, fieldPath, targetTy);
|
|
126
|
+
}
|
|
127
|
+
case 'union': {
|
|
128
|
+
const variants = (0, types_kernel_1.createLabelsForUnion)(ctx.symbols, ty.variants);
|
|
129
|
+
const infoForTypeId = {};
|
|
130
|
+
for (let v of variants) {
|
|
131
|
+
infoForTypeId[v.stack_type_id] = [v.stack_width, v.hasValueField ? v.labelStr : null,
|
|
132
|
+
(r) => debugFormat(ctx, r, `${fieldPath}#${v.labelStr}`, v.variant_ty)
|
|
133
|
+
];
|
|
134
|
+
}
|
|
135
|
+
// readUnionType returns `valueT` (if no label) or `{ $: "label", value: valueT }`
|
|
136
|
+
// In our case, valueT is already a string.
|
|
137
|
+
const result = r.readUnionType(ty.stack_width, infoForTypeId);
|
|
138
|
+
if (typeof result === 'string') {
|
|
139
|
+
// label is null, then it's a struct with its own $, like "Point { ... }", or it's "null"
|
|
140
|
+
return result;
|
|
141
|
+
}
|
|
142
|
+
// render "#label value": notation "#label" means "active variant of a union"
|
|
143
|
+
return `#${result.$} ${result.value}`;
|
|
144
|
+
}
|
|
145
|
+
case 'callable': {
|
|
146
|
+
r.readUnknown();
|
|
147
|
+
return 'continuation';
|
|
148
|
+
}
|
|
149
|
+
case 'genericT': throw new Error(`unexpected genericT=${ty.name_t}`);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
// Format a value that was already parsed by dynamicUnpack into a JS representation.
|
|
153
|
+
// This is used for inner values of `Cell<T>` and map entries, where we parse via `dynamicUnpack`
|
|
154
|
+
// and then need to show the result as a string.
|
|
155
|
+
function debugFormatValue(ctx, fieldPath, ty, value) {
|
|
156
|
+
// unlike `debugFormat()`, here we don't read `ty` from a stack: we already have `value` of type `ty`;
|
|
157
|
+
// to visualize it, instead of making a giant switch-case for all types, do the following trick:
|
|
158
|
+
// pack value back to a tuple, and render this tuple as if it's a stack value
|
|
159
|
+
const backToTuple = (0, dynamic_get_methods_1.makeTvmTupleDynamic)(ctx, ty, value);
|
|
160
|
+
return debugFormat(ctx, new dynamic_get_methods_1.StackReader(backToTuple), fieldPath, ty);
|
|
161
|
+
}
|
|
162
|
+
// `unknown` is a raw TVM tuple item; `tuple`, by definition, is `array<unknown>`,
|
|
163
|
+
// it has no compile-time type information, so visualize it anyhow
|
|
164
|
+
function debugPrintUnknown(item) {
|
|
165
|
+
switch (item.type) {
|
|
166
|
+
case 'int': return `${item.value}`;
|
|
167
|
+
case 'cell': return `cell{${printRawCellContents(item.cell)}}`;
|
|
168
|
+
case 'slice': return `slice{${printRawCellContents(item.cell)}}`;
|
|
169
|
+
case 'builder': return `builder{${printRawCellContents(item.cell)}}`;
|
|
170
|
+
case 'null': return 'null';
|
|
171
|
+
case 'tuple': return `(${item.items.map(debugPrintUnknown).join(', ')})`;
|
|
172
|
+
case 'nan': return 'NaN';
|
|
173
|
+
default: return `<unknown>`;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* Read a value of type `ty` from the TVM stack `tuple` and return a human-readable string.
|
|
178
|
+
* Consumes `calcWidthOnStack(ty)` elements from the beginning of the array.
|
|
179
|
+
* Example: given `Point { x: int, y: int }` and stack `[10n, 20n]`, returns "Point { x: 10, y: 20 }".
|
|
180
|
+
*/
|
|
181
|
+
function debugPrintFromStack(ctx, r, ty) {
|
|
182
|
+
return debugFormat(ctx, r, 'self', ty);
|
|
183
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import * as c from '@ton/core';
|
|
2
|
+
import { DynamicCtx } from './dynamic-ctx';
|
|
3
|
+
import { Ty } from './abi-types';
|
|
4
|
+
type LoadCallback<T> = (s: c.Slice) => T;
|
|
5
|
+
export declare class StackReader {
|
|
6
|
+
private tuple;
|
|
7
|
+
constructor(tuple: c.TupleItem[]);
|
|
8
|
+
static fromGetMethod(expectedN: number, getMethodResult: {
|
|
9
|
+
stack: c.TupleReader;
|
|
10
|
+
}): StackReader;
|
|
11
|
+
private popExpecting;
|
|
12
|
+
readBigInt(): bigint;
|
|
13
|
+
readBoolean(): boolean;
|
|
14
|
+
readCell(): c.Cell;
|
|
15
|
+
readSlice(): c.Slice;
|
|
16
|
+
readBuilder(): c.Builder;
|
|
17
|
+
readUnknown(): c.TupleItem;
|
|
18
|
+
readArrayOf<T>(readFn_T: (nestedReader: StackReader) => T): T[];
|
|
19
|
+
readLispListOf<T>(readFn_T: (nestedReader: StackReader) => T): T[];
|
|
20
|
+
readSnakeString(): string;
|
|
21
|
+
readTuple<T>(expectedN: number, readFn_T: (nestedReader: StackReader) => T): T;
|
|
22
|
+
readNullLiteral(): null;
|
|
23
|
+
readNullable<T>(readFn_T: (r: StackReader) => T): T | null;
|
|
24
|
+
readWideNullable<T>(stackW: number, readFn_T: (r: StackReader) => T): T | null;
|
|
25
|
+
readUnionType<T>(stackW: number, infoForTypeId: Record<number, [number, string | null, (r: StackReader) => any]>): T;
|
|
26
|
+
readCellRef<T>(loadFn_T: LoadCallback<T>): {
|
|
27
|
+
ref: T;
|
|
28
|
+
};
|
|
29
|
+
readDictionary<K extends c.DictionaryKeyTypes, V>(keySerializer: c.DictionaryKey<K>, valueSerializer: c.DictionaryValue<V>): c.Dictionary<K, V>;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Pack any `value` of type `ty` to a TVM tuple.
|
|
33
|
+
* This tuple can be used as a get method argument or debug-printed as human-readable.
|
|
34
|
+
*/
|
|
35
|
+
export declare function makeTvmTupleDynamic(ctx: DynamicCtx, ty: Ty, value: any): c.TupleItem[];
|
|
36
|
+
/**
|
|
37
|
+
* Invoke any get method taking plain JS variables as arguments and interpreting the resulting TVM tuple according to ABI.
|
|
38
|
+
* Example: `get fun intAndPoint(i: int, p: Point): Point`.
|
|
39
|
+
* Call: `callGetMethodDynamic(provider, ctx, 'intAndPoint', [num, {x: num, y: num}])` returns `{x: num, y: num}`.
|
|
40
|
+
* When input is incorrect (e.g. missing property in a JS object), throws InvalidDynamicInput.
|
|
41
|
+
*/
|
|
42
|
+
export declare function callGetMethodDynamic(provider: c.ContractProvider, ctx: DynamicCtx, getMethodName: string, args: any[]): Promise<any>;
|
|
43
|
+
export {};
|