UNPKG

@fuel-ts/abi-typegen

Version:

Generates Typescript definitions from Sway ABI Json files

1,718 lines (1,604 loc) • 58.4 kB
var __defProp = Object.defineProperty; var __name = (target, value) => __defProp(target, "name", { value, configurable: true }); // src/runTypegen.ts import { ErrorCode as ErrorCode10, FuelError as FuelError9 } from "@fuel-ts/errors"; import { versions as builtinVersions } from "@fuel-ts/versions"; import { readFileSync as readFileSync3, writeFileSync } from "fs"; import { globSync } from "glob"; import { mkdirp } from "mkdirp"; import { basename } from "path"; import { rimrafSync } from "rimraf"; // src/AbiTypeGen.ts import { ErrorCode as ErrorCode9, FuelError as FuelError8 } from "@fuel-ts/errors"; // src/abi/Abi.ts import { ErrorCode as ErrorCode5, FuelError as FuelError4 } from "@fuel-ts/errors"; import { normalizeString } from "@fuel-ts/utils"; // src/abi/errors/ErrorCode.ts var ErrorCode = class { static { __name(this, "ErrorCode"); } code; value; constructor(params) { this.code = params.code; this.value = params.value; } }; // src/utils/makeErrorCodes.ts function makeErrorCode(params) { return new ErrorCode(params); } __name(makeErrorCode, "makeErrorCode"); // src/utils/parseErrorCodes.ts function parseErrorCodes(params) { const { rawErrorCodes } = params; const errorCodes = Object.entries(rawErrorCodes ?? {}).map( ([code, value]) => makeErrorCode({ code, value }) ); return errorCodes; } __name(parseErrorCodes, "parseErrorCodes"); // src/abi/types/AType.ts var AType = class { static { __name(this, "AType"); } rawAbiType; attributes; requiredFuelsMembersImports; constructor(params) { this.rawAbiType = params.rawAbiType; this.attributes = { inputLabel: "unknown", outputLabel: "unknown" }; this.requiredFuelsMembersImports = []; } }; // src/abi/types/EmptyType.ts var EmptyType = class _EmptyType extends AType { static { __name(this, "EmptyType"); } static swayType = "()"; name = "empty"; static MATCH_REGEX = /^\(\)$/m; constructor(params) { super(params); this.attributes = { inputLabel: "undefined", outputLabel: "void" }; } static isSuitableFor(params) { return _EmptyType.MATCH_REGEX.test(params.type); } parseComponentsAttributes(_params) { return this.attributes; } }; // src/abi/types/OptionType.ts var OptionType = class _OptionType extends AType { static { __name(this, "OptionType"); } static swayType = "enum Option"; name = "option"; static MATCH_REGEX = /^enum (std::option::)?Option$/m; static isSuitableFor(params) { return _OptionType.MATCH_REGEX.test(params.type); } parseComponentsAttributes(_params) { this.attributes = { inputLabel: `Option`, outputLabel: `Option` }; return this.attributes; } }; // src/utils/findType.ts import { ErrorCode as ErrorCode2, FuelError } from "@fuel-ts/errors"; function findType(params) { const { types, typeId } = params; const foundType = types.find(({ rawAbiType: { typeId: tid } }) => tid === typeId); if (!foundType) { throw new FuelError(ErrorCode2.TYPE_ID_NOT_FOUND, `Type ID not found: ${typeId}.`); } foundType.parseComponentsAttributes({ types }); return foundType; } __name(findType, "findType"); // src/utils/getFunctionInputs.ts var getFunctionInputs = /* @__PURE__ */ __name((params) => { const { types, inputs } = params; let isMandatory = false; return inputs.reduceRight((result, input) => { const type = findType({ types, typeId: input.type }); const isTypeMandatory = !EmptyType.isSuitableFor({ type: type.rawAbiType.type }) && !OptionType.isSuitableFor({ type: type.rawAbiType.type }); isMandatory = isMandatory || isTypeMandatory; return [{ ...input, isOptional: !isMandatory }, ...result]; }, []); }, "getFunctionInputs"); // src/utils/parseTypeArguments.ts function parseTypeArguments(params) { const { types, typeArguments, parentTypeId, target } = params; const attributeKey = `${target}Label`; const buffer = []; let parentType; let parentLabel; if (parentTypeId !== void 0) { parentType = findType({ types, typeId: parentTypeId }); parentLabel = parentType.attributes[attributeKey]; } typeArguments.forEach((typeArgument) => { const currentTypeId = typeArgument.type; const currentType = findType({ types, typeId: currentTypeId }); const currentLabel = currentType.attributes[attributeKey]; if (typeArgument.typeArguments) { const nestedParsed = parseTypeArguments({ types, target, parentTypeId: typeArgument.type, typeArguments: typeArgument.typeArguments }); buffer.push(nestedParsed); } else { buffer.push(`${currentLabel}`); } }); let output = buffer.join(", "); if (parentLabel) { output = `${parentLabel}<${output}>`; } return output; } __name(parseTypeArguments, "parseTypeArguments"); // src/utils/getTypeDeclaration.ts function resolveInputLabel(types, typeId, typeArguments) { const type = findType({ types, typeId }); let typeDecl; if (typeArguments?.length) { typeDecl = parseTypeArguments({ types, target: "input" /* INPUT */, parentTypeId: typeId, typeArguments }); } else { typeDecl = type.attributes.inputLabel; } return typeDecl; } __name(resolveInputLabel, "resolveInputLabel"); // src/abi/functions/Function.ts var Function = class { static { __name(this, "Function"); } name; types; rawAbiFunction; attributes; constructor(params) { this.rawAbiFunction = params.rawAbiFunction; this.types = params.types; this.name = params.rawAbiFunction.name; this.attributes = { inputs: this.bundleInputTypes(), output: this.bundleOutputTypes(), prefixedInputs: this.bundleInputTypes(true) }; } bundleInputTypes(shouldPrefixParams = false) { const { types } = this; const inputs = getFunctionInputs({ types, inputs: this.rawAbiFunction.inputs }).map( ({ isOptional, ...input }) => { const { name, type: typeId, typeArguments } = input; const typeDecl = resolveInputLabel(types, typeId, typeArguments); if (shouldPrefixParams) { const optionalSuffix = isOptional ? "?" : ""; return `${name}${optionalSuffix}: ${typeDecl}`; } return typeDecl; } ); return inputs.join(", "); } bundleOutputTypes() { return parseTypeArguments({ types: this.types, target: "output" /* OUTPUT */, typeArguments: [this.rawAbiFunction.output] }); } getDeclaration() { const { name } = this; const { prefixedInputs, output } = this.attributes; const decl = `${name}: InvokeFunction<[${prefixedInputs}], ${output}>`; return decl; } }; // src/utils/makeFunction.ts function makeFunction(params) { const { types, rawAbiFunction } = params; return new Function({ types, rawAbiFunction }); } __name(makeFunction, "makeFunction"); // src/utils/parseFunctions.ts function parseFunctions(params) { const { types, rawAbiFunctions } = params; const functions = rawAbiFunctions.map( (rawAbiFunction) => makeFunction({ types, rawAbiFunction }) ); return functions; } __name(parseFunctions, "parseFunctions"); // src/utils/makeType.ts import { ErrorCode as ErrorCode4, FuelError as FuelError3 } from "@fuel-ts/errors"; // src/abi/types/ArrayType.ts var ArrayType = class _ArrayType extends AType { static { __name(this, "ArrayType"); } // Note: the array length expressed in '; 2]' could be any length static swayType = "[_; 2]"; name = "array"; static MATCH_REGEX = /^\[_; ([0-9]+)\]$/m; static isSuitableFor(params) { return _ArrayType.MATCH_REGEX.test(params.type); } parseComponentsAttributes(params) { const { types } = params; const { type } = this.rawAbiType; const arrayLen = Number(type.match(_ArrayType.MATCH_REGEX)?.[1]); const inputs = []; const outputs = []; this.rawAbiType.components?.forEach((component) => { const { type: typeId, typeArguments } = component; if (!typeArguments) { const { attributes } = findType({ types, typeId }); inputs.push(attributes.inputLabel); outputs.push(attributes.outputLabel); } else { const inputLabel = parseTypeArguments({ types, typeArguments, parentTypeId: typeId, target: "input" /* INPUT */ }); const outputLabel = parseTypeArguments({ types, typeArguments, parentTypeId: typeId, target: "output" /* OUTPUT */ }); inputs.push(inputLabel); outputs.push(outputLabel); } }); const inputTypes = Array(arrayLen).fill(inputs[0]).join(", "); const outputTypes = Array(arrayLen).fill(outputs[0]).join(", "); this.attributes = { inputLabel: `[${inputTypes}]`, outputLabel: `[${outputTypes}]` }; return this.attributes; } }; // src/abi/types/StrType.ts var StrType = class _StrType extends AType { static { __name(this, "StrType"); } // Note: the str length expressed in '[3]' could be any length static swayType = "str[3]"; name = "str"; static MATCH_REGEX = /^str\[(.+)\]$/m; static isSuitableFor(params) { return _StrType.MATCH_REGEX.test(params.type); } parseComponentsAttributes(_params) { this.attributes = { inputLabel: "string", outputLabel: "string" }; return this.attributes; } }; // src/abi/types/B256Type.ts var B256Type = class _B256Type extends StrType { static { __name(this, "B256Type"); } static swayType = "b256"; name = "b256"; static MATCH_REGEX = /^b256$/m; static isSuitableFor(params) { return _B256Type.MATCH_REGEX.test(params.type); } }; // src/abi/types/B512Type.ts var B512Type = class _B512Type extends B256Type { static { __name(this, "B512Type"); } static swayType = "struct B512"; name = "b512"; static MATCH_REGEX = /^struct (std::b512::)?B512$/m; static isSuitableFor(params) { return _B512Type.MATCH_REGEX.test(params.type); } }; // src/abi/types/BoolType.ts var BoolType = class _BoolType extends AType { static { __name(this, "BoolType"); } static swayType = "bool"; name = "bool"; static MATCH_REGEX = /^bool$/m; static isSuitableFor(params) { return _BoolType.MATCH_REGEX.test(params.type); } parseComponentsAttributes(_params) { this.attributes = { inputLabel: "boolean", outputLabel: "boolean" }; return this.attributes; } }; // src/abi/types/BytesType.ts var BytesType = class _BytesType extends ArrayType { static { __name(this, "BytesType"); } static swayType = "struct Bytes"; name = "bytes"; static MATCH_REGEX = /^struct (std::bytes::)?Bytes/m; static isSuitableFor(params) { return _BytesType.MATCH_REGEX.test(params.type); } parseComponentsAttributes(_params) { const capitalizedName = "Bytes"; this.attributes = { inputLabel: capitalizedName, outputLabel: capitalizedName }; this.requiredFuelsMembersImports = [capitalizedName]; return this.attributes; } }; // src/utils/extractStructName.ts import { ErrorCode as ErrorCode3, FuelError as FuelError2 } from "@fuel-ts/errors"; function extractStructName(params) { const { rawAbiType, regex } = params; const matches = rawAbiType.type.match(regex); const match = matches?.[2] ?? matches?.[1]; if (!match) { let errorMessage = `Couldn't extract struct name with: '${regex}'. `; errorMessage += `Check your JSON ABI. [source] `; errorMessage += `${JSON.stringify(rawAbiType, null, 2)}`; throw new FuelError2(ErrorCode3.JSON_ABI_ERROR, errorMessage); } return match; } __name(extractStructName, "extractStructName"); // src/abi/types/ResultType.ts var ResultType = class _ResultType extends AType { static { __name(this, "ResultType"); } static swayType = "enum Result"; name = "result"; static MATCH_REGEX = /^enum (std::result::)?Result$/m; static isSuitableFor(params) { return _ResultType.MATCH_REGEX.test(params.type); } parseComponentsAttributes(_params) { this.attributes = { inputLabel: `Result`, outputLabel: `Result` }; return this.attributes; } }; // src/abi/types/EnumType.ts var EnumType = class _EnumType extends AType { static { __name(this, "EnumType"); } static swayType = "enum MyEnumName"; name = "enum"; static MATCH_REGEX = /^enum (.+::)?(.+)$/m; static IGNORE_REGEXES = [OptionType.MATCH_REGEX, ResultType.MATCH_REGEX]; static isSuitableFor(params) { const isAMatch = _EnumType.MATCH_REGEX.test(params.type); const shouldBeIgnored = _EnumType.IGNORE_REGEXES.some((r) => r.test(params.type)); return isAMatch && !shouldBeIgnored; } parseComponentsAttributes(_params) { const structName = this.getStructName(); this.attributes = { structName, inputLabel: `${structName}Input`, outputLabel: `${structName}Output` }; return this.attributes; } getStructName() { const name = extractStructName({ rawAbiType: this.rawAbiType, regex: _EnumType.MATCH_REGEX }); return name; } getNativeEnum(params) { const { types } = params; const typeHash = types.reduce( (hash, row) => ({ ...hash, [row.rawAbiType.typeId]: row.rawAbiType.type }), {} ); const { components } = this.rawAbiType; const enumComponents = components; if (!enumComponents.every(({ type }) => typeHash[type] === EmptyType.swayType)) { return void 0; } return enumComponents.map(({ name }) => `${name} = '${name}'`).join(", "); } getStructContents(params) { const { types, target } = params; const { components } = this.rawAbiType; const enumComponents = components; const attributeKey = `${target}Label`; const contents = enumComponents.map((component) => { const { name, type: typeId, typeArguments } = component; if (typeId === 0) { return `${name}: []`; } const type = findType({ types, typeId }); let typeDecl; if (typeArguments) { typeDecl = parseTypeArguments({ types, target, parentTypeId: typeId, typeArguments }); } else { typeDecl = type.attributes[attributeKey]; } return `${name}: ${typeDecl}`; }); return contents.join(", "); } getStructDeclaration(params) { const { types } = params; const { typeParameters } = this.rawAbiType; if (typeParameters) { const structs = typeParameters.map((typeId) => findType({ types, typeId })); const labels = structs.map(({ attributes: { inputLabel } }) => inputLabel); return `<${labels.join(", ")}>`; } return ""; } }; // src/abi/types/EvmAddressType.ts var EvmAddressType = class _EvmAddressType extends AType { static { __name(this, "EvmAddressType"); } static swayType = "struct EvmAddress"; name = "evmAddress"; static MATCH_REGEX = /^struct (std::vm::evm::evm_address::)?EvmAddress$/m; static isSuitableFor(params) { return _EvmAddressType.MATCH_REGEX.test(params.type); } parseComponentsAttributes(_params) { const capitalizedName = "EvmAddress"; this.attributes = { inputLabel: capitalizedName, outputLabel: capitalizedName }; this.requiredFuelsMembersImports = [capitalizedName]; return this.attributes; } }; // src/abi/types/GenericType.ts var GenericType = class _GenericType extends AType { static { __name(this, "GenericType"); } static swayType = "generic T"; name = "generic"; static MATCH_REGEX = /^generic ([^\s]+)$/m; static isSuitableFor(params) { return _GenericType.MATCH_REGEX.test(params.type); } getStructName() { const name = extractStructName({ rawAbiType: this.rawAbiType, regex: _GenericType.MATCH_REGEX }); return name; } parseComponentsAttributes(_params) { const label = this.getStructName(); this.attributes = { inputLabel: label, outputLabel: label }; return this.attributes; } }; // src/abi/types/U8Type.ts var U8Type = class _U8Type extends AType { static { __name(this, "U8Type"); } static swayType = "u8"; name = "u8"; static MATCH_REGEX = /^u8$/m; constructor(params) { super(params); this.attributes = { inputLabel: `BigNumberish`, outputLabel: `number` }; this.requiredFuelsMembersImports = [this.attributes.inputLabel]; } static isSuitableFor(params) { return _U8Type.MATCH_REGEX.test(params.type); } parseComponentsAttributes(_params) { return this.attributes; } }; // src/abi/types/U64Type.ts var U64Type = class _U64Type extends U8Type { static { __name(this, "U64Type"); } static swayType = "u64"; name = "u64"; static MATCH_REGEX = /^u64$/m; parseComponentsAttributes(_params) { this.attributes = { inputLabel: `BigNumberish`, outputLabel: `BN` }; this.requiredFuelsMembersImports = Object.values(this.attributes); return this.attributes; } static isSuitableFor(params) { return _U64Type.MATCH_REGEX.test(params.type); } }; // src/abi/types/RawUntypedPtr.ts var RawUntypedPtr = class _RawUntypedPtr extends U64Type { static { __name(this, "RawUntypedPtr"); } static swayType = "raw untyped ptr"; name = "rawUntypedPtr"; static MATCH_REGEX = /^raw untyped ptr$/m; static isSuitableFor(params) { return _RawUntypedPtr.MATCH_REGEX.test(params.type); } }; // src/abi/types/RawUntypedSlice.ts var RawUntypedSlice = class _RawUntypedSlice extends ArrayType { static { __name(this, "RawUntypedSlice"); } static swayType = "raw untyped slice"; name = "rawUntypedSlice"; static MATCH_REGEX = /^raw untyped slice$/m; static isSuitableFor(params) { return _RawUntypedSlice.MATCH_REGEX.test(params.type); } parseComponentsAttributes(_params) { const capitalizedName = "RawSlice"; this.attributes = { inputLabel: capitalizedName, outputLabel: capitalizedName }; this.requiredFuelsMembersImports = [capitalizedName]; return this.attributes; } }; // src/abi/types/StdStringType.ts var StdStringType = class _StdStringType extends AType { static { __name(this, "StdStringType"); } static swayType = "struct String"; name = "stdString"; static MATCH_REGEX = /^struct (std::string::)?String/m; static isSuitableFor(params) { return _StdStringType.MATCH_REGEX.test(params.type); } parseComponentsAttributes(_params) { const capitalizedName = "StdString"; this.attributes = { inputLabel: capitalizedName, outputLabel: capitalizedName }; this.requiredFuelsMembersImports = [capitalizedName]; return this.attributes; } }; // src/abi/types/StrSliceType.ts var StrSliceType = class _StrSliceType extends AType { static { __name(this, "StrSliceType"); } static swayType = "str"; name = "strSlice"; static MATCH_REGEX = /^str$/m; static isSuitableFor(params) { return _StrSliceType.MATCH_REGEX.test(params.type); } parseComponentsAttributes(_params) { const capitalizedName = "StrSlice"; this.attributes = { inputLabel: capitalizedName, outputLabel: capitalizedName }; this.requiredFuelsMembersImports = [capitalizedName]; return this.attributes; } }; // src/abi/types/StructType.ts var StructType = class _StructType extends AType { static { __name(this, "StructType"); } static swayType = "struct MyStruct"; name = "struct"; static MATCH_REGEX = /^struct (.+::)?(.+)$/m; static IGNORE_REGEX = /^struct (std::.*)?(Vec|RawVec|EvmAddress|Bytes|String|RawBytes)$/m; static isSuitableFor(params) { const isAMatch = _StructType.MATCH_REGEX.test(params.type); const shouldBeIgnored = _StructType.IGNORE_REGEX.test(params.type); return isAMatch && !shouldBeIgnored; } parseComponentsAttributes(_params) { const structName = this.getStructName(); this.attributes = { structName, inputLabel: `${structName}Input`, outputLabel: `${structName}Output` }; return this.attributes; } getStructName() { const name = extractStructName({ rawAbiType: this.rawAbiType, regex: _StructType.MATCH_REGEX }); return name; } getStructContents(params) { const { types, target } = params; const { components } = this.rawAbiType; const structComponents = components; const members = structComponents.map((component) => { const { name, type: typeId, typeArguments } = component; const type = findType({ types, typeId }); let typeDecl; if (typeArguments) { typeDecl = parseTypeArguments({ types, target, parentTypeId: typeId, typeArguments }); } else { const attributeKey = `${target}Label`; typeDecl = type.attributes[attributeKey]; } return `${name}: ${typeDecl}`; }); return members.join(", "); } getStructDeclaration(params) { const { types } = params; const { typeParameters } = this.rawAbiType; if (typeParameters) { const structs = typeParameters.map((typeId) => findType({ types, typeId })); const labels = structs.map(({ attributes: { inputLabel } }) => inputLabel); return `<${labels.join(", ")}>`; } return ""; } }; // src/abi/types/TupleType.ts var TupleType = class _TupleType extends AType { static { __name(this, "TupleType"); } // Note: a tuple can have more/less than 3x items (like the one bellow) static swayType = "(_, _, _)"; name = "tupple"; static MATCH_REGEX = /^\([_,\s]+\)$/m; static isSuitableFor(params) { return _TupleType.MATCH_REGEX.test(params.type); } parseComponentsAttributes(params) { const { types } = params; const inputs = []; const outputs = []; this.rawAbiType.components?.forEach((component) => { const { type: typeId, typeArguments } = component; if (!typeArguments) { const { attributes } = findType({ types, typeId }); inputs.push(attributes.inputLabel); outputs.push(attributes.outputLabel); } else { const inputLabel = parseTypeArguments({ types, typeArguments, parentTypeId: typeId, target: "input" /* INPUT */ }); const outputLabel = parseTypeArguments({ types, typeArguments, parentTypeId: typeId, target: "output" /* OUTPUT */ }); inputs.push(inputLabel); outputs.push(outputLabel); } }); this.attributes = { inputLabel: `[${inputs.join(", ")}]`, outputLabel: `[${outputs.join(", ")}]` }; return this.attributes; } }; // src/abi/types/U16Type.ts var U16Type = class _U16Type extends U8Type { static { __name(this, "U16Type"); } static swayType = "u16"; name = "u16"; static MATCH_REGEX = /^u16$/m; static isSuitableFor(params) { return _U16Type.MATCH_REGEX.test(params.type); } }; // src/abi/types/U256Type.ts var U256Type = class _U256Type extends U64Type { static { __name(this, "U256Type"); } static swayType = "u256"; name = "u256"; static MATCH_REGEX = /^u256$/m; static isSuitableFor(params) { return _U256Type.MATCH_REGEX.test(params.type); } }; // src/abi/types/U32Type.ts var U32Type = class _U32Type extends U8Type { static { __name(this, "U32Type"); } static swayType = "u32"; name = "u32"; static MATCH_REGEX = /^u32$/m; static isSuitableFor(params) { return _U32Type.MATCH_REGEX.test(params.type); } }; // src/abi/types/VectorType.ts var VectorType = class _VectorType extends ArrayType { static { __name(this, "VectorType"); } static swayType = "struct Vec"; name = "vector"; static MATCH_REGEX = /^struct (std::vec::)?Vec/m; static IGNORE_REGEX = /^struct (std::vec::)?RawVec$/m; static isSuitableFor(params) { const isAMatch = _VectorType.MATCH_REGEX.test(params.type); const shouldBeIgnored = _VectorType.IGNORE_REGEX.test(params.type); return isAMatch && !shouldBeIgnored; } parseComponentsAttributes(_params) { this.attributes = { inputLabel: `Vec`, outputLabel: `Vec` }; return this.attributes; } }; // src/utils/supportedTypes.ts var supportedTypes = [ EmptyType, ArrayType, B256Type, B512Type, BoolType, BytesType, EnumType, GenericType, OptionType, RawUntypedPtr, RawUntypedSlice, StdStringType, StrType, StrSliceType, StructType, TupleType, U16Type, U32Type, U64Type, U256Type, U8Type, VectorType, EvmAddressType, ResultType ]; // src/utils/makeType.ts function makeType(params) { const { rawAbiType } = params; const { type } = rawAbiType; const TypeClass = supportedTypes.find((tc) => tc.isSuitableFor({ type })); if (!TypeClass) { throw new FuelError3(ErrorCode4.TYPE_NOT_SUPPORTED, `Type not supported: ${type}`); } return new TypeClass(params); } __name(makeType, "makeType"); // src/utils/shouldSkipAbiType.ts function shouldSkipAbiType(params) { const ignoreList = [ "struct RawVec", "struct std::vec::RawVec", "struct RawBytes", "struct std::bytes::RawBytes" ]; const shouldSkip = ignoreList.indexOf(params.type) >= 0; return shouldSkip; } __name(shouldSkipAbiType, "shouldSkipAbiType"); // src/utils/parseTypes.ts function parseTypes(params) { const types = []; params.rawAbiTypes.forEach((rawAbiType) => { const { type } = rawAbiType; const skip = shouldSkipAbiType({ type }); if (!skip) { const parsedType = makeType({ rawAbiType }); types.push(parsedType); } }); types.forEach((type) => { type.parseComponentsAttributes({ types }); }); return types; } __name(parseTypes, "parseTypes"); // src/utils/transpile-abi.ts var findTypeByConcreteId = /* @__PURE__ */ __name((types, id) => types.find((x) => x.concreteTypeId === id), "findTypeByConcreteId"); var findConcreteTypeById = /* @__PURE__ */ __name((abi, id) => abi.concreteTypes.find((x) => x.concreteTypeId === id), "findConcreteTypeById"); function finsertTypeIdByConcreteTypeId(abi, types, id) { const concreteType = findConcreteTypeById(abi, id); if (concreteType.metadataTypeId !== void 0) { return concreteType.metadataTypeId; } const type = findTypeByConcreteId(types, id); if (type) { return type.typeId; } types.push({ typeId: types.length, type: concreteType.type, components: parseComponents(concreteType.components), concreteTypeId: id, typeParameters: concreteType.typeParameters ?? null, originalConcreteTypeId: concreteType?.concreteTypeId }); return types.length - 1; } __name(finsertTypeIdByConcreteTypeId, "finsertTypeIdByConcreteTypeId"); function parseFunctionTypeArguments(abi, types, concreteType) { return concreteType.typeArguments?.map((cTypeId) => { const self = findConcreteTypeById(abi, cTypeId); const type = !isNaN(cTypeId) ? cTypeId : finsertTypeIdByConcreteTypeId(abi, types, cTypeId); return { name: "", type, // originalTypeId: cTypeId, typeArguments: parseFunctionTypeArguments(abi, types, self) }; }) ?? null; } __name(parseFunctionTypeArguments, "parseFunctionTypeArguments"); function parseConcreteType(abi, types, concreteTypeId, name) { const type = finsertTypeIdByConcreteTypeId(abi, types, concreteTypeId); const concrete = findConcreteTypeById(abi, concreteTypeId); return { name: name ?? "", type, // concreteTypeId, typeArguments: parseFunctionTypeArguments(abi, types, concrete) }; } __name(parseConcreteType, "parseConcreteType"); function parseComponents(abi, types, components) { return components?.map((component) => { const { typeId, name, typeArguments } = component; const type = !isNaN(typeId) ? typeId : finsertTypeIdByConcreteTypeId(abi, types, typeId); return { name, type, // originalTypeId: typeId, typeArguments: parseComponents(abi, types, typeArguments) }; }) ?? null; } __name(parseComponents, "parseComponents"); function transpileAbi(abi) { if (!abi.specVersion) { return abi; } const types = []; abi.metadataTypes.forEach((m) => { const t = { typeId: m.metadataTypeId, type: m.type, components: m.components ?? (m.type === "()" ? [] : null), typeParameters: m.typeParameters ?? null }; types.push(t); }); types.forEach((t) => { t.components = parseComponents(abi, types, t.components); }); const functions = abi.functions.map((fn) => { const inputs = fn.inputs.map( ({ concreteTypeId, name }) => parseConcreteType(abi, types, concreteTypeId, name) ); const output = parseConcreteType(abi, types, fn.output, ""); return { ...fn, inputs, output }; }); const configurables = abi.configurables.map((conf) => ({ name: conf.name, configurableType: parseConcreteType(abi, types, conf.concreteTypeId), offset: conf.offset })); const loggedTypes = abi.loggedTypes.map((log) => ({ logId: log.logId, loggedType: parseConcreteType(abi, types, log.concreteTypeId) })); const transpiled = { encoding: abi.encodingVersion, types, functions, loggedTypes, messagesTypes: abi.messagesTypes, configurables, errorCodes: abi.errorCodes }; return transpiled; } __name(transpileAbi, "transpileAbi"); // src/abi/configurable/Configurable.ts var Configurable = class { static { __name(this, "Configurable"); } name; inputLabel; constructor(params) { const { types, rawAbiConfigurable: { name, configurableType: { type, typeArguments } } } = params; this.name = name; this.inputLabel = resolveInputLabel(types, type, typeArguments); } }; // src/abi/Abi.ts var Abi = class { static { __name(this, "Abi"); } capitalizedName; camelizedName; programType; filepath; outputDir; commonTypesInUse = []; rawContents; hexlifiedBinContents; storageSlotsContents; types; functions; configurables; errorCodes; constructor(params) { const { filepath, outputDir, rawContents, hexlifiedBinContents, programType, storageSlotsContents } = params; const abiNameRegex = /([^/]+)-abi\.json$/m; const abiName = filepath.match(abiNameRegex); const couldNotParseName = !abiName || abiName.length === 0; if (couldNotParseName) { throw new FuelError4( ErrorCode5.PARSE_FAILED, `Could not parse name from ABI file: ${filepath}.` ); } this.programType = programType; this.capitalizedName = `${normalizeString(abiName[1])}`; this.camelizedName = this.capitalizedName.replace(/^./m, (x) => x.toLowerCase()); this.filepath = filepath; this.rawContents = rawContents; this.hexlifiedBinContents = hexlifiedBinContents; this.storageSlotsContents = storageSlotsContents; this.outputDir = outputDir; const { types, functions, configurables, errorCodes } = this.parse(); this.types = types; this.functions = functions; this.configurables = configurables; this.errorCodes = errorCodes; this.computeCommonTypesInUse(); } parse() { const transpiled = transpileAbi(this.rawContents); const { types: rawAbiTypes, functions: rawAbiFunctions, configurables: rawAbiConfigurables, errorCodes: rawErrorCodes } = transpiled; const types = parseTypes({ rawAbiTypes }); const functions = parseFunctions({ rawAbiFunctions, types }); const configurables = rawAbiConfigurables.map( (rawAbiConfigurable) => new Configurable({ types, rawAbiConfigurable }) ); const errorCodes = parseErrorCodes({ rawErrorCodes, types }); return { types, functions, configurables, errorCodes }; } computeCommonTypesInUse() { const customTypesTable = { option: "Option", enum: "Enum", vector: "Vec", result: "Result" }; this.commonTypesInUse = []; Object.keys(customTypesTable).forEach((typeName) => { const isInUse = !!this.types.find((t) => t.name === typeName); if (isInUse) { const commonTypeLabel = customTypesTable[typeName]; this.commonTypesInUse.push(commonTypeLabel); } }); } }; // src/types/enums/ProgramTypeEnum.ts var ProgramTypeEnum = /* @__PURE__ */ ((ProgramTypeEnum2) => { ProgramTypeEnum2["CONTRACT"] = "contract"; ProgramTypeEnum2["SCRIPT"] = "script"; ProgramTypeEnum2["PREDICATE"] = "predicate"; return ProgramTypeEnum2; })(ProgramTypeEnum || {}); // src/utils/assembleContracts.ts import { join } from "path"; // src/templates/renderHbsTemplate.ts import Handlebars from "handlebars"; // src/templates/common/_header.hbs var header_default = "/* Autogenerated file. Do not edit manually. */\n\n/* eslint-disable max-classes-per-file */\n/* eslint-disable @typescript-eslint/no-unused-vars */\n/* eslint-disable @typescript-eslint/consistent-type-imports */\n\n\n/*\n Fuels version: {{FUELS}}\n{{#if FORC}}\n Forc version: {{FORC}}\n{{/if}}\n{{#if FUEL_CORE}}\n Fuel-Core version: {{FUEL_CORE}}\n{{/if}}\n*/\n"; // src/templates/renderHbsTemplate.ts function renderHbsTemplate(params) { const { data, template, versions } = params; const options = { strict: true, noEscape: true }; const renderTemplate = Handlebars.compile(template, options); const renderHeaderTemplate = Handlebars.compile(header_default, options); const text = renderTemplate({ ...data, header: renderHeaderTemplate(versions) }); return text.replace(/[\n]{3,}/gm, "\n\n"); } __name(renderHbsTemplate, "renderHbsTemplate"); // src/templates/common/common.hbs var common_default = "{{header}}\n\n/**\n * Mimics Sway Enum.\n * Requires one and only one Key-Value pair and raises error if more are provided.\n */\nexport type Enum<T> = {\n [K in keyof T]: Pick<T, K> & { [P in Exclude<keyof T, K>]?: never };\n}[keyof T];\n\n/**\n * Mimics Sway Option and Vectors.\n * Vectors are treated like arrays in Typescript.\n */\nexport type Option<T> = T | undefined;\n\nexport type Vec<T> = T[];\n\n/**\n * Mimics Sway Result enum type.\n * Ok represents the success case, while Err represents the error case.\n */\nexport type Result<T, E> = Enum<{Ok: T, Err: E}>;\n"; // src/templates/common/common.ts function renderCommonTemplate(params) { const { versions } = params; const text = renderHbsTemplate({ template: common_default, versions }); return text; } __name(renderCommonTemplate, "renderCommonTemplate"); // src/templates/common/index.hbs var common_default2 = "{{header}}\n\n{{#each members}}\nexport { {{this}} } from './{{this}}';\n{{/each}}\n"; // src/templates/common/index.ts function renderIndexTemplate(params) { const { files, versions } = params; const members = files.map((f) => f.path.match(/([^/]+)\.ts$/m)?.[1]); const text = renderHbsTemplate({ template: common_default2, versions, data: { members } }); return text; } __name(renderIndexTemplate, "renderIndexTemplate"); // src/templates/contract/factory.ts import { compressBytecode } from "@fuel-ts/utils"; // src/templates/contract/factory.hbs var factory_default = '{{header}}\n\nimport { ContractFactory as __ContractFactory, decompressBytecode } from "fuels";\nimport type { Provider, Account, DeployContractOptions } from "fuels";\n\nimport { {{capitalizedName}} } from "./{{capitalizedName}}";\n\nconst bytecode = decompressBytecode("{{compressedBytecode}}");\n\nexport class {{capitalizedName}}Factory extends __ContractFactory<{{capitalizedName}}> {\n\n static readonly bytecode = bytecode;\n\n constructor(accountOrProvider: Account | Provider) {\n super(\n bytecode,\n {{capitalizedName}}.abi,\n accountOrProvider,\n {{capitalizedName}}.storageSlots\n );\n }\n\n static deploy (\n wallet: Account,\n options: DeployContractOptions = {}\n ) {\n const factory = new {{capitalizedName}}Factory(wallet);\n return factory.deploy(options);\n }\n}\n'; // src/templates/contract/factory.ts function renderFactoryTemplate(params) { const { versions, abi } = params; const { camelizedName, capitalizedName, rawContents, storageSlotsContents, hexlifiedBinContents: hexlifiedBinString } = abi; const abiJsonString = JSON.stringify(rawContents, null, 2); const storageSlotsJsonString = storageSlotsContents ?? "[]"; const text = renderHbsTemplate({ template: factory_default, versions, data: { camelizedName, capitalizedName, abiJsonString, storageSlotsJsonString, compressedBytecode: compressBytecode(hexlifiedBinString) } }); return text; } __name(renderFactoryTemplate, "renderFactoryTemplate"); // src/templates/utils/formatEnums.ts function formatEnums(params) { const { types } = params; const enums = types.filter((t) => t.name === "enum").map((t) => { const et = t; const structName = et.getStructName(); const inputValues = et.getStructContents({ types, target: "input" /* INPUT */ }); const outputValues = et.getStructContents({ types, target: "output" /* OUTPUT */ }); const inputNativeValues = et.getNativeEnum({ types }); const outputNativeValues = et.getNativeEnum({ types }); const typeAnnotations = et.getStructDeclaration({ types }); return { structName, inputValues, outputValues, recycleRef: inputValues === outputValues, // reduces duplication inputNativeValues, outputNativeValues, typeAnnotations }; }).sort((a, b) => a.structName < b.structName ? -1 : 1); return { enums }; } __name(formatEnums, "formatEnums"); // src/templates/utils/formatImports.ts import { uniq } from "ramda"; var caseInsensitiveSort = /* @__PURE__ */ __name((a, b) => a.toLowerCase().localeCompare(b.toLowerCase()), "caseInsensitiveSort"); function formatImports(params) { const { types, baseMembers = [] } = params; const members = types.flatMap((t) => t.requiredFuelsMembersImports); const imports = uniq(baseMembers.concat(members).sort(caseInsensitiveSort)); return { imports: imports.length ? imports : void 0 }; } __name(formatImports, "formatImports"); // src/templates/utils/formatStructs.ts function formatStructs(params) { const { types } = params; const structs = types.filter((t) => t.name === "struct").map((t) => { const st = t; const structName = st.getStructName(); const inputValues = st.getStructContents({ types, target: "input" /* INPUT */ }); const outputValues = st.getStructContents({ types, target: "output" /* OUTPUT */ }); const typeAnnotations = st.getStructDeclaration({ types }); return { structName, typeAnnotations, inputValues, outputValues, recycleRef: inputValues === outputValues // reduces duplication }; }).sort((a, b) => a.structName < b.structName ? -1 : 1); return { structs }; } __name(formatStructs, "formatStructs"); // src/templates/contract/main.hbs var main_default = `{{header}} import { Contract as __Contract, Interface } from "fuels"; {{#if imports}} import type { Provider, Account, StorageSlot, Address, {{#each imports}} {{this}}, {{/each}} } from 'fuels'; {{/if}} {{#if commonTypesInUse}} import type { {{commonTypesInUse}} } from "./common"; {{/if}} {{#each enums}} {{#if inputNativeValues}} export enum {{structName}}Input { {{inputNativeValues}} }; {{else}} export type {{structName}}Input{{typeAnnotations}} = Enum<{ {{inputValues}} }>; {{/if}} {{#if outputNativeValues}} export enum {{structName}}Output { {{outputNativeValues}} }; {{else}} {{#if recycleRef}} export type {{structName}}Output{{typeAnnotations}} = {{structName}}Input{{typeAnnotations}}; {{else}} export type {{structName}}Output{{typeAnnotations}} = Enum<{ {{outputValues}} }>; {{/if}} {{/if}} {{/each}} {{#each structs}} export type {{structName}}Input{{typeAnnotations}} = { {{inputValues}} }; {{#if recycleRef}} export type {{structName}}Output{{typeAnnotations}} = {{structName}}Input{{typeAnnotations}}; {{else}} export type {{structName}}Output{{typeAnnotations}} = { {{outputValues}} }; {{/if}} {{/each}} {{#if configurables}} export type {{capitalizedName}}Configurables = Partial<{ {{#each configurables}} {{name}}: {{inputLabel}}; {{/each}} }>; {{/if}} const abi = {{abiJsonString}}; const storageSlots: StorageSlot[] = {{storageSlotsJsonString}}; export class {{capitalizedName}}Interface extends Interface { constructor() { super(abi); } declare functions: { {{#each functionsFragments}} {{this}}: FunctionFragment; {{/each}} }; } export class {{capitalizedName}} extends __Contract { static readonly abi = abi; static readonly storageSlots = storageSlots; declare interface: {{capitalizedName}}Interface; declare functions: { {{#each functionsTypedefs}} {{this}}; {{/each}} }; constructor( id: string | Address, accountOrProvider: Account | Provider, ) { super(id, abi, accountOrProvider); } } `; // src/templates/contract/main.ts function renderMainTemplate(params) { const { versions, abi } = params; const { camelizedName, capitalizedName, types, functions, commonTypesInUse, configurables } = abi; const functionsTypedefs = functions.map((f) => f.getDeclaration()); const functionsFragments = functions.map((f) => f.name); const encoders = functions.map((f) => ({ functionName: f.name, input: f.attributes.inputs })); const decoders = functions.map((f) => ({ functionName: f.name })); const { enums } = formatEnums({ types }); const { structs } = formatStructs({ types }); const { imports } = formatImports({ types, baseMembers: ["FunctionFragment", "InvokeFunction"] }); const { rawContents, storageSlotsContents } = params.abi; const abiJsonString = JSON.stringify(rawContents, null, 2); const storageSlotsJsonString = storageSlotsContents ?? "[]"; const text = renderHbsTemplate({ template: main_default, versions, data: { camelizedName, capitalizedName, commonTypesInUse: commonTypesInUse.join(", "), functionsTypedefs, functionsFragments, encoders, decoders, structs, enums, imports, abiJsonString, storageSlotsJsonString, configurables } }); return text; } __name(renderMainTemplate, "renderMainTemplate"); // src/utils/assembleContracts.ts function assembleContracts(params) { const { abis, outputDir, versions } = params; const files = []; const usesCommonTypes = abis.find((a) => a.commonTypesInUse.length > 0); abis.forEach((abi) => { const { capitalizedName } = abi; const mainFilepath = `${outputDir}/${capitalizedName}.ts`; const factoryFilepath = `${outputDir}/${capitalizedName}Factory.ts`; const main = { path: mainFilepath, contents: renderMainTemplate({ abi, versions }) }; const factory = { path: factoryFilepath, contents: renderFactoryTemplate({ abi, versions }) }; files.push(main); files.push(factory); }); const indexFile = { path: `${outputDir}/index.ts`, contents: renderIndexTemplate({ files, versions }) }; files.push(indexFile); if (usesCommonTypes) { const commonsFilepath = join(outputDir, "common.ts"); const file = { path: commonsFilepath, contents: renderCommonTemplate({ versions }) }; files.push(file); } return files; } __name(assembleContracts, "assembleContracts"); // src/utils/assemblePredicates.ts import { join as join2 } from "path"; // src/templates/predicate/main.ts import { ErrorCode as ErrorCode6, FuelError as FuelError5 } from "@fuel-ts/errors"; import { compressBytecode as compressBytecode2 } from "@fuel-ts/utils"; // src/templates/predicate/main.hbs var main_default2 = `{{header}} {{#if imports}} import { {{#each imports}} {{this}}, {{/each}} } from 'fuels'; {{/if}} {{#if commonTypesInUse}} import type { {{commonTypesInUse}} } from "./common"; {{/if}} {{#each enums}} {{#if inputNativeValues}} export enum {{structName}}Input { {{inputNativeValues}} }; {{else}} export type {{structName}}Input{{typeAnnotations}} = Enum<{ {{inputValues}} }>; {{/if}} {{#if outputNativeValues}} export enum {{structName}}Output { {{outputNativeValues}} }; {{else}} {{#if recycleRef}} export type {{structName}}Output{{typeAnnotations}} = {{structName}}Input{{typeAnnotations}}; {{else}} export type {{structName}}Output{{typeAnnotations}} = Enum<{ {{outputValues}} }>; {{/if}} {{/if}} {{/each}} {{#each structs}} export type {{structName}}Input{{typeAnnotations}} = { {{inputValues}} }; {{#if recycleRef}} export type {{structName}}Output{{typeAnnotations}} = {{structName}}Input{{typeAnnotations}}; {{else}} export type {{structName}}Output{{typeAnnotations}} = { {{outputValues}} }; {{/if}} {{/each}} {{#if configurables}} export type {{capitalizedName}}Configurables = Partial<{ {{#each configurables}} {{name}}: {{inputLabel}}; {{/each}} }>; {{else}} export type {{capitalizedName}}Configurables = undefined; {{/if}} export type {{capitalizedName}}Inputs = [{{inputs}}]; export type {{capitalizedName}}Parameters = Omit< PredicateParams<{{capitalizedName}}Inputs, {{capitalizedName}}Configurables>, 'abi' | 'bytecode' >; const abi = {{abiJsonString}}; const bytecode = decompressBytecode('{{compressedBytecode}}'); export class {{capitalizedName}} extends __Predicate< {{capitalizedName}}Inputs, {{capitalizedName}}Configurables > { static readonly abi = abi; static readonly bytecode = bytecode; constructor(params: {{capitalizedName}}Parameters) { super({ abi, bytecode, ...params }); } } `; // src/templates/predicate/main.ts function renderMainTemplate2(params) { const { abi, versions } = params; const { types, configurables } = abi; const { rawContents, capitalizedName, hexlifiedBinContents: hexlifiedBinString, commonTypesInUse } = params.abi; const abiJsonString = JSON.stringify(rawContents, null, 2); const func = abi.functions.find((f) => f.name === "main"); if (!func) { throw new FuelError5(ErrorCode6.ABI_MAIN_METHOD_MISSING, `ABI doesn't have a 'main()' method.`); } const { enums } = formatEnums({ types }); const { structs } = formatStructs({ types }); const { imports } = formatImports({ types, baseMembers: [ "Predicate as __Predicate", "Provider", "InputValue", "PredicateParams", "decompressBytecode" ] }); const { prefixedInputs: inputs, output } = func.attributes; const text = renderHbsTemplate({ template: main_default2, versions, data: { inputs, output, structs, enums, abiJsonString, compressedBytecode: compressBytecode2(hexlifiedBinString), capitalizedName, imports, configurables, commonTypesInUse: commonTypesInUse.join(", ") } }); return text; } __name(renderMainTemplate2, "renderMainTemplate"); // src/utils/assemblePredicates.ts function assemblePredicates(params) { const { abis, outputDir, versions } = params; const files = []; const usesCommonTypes = abis.find((a) => a.commonTypesInUse.length > 0); abis.forEach((abi) => { const { capitalizedName: name } = abi; const factoryFilepath = `${outputDir}/${name}.ts`; const factory = { path: factoryFilepath, contents: renderMainTemplate2({ abi, versions }) }; files.push(factory); }); const indexFile = { path: `${outputDir}/index.ts`, contents: renderIndexTemplate({ files, versions }) }; files.push(indexFile); if (usesCommonTypes) { const commonsFilepath = join2(outputDir, "common.ts"); const file = { path: commonsFilepath, contents: renderCommonTemplate({ versions }) }; files.push(file); } return files; } __name(assemblePredicates, "assemblePredicates"); // src/utils/assembleScripts.ts import { join as join3 } from "path"; // src/templates/script/main.ts import { ErrorCode as ErrorCode7, FuelError as FuelError6 } from "@fuel-ts/errors"; import { compressBytecode as compressBytecode3 } from "@fuel-ts/utils"; // src/templates/script/main.hbs var main_default3 = `{{header}} {{#if imports}} import { {{#each imports}} {{this}}, {{/each}} } from 'fuels'; {{/if}} {{#if commonTypesInUse}} import type { {{commonTypesInUse}} } from "./common"; {{/if}} {{#each enums}} {{#if inputNativeValues}} export enum {{structName}}Input { {{inputNativeValues}} }; {{else}} export type {{structName}}Input{{typeAnnotations}} = Enum<{ {{inputValues}} }>; {{/if}} {{#if outputNativeValues}} export enum {{structName}}Output { {{outputNativeValues}} }; {{else}} {{#if recycleRef}} export type {{structName}}Output{{typeAnnotations}} = {{structName}}Input{{typeAnnotations}}; {{else}} export type {{structName}}Output{{typeAnnotations}} = Enum<{ {{outputValues}} }>; {{/if}} {{/if}} {{/each}} {{#each structs}} export type {{structName}}Input{{typeAnnotations}} = { {{inputValues}} }; {{#if recycleRef}} export type {{structName}}Output{{typeAnnotations}} = {{structName}}Input{{typeAnnotations}}; {{else}} export type {{structName}}Output{{typeAnnotations}} = { {{outputValues}} }; {{/if}} {{/each}} export type {{capitalizedName}}Inputs = [{{inputs}}]; export type {{capitalizedName}}Output = {{output}}; {{#if configurables}} export type {{capitalizedName}}Configurables = Partial<{ {{#each configurables}} {{name}}: {{inputLabel}}; {{/each}} }>; {{/if}} const abi = {{abiJsonString}}; const bytecode = decompressBytecode('{{compressedBytecode}}'); export class {{capitalizedName}} extends __Script<{{capitalizedName}}Inputs, {{capitalizedName}}Output> { static readonly abi