@eliseev_s/tolk-tlb-transpiler
Version:
Transpile Tolk structs to TLB definitions and generate TypeScript wrappers for TON blockchain smart contracts
244 lines • 8.61 kB
JavaScript
"use strict";
// ============================================================================
// Type Converters - Shared utilities for converting Tolk types to TS/TLB
// ============================================================================
Object.defineProperty(exports, "__esModule", { value: true });
exports.tolkTypeToTSType = tolkTypeToTSType;
exports.isSmallInt = isSmallInt;
exports.tolkTypeToStoreName = tolkTypeToStoreName;
exports.getIntWidth = getIntWidth;
exports.getNumericTSType = getNumericTSType;
exports.generateDictKeyDescriptor = generateDictKeyDescriptor;
exports.getTypeIdentifier = getTypeIdentifier;
exports.getDictLoaderName = getDictLoaderName;
exports.getMapKeyBitWidth = getMapKeyBitWidth;
/**
* Convert Tolk type to TypeScript type string
*/
function tolkTypeToTSType(type) {
switch (type.kind) {
case 'primitive':
return primitiveToTSType(type.name);
case 'int':
case 'uint':
return 'bigint';
case 'type_identifier':
if (type.name === 'void')
return 'void';
// Handle untyped tuple (just 'tuple' keyword without parameters)
if (type.name === 'tuple')
return 'TupleItem[]';
// Check common type identifiers - always use primitiveToTSType for known types
const mappedType = primitiveToTSType(type.name);
// If it's not a built-in type, use the original name (for custom types)
if (mappedType === 'Cell' && !['cell', 'slice', 'builder'].includes(type.name)) {
return type.name; // Custom type
}
return mappedType;
case 'dict':
return 'Cell | null';
case 'map': {
const keyTs = tolkTypeToTSTypeForMapKey(type.key);
const valueTs = tolkTypeToTSType(type.value);
return `Dictionary<${keyTs}, ${valueTs}>`;
}
case 'special':
return 'Cell';
case 'nullable':
// Special handling for nullable untyped tuple (tuple?)
if (type.inner.kind === 'type_identifier' && type.inner.name === 'tuple') {
return 'TupleItem[] | null';
}
return `${tolkTypeToTSType(type.inner)} | null`;
case 'tuple':
case 'tensor':
if (type.items.length === 0)
return 'void';
const itemTypes = type.items.map(tolkTypeToTSType);
return `[${itemTypes.join(', ')}]`;
default:
return 'Cell';
}
}
/**
* Convert Tolk type to TypeScript type for Dictionary map keys
* For int/uint types: width <= 32 => number, otherwise bigint
*/
function tolkTypeToTSTypeForMapKey(type) {
// For int/uint types with specific widths, use the correct numeric type
if (type.kind === 'int' || type.kind === 'uint') {
return getNumericTSType(type.width);
}
// For primitive int/uint types, check width
if (type.kind === 'primitive' || type.kind === 'type_identifier') {
const width = getIntWidth(type);
if (width !== null) {
return getNumericTSType(width);
}
}
// For other types, use the standard conversion
return tolkTypeToTSType(type);
}
/**
* Convert primitive type name to TypeScript type
*/
function primitiveToTSType(name) {
switch (name) {
case 'void':
return 'void';
case 'bool':
case 'Bool':
return 'boolean';
case 'int':
case 'uint':
case 'coins':
return 'bigint';
case 'address':
return 'Address';
case 'cell':
case 'slice':
case 'builder':
return 'Cell';
default: {
// Handle uint8, uint16, etc.
const uintMatch = name.match(/^uint(\d+)$/);
if (uintMatch) {
const width = parseInt(uintMatch[1], 10);
return width <= 32 ? 'number' : 'bigint';
}
const intMatch = name.match(/^int(\d+)$/);
if (intMatch) {
const width = parseInt(intMatch[1], 10);
return width <= 32 ? 'number' : 'bigint';
}
return 'Cell';
}
}
}
/**
* Check if a width value represents a "small" integer (fits in number)
*/
function isSmallInt(width) {
return width <= 32;
}
/**
* Convert Tolk type to store function name
*/
function tolkTypeToStoreName(type) {
if (type.kind === 'type_identifier') {
return type.name;
}
return 'Cell';
}
/**
* Get numeric width from a type if it's an int/uint type
*/
function getIntWidth(type) {
if (type.kind === 'int' || type.kind === 'uint') {
return type.width;
}
if (type.kind === 'primitive' || type.kind === 'type_identifier') {
const match = type.name.match(/^(?:u)?int(\d+)$/);
if (match) {
return parseInt(match[1], 10);
}
}
return null;
}
/**
* Generate TypeScript type for number/bigint based on width
*/
function getNumericTSType(width) {
return isSmallInt(width) ? 'number' : 'bigint';
}
/**
* Generate Dictionary key descriptor (for @ton/core)
* @ton/core has different methods for small vs big integers:
* - Int(bits) / Uint(bits) for <= 32 bits (returns DictionaryKey<number>)
* - BigInt(bits) / BigUint(bits) for > 32 bits (returns DictionaryKey<bigint>)
*/
function generateDictKeyDescriptor(keyType) {
const width = getIntWidth(keyType);
if (width !== null) {
// Determine if the key is signed or unsigned
const isSigned = keyType.kind === 'int' ||
(keyType.kind === 'type_identifier' && keyType.name.startsWith('int')) ||
(keyType.kind === 'primitive' && keyType.name.startsWith('int'));
// For both signed and unsigned: width <= 32 => number, otherwise bigint
const ts = getNumericTSType(width);
// Select the correct @ton/core method based on width
let method;
if (isSmallInt(width)) {
// Use Int/Uint for <= 32 bits (returns DictionaryKey<number>)
method = isSigned ? 'Int' : 'Uint';
}
else {
// Use BigInt/BigUint for > 32 bits (returns DictionaryKey<bigint>)
method = isSigned ? 'BigInt' : 'BigUint';
}
return { expr: `Dictionary.Keys.${method}(${width})`, ts };
}
// Fallback for unknown types
return { expr: `Dictionary.Keys.BigUint(256)`, ts: 'bigint' };
}
/**
* Generate a compact identifier for a type (for generated variable names)
* For int types, includes signedness to distinguish int32 from uint32
*/
function getTypeIdentifier(type) {
// For int/uint types, use the original type name to preserve signedness
if (type.kind === 'int') {
return `int${type.width}`;
}
if (type.kind === 'uint') {
return `uint${type.width}`;
}
if (type.kind === 'primitive' || type.kind === 'type_identifier') {
// Check if it's an int/uint type
const match = type.name.match(/^(u?int)(\d+)$/);
if (match) {
return type.name; // Return as-is: int32, uint32, etc.
}
}
const tsType = tolkTypeToTSType(type);
// Replace non-alphanumeric characters with underscores
return tsType.replace(/[^A-Za-z0-9_]/g, '_') || 'Cell';
}
/**
* Generate dictionary loader function name
*/
function getDictLoaderName(keyType, valueType) {
const keyId = getTypeIdentifier(keyType);
const valueId = getTypeIdentifier(valueType);
return `loadDict_${keyId}_${valueId}`;
}
/**
* Extract key bit width from map key type for HashmapE generation
* Returns null if the key type is not supported
*/
function getMapKeyBitWidth(keyType) {
if (keyType.kind === 'uint' || keyType.kind === 'int') {
return keyType.width;
}
if (keyType.kind === 'primitive') {
const match = keyType.name.match(/^(?:u)?int(\d+)$/);
if (match && match[1]) {
return parseInt(match[1], 10);
}
// Special case: coins as key (not typical, but possible)
if (keyType.name === 'coins')
return 64;
}
if (keyType.kind === 'type_identifier') {
const match = keyType.name.match(/^(?:u)?int(\d+)$/);
if (match && match[1]) {
return parseInt(match[1], 10);
}
// Generic int/uint defaults to 256 bits
if (keyType.name === 'uint' || keyType.name === 'int') {
return 256;
}
}
return null;
}
//# sourceMappingURL=type-converters.js.map