UNPKG

@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
"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