UNPKG

@honeycomb-protocol/solita

Version:

Generates SDK API from solana contract IDL.

284 lines 9.81 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.adaptIdl = void 0; const assert_1 = __importDefault(require("assert")); const types_1 = require("./types"); const premitiveTypes = { bool: 'bool', pubkey: 'publicKey', publickey: 'publicKey', string: 'string', u8: 'u8', u16: 'u16', u32: 'u32', u64: 'u64', u128: 'u128', f64: { array: ['u8', 8], }, }; let idlTypeFallback = (strType, resolveType) => null; const parseGenericType = (input) => { let result = { type: '', parameters: [], }; let depth = 0, param = '', typeName = ''; for (let char of input) { if (char === '<') { if (depth++ === 0) result.type = typeName.trim(); else param += char; } else if (char === '>') { if (--depth === 0) { result.parameters.push(param.trim()); param = ''; } else param += char; } else if (char === ',' && depth === 1) { result.parameters.push(param.trim()); param = ''; } else if (depth > 0) param += char; else typeName += char; } return result; }; const mapMapper = (strType, resolveType) => { const parsed = parseGenericType(strType); if (parsed && parsed.type.endsWith('Map')) { const [inner1, inner2] = parsed.parameters; const innerTy1 = resolveType(inner1); const innerTy2 = resolveType(inner2); if (parsed.type === 'BTreeMap') { const map = { bTreeMap: [innerTy1, innerTy2] }; return map; } else if (parsed.type === 'VecMap') { return { vec: resolveType('(' + strType.slice(7, -1) + ')'), // Adjust slicing based on "VecMap" }; } else { const map = { hashMap: [innerTy1, innerTy2] }; return map; } } return null; }; const tuppleMapper = (strType, resolveType) => { if (strType.startsWith('(') && strType.endsWith(')')) { const items = strType .slice(1, -1) .split(/\s*,\s*/) .map(resolveType); return { tuple: items, }; } return null; }; const vecMapper = (strType, resolveType) => { if (strType.startsWith('Vec<')) { return { vec: resolveType(strType.slice(4, -1)), }; } return null; }; const optionMapper = (strType, resolveType) => { if (strType.startsWith('Option<')) { return { option: resolveType(strType.slice(7, -1)), }; } return null; }; const nodeMapper = (strType, resolveType) => { if (strType === 'Node') { return { array: ['u8', 32], }; } return null; }; const customTypeMappers = [ mapMapper, vecMapper, tuppleMapper, optionMapper, nodeMapper, ]; const generatedTypes = new Map(); /** * When anchor doesn't understand a type it just assumes it is a user defined one. * This includes HashMaps and BTreeMaps. However it doesn't check if that type * is actually defined somewhere. * Thus we end up with invalid types here like `HashMap<String,DataItem>` which * is basically just the type definition copied from the Rust code. * * This function attempts to fix this. At this point only top level struct * fields are supported. * * Whenever more cases of incorrect types are encountered this transformer needs * to be updated to handle them. */ function adaptIdl(idl, config) { // Apply Idl hook if provided if (config.idlHook != null) { assert_1.default.equal(typeof config.idlHook, 'function', `idlHook needs to be a function of the type: (idl: Idl) => idl, but is of type ${typeof config.idlHook}`); idl = config.idlHook(idl); } if (config.customTypeMappers != null) { if (!Array.isArray(config.customTypeMappers)) throw new Error(`customTypeMappers needs to be array of the type: (strType: string, resolveType: (strType: string) => IdlType, registerGeneratedType: (def: IdlDefinedTypeDefinition) => void) => IdlType | null, but is of type ${typeof config.customTypeMappers}`); config.customTypeMappers.forEach((mapper) => { assert_1.default.equal(typeof mapper, 'function', `customTypeMappers items needs to be of the type: (strType: string, resolveType: (strType: string) => IdlType, registerGeneratedType: (def: IdlDefinedTypeDefinition) => void) => IdlType | null, but one of them is of type ${typeof mapper}`); customTypeMappers.push(mapper); }); } // Set Idl type fallback if provided if (config.idlTypeFallback != null) { assert_1.default.equal(typeof config.idlTypeFallback, 'function', `idlTypeFallback needs to be a function of the type: (strType: string, resolveType: (strType: string) => IdlType) => IdlType | null, but is of type ${typeof config.idlTypeFallback}`); idlTypeFallback = config.idlTypeFallback; } if ((0, types_1.isShankIdl)(idl)) return idl; const typeCache = new Map(); if (idl.types != null) { for (let i = 0; i < idl.types.length; i++) { typeCache.set(idl.types[i].name, transformDefinition(idl.types[i])); } } if (idl.accounts != null) { for (let i = 0; i < idl.accounts.length; i++) { const accountType = typeCache.get(idl.accounts[i].name); typeCache.delete(idl.accounts[i].name); const account = { name: idl.accounts[i].name, discriminator: idl.accounts[i].discriminator, type: accountType.type, }; idl.accounts[i] = account; } } idl.types = Array.from(typeCache.values()); for (let ix of idl.instructions) { ix.name = snakeToCamel(ix.name); for (let account of ix.accounts) { account.name = snakeToCamel(account.name); } for (let i = 0; i < ix.args.length; i++) { ix.args[i].name = snakeToCamel(ix.args[i].name); ix.args[i].type = transformType(ix.args[i].type); } } if (generatedTypes.size > 0) { if (idl.types == null) idl.types = []; idl.types.push(...Array.from(generatedTypes.values())); } if (config.idlHookPostAdaption != null) { assert_1.default.equal(typeof config.idlHookPostAdaption, 'function', `idlHookPostAdaption needs to be a function of the type: (idl: Idl) => idl, but is of type ${typeof config.idlHookPostAdaption}`); idl = config.idlHookPostAdaption(idl); } return idl; } exports.adaptIdl = adaptIdl; // ----------------- // Types // ----------------- function transformDefinition(def) { if (def.name == 'Number') debugger; const ty = def.type; if ((0, types_1.isFieldsType)(ty)) { for (const f of ty.fields) { f.name = snakeToCamel(f.name); f.type = transformType(f.type); } } else if ((0, types_1.isIdlTypeDataEnum)(ty)) { for (const v of ty.variants) { if ((0, types_1.isDataEnumVariantWithNamedFields)(v)) { for (const f of v.fields) { f.name = snakeToCamel(f.name); f.type = transformType(f.type); } } else if ((0, types_1.isDataEnumVariantWithUnnamedFields)(v)) { for (const f in v.fields) { v.fields[f] = transformType(v.fields[f]); } } } } return def; } const snakeToCamel = (str) => str .toLowerCase() .replace(/([-_][a-z0-9])/g, (group) => group.toUpperCase().replace('-', '').replace('_', '')); function transformType(ty) { var _a, _b; if ((0, types_1.isIdlTypeOption)(ty)) { const option = { option: transformType(ty.option), }; return option; } if ((0, types_1.isIdlTypeVec)(ty)) { const vec = { vec: transformType(ty.vec), }; return vec; } if ((0, types_1.isIdlTypeDefined)(ty)) { const resolvedType = resolveType(ty.defined.name); if ((0, types_1.isIdlTypeDefined)(resolvedType) && ((_a = ty.defined.generics) === null || _a === void 0 ? void 0 : _a.length)) { const mapped = { defined: { ...resolvedType.defined, generics: (_b = ty.defined.generics) === null || _b === void 0 ? void 0 : _b.map((t) => ({ kind: 'type', type: transformType(t.type), })), }, }; return mapped; } return resolvedType; } if (typeof ty === 'string') { let k = ty.toLocaleLowerCase(); if (k in premitiveTypes) { // @ts-ignore return premitiveTypes[k]; } } return ty; } const resolveType = (strType) => { if (strType.toLocaleLowerCase() in premitiveTypes) { // @ts-ignore return premitiveTypes[strType.toLocaleLowerCase()]; } for (let mapper of customTypeMappers) { const type = mapper(strType, resolveType, (def) => generatedTypes.set(def.name, def)); if (type) return type; } return idlTypeFallback(strType, resolveType) || { defined: { name: strType } }; }; // ----------------- // Instruction // ----------------- //# sourceMappingURL=transform-type.js.map