gen-typescript-from-tolk-dev 0.1.0 → 0.2.0
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/README.md +53 -27
- package/bin/generator.js +1 -13
- package/dist/abi-types.d.ts +169 -0
- package/dist/abi-types.js +8 -0
- package/dist/abi.d.ts +53 -0
- package/dist/abi.js +13 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.js +122 -0
- package/dist/codegen-ctx.d.ts +66 -0
- package/dist/codegen-ctx.js +108 -0
- 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/{src/dynamic-debug-print.ts → dist/dynamic-debug-print.js} +57 -65
- 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/{src/dynamic-validation.ts → dist/dynamic-validation.js} +19 -18
- package/dist/emit-field-defs.d.ts +5 -0
- package/dist/emit-field-defs.js +61 -0
- package/dist/emit-pack-unpack.d.ts +9 -0
- package/dist/emit-pack-unpack.js +296 -0
- package/dist/emit-stack-rw.d.ts +4 -0
- package/dist/emit-stack-rw.js +232 -0
- package/dist/emit-ts-types.d.ts +6 -0
- package/dist/emit-ts-types.js +74 -0
- package/dist/formatting.d.ts +15 -0
- package/{src/formatting.ts → dist/formatting.js} +26 -28
- package/dist/generate-ts-wrappers.d.ts +7 -0
- package/dist/generate-ts-wrappers.js +444 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +11 -0
- package/dist/out-template.generated.d.ts +1 -0
- package/dist/out-template.generated.js +6 -0
- package/dist/tolk-to-abi.d.ts +2 -0
- package/dist/tolk-to-abi.js +22 -0
- package/dist/types-kernel.d.ts +10 -0
- package/dist/types-kernel.js +212 -0
- package/dist/unsupported-errors.d.ts +28 -0
- package/{src/unsupported-errors.ts → dist/unsupported-errors.js} +33 -39
- package/package.json +73 -27
- package/src/abi-types.ts +0 -157
- package/src/abi.ts +0 -132
- package/src/cli-generate-from-abi-json.ts +0 -21
- package/src/codegen-ctx.ts +0 -115
- package/src/dynamic-ctx.ts +0 -55
- package/src/dynamic-get-methods.ts +0 -454
- package/src/dynamic-serialization.ts +0 -430
- package/src/emit-field-defs.ts +0 -60
- package/src/emit-pack-unpack.ts +0 -280
- package/src/emit-stack-rw.ts +0 -239
- package/src/emit-ts-types.ts +0 -66
- package/src/generate-from-abi-json.ts +0 -22
- package/src/generate-ts-wrappers.ts +0 -477
- package/src/out-template.ts +0 -514
- package/src/tolk-to-abi.ts +0 -5
- package/src/types-kernel.ts +0 -215
- package/tsconfig.json +0 -13
|
@@ -0,0 +1,453 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.createTonCoreDictionaryKey = createTonCoreDictionaryKey;
|
|
37
|
+
exports.createTonCoreDictionaryValue = createTonCoreDictionaryValue;
|
|
38
|
+
exports.dynamicPack = dynamicPack;
|
|
39
|
+
exports.dynamicUnpack = dynamicUnpack;
|
|
40
|
+
exports.packToBuilderDynamic = packToBuilderDynamic;
|
|
41
|
+
exports.unpackFromSliceDynamic = unpackFromSliceDynamic;
|
|
42
|
+
const c = __importStar(require("@ton/core"));
|
|
43
|
+
const unsupported_errors_1 = require("./unsupported-errors");
|
|
44
|
+
const dynamic_validation_1 = require("./dynamic-validation");
|
|
45
|
+
const types_kernel_1 = require("./types-kernel");
|
|
46
|
+
/*
|
|
47
|
+
Dynamic serialization works without generating TypeScript wrappers.
|
|
48
|
+
Just given an ABI, serialize any JS input to a cell, and unpack back.
|
|
49
|
+
Its purpose is orthogonal to wrappers:
|
|
50
|
+
- wrappers — for manual development
|
|
51
|
+
(write tests, deployment, and other manual interactions with your contract)
|
|
52
|
+
- dynamic serialization — for tolk-js, explorers, etc.
|
|
53
|
+
(pass some data from auto-generated UI to some contract just given its ABI)
|
|
54
|
+
*/
|
|
55
|
+
function lookupPrefix(s, expected, prefixLen) {
|
|
56
|
+
return s.remainingBits >= prefixLen && s.preloadUint(prefixLen) === expected;
|
|
57
|
+
}
|
|
58
|
+
function createTonCoreDictionaryKey(fieldPath, tyK) {
|
|
59
|
+
if (tyK.kind === 'intN')
|
|
60
|
+
return c.Dictionary.Keys.BigInt(tyK.n);
|
|
61
|
+
if (tyK.kind === 'uintN')
|
|
62
|
+
return c.Dictionary.Keys.BigUint(tyK.n);
|
|
63
|
+
if (tyK.kind === 'address')
|
|
64
|
+
return c.Dictionary.Keys.Address();
|
|
65
|
+
throw new unsupported_errors_1.NonStandardDictKey(`'${fieldPath}' is 'map<${(0, types_kernel_1.renderTy)(tyK)}, ...>': such a non-standard map key can not be handled by @ton/core library`);
|
|
66
|
+
}
|
|
67
|
+
function createTonCoreDictionaryValue(ctx, fieldPath, tyV) {
|
|
68
|
+
return {
|
|
69
|
+
serialize(self, b) {
|
|
70
|
+
dynamicPack(ctx, fieldPath, tyV, self, b);
|
|
71
|
+
},
|
|
72
|
+
parse(s) {
|
|
73
|
+
return dynamicUnpack(ctx, fieldPath, tyV, s);
|
|
74
|
+
}
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
// Parameter `fieldPath` is used for error messages only, e.g. when provided invalid input.
|
|
78
|
+
function dynamicPack(ctx, fieldPath, ty, v, b) {
|
|
79
|
+
switch (ty.kind) {
|
|
80
|
+
case 'intN': {
|
|
81
|
+
(0, dynamic_validation_1.checkIsNumber)(fieldPath, ty, v);
|
|
82
|
+
b.storeInt(v, ty.n);
|
|
83
|
+
break;
|
|
84
|
+
}
|
|
85
|
+
case 'uintN': {
|
|
86
|
+
(0, dynamic_validation_1.checkIsNumber)(fieldPath, ty, v);
|
|
87
|
+
b.storeUint(v, ty.n);
|
|
88
|
+
break;
|
|
89
|
+
}
|
|
90
|
+
case 'varintN': {
|
|
91
|
+
(0, dynamic_validation_1.checkIsNumber)(fieldPath, ty, v);
|
|
92
|
+
b.storeVarInt(v, Math.log2(ty.n));
|
|
93
|
+
break;
|
|
94
|
+
}
|
|
95
|
+
case 'varuintN': {
|
|
96
|
+
(0, dynamic_validation_1.checkIsNumber)(fieldPath, ty, v);
|
|
97
|
+
b.storeVarUint(v, Math.log2(ty.n));
|
|
98
|
+
break;
|
|
99
|
+
}
|
|
100
|
+
case 'coins': {
|
|
101
|
+
(0, dynamic_validation_1.checkIsNumber)(fieldPath, ty, v);
|
|
102
|
+
b.storeCoins(v);
|
|
103
|
+
break;
|
|
104
|
+
}
|
|
105
|
+
case 'bool': {
|
|
106
|
+
(0, dynamic_validation_1.checkIsBoolean)(fieldPath, ty, v);
|
|
107
|
+
b.storeBit(v);
|
|
108
|
+
break;
|
|
109
|
+
}
|
|
110
|
+
case 'cell': {
|
|
111
|
+
(0, dynamic_validation_1.checkIsObject)(fieldPath, ty, v);
|
|
112
|
+
b.storeRef(v);
|
|
113
|
+
break;
|
|
114
|
+
}
|
|
115
|
+
case 'builder': {
|
|
116
|
+
(0, dynamic_validation_1.checkIsObject)(fieldPath, ty, v);
|
|
117
|
+
b.storeBuilder(v);
|
|
118
|
+
break;
|
|
119
|
+
}
|
|
120
|
+
case 'slice': {
|
|
121
|
+
(0, dynamic_validation_1.checkIsObject)(fieldPath, ty, v);
|
|
122
|
+
b.storeSlice(v);
|
|
123
|
+
break;
|
|
124
|
+
}
|
|
125
|
+
case 'string': {
|
|
126
|
+
(0, dynamic_validation_1.checkIsString)(fieldPath, ty, v);
|
|
127
|
+
b.storeStringRefTail(v);
|
|
128
|
+
break;
|
|
129
|
+
}
|
|
130
|
+
case 'remaining': {
|
|
131
|
+
(0, dynamic_validation_1.checkIsObject)(fieldPath, ty, v);
|
|
132
|
+
b.storeSlice(v);
|
|
133
|
+
break;
|
|
134
|
+
}
|
|
135
|
+
case 'address': {
|
|
136
|
+
(0, dynamic_validation_1.checkIsObject)(fieldPath, ty, v);
|
|
137
|
+
b.storeAddress(v);
|
|
138
|
+
break;
|
|
139
|
+
}
|
|
140
|
+
case 'addressOpt': {
|
|
141
|
+
(0, dynamic_validation_1.checkIsObject)(fieldPath, ty, v, true);
|
|
142
|
+
b.storeAddress(v);
|
|
143
|
+
break;
|
|
144
|
+
}
|
|
145
|
+
case 'addressExt': {
|
|
146
|
+
(0, dynamic_validation_1.checkIsObject)(fieldPath, ty, v);
|
|
147
|
+
b.storeAddress(v);
|
|
148
|
+
break;
|
|
149
|
+
}
|
|
150
|
+
case 'addressAny': {
|
|
151
|
+
if (v === 'none') {
|
|
152
|
+
b.storeAddress(null);
|
|
153
|
+
}
|
|
154
|
+
else {
|
|
155
|
+
(0, dynamic_validation_1.checkIsObject)(fieldPath, ty, v);
|
|
156
|
+
b.storeAddress(v);
|
|
157
|
+
}
|
|
158
|
+
break;
|
|
159
|
+
}
|
|
160
|
+
case 'bitsN': {
|
|
161
|
+
(0, dynamic_validation_1.checkIsObject)(fieldPath, ty, v);
|
|
162
|
+
if (v.remainingBits !== ty.n || v.remainingRefs !== 0) {
|
|
163
|
+
(0, dynamic_validation_1.throwInvalidInput)(fieldPath, ty, `expected ${ty.n} bits and 0 refs, got ${v.remainingBits} bits and ${v.remainingRefs} refs`);
|
|
164
|
+
}
|
|
165
|
+
b.storeSlice(v);
|
|
166
|
+
break;
|
|
167
|
+
}
|
|
168
|
+
case 'nullable': {
|
|
169
|
+
if (v === null) {
|
|
170
|
+
b.storeUint(0, 1);
|
|
171
|
+
}
|
|
172
|
+
else {
|
|
173
|
+
b.storeUint(1, 1);
|
|
174
|
+
dynamicPack(ctx, fieldPath, ty.inner, v, b);
|
|
175
|
+
}
|
|
176
|
+
break;
|
|
177
|
+
}
|
|
178
|
+
case 'cellOf': {
|
|
179
|
+
(0, dynamic_validation_1.checkIsObjectWithProperty)(fieldPath, ty, v, 'ref');
|
|
180
|
+
let b_ref = c.beginCell();
|
|
181
|
+
dynamicPack(ctx, fieldPath, ty.inner, v.ref, b_ref);
|
|
182
|
+
b.storeRef(b_ref.endCell());
|
|
183
|
+
break;
|
|
184
|
+
}
|
|
185
|
+
case 'arrayOf': {
|
|
186
|
+
(0, dynamic_validation_1.checkIsArray)(fieldPath, ty, v);
|
|
187
|
+
// the compiler stores array<T> in chunks; in TypeScript, for simplicity, store "1 elem = 1 ref"
|
|
188
|
+
let tail = null;
|
|
189
|
+
for (let i = 0; i < v.length; ++i) {
|
|
190
|
+
let chunkB = c.beginCell().storeMaybeRef(tail);
|
|
191
|
+
dynamicPack(ctx, fieldPath + '[ith]', ty.inner, v[v.length - 1 - i], chunkB);
|
|
192
|
+
tail = chunkB.endCell();
|
|
193
|
+
}
|
|
194
|
+
b.storeUint(v.length, 8);
|
|
195
|
+
b.storeMaybeRef(tail);
|
|
196
|
+
break;
|
|
197
|
+
}
|
|
198
|
+
case 'lispListOf': {
|
|
199
|
+
(0, dynamic_validation_1.checkIsArray)(fieldPath, ty, v);
|
|
200
|
+
let tail = c.Cell.EMPTY;
|
|
201
|
+
for (let i = 0; i < v.length; ++i) {
|
|
202
|
+
let itemB = c.beginCell();
|
|
203
|
+
dynamicPack(ctx, `${fieldPath}[${i}]`, ty.inner, v[i], itemB);
|
|
204
|
+
tail = itemB.storeRef(tail).endCell();
|
|
205
|
+
}
|
|
206
|
+
b.storeRef(tail);
|
|
207
|
+
break;
|
|
208
|
+
}
|
|
209
|
+
case 'tensor': // `(T1, T2)` and `[T1, T2]` are both TypeScript arrays
|
|
210
|
+
case 'shapedTuple': { // (but in Tolk, they are different: a tensor and a TVM shaped tuple)
|
|
211
|
+
(0, dynamic_validation_1.checkIsArray)(fieldPath, ty, v, ty.items.length);
|
|
212
|
+
for (let i = 0; i < v.length; ++i) {
|
|
213
|
+
dynamicPack(ctx, `${fieldPath}[${i}]`, ty.items[i], v[i], b);
|
|
214
|
+
}
|
|
215
|
+
break;
|
|
216
|
+
}
|
|
217
|
+
case 'mapKV': {
|
|
218
|
+
(0, dynamic_validation_1.checkIsObject)(fieldPath, ty, v);
|
|
219
|
+
let dictKey = createTonCoreDictionaryKey(fieldPath, ty.k);
|
|
220
|
+
let dictValue = createTonCoreDictionaryValue(ctx, fieldPath, ty.v);
|
|
221
|
+
b.storeDict(v, dictKey, dictValue);
|
|
222
|
+
break;
|
|
223
|
+
}
|
|
224
|
+
case 'EnumRef': {
|
|
225
|
+
(0, dynamic_validation_1.checkIsNumber)(fieldPath, ty, v);
|
|
226
|
+
let enumRef = ctx.symbols.getEnum(ty.enum_name);
|
|
227
|
+
if (enumRef.custom_pack_unpack?.pack_to_builder) {
|
|
228
|
+
ctx.getCustomPackFnOrThrow(ty.enum_name, fieldPath)(v, b);
|
|
229
|
+
break;
|
|
230
|
+
}
|
|
231
|
+
dynamicPack(ctx, fieldPath, enumRef.encoded_as, v, b);
|
|
232
|
+
break;
|
|
233
|
+
}
|
|
234
|
+
case 'StructRef': {
|
|
235
|
+
(0, dynamic_validation_1.checkIsObject)(fieldPath, ty, v);
|
|
236
|
+
let structRef = ctx.symbols.getStruct(ty.struct_name);
|
|
237
|
+
if (structRef.custom_pack_unpack?.pack_to_builder) {
|
|
238
|
+
ctx.getCustomPackFnOrThrow(ty.struct_name, fieldPath)(v, b);
|
|
239
|
+
break;
|
|
240
|
+
}
|
|
241
|
+
if (structRef.prefix) {
|
|
242
|
+
b.storeUint(+structRef.prefix.prefix_str, structRef.prefix.prefix_len);
|
|
243
|
+
}
|
|
244
|
+
for (let f of structRef.fields) {
|
|
245
|
+
const fTy = ty.type_args ? (0, types_kernel_1.instantiateGenerics)(f.ty, structRef.type_params, ty.type_args) : f.ty;
|
|
246
|
+
try {
|
|
247
|
+
dynamicPack(ctx, `${fieldPath}.${f.name}`, fTy, v[f.name], b);
|
|
248
|
+
}
|
|
249
|
+
catch (ex) {
|
|
250
|
+
if (ex instanceof unsupported_errors_1.InvalidDynamicInput) {
|
|
251
|
+
throw ex;
|
|
252
|
+
}
|
|
253
|
+
// serialization errors from @ton/core, like "value is out of range"
|
|
254
|
+
(0, dynamic_validation_1.throwInvalidInput)(`${fieldPath}.${f.name}`, fTy, ex.message ?? ex.toString());
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
break;
|
|
258
|
+
}
|
|
259
|
+
case 'AliasRef': {
|
|
260
|
+
let aliasRef = ctx.symbols.getAlias(ty.alias_name);
|
|
261
|
+
if (aliasRef.custom_pack_unpack?.pack_to_builder) {
|
|
262
|
+
ctx.getCustomPackFnOrThrow(ty.alias_name, fieldPath)(v, b);
|
|
263
|
+
break;
|
|
264
|
+
}
|
|
265
|
+
const targetTy = ty.type_args ? (0, types_kernel_1.instantiateGenerics)(aliasRef.target_ty, aliasRef.type_params, ty.type_args) : aliasRef.target_ty;
|
|
266
|
+
dynamicPack(ctx, fieldPath, targetTy, v, b);
|
|
267
|
+
break;
|
|
268
|
+
}
|
|
269
|
+
case 'union': {
|
|
270
|
+
const variants = (0, types_kernel_1.createLabelsForUnion)(ctx.symbols, ty.variants);
|
|
271
|
+
const hasNull = variants.find(v => v.variant_ty.kind === 'nullLiteral');
|
|
272
|
+
if (hasNull && v === null) {
|
|
273
|
+
b.storeUint(+hasNull.prefix_str, hasNull.prefix_len);
|
|
274
|
+
}
|
|
275
|
+
else {
|
|
276
|
+
(0, dynamic_validation_1.checkIsObjectWithProperty)(fieldPath, ty, v, '$');
|
|
277
|
+
const activeVariant = variants.find(variant => v.$ === variant.labelStr);
|
|
278
|
+
if (!activeVariant) {
|
|
279
|
+
(0, dynamic_validation_1.throwInvalidInput)(fieldPath, ty, `non-existing union variant for $ = '${v.$}'`);
|
|
280
|
+
}
|
|
281
|
+
if (activeVariant.hasValueField && !v.hasOwnProperty('value')) {
|
|
282
|
+
(0, dynamic_validation_1.throwInvalidInput)(fieldPath, ty, `expected {$,value} but field 'value' not provided`);
|
|
283
|
+
}
|
|
284
|
+
if (activeVariant.is_prefix_implicit) {
|
|
285
|
+
b.storeUint(+activeVariant.prefix_str, activeVariant.prefix_len);
|
|
286
|
+
}
|
|
287
|
+
let actualValue = activeVariant.hasValueField ? v.value : v;
|
|
288
|
+
dynamicPack(ctx, `${fieldPath}#${activeVariant.labelStr}`, activeVariant.variant_ty, actualValue, b);
|
|
289
|
+
}
|
|
290
|
+
break;
|
|
291
|
+
}
|
|
292
|
+
case 'void':
|
|
293
|
+
break;
|
|
294
|
+
default:
|
|
295
|
+
throw new unsupported_errors_1.CantPackDynamic(fieldPath, `type '${(0, types_kernel_1.renderTy)(ty)}' is not serializable`);
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
// Parameter `fieldPath` is used for error messages only, e.g. when can't deserialize exact field (bad slice).
|
|
299
|
+
function dynamicUnpack(ctx, fieldPath, ty, s) {
|
|
300
|
+
switch (ty.kind) {
|
|
301
|
+
case 'intN': return s.loadIntBig(ty.n);
|
|
302
|
+
case 'uintN': return s.loadUintBig(ty.n);
|
|
303
|
+
case 'varintN': return s.loadVarIntBig(Math.log2(ty.n));
|
|
304
|
+
case 'varuintN': return s.loadVarUintBig(Math.log2(ty.n));
|
|
305
|
+
case 'coins': return s.loadCoins();
|
|
306
|
+
case 'bool': return s.loadBoolean();
|
|
307
|
+
case 'cell': return s.loadRef();
|
|
308
|
+
case 'string': return s.loadStringRefTail();
|
|
309
|
+
case 'remaining': {
|
|
310
|
+
let rest = s.clone();
|
|
311
|
+
s.loadBits(s.remainingBits);
|
|
312
|
+
while (s.remainingRefs) {
|
|
313
|
+
s.loadRef();
|
|
314
|
+
}
|
|
315
|
+
return rest;
|
|
316
|
+
}
|
|
317
|
+
case 'address': return s.loadAddress();
|
|
318
|
+
case 'addressOpt': return s.loadMaybeAddress();
|
|
319
|
+
case 'addressExt': return s.loadExternalAddress();
|
|
320
|
+
case 'addressAny': {
|
|
321
|
+
let maybe_addr = s.loadAddressAny();
|
|
322
|
+
return maybe_addr === null ? 'none' : maybe_addr;
|
|
323
|
+
}
|
|
324
|
+
case 'bitsN': return new c.Slice(new c.BitReader(s.loadBits(ty.n)), []);
|
|
325
|
+
case 'nullLiteral': return null;
|
|
326
|
+
case 'nullable': return s.loadBoolean() ? dynamicUnpack(ctx, fieldPath, ty.inner, s) : null;
|
|
327
|
+
case 'cellOf': {
|
|
328
|
+
let s_ref = s.loadRef().beginParse();
|
|
329
|
+
return { ref: dynamicUnpack(ctx, fieldPath, ty.inner, s_ref) };
|
|
330
|
+
}
|
|
331
|
+
case 'arrayOf': {
|
|
332
|
+
let len = s.loadUint(8);
|
|
333
|
+
let head = s.loadMaybeRef();
|
|
334
|
+
let outArr = [];
|
|
335
|
+
while (head != null) {
|
|
336
|
+
let s = head.beginParse();
|
|
337
|
+
head = s.loadMaybeRef();
|
|
338
|
+
while (s.remainingBits || s.remainingRefs) {
|
|
339
|
+
outArr.push(dynamicUnpack(ctx, fieldPath + '[ith]', ty.inner, s));
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
if (len !== outArr.length) {
|
|
343
|
+
throw new unsupported_errors_1.CantUnpackDynamic(fieldPath, `mismatch array binary data: expected ${len} elements, got ${outArr.length}`);
|
|
344
|
+
}
|
|
345
|
+
return outArr;
|
|
346
|
+
}
|
|
347
|
+
case 'lispListOf': {
|
|
348
|
+
let outArr = [];
|
|
349
|
+
let head = s.loadRef().beginParse();
|
|
350
|
+
while (head.remainingRefs) {
|
|
351
|
+
let tailSnaked = head.loadRef();
|
|
352
|
+
let headValue = dynamicUnpack(ctx, fieldPath + '[ith]', ty.inner, head);
|
|
353
|
+
head.endParse(); // ensure no data is present besides T
|
|
354
|
+
outArr.unshift(headValue);
|
|
355
|
+
head = tailSnaked.beginParse();
|
|
356
|
+
}
|
|
357
|
+
return outArr;
|
|
358
|
+
}
|
|
359
|
+
case 'tensor':
|
|
360
|
+
case 'shapedTuple': {
|
|
361
|
+
return ty.items.map((item, idx) => dynamicUnpack(ctx, `${fieldPath}[${idx}]`, item, s));
|
|
362
|
+
}
|
|
363
|
+
case 'mapKV': {
|
|
364
|
+
let dictKey = createTonCoreDictionaryKey(fieldPath, ty.k);
|
|
365
|
+
let dictValue = createTonCoreDictionaryValue(ctx, fieldPath, ty.v);
|
|
366
|
+
return s.loadDict(dictKey, dictValue);
|
|
367
|
+
}
|
|
368
|
+
case 'EnumRef': {
|
|
369
|
+
let enumRef = ctx.symbols.getEnum(ty.enum_name);
|
|
370
|
+
if (enumRef.custom_pack_unpack?.unpack_from_slice) {
|
|
371
|
+
return ctx.getCustomUnpackFnOrThrow(ty.enum_name, fieldPath)(s);
|
|
372
|
+
}
|
|
373
|
+
return dynamicUnpack(ctx, fieldPath, enumRef.encoded_as, s);
|
|
374
|
+
}
|
|
375
|
+
case 'StructRef': {
|
|
376
|
+
let structRef = ctx.symbols.getStruct(ty.struct_name);
|
|
377
|
+
if (structRef.custom_pack_unpack?.unpack_from_slice) {
|
|
378
|
+
return ctx.getCustomUnpackFnOrThrow(ty.struct_name, fieldPath)(s);
|
|
379
|
+
}
|
|
380
|
+
let result = { $: ty.struct_name };
|
|
381
|
+
if (structRef.prefix) {
|
|
382
|
+
let prefix = s.loadUint(structRef.prefix.prefix_len);
|
|
383
|
+
if (prefix !== +structRef.prefix.prefix_str) {
|
|
384
|
+
throw new unsupported_errors_1.CantUnpackDynamic(fieldPath, `incorrect prefix for '${ty.struct_name}', expected ${structRef.prefix.prefix_str}`);
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
for (let f of structRef.fields) {
|
|
388
|
+
const fTy = ty.type_args ? (0, types_kernel_1.instantiateGenerics)(f.ty, structRef.type_params, ty.type_args) : f.ty;
|
|
389
|
+
try {
|
|
390
|
+
result[f.name] = dynamicUnpack(ctx, `${fieldPath}.${f.name}`, fTy, s);
|
|
391
|
+
}
|
|
392
|
+
catch (ex) {
|
|
393
|
+
if (ex instanceof unsupported_errors_1.CantUnpackDynamic) {
|
|
394
|
+
throw ex;
|
|
395
|
+
}
|
|
396
|
+
// deserialization errors due to invalid slice, show field name
|
|
397
|
+
throw new unsupported_errors_1.CantUnpackDynamic(`${fieldPath}.${f.name}`, ex.message ?? ex.toString());
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
return result;
|
|
401
|
+
}
|
|
402
|
+
case 'AliasRef': {
|
|
403
|
+
let aliasRef = ctx.symbols.getAlias(ty.alias_name);
|
|
404
|
+
if (aliasRef.custom_pack_unpack?.unpack_from_slice) {
|
|
405
|
+
return ctx.getCustomUnpackFnOrThrow(ty.alias_name, fieldPath)(s);
|
|
406
|
+
}
|
|
407
|
+
const targetTy = ty.type_args ? (0, types_kernel_1.instantiateGenerics)(aliasRef.target_ty, aliasRef.type_params, ty.type_args) : aliasRef.target_ty;
|
|
408
|
+
return dynamicUnpack(ctx, fieldPath, targetTy, s);
|
|
409
|
+
}
|
|
410
|
+
case 'genericT': throw new unsupported_errors_1.CantUnpackDynamic(fieldPath, 'unexpected genericT');
|
|
411
|
+
case 'union': {
|
|
412
|
+
for (const variant of (0, types_kernel_1.createLabelsForUnion)(ctx.symbols, ty.variants)) {
|
|
413
|
+
if (!lookupPrefix(s, +variant.prefix_str, variant.prefix_len)) {
|
|
414
|
+
continue;
|
|
415
|
+
}
|
|
416
|
+
if (variant.is_prefix_implicit) {
|
|
417
|
+
s.skip(variant.prefix_len);
|
|
418
|
+
}
|
|
419
|
+
let actualValue = dynamicUnpack(ctx, `${fieldPath}#${variant.labelStr}`, variant.variant_ty, s);
|
|
420
|
+
if (!variant.hasValueField) {
|
|
421
|
+
return actualValue;
|
|
422
|
+
}
|
|
423
|
+
return { $: variant.labelStr, value: actualValue };
|
|
424
|
+
}
|
|
425
|
+
throw new unsupported_errors_1.CantUnpackDynamic(fieldPath, 'none of union prefixes match');
|
|
426
|
+
}
|
|
427
|
+
case 'void':
|
|
428
|
+
return void 0;
|
|
429
|
+
default:
|
|
430
|
+
throw new unsupported_errors_1.CantUnpackDynamic(fieldPath, `type '${(0, types_kernel_1.renderTy)(ty)}' is not serializable`);
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
/**
|
|
434
|
+
* Pack any input to a builder according to an ABI schema.
|
|
435
|
+
* Example: `struct Point { x: int8, y: int8 }`.
|
|
436
|
+
* After being converted, it's stored as ABI.
|
|
437
|
+
* Call: `packToBuilderDynamic(ctx, structTy, { x: 10, y: 20 }, b)` appends 0x0A14.
|
|
438
|
+
* When input is incorrect (e.g. missing property in a JS object), throws InvalidDynamicInput.
|
|
439
|
+
*/
|
|
440
|
+
function packToBuilderDynamic(ctx, ty, value, b) {
|
|
441
|
+
let fieldPath = ty.kind === 'StructRef' ? ty.struct_name : 'self';
|
|
442
|
+
dynamicPack(ctx, fieldPath, ty, value, b);
|
|
443
|
+
}
|
|
444
|
+
/**
|
|
445
|
+
* Unpack any slice to a JS variable according to an ABI schema.
|
|
446
|
+
* Example: `struct Point { x: int8, y: int8 }`.
|
|
447
|
+
* Call: `unpackFromSliceDynamic(ctx, structTy, hex"0A14")` returns `{ x: 10, y: 20 }`.
|
|
448
|
+
* When ty can't be deserialized, throws CantUnpackDynamic.
|
|
449
|
+
*/
|
|
450
|
+
function unpackFromSliceDynamic(ctx, ty, s) {
|
|
451
|
+
let fieldPath = ty.kind === 'StructRef' ? ty.struct_name : 'self';
|
|
452
|
+
return dynamicUnpack(ctx, fieldPath, ty, s);
|
|
453
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { Ty } from './abi-types';
|
|
2
|
+
export declare function throwInvalidInput(fieldPath: string, expectedTy: Ty, msgWhyInvalid: string): never;
|
|
3
|
+
export declare function checkIsNumber(fieldPath: string, expectedTy: Ty, passedV: any): void;
|
|
4
|
+
export declare function checkIsBoolean(fieldPath: string, expectedTy: Ty, passedV: any): void;
|
|
5
|
+
export declare function checkIsString(fieldPath: string, expectedTy: Ty, passedV: any): void;
|
|
6
|
+
export declare function checkIsArray(fieldPath: string, expectedTy: Ty, passedV: any, expectedLen?: number): void;
|
|
7
|
+
export declare function checkIsObject(fieldPath: string, expectedTy: Ty, passedV: any, allowNull?: boolean): void;
|
|
8
|
+
export declare function checkIsObjectWithProperty(fieldPath: string, expectedTy: Ty, passedV: any, propertyName: string): void;
|
|
@@ -1,33 +1,36 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.throwInvalidInput = throwInvalidInput;
|
|
4
|
+
exports.checkIsNumber = checkIsNumber;
|
|
5
|
+
exports.checkIsBoolean = checkIsBoolean;
|
|
6
|
+
exports.checkIsString = checkIsString;
|
|
7
|
+
exports.checkIsArray = checkIsArray;
|
|
8
|
+
exports.checkIsObject = checkIsObject;
|
|
9
|
+
exports.checkIsObjectWithProperty = checkIsObjectWithProperty;
|
|
10
|
+
const unsupported_errors_1 = require("./unsupported-errors");
|
|
11
|
+
const types_kernel_1 = require("./types-kernel");
|
|
12
|
+
function throwInvalidInput(fieldPath, expectedTy, msgWhyInvalid) {
|
|
13
|
+
throw new unsupported_errors_1.InvalidDynamicInput(`invalid value passed for '${fieldPath}' of type '${(0, types_kernel_1.renderTy)(expectedTy)}': ${msgWhyInvalid}`);
|
|
7
14
|
}
|
|
8
|
-
|
|
9
|
-
export function checkIsNumber(fieldPath: string, expectedTy: Ty, passedV: any): void {
|
|
15
|
+
function checkIsNumber(fieldPath, expectedTy, passedV) {
|
|
10
16
|
let isNumber = typeof passedV === 'bigint' || typeof passedV === 'number';
|
|
11
17
|
if (!isNumber) {
|
|
12
18
|
throwInvalidInput(fieldPath, expectedTy, 'not a number');
|
|
13
19
|
}
|
|
14
20
|
}
|
|
15
|
-
|
|
16
|
-
export function checkIsBoolean(fieldPath: string, expectedTy: Ty, passedV: any): void {
|
|
21
|
+
function checkIsBoolean(fieldPath, expectedTy, passedV) {
|
|
17
22
|
let isBoolean = typeof passedV === 'boolean';
|
|
18
23
|
if (!isBoolean) {
|
|
19
24
|
throwInvalidInput(fieldPath, expectedTy, 'not a boolean');
|
|
20
25
|
}
|
|
21
26
|
}
|
|
22
|
-
|
|
23
|
-
export function checkIsString(fieldPath: string, expectedTy: Ty, passedV: any): void {
|
|
27
|
+
function checkIsString(fieldPath, expectedTy, passedV) {
|
|
24
28
|
let isString = typeof passedV === 'string';
|
|
25
29
|
if (!isString) {
|
|
26
30
|
throwInvalidInput(fieldPath, expectedTy, 'not a string');
|
|
27
31
|
}
|
|
28
32
|
}
|
|
29
|
-
|
|
30
|
-
export function checkIsArray(fieldPath: string, expectedTy: Ty, passedV: any, expectedLen?: number): void {
|
|
33
|
+
function checkIsArray(fieldPath, expectedTy, passedV, expectedLen) {
|
|
31
34
|
let isArray = Array.isArray(passedV);
|
|
32
35
|
if (!isArray) {
|
|
33
36
|
throwInvalidInput(fieldPath, expectedTy, 'not an array');
|
|
@@ -36,8 +39,7 @@ export function checkIsArray(fieldPath: string, expectedTy: Ty, passedV: any, ex
|
|
|
36
39
|
throwInvalidInput(fieldPath, expectedTy, `expected ${expectedLen} elements, got ${passedV.length}`);
|
|
37
40
|
}
|
|
38
41
|
}
|
|
39
|
-
|
|
40
|
-
export function checkIsObject(fieldPath: string, expectedTy: Ty, passedV: any, allowNull = false): void {
|
|
42
|
+
function checkIsObject(fieldPath, expectedTy, passedV, allowNull = false) {
|
|
41
43
|
let isObject = typeof passedV === 'object' && !Array.isArray(passedV);
|
|
42
44
|
if (passedV === null && !allowNull) {
|
|
43
45
|
isObject = false;
|
|
@@ -46,8 +48,7 @@ export function checkIsObject(fieldPath: string, expectedTy: Ty, passedV: any, a
|
|
|
46
48
|
throwInvalidInput(fieldPath, expectedTy, 'not an object');
|
|
47
49
|
}
|
|
48
50
|
}
|
|
49
|
-
|
|
50
|
-
export function checkIsObjectWithProperty(fieldPath: string, expectedTy: Ty, passedV: any, propertyName: string): void {
|
|
51
|
+
function checkIsObjectWithProperty(fieldPath, expectedTy, passedV, propertyName) {
|
|
51
52
|
let isObject = typeof passedV === 'object' && !Array.isArray(passedV) && passedV !== null;
|
|
52
53
|
if (!isObject || !passedV.hasOwnProperty(propertyName)) {
|
|
53
54
|
throwInvalidInput(fieldPath, expectedTy, `not an object with property ${propertyName}`);
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { ABIConstExpression, Ty } from './abi-types';
|
|
2
|
+
import { CodegenCtx } from './codegen-ctx';
|
|
3
|
+
export declare function isDefaultValueSupported(fieldTy: Ty): boolean;
|
|
4
|
+
export declare function emitFieldDefault(ctx: CodegenCtx, expr: ABIConstExpression): string;
|
|
5
|
+
export declare function emitFieldDefaultInComment(expr: ABIConstExpression): string;
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.isDefaultValueSupported = isDefaultValueSupported;
|
|
4
|
+
exports.emitFieldDefault = emitFieldDefault;
|
|
5
|
+
exports.emitFieldDefaultInComment = emitFieldDefaultInComment;
|
|
6
|
+
const formatting_1 = require("./formatting");
|
|
7
|
+
const types_kernel_1 = require("./types-kernel");
|
|
8
|
+
// Default values of struct fields are also exported to TypeScript unless they are hard to be represented.
|
|
9
|
+
// In practice, all simple values are okay: `f: int = 5`, `f: coins = ton("1")`, etc.
|
|
10
|
+
// But in theory, a field can be a union, for example. It will require a large amount of work to support
|
|
11
|
+
// cases like `f: int8 | slice = 5` or `f: int32 | int64 = 5 as int64` (to generate correct `$` labels).
|
|
12
|
+
// So, if such a field exists, then we just assume it has no default.
|
|
13
|
+
function isDefaultValueSupported(fieldTy) {
|
|
14
|
+
if (fieldTy.kind === 'arrayOf')
|
|
15
|
+
return isDefaultValueSupported(fieldTy.inner);
|
|
16
|
+
if (fieldTy.kind === 'lispListOf')
|
|
17
|
+
return isDefaultValueSupported(fieldTy.inner);
|
|
18
|
+
if (fieldTy.kind === 'tensor')
|
|
19
|
+
return fieldTy.items.every(isDefaultValueSupported);
|
|
20
|
+
if (fieldTy.kind === 'shapedTuple')
|
|
21
|
+
return fieldTy.items.every(isDefaultValueSupported);
|
|
22
|
+
return fieldTy.kind !== 'union' && fieldTy.kind !== 'mapKV';
|
|
23
|
+
}
|
|
24
|
+
// Default values of fields (particularly, in storage) are precalculated by the compiler
|
|
25
|
+
// and stored as "const expression" intermediate representation in ABI.
|
|
26
|
+
// Here we output them to a valid TypeScript expression.
|
|
27
|
+
// Default parameters for get methods follow the same logic, they are also "const expressions".
|
|
28
|
+
function emitFieldDefault(ctx, expr) {
|
|
29
|
+
switch (expr.kind) {
|
|
30
|
+
case 'int': return expr.v + 'n';
|
|
31
|
+
case 'bool': return expr.v ? 'true' : 'false';
|
|
32
|
+
case 'slice': return `new c.Slice(new c.BitReader(new c.BitString(Buffer.from('${expr.hex}', 'hex'), 0, ${expr.hex.length * 4})), [])`;
|
|
33
|
+
case 'string': return JSON.stringify(expr.str);
|
|
34
|
+
case 'address': return `c.Address.parse('${expr.addr}')`;
|
|
35
|
+
case 'tensor': return `[${expr.items.map(i => emitFieldDefault(ctx, i)).join(', ')}]`;
|
|
36
|
+
case 'shapedTuple': return `[${expr.items.map(i => emitFieldDefault(ctx, i)).join(', ')}]`;
|
|
37
|
+
case 'object': {
|
|
38
|
+
const structRef = ctx.symbols.getStruct(expr.struct_name);
|
|
39
|
+
return `{ $: '${structRef.name}', ${[...structRef.fields.map((f, i) => `${(0, formatting_1.safeFieldDecl)(f.name)}: ${emitFieldDefault(ctx, expr.fields[i])}`)].join(', ')} }`;
|
|
40
|
+
}
|
|
41
|
+
case 'castTo': return emitFieldDefault(ctx, expr.inner);
|
|
42
|
+
case 'null': return `null`;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
// Output a default value not as a TypeScript expression, but as a human-readable one.
|
|
46
|
+
// For instance, "123" instead of bigint "123n".
|
|
47
|
+
// It's inserted inside comments next to fields having defaults.
|
|
48
|
+
function emitFieldDefaultInComment(expr) {
|
|
49
|
+
switch (expr.kind) {
|
|
50
|
+
case 'int': return expr.v;
|
|
51
|
+
case 'bool': return expr.v ? 'true' : 'false';
|
|
52
|
+
case 'slice': return `hex('${expr.hex}')`;
|
|
53
|
+
case 'string': return JSON.stringify(expr.str);
|
|
54
|
+
case 'address': return `address('${expr.addr}')`;
|
|
55
|
+
case 'tensor': return `[${expr.items.map(emitFieldDefaultInComment).join(', ')}]`;
|
|
56
|
+
case 'shapedTuple': return `[${expr.items.map(emitFieldDefaultInComment).join(', ')}]`;
|
|
57
|
+
case 'object': return `${expr.struct_name} { ${expr.fields.map(emitFieldDefaultInComment).join(', ')} }`;
|
|
58
|
+
case 'castTo': return `${emitFieldDefaultInComment(expr.inner)} as ${(0, types_kernel_1.renderTy)(expr.cast_to)}`;
|
|
59
|
+
case 'null': return `null`;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { Ty } from './abi-types';
|
|
2
|
+
import { CodegenCtx } from './codegen-ctx';
|
|
3
|
+
export declare function emitLoadExpr(ctx: CodegenCtx, fieldPath: string, ty: Ty): string;
|
|
4
|
+
export declare function emitLoadCallback(ctx: CodegenCtx, fieldPath: string, ty: Ty): string;
|
|
5
|
+
export declare function emitStoreStatement(ctx: CodegenCtx, tsExpr: string, ty: Ty): string;
|
|
6
|
+
export declare function emitStoreCallback(ctx: CodegenCtx, ty: Ty): string;
|
|
7
|
+
export declare function emitMakeCellFromExpr(ctx: CodegenCtx, tsExpr: string, ty: Ty, disableShortHand?: boolean): string;
|
|
8
|
+
export declare function emitCallToCreateMethodExpr(ctx: CodegenCtx, bodyArg: string, ty: Ty): string;
|
|
9
|
+
export declare function emitDictKVSerializers(ctx: CodegenCtx, fieldPath: string, tyK: Ty, tyV: Ty): string;
|