@codama/renderers-js
Version:
JavaScript renderer compatible with the Solana Kit library
1,180 lines (1,150 loc) • 137 kB
JavaScript
// src/ImportMap.ts
var DEFAULT_EXTERNAL_MODULE_MAP = {
solanaAccounts: "@solana/kit",
solanaAddresses: "@solana/kit",
solanaCodecsCore: "@solana/kit",
solanaCodecsDataStructures: "@solana/kit",
solanaCodecsNumbers: "@solana/kit",
solanaCodecsStrings: "@solana/kit",
solanaErrors: "@solana/kit",
solanaInstructions: "@solana/kit",
solanaOptions: "@solana/kit",
solanaPrograms: "@solana/kit",
solanaRpcTypes: "@solana/kit",
solanaSigners: "@solana/kit"
};
var DEFAULT_GRANULAR_EXTERNAL_MODULE_MAP = {
solanaAccounts: "@solana/accounts",
solanaAddresses: "@solana/addresses",
solanaCodecsCore: "@solana/codecs",
solanaCodecsDataStructures: "@solana/codecs",
solanaCodecsNumbers: "@solana/codecs",
solanaCodecsStrings: "@solana/codecs",
solanaErrors: "@solana/errors",
solanaInstructions: "@solana/instructions",
solanaOptions: "@solana/codecs",
solanaPrograms: "@solana/programs",
solanaRpcTypes: "@solana/rpc-types",
solanaSigners: "@solana/signers"
};
var DEFAULT_INTERNAL_MODULE_MAP = {
errors: "../errors",
generated: "..",
generatedAccounts: "../accounts",
generatedErrors: "../errors",
generatedInstructions: "../instructions",
generatedPdas: "../pdas",
generatedPrograms: "../programs",
generatedTypes: "../types",
hooked: "../../hooked",
shared: "../shared",
types: "../types"
};
var ImportMap = class {
_imports = /* @__PURE__ */ new Map();
_aliases = /* @__PURE__ */ new Map();
add(module, imports) {
const newImports = new Set(typeof imports === "string" ? [imports] : imports);
if (newImports.size === 0) return this;
const currentImports = this._imports.get(module) ?? /* @__PURE__ */ new Set();
newImports.forEach((i) => currentImports.add(i));
this._imports.set(module, currentImports);
return this;
}
remove(module, imports) {
const importsToRemove = new Set(typeof imports === "string" ? [imports] : imports);
if (importsToRemove.size === 0) return this;
const currentImports = this._imports.get(module) ?? /* @__PURE__ */ new Set();
importsToRemove.forEach((i) => currentImports.delete(i));
if (currentImports.size === 0) {
this._imports.delete(module);
} else {
this._imports.set(module, currentImports);
}
return this;
}
mergeWith(...others) {
others.forEach((rawOther) => {
const other = "imports" in rawOther ? rawOther.imports : rawOther;
other._imports.forEach((imports, module) => {
this.add(module, imports);
});
other._aliases.forEach((aliases, module) => {
Object.entries(aliases).forEach(([name, alias]) => {
this.addAlias(module, name, alias);
});
});
});
return this;
}
mergeWithManifest(manifest) {
return this.mergeWith(manifest.strictType, manifest.looseType, manifest.encoder, manifest.decoder);
}
addAlias(module, name, alias) {
const currentAliases = this._aliases.get(module) ?? {};
currentAliases[name] = alias;
this._aliases.set(module, currentAliases);
return this;
}
isEmpty() {
return this._imports.size === 0;
}
resolve(dependencies = {}, useGranularImports = false) {
const aliasedMap = new Map(
[...this._imports.entries()].map(([module, imports]) => {
const aliasMap = this._aliases.get(module) ?? {};
const joinedImports = [...imports].map((i) => aliasMap[i] ? `${i} as ${aliasMap[i]}` : i);
return [module, new Set(joinedImports)];
})
);
const dependencyMap = {
...useGranularImports ? DEFAULT_GRANULAR_EXTERNAL_MODULE_MAP : DEFAULT_EXTERNAL_MODULE_MAP,
...DEFAULT_INTERNAL_MODULE_MAP,
...dependencies
};
const resolvedMap = /* @__PURE__ */ new Map();
aliasedMap.forEach((imports, module) => {
const resolvedModule = dependencyMap[module] ?? module;
const currentImports = resolvedMap.get(resolvedModule) ?? /* @__PURE__ */ new Set();
imports.forEach((i) => currentImports.add(i));
resolvedMap.set(resolvedModule, currentImports);
});
return resolvedMap;
}
toString(dependencies = {}, useGranularImports = false) {
return [...this.resolve(dependencies, useGranularImports).entries()].sort(([a], [b]) => {
const aIsRelative = a.startsWith(".");
const bIsRelative = b.startsWith(".");
if (aIsRelative && !bIsRelative) return 1;
if (!aIsRelative && bIsRelative) return -1;
return a.localeCompare(b);
}).map(([module, imports]) => {
const joinedImports = [...imports].sort().filter((i) => {
const name = i.split(" ");
if (name.length > 1) {
return !imports.has(name[1]);
}
return true;
}).join(", ");
return `import { ${joinedImports} } from '${module}';`;
}).join("\n");
}
};
// src/fragments/accountFetchHelpers.ts
import { getLastNodeFromPath } from "@codama/visitors-core";
// src/fragments/common.ts
import { join as join2 } from "path";
// src/utils/async.ts
import {
accountValueNode,
argumentValueNode,
isNode
} from "@codama/nodes";
import { deduplicateInstructionDependencies } from "@codama/visitors-core";
function hasAsyncFunction(instructionNode, resolvedInputs, asyncResolvers) {
const hasByteDeltasAsync = (instructionNode.byteDeltas ?? []).some(
({ value }) => isNode(value, "resolverValueNode") && asyncResolvers.includes(value.name)
);
const hasRemainingAccountsAsync = (instructionNode.remainingAccounts ?? []).some(
({ value }) => isNode(value, "resolverValueNode") && asyncResolvers.includes(value.name)
);
return hasAsyncDefaultValues(resolvedInputs, asyncResolvers) || hasByteDeltasAsync || hasRemainingAccountsAsync;
}
function hasAsyncDefaultValues(resolvedInputs, asyncResolvers) {
return resolvedInputs.some(
(input) => !!input.defaultValue && isAsyncDefaultValue(input.defaultValue, asyncResolvers)
);
}
function isAsyncDefaultValue(defaultValue, asyncResolvers) {
switch (defaultValue.kind) {
case "pdaValueNode":
return true;
case "resolverValueNode":
return asyncResolvers.includes(defaultValue.name);
case "conditionalValueNode":
return isAsyncDefaultValue(defaultValue.condition, asyncResolvers) || (defaultValue.ifFalse == null ? false : isAsyncDefaultValue(defaultValue.ifFalse, asyncResolvers)) || (defaultValue.ifTrue == null ? false : isAsyncDefaultValue(defaultValue.ifTrue, asyncResolvers));
default:
return false;
}
}
function getInstructionDependencies(input, asyncResolvers, useAsync) {
if (isNode(input, "instructionNode")) {
return deduplicateInstructionDependencies([
...input.accounts.flatMap((x) => getInstructionDependencies(x, asyncResolvers, useAsync)),
...input.arguments.flatMap((x) => getInstructionDependencies(x, asyncResolvers, useAsync)),
...(input.extraArguments ?? []).flatMap((x) => getInstructionDependencies(x, asyncResolvers, useAsync))
]);
}
if (!input.defaultValue) return [];
const getNestedDependencies = (defaultValue) => {
if (!defaultValue) return [];
return getInstructionDependencies({ ...input, defaultValue }, asyncResolvers, useAsync);
};
if (isNode(input.defaultValue, ["accountValueNode", "accountBumpValueNode"])) {
return [accountValueNode(input.defaultValue.name)];
}
if (isNode(input.defaultValue, ["argumentValueNode"])) {
return [argumentValueNode(input.defaultValue.name)];
}
if (isNode(input.defaultValue, "pdaValueNode")) {
const dependencies = /* @__PURE__ */ new Map();
input.defaultValue.seeds.forEach((seed) => {
if (isNode(seed.value, ["accountValueNode", "argumentValueNode"])) {
dependencies.set(seed.value.name, { ...seed.value });
}
});
return [...dependencies.values()];
}
if (isNode(input.defaultValue, "resolverValueNode")) {
const isSynchronousResolver = !asyncResolvers.includes(input.defaultValue.name);
if (useAsync || isSynchronousResolver) {
return input.defaultValue.dependsOn ?? [];
}
}
if (isNode(input.defaultValue, "conditionalValueNode")) {
return deduplicateInstructionDependencies([
...getNestedDependencies(input.defaultValue.condition),
...getNestedDependencies(input.defaultValue.ifTrue),
...getNestedDependencies(input.defaultValue.ifFalse)
]);
}
return [];
}
// src/utils/codecs.ts
import { getBase16Encoder, getBase58Encoder, getBase64Encoder, getUtf8Encoder } from "@solana/codecs-strings";
function getBytesFromBytesValueNode(node) {
switch (node.encoding) {
case "utf8":
return getUtf8Encoder().encode(node.data);
case "base16":
return getBase16Encoder().encode(node.data);
case "base58":
return getBase58Encoder().encode(node.data);
case "base64":
default:
return getBase64Encoder().encode(node.data);
}
}
// src/utils/customData.ts
import {
camelCase,
definedTypeLinkNode,
definedTypeNode,
isNode as isNode2,
structTypeNodeFromInstructionArgumentNodes
} from "@codama/nodes";
var parseCustomDataOptions = (customDataOptions, defaultSuffix) => new Map(
customDataOptions.map((o) => {
const options = typeof o === "string" ? { name: o } : o;
const importAs = camelCase(options.importAs ?? `${options.name}${defaultSuffix}`);
const importFrom = options.importFrom ?? "hooked";
return [
camelCase(options.name),
{
extract: options.extract ?? false,
extractAs: options.extractAs ? camelCase(options.extractAs) : importAs,
importAs,
importFrom,
linkNode: definedTypeLinkNode(importAs)
}
];
})
);
var getDefinedTypeNodesToExtract = (nodes, parsedCustomDataOptions) => nodes.flatMap((node) => {
const options = parsedCustomDataOptions.get(node.name);
if (!options || !options.extract) return [];
if (isNode2(node, "accountNode")) {
return [definedTypeNode({ name: options.extractAs, type: { ...node.data } })];
}
return [
definedTypeNode({
name: options.extractAs,
type: structTypeNodeFromInstructionArgumentNodes(node.arguments)
})
];
});
// src/utils/linkOverrides.ts
import { CODAMA_ERROR__UNEXPECTED_NODE_KIND, CodamaError } from "@codama/errors";
function getImportFromFactory(overrides, customAccountData, customInstructionData) {
const customDataOverrides = Object.fromEntries(
[...customAccountData.values(), ...customInstructionData.values()].map(({ importFrom, importAs }) => [
importAs,
importFrom
])
);
const linkOverrides = {
accounts: overrides.accounts ?? {},
definedTypes: { ...customDataOverrides, ...overrides.definedTypes },
instructions: overrides.instructions ?? {},
pdas: overrides.pdas ?? {},
programs: overrides.programs ?? {},
resolvers: overrides.resolvers ?? {}
};
return (node) => {
const kind = node.kind;
switch (kind) {
case "accountLinkNode":
return linkOverrides.accounts[node.name] ?? "generatedAccounts";
case "definedTypeLinkNode":
return linkOverrides.definedTypes[node.name] ?? "generatedTypes";
case "instructionLinkNode":
return linkOverrides.instructions[node.name] ?? "generatedInstructions";
case "pdaLinkNode":
return linkOverrides.pdas[node.name] ?? "generatedPdas";
case "programLinkNode":
return linkOverrides.programs[node.name] ?? "generatedPrograms";
case "resolverValueNode":
return linkOverrides.resolvers[node.name] ?? "hooked";
default:
throw new CodamaError(CODAMA_ERROR__UNEXPECTED_NODE_KIND, {
expectedKinds: [
"AccountLinkNode",
"DefinedTypeLinkNode",
"InstructionLinkNode",
"PdaLinkNode",
"ProgramLinkNode",
"resolverValueNode"
],
kind,
node
});
}
};
}
// src/utils/render.ts
import { dirname as pathDirname, join } from "path";
import { fileURLToPath } from "url";
import { camelCase as camelCase2, kebabCase, pascalCase, snakeCase, titleCase } from "@codama/nodes";
import nunjucks from "nunjucks";
function jsDocblock(docs) {
if (docs.length <= 0) return "";
if (docs.length === 1) return `/** ${docs[0]} */
`;
const lines = docs.map((doc) => ` * ${doc}`);
return `/**
${lines.join("\n")}
*/
`;
}
var render = (template, context, options) => {
const dirname = true ? pathDirname(fileURLToPath(import.meta.url)) : __dirname;
const templates = false ? join(dirname, "..", "..", "public", "templates") : join(dirname, "templates");
const env = nunjucks.configure(templates, { autoescape: false, trimBlocks: true, ...options });
env.addFilter("pascalCase", pascalCase);
env.addFilter("camelCase", camelCase2);
env.addFilter("snakeCase", snakeCase);
env.addFilter("kebabCase", kebabCase);
env.addFilter("titleCase", titleCase);
env.addFilter("jsDocblock", jsDocblock);
return env.render(template, context);
};
// src/fragments/common.ts
function fragment(render2, imports) {
return new Fragment(render2, imports);
}
function fragmentFromTemplate(fragmentFile, context, options) {
return fragment(render(join2("fragments", fragmentFile), context, options));
}
function mergeFragments(fragments, mergeRenders) {
return new Fragment(
mergeRenders(fragments.map((f) => f.render)),
new ImportMap().mergeWith(...fragments),
new Set(fragments.flatMap((f) => [...f.features]))
);
}
var Fragment = class _Fragment {
render;
imports;
features;
constructor(render2, imports, features) {
this.render = render2;
this.imports = imports ? new ImportMap().mergeWith(imports) : new ImportMap();
this.features = /* @__PURE__ */ new Set([...features ?? []]);
}
setRender(render2) {
this.render = render2;
return this;
}
mapRender(fn) {
this.render = fn(this.render);
return this;
}
addImports(module, imports) {
this.imports.add(module, imports);
return this;
}
removeImports(module, imports) {
this.imports.remove(module, imports);
return this;
}
mergeImportsWith(...others) {
this.imports.mergeWith(...others);
return this;
}
addImportAlias(module, name, alias) {
this.imports.addAlias(module, name, alias);
return this;
}
addFeatures(features) {
const featureArray = typeof features === "string" ? [features] : features;
featureArray.forEach((f) => this.features.add(f));
return this;
}
removeFeatures(features) {
const featureArray = typeof features === "string" ? [features] : features;
featureArray.forEach((f) => this.features.delete(f));
return this;
}
hasFeatures(features) {
const featureArray = typeof features === "string" ? [features] : features;
return featureArray.every((f) => this.features.has(f));
}
mergeFeaturesWith(...others) {
others.forEach((f) => this.addFeatures([...f.features]));
return this;
}
clone() {
return new _Fragment(this.render).mergeImportsWith(this.imports);
}
toString() {
return this.render;
}
};
// src/fragments/accountFetchHelpers.ts
function getAccountFetchHelpersFragment(scope) {
const { accountPath, typeManifest: typeManifest2, nameApi, customAccountData } = scope;
const accountNode = getLastNodeFromPath(accountPath);
const hasCustomData = customAccountData.has(accountNode.name);
const accountTypeFragment = hasCustomData ? typeManifest2.strictType.clone() : fragment(nameApi.dataType(accountNode.name));
const decoderFunctionFragment = hasCustomData ? typeManifest2.decoder.clone() : fragment(`${nameApi.decoderFunction(accountNode.name)}()`);
return fragmentFromTemplate("accountFetchHelpers.njk", {
accountType: accountTypeFragment.render,
decodeFunction: nameApi.accountDecodeFunction(accountNode.name),
decoderFunction: decoderFunctionFragment.render,
fetchAllFunction: nameApi.accountFetchAllFunction(accountNode.name),
fetchAllMaybeFunction: nameApi.accountFetchAllMaybeFunction(accountNode.name),
fetchFunction: nameApi.accountFetchFunction(accountNode.name),
fetchMaybeFunction: nameApi.accountFetchMaybeFunction(accountNode.name)
}).mergeImportsWith(accountTypeFragment, decoderFunctionFragment).addImports("solanaAddresses", ["type Address"]).addImports("solanaAccounts", [
"type Account",
"assertAccountExists",
"assertAccountsExist",
"decodeAccount",
"type EncodedAccount",
"fetchEncodedAccount",
"fetchEncodedAccounts",
"type FetchAccountConfig",
"type FetchAccountsConfig",
"type MaybeAccount",
"type MaybeEncodedAccount"
]);
}
// src/fragments/accountPdaHelpers.ts
import { isNodeFilter } from "@codama/nodes";
import { findProgramNodeFromPath, getLastNodeFromPath as getLastNodeFromPath2 } from "@codama/visitors-core";
function getAccountPdaHelpersFragment(scope) {
const { accountPath, nameApi, linkables, customAccountData, typeManifest: typeManifest2 } = scope;
const accountNode = getLastNodeFromPath2(accountPath);
const programNode = findProgramNodeFromPath(accountPath);
const pdaNode = accountNode.pda ? linkables.get([...accountPath, accountNode.pda]) : void 0;
if (!pdaNode) {
return fragment("");
}
const accountTypeFragment = customAccountData.has(accountNode.name) ? typeManifest2.strictType.clone() : fragment(nameApi.dataType(accountNode.name));
const importFrom = "generatedPdas";
const pdaSeedsType = nameApi.pdaSeedsType(pdaNode.name);
const findPdaFunction = nameApi.pdaFindFunction(pdaNode.name);
const hasVariableSeeds = pdaNode.seeds.filter(isNodeFilter("variablePdaSeedNode")).length > 0;
return fragmentFromTemplate("accountPdaHelpers.njk", {
accountType: accountTypeFragment.render,
fetchFromSeedsFunction: nameApi.accountFetchFromSeedsFunction(accountNode.name),
fetchFunction: nameApi.accountFetchFunction(accountNode.name),
fetchMaybeFromSeedsFunction: nameApi.accountFetchMaybeFromSeedsFunction(accountNode.name),
fetchMaybeFunction: nameApi.accountFetchMaybeFunction(accountNode.name),
findPdaFunction,
hasVariableSeeds,
pdaSeedsType,
program: programNode
}).mergeImportsWith(accountTypeFragment).addImports(importFrom, hasVariableSeeds ? [pdaSeedsType, findPdaFunction] : [findPdaFunction]).addImports("solanaAddresses", ["type Address"]).addImports("solanaAccounts", [
"type Account",
"assertAccountExists",
"type FetchAccountConfig",
"type MaybeAccount"
]);
}
// src/fragments/accountSizeHelpers.ts
import { getLastNodeFromPath as getLastNodeFromPath3 } from "@codama/visitors-core";
function getAccountSizeHelpersFragment(scope) {
const { accountPath, nameApi } = scope;
const accountNode = getLastNodeFromPath3(accountPath);
if (accountNode.size == null) {
return fragment("");
}
return fragmentFromTemplate("accountSizeHelpers.njk", {
account: accountNode,
getSizeFunction: nameApi.accountGetSizeFunction(accountNode.name)
});
}
// src/fragments/accountType.ts
import { resolveNestedTypeNode } from "@codama/nodes";
import { getLastNodeFromPath as getLastNodeFromPath4 } from "@codama/visitors-core";
// src/fragments/type.ts
function getTypeFragment(scope) {
const { name, manifest, nameApi, docs = [] } = scope;
const typeFragment = fragmentFromTemplate("type.njk", {
docs,
looseName: nameApi.dataArgsType(name),
manifest,
strictName: nameApi.dataType(name)
});
if (!manifest.isEnum) {
typeFragment.mergeImportsWith(manifest.strictType, manifest.looseType);
}
return typeFragment;
}
// src/fragments/typeDecoder.ts
import { isDataEnum, isNode as isNode3 } from "@codama/nodes";
function getTypeDecoderFragment(scope) {
const { name, node, manifest, nameApi, docs = [] } = scope;
const decoderType = typeof scope.size === "number" ? "FixedSizeDecoder" : "Decoder";
const useTypeCast = isNode3(node, "enumTypeNode") && isDataEnum(node) && typeof scope.size === "number";
return fragmentFromTemplate("typeDecoder.njk", {
decoderFunction: nameApi.decoderFunction(name),
decoderType,
docs,
looseName: nameApi.dataArgsType(name),
manifest,
strictName: nameApi.dataType(name),
useTypeCast
}).mergeImportsWith(manifest.decoder).addImports("solanaCodecsCore", `type ${decoderType}`);
}
// src/fragments/typeEncoder.ts
import { isDataEnum as isDataEnum2, isNode as isNode4 } from "@codama/nodes";
function getTypeEncoderFragment(scope) {
const { name, node, manifest, nameApi, docs = [] } = scope;
const encoderType = typeof scope.size === "number" ? "FixedSizeEncoder" : "Encoder";
const useTypeCast = isNode4(node, "enumTypeNode") && isDataEnum2(node) && typeof scope.size === "number";
return fragmentFromTemplate("typeEncoder.njk", {
docs,
encoderFunction: nameApi.encoderFunction(name),
encoderType,
looseName: nameApi.dataArgsType(name),
manifest,
strictName: nameApi.dataType(name),
useTypeCast
}).mergeImportsWith(manifest.encoder).addImports("solanaCodecsCore", `type ${encoderType}`);
}
// src/fragments/typeCodec.ts
function getTypeCodecFragment(scope) {
const { name, manifest, nameApi } = scope;
const codecType = typeof scope.size === "number" ? "FixedSizeCodec" : "Codec";
return mergeFragments(
[
getTypeEncoderFragment({ ...scope, docs: scope.encoderDocs }),
getTypeDecoderFragment({ ...scope, docs: scope.decoderDocs }),
fragmentFromTemplate("typeCodec.njk", {
codecFunction: nameApi.codecFunction(name),
codecType,
decoderFunction: nameApi.decoderFunction(name),
docs: scope.codecDocs,
encoderFunction: nameApi.encoderFunction(name),
looseName: nameApi.dataArgsType(name),
manifest,
strictName: nameApi.dataType(name)
}).addImports("solanaCodecsCore", [`type ${codecType}`, "combineCodec"])
],
(renders) => renders.join("\n\n")
);
}
// src/fragments/typeWithCodec.ts
function getTypeWithCodecFragment(scope) {
return mergeFragments(
[getTypeFragment({ ...scope, docs: scope.typeDocs }), getTypeCodecFragment(scope)],
(renders) => renders.join("\n\n")
);
}
// src/fragments/accountType.ts
function getAccountTypeFragment(scope) {
const { accountPath, typeManifest: typeManifest2, nameApi, customAccountData } = scope;
const accountNode = getLastNodeFromPath4(accountPath);
if (customAccountData.has(accountNode.name)) {
return fragment("");
}
return getTypeWithCodecFragment({
manifest: typeManifest2,
name: accountNode.name,
nameApi,
node: resolveNestedTypeNode(accountNode.data),
size: scope.size
});
}
// src/fragments/discriminatorCondition.ts
import {
constantDiscriminatorNode,
constantValueNode,
constantValueNodeFromBytes,
isNode as isNode5,
isNodeFilter as isNodeFilter2
} from "@codama/nodes";
import { visit } from "@codama/visitors-core";
import { getBase64Decoder } from "@solana/codecs-strings";
function getDiscriminatorConditionFragment(scope) {
return mergeFragments(
scope.discriminators.flatMap((discriminator) => {
if (isNode5(discriminator, "sizeDiscriminatorNode")) {
return [getSizeConditionFragment(discriminator, scope)];
}
if (isNode5(discriminator, "constantDiscriminatorNode")) {
return [getByteConditionFragment(discriminator, scope)];
}
if (isNode5(discriminator, "fieldDiscriminatorNode")) {
return [getFieldConditionFragment(discriminator, scope)];
}
return [];
}),
(r) => r.join(" && ")
).mapRender((r) => `if (${r}) { ${scope.ifTrue}; }`);
}
function getSizeConditionFragment(discriminator, scope) {
const { dataName } = scope;
return fragment(`${dataName}.length === ${discriminator.size}`);
}
function getByteConditionFragment(discriminator, scope) {
const { dataName, typeManifestVisitor } = scope;
const constant = visit(discriminator.constant, typeManifestVisitor).value;
return constant.mapRender((r) => `containsBytes(${dataName}, ${r}, ${discriminator.offset})`).addImports("solanaCodecsCore", "containsBytes");
}
function getFieldConditionFragment(discriminator, scope) {
const field = scope.struct.fields.find((f) => f.name === discriminator.name);
if (!field || !field.defaultValue) {
throw new Error(
`Field discriminator "${discriminator.name}" does not have a matching argument with default value.`
);
}
if (isNode5(field.type, "arrayTypeNode") && isNode5(field.type.item, "numberTypeNode") && field.type.item.format === "u8" && isNode5(field.type.count, "fixedCountNode") && isNode5(field.defaultValue, "arrayValueNode") && field.defaultValue.items.every(isNodeFilter2("numberValueNode"))) {
const base64Bytes = getBase64Decoder().decode(
new Uint8Array(field.defaultValue.items.map((node) => node.number))
);
return getByteConditionFragment(
constantDiscriminatorNode(constantValueNodeFromBytes("base64", base64Bytes), discriminator.offset),
scope
);
}
return getByteConditionFragment(
constantDiscriminatorNode(constantValueNode(field.type, field.defaultValue), discriminator.offset),
scope
);
}
// src/fragments/instructionAccountMeta.ts
import { pascalCase as pascalCase2 } from "@codama/nodes";
function getInstructionAccountMetaFragment(instructionAccountNode) {
const typeParam = `TAccount${pascalCase2(instructionAccountNode.name)}`;
if (instructionAccountNode.isSigner === true && instructionAccountNode.isWritable) {
return fragment(`WritableSignerAccount<${typeParam}> & AccountSignerMeta<${typeParam}>`).addImports("solanaInstructions", ["type WritableSignerAccount"]).addImports("solanaSigners", ["type AccountSignerMeta"]);
}
if (instructionAccountNode.isSigner === true) {
return fragment(`ReadonlySignerAccount<${typeParam}> & AccountSignerMeta<${typeParam}>`).addImports("solanaInstructions", ["type ReadonlySignerAccount"]).addImports("solanaSigners", ["type AccountSignerMeta"]);
}
if (instructionAccountNode.isWritable) {
return fragment(`WritableAccount<${typeParam}>`).addImports("solanaInstructions", "type WritableAccount");
}
return fragment(`ReadonlyAccount<${typeParam}>`).addImports("solanaInstructions", "type ReadonlyAccount");
}
// src/fragments/instructionAccountTypeParam.ts
import { pascalCase as pascalCase3 } from "@codama/nodes";
import {
findInstructionNodeFromPath,
findProgramNodeFromPath as findProgramNodeFromPath2,
getLastNodeFromPath as getLastNodeFromPath5
} from "@codama/visitors-core";
function getInstructionAccountTypeParamFragment(scope) {
const { instructionAccountPath, allowAccountMeta, linkables } = scope;
const instructionAccountNode = getLastNodeFromPath5(instructionAccountPath);
const instructionNode = findInstructionNodeFromPath(instructionAccountPath);
const programNode = findProgramNodeFromPath2(instructionAccountPath);
const typeParam = `TAccount${pascalCase3(instructionAccountNode.name)}`;
const accountMeta = allowAccountMeta ? " | AccountMeta<string>" : "";
const imports = new ImportMap();
if (allowAccountMeta) {
imports.add("solanaInstructions", "type AccountMeta");
}
if (instructionNode.optionalAccountStrategy === "omitted" && instructionAccountNode.isOptional) {
return fragment(`${typeParam} extends string${accountMeta} | undefined = undefined`, imports);
}
const defaultAddress = getDefaultAddress(instructionAccountNode.defaultValue, programNode.publicKey, linkables);
return fragment(`${typeParam} extends string${accountMeta} = ${defaultAddress}`, imports);
}
function getDefaultAddress(defaultValue, programId, linkables) {
switch (defaultValue?.kind) {
case "publicKeyValueNode":
return `"${defaultValue.publicKey}"`;
case "programLinkNode":
const programNode = linkables.get([defaultValue]);
return programNode ? `"${programNode.publicKey}"` : "string";
case "programIdValueNode":
return `"${programId}"`;
default:
return "string";
}
}
// src/fragments/instructionByteDelta.ts
import { assertIsNode, camelCase as camelCase3, isNode as isNode6 } from "@codama/nodes";
import { getLastNodeFromPath as getLastNodeFromPath6 } from "@codama/visitors-core";
function getInstructionByteDeltaFragment(scope) {
const { byteDeltas } = getLastNodeFromPath6(scope.instructionPath);
const fragments = (byteDeltas ?? []).flatMap((r) => getByteDeltaFragment(r, scope));
if (fragments.length === 0) return fragment("");
return mergeFragments(
fragments,
(r) => `// Bytes created or reallocated by the instruction.
const byteDelta: number = [${r.join(",")}].reduce((a, b) => a + b, 0);`
);
}
function getByteDeltaFragment(byteDelta, scope) {
const bytesFragment = (() => {
if (isNode6(byteDelta.value, "numberValueNode")) {
return getNumberValueNodeFragment(byteDelta);
}
if (isNode6(byteDelta.value, "argumentValueNode")) {
return getArgumentValueNodeFragment(byteDelta);
}
if (isNode6(byteDelta.value, "accountLinkNode")) {
return getAccountLinkNodeFragment(byteDelta, scope);
}
if (isNode6(byteDelta.value, "resolverValueNode")) {
return getResolverValueNodeFragment(byteDelta, scope);
}
return null;
})();
if (bytesFragment === null) return [];
if (byteDelta.withHeader) {
bytesFragment.mapRender((r) => `${r} + BASE_ACCOUNT_SIZE`).addImports("solanaAccounts", "BASE_ACCOUNT_SIZE");
}
if (byteDelta.subtract) {
bytesFragment.mapRender((r) => `- (${r})`);
}
return [bytesFragment];
}
function getNumberValueNodeFragment(byteDelta) {
assertIsNode(byteDelta.value, "numberValueNode");
return fragment(byteDelta.value.number.toString());
}
function getArgumentValueNodeFragment(byteDelta) {
assertIsNode(byteDelta.value, "argumentValueNode");
const argumentName = camelCase3(byteDelta.value.name);
return fragment(`Number(args.${argumentName})`);
}
function getAccountLinkNodeFragment(byteDelta, scope) {
assertIsNode(byteDelta.value, "accountLinkNode");
const functionName = scope.nameApi.accountGetSizeFunction(byteDelta.value.name);
return fragment(`${functionName}()`).addImports(scope.getImportFrom(byteDelta.value), functionName);
}
function getResolverValueNodeFragment(byteDelta, scope) {
assertIsNode(byteDelta.value, "resolverValueNode");
const isAsync = scope.asyncResolvers.includes(byteDelta.value.name);
if (!scope.useAsync && isAsync) return null;
const awaitKeyword = scope.useAsync && isAsync ? "await " : "";
const functionName = scope.nameApi.resolverFunction(byteDelta.value.name);
return fragment(`${awaitKeyword}${functionName}(resolverScope)`).addImports(scope.getImportFrom(byteDelta.value), functionName).addFeatures(["instruction:resolverScopeVariable"]);
}
// src/fragments/instructionData.ts
import { structTypeNodeFromInstructionArgumentNodes as structTypeNodeFromInstructionArgumentNodes2 } from "@codama/nodes";
import { getLastNodeFromPath as getLastNodeFromPath7 } from "@codama/visitors-core";
function getInstructionDataFragment(scope) {
const { instructionPath, dataArgsManifest, nameApi, customInstructionData } = scope;
const instructionNode = getLastNodeFromPath7(instructionPath);
if (instructionNode.arguments.length === 0 || customInstructionData.has(instructionNode.name)) {
return fragment("");
}
const instructionDataName = nameApi.instructionDataType(instructionNode.name);
return getTypeWithCodecFragment({
manifest: dataArgsManifest,
name: instructionDataName,
nameApi,
node: structTypeNodeFromInstructionArgumentNodes2(instructionNode.arguments),
size: scope.size
});
}
// src/fragments/discriminatorConstants.ts
import {
camelCase as camelCase4,
isNode as isNode7,
isNodeFilter as isNodeFilter3,
VALUE_NODES
} from "@codama/nodes";
import { visit as visit2 } from "@codama/visitors-core";
function getDiscriminatorConstantsFragment(scope) {
const fragments = scope.discriminatorNodes.map((node) => getDiscriminatorConstantFragment(node, scope)).filter(Boolean);
return mergeFragments(fragments, (r) => r.join("\n\n"));
}
function getDiscriminatorConstantFragment(discriminatorNode, scope) {
switch (discriminatorNode.kind) {
case "constantDiscriminatorNode":
return getConstantDiscriminatorConstantFragment(discriminatorNode, scope);
case "fieldDiscriminatorNode":
return getFieldDiscriminatorConstantFragment(discriminatorNode, scope);
default:
return null;
}
}
function getConstantDiscriminatorConstantFragment(discriminatorNode, scope) {
const { discriminatorNodes, typeManifestVisitor, prefix } = scope;
const index = discriminatorNodes.filter(isNodeFilter3("constantDiscriminatorNode")).indexOf(discriminatorNode);
const suffix = index <= 0 ? "" : `_${index + 1}`;
const name = camelCase4(`${prefix}_discriminator${suffix}`);
const encoder = visit2(discriminatorNode.constant.type, typeManifestVisitor).encoder;
const value = visit2(discriminatorNode.constant.value, typeManifestVisitor).value;
return getConstantFragment({ ...scope, encoder, name, value });
}
function getFieldDiscriminatorConstantFragment(discriminatorNode, scope) {
const { fields, prefix, typeManifestVisitor } = scope;
const field = fields.find((f) => f.name === discriminatorNode.name);
if (!field || !field.defaultValue || !isNode7(field.defaultValue, VALUE_NODES)) {
return null;
}
const name = camelCase4(`${prefix}_${discriminatorNode.name}`);
const encoder = visit2(field.type, typeManifestVisitor).encoder;
const value = visit2(field.defaultValue, typeManifestVisitor).value;
return getConstantFragment({ ...scope, encoder, name, value });
}
function getConstantFragment(scope) {
const { encoder, name, nameApi, value } = scope;
const constantName = nameApi.constant(name);
const constantFunction = nameApi.constantFunction(name);
return mergeFragments(
[
value.mapRender((r) => `export const ${constantName} = ${r};`),
encoder.mapRender((r) => `export function ${constantFunction}() { return ${r}.encode(${constantName}); }`)
],
(r) => r.join("\n\n")
);
}
// src/fragments/instructionExtraArgs.ts
import { getLastNodeFromPath as getLastNodeFromPath8 } from "@codama/visitors-core";
function getInstructionExtraArgsFragment(scope) {
const { instructionPath, extraArgsManifest, nameApi } = scope;
const instructionNode = getLastNodeFromPath8(instructionPath);
if ((instructionNode.extraArguments ?? []).length === 0) {
return fragment("");
}
const instructionExtraName = nameApi.instructionExtraType(instructionNode.name);
return fragmentFromTemplate("instructionExtraArgs.njk", {
looseName: nameApi.dataArgsType(instructionExtraName),
manifest: extraArgsManifest,
strictName: nameApi.dataType(instructionExtraName)
}).mergeImportsWith(extraArgsManifest.looseType);
}
// src/fragments/instructionFunction.ts
import { camelCase as camelCase9, isNode as isNode12, isNodeFilter as isNodeFilter4, pascalCase as pascalCase5 } from "@codama/nodes";
import {
findProgramNodeFromPath as findProgramNodeFromPath3,
getLastNodeFromPath as getLastNodeFromPath12
} from "@codama/visitors-core";
// src/fragments/instructionInputResolved.ts
import { camelCase as camelCase6, isNode as isNode9, parseOptionalAccountStrategy } from "@codama/nodes";
import { getLastNodeFromPath as getLastNodeFromPath9 } from "@codama/visitors-core";
// src/fragments/instructionInputDefault.ts
import { camelCase as camelCase5, isNode as isNode8 } from "@codama/nodes";
import { visit as visit3 } from "@codama/visitors-core";
function getInstructionInputDefaultFragment(scope) {
const { input, optionalAccountStrategy, asyncResolvers, useAsync, nameApi, typeManifestVisitor, getImportFrom } = scope;
if (!input.defaultValue) {
return fragment("");
}
if (!useAsync && isAsyncDefaultValue(input.defaultValue, asyncResolvers)) {
return fragment("");
}
const { defaultValue } = input;
const defaultFragment = (renderedValue, isWritable) => {
const inputName = camelCase5(input.name);
if (input.kind === "instructionAccountNode" && isNode8(defaultValue, "resolverValueNode")) {
return fragment(`accounts.${inputName} = { ...accounts.${inputName}, ...${renderedValue} };`);
}
if (input.kind === "instructionAccountNode" && isWritable === void 0) {
return fragment(`accounts.${inputName}.value = ${renderedValue};`);
}
if (input.kind === "instructionAccountNode") {
return fragment(
`accounts.${inputName}.value = ${renderedValue};
accounts.${inputName}.isWritable = ${isWritable ? "true" : "false"}`
);
}
return fragment(`args.${inputName} = ${renderedValue};`);
};
switch (defaultValue.kind) {
case "accountValueNode":
const name = camelCase5(defaultValue.name);
if (input.kind === "instructionAccountNode" && input.resolvedIsSigner && !input.isSigner) {
return defaultFragment(`expectTransactionSigner(accounts.${name}.value).address`).addImports(
"shared",
"expectTransactionSigner"
);
}
if (input.kind === "instructionAccountNode") {
return defaultFragment(`expectSome(accounts.${name}.value)`).addImports("shared", "expectSome");
}
return defaultFragment(`expectAddress(accounts.${name}.value)`).addImports("shared", "expectAddress");
case "pdaValueNode":
if (isNode8(defaultValue.pda, "pdaNode")) {
const pdaProgram = defaultValue.pda.programId ? fragment(
`'${defaultValue.pda.programId}' as Address<'${defaultValue.pda.programId}'>`
).addImports("solanaAddresses", "type Address") : fragment("programAddress");
const pdaSeeds2 = defaultValue.pda.seeds.flatMap((seed) => {
if (isNode8(seed, "constantPdaSeedNode") && isNode8(seed.value, "programIdValueNode")) {
return [
fragment(`getAddressEncoder().encode(${pdaProgram.render})`).mergeImportsWith(pdaProgram).addImports("solanaAddresses", "getAddressEncoder")
];
}
if (isNode8(seed, "constantPdaSeedNode") && !isNode8(seed.value, "programIdValueNode")) {
const typeManifest2 = visit3(seed.type, typeManifestVisitor);
const valueManifest2 = visit3(seed.value, typeManifestVisitor);
return [
fragment(
`${typeManifest2.encoder.render}.encode(${valueManifest2.value.render})`
).mergeImportsWith(typeManifest2.encoder, valueManifest2.value)
];
}
if (isNode8(seed, "variablePdaSeedNode")) {
const typeManifest2 = visit3(seed.type, typeManifestVisitor);
const valueSeed = defaultValue.seeds.find((s) => s.name === seed.name)?.value;
if (!valueSeed) return [];
if (isNode8(valueSeed, "accountValueNode")) {
return [
fragment(
`${typeManifest2.encoder.render}.encode(expectAddress(accounts.${camelCase5(valueSeed.name)}.value))`
).mergeImportsWith(typeManifest2.encoder).addImports("shared", "expectAddress")
];
}
if (isNode8(valueSeed, "argumentValueNode")) {
return [
fragment(
`${typeManifest2.encoder.render}.encode(expectSome(args.${camelCase5(valueSeed.name)}))`
).mergeImportsWith(typeManifest2.encoder).addImports("shared", "expectSome")
];
}
const valueManifest2 = visit3(valueSeed, typeManifestVisitor);
return [
fragment(
`${typeManifest2.encoder.render}.encode(${valueManifest2.value.render})`
).mergeImportsWith(typeManifest2.encoder, valueManifest2.value)
];
}
return [];
});
const pdaStatement = mergeFragments([pdaProgram, ...pdaSeeds2], ([p, ...s]) => {
const programAddress2 = p === "programAddress" ? p : `programAddress: ${p}`;
return `await getProgramDerivedAddress({ ${programAddress2}, seeds: [${s.join(", ")}] })`;
}).addImports("solanaAddresses", "getProgramDerivedAddress");
return defaultFragment(pdaStatement.render).mergeImportsWith(pdaStatement);
}
const pdaFunction = nameApi.pdaFindFunction(defaultValue.pda.name);
const pdaArgs = [];
const pdaSeeds = defaultValue.seeds.map((seed) => {
if (isNode8(seed.value, "accountValueNode")) {
return fragment(
`${seed.name}: expectAddress(accounts.${camelCase5(seed.value.name)}.value)`
).addImports("shared", "expectAddress");
}
if (isNode8(seed.value, "argumentValueNode")) {
return fragment(`${seed.name}: expectSome(args.${camelCase5(seed.value.name)})`).addImports(
"shared",
"expectSome"
);
}
return visit3(seed.value, typeManifestVisitor).value.mapRender((r) => `${seed.name}: ${r}`);
});
const pdaSeedsFragment = mergeFragments(pdaSeeds, (renders) => renders.join(", ")).mapRender((r) => `{ ${r} }`);
if (pdaSeeds.length > 0) {
pdaArgs.push(pdaSeedsFragment.render);
}
return defaultFragment(`await ${pdaFunction}(${pdaArgs.join(", ")})`).mergeImportsWith(pdaSeedsFragment).addImports(getImportFrom(defaultValue.pda), pdaFunction);
case "publicKeyValueNode":
return defaultFragment(`'${defaultValue.publicKey}' as Address<'${defaultValue.publicKey}'>`).addImports(
"solanaAddresses",
"type Address"
);
case "programLinkNode":
const programAddress = nameApi.programAddressConstant(defaultValue.name);
return defaultFragment(programAddress, false).addImports(getImportFrom(defaultValue), programAddress);
case "programIdValueNode":
if (optionalAccountStrategy === "programId" && input.kind === "instructionAccountNode" && input.isOptional) {
return fragment("");
}
return defaultFragment("programAddress", false);
case "identityValueNode":
case "payerValueNode":
return fragment("");
case "accountBumpValueNode":
return defaultFragment(
`expectProgramDerivedAddress(accounts.${camelCase5(defaultValue.name)}.value)[1]`
).addImports("shared", "expectProgramDerivedAddress");
case "argumentValueNode":
return defaultFragment(`expectSome(args.${camelCase5(defaultValue.name)})`).addImports(
"shared",
"expectSome"
);
case "resolverValueNode":
const resolverFunction = nameApi.resolverFunction(defaultValue.name);
const resolverAwait = useAsync && asyncResolvers.includes(defaultValue.name) ? "await " : "";
return defaultFragment(`${resolverAwait}${resolverFunction}(resolverScope)`).addImports(getImportFrom(defaultValue), resolverFunction).addFeatures(["instruction:resolverScopeVariable"]);
case "conditionalValueNode":
const ifTrueRenderer = renderNestedInstructionDefault({
...scope,
defaultValue: defaultValue.ifTrue
});
const ifFalseRenderer = renderNestedInstructionDefault({
...scope,
defaultValue: defaultValue.ifFalse
});
if (!ifTrueRenderer && !ifFalseRenderer) {
return fragment("");
}
const conditionalFragment = fragment("");
if (ifTrueRenderer) {
conditionalFragment.mergeImportsWith(ifTrueRenderer).mergeFeaturesWith(ifTrueRenderer);
}
if (ifFalseRenderer) {
conditionalFragment.mergeImportsWith(ifFalseRenderer).mergeFeaturesWith(ifFalseRenderer);
}
const negatedCondition = !ifTrueRenderer;
let condition = "true";
if (isNode8(defaultValue.condition, "resolverValueNode")) {
const conditionalResolverFunction = nameApi.resolverFunction(defaultValue.condition.name);
conditionalFragment.addImports(getImportFrom(defaultValue.condition), conditionalResolverFunction).addFeatures(["instruction:resolverScopeVariable"]);
const conditionalResolverAwait = useAsync && asyncResolvers.includes(defaultValue.condition.name) ? "await " : "";
condition = `${conditionalResolverAwait}${conditionalResolverFunction}(resolverScope)`;
condition = negatedCondition ? `!${condition}` : condition;
} else {
const comparedInputName = isNode8(defaultValue.condition, "accountValueNode") ? `accounts.${camelCase5(defaultValue.condition.name)}.value` : `args.${camelCase5(defaultValue.condition.name)}`;
if (defaultValue.value) {
const comparedValue = visit3(defaultValue.value, typeManifestVisitor).value;
conditionalFragment.mergeImportsWith(comparedValue).mergeFeaturesWith(comparedValue);
const operator = negatedCondition ? "!==" : "===";
condition = `${comparedInputName} ${operator} ${comparedValue.render}`;
} else {
condition = negatedCondition ? `!${comparedInputName}` : comparedInputName;
}
}
if (ifTrueRenderer && ifFalseRenderer) {
return conditionalFragment.setRender(
`if (${condition}) {
${ifTrueRenderer.render}
} else {
${ifFalseRenderer.render}
}`
);
}
return conditionalFragment.setRender(
`if (${condition}) {
${ifTrueRenderer ? ifTrueRenderer.render : ifFalseRenderer?.render}
}`
);
default:
const valueManifest = visit3(defaultValue, typeManifestVisitor).value;
return defaultFragment(valueManifest.render).mergeImportsWith(valueManifest);
}
}
function renderNestedInstructionDefault(scope) {
const { input, defaultValue } = scope;
if (!defaultValue) return void 0;
return getInstructionInputDefaultFragment({
...scope,
input: { ...input, defaultValue }
});
}
// src/fragments/instructionInputResolved.ts
function getInstructionInputResolvedFragment(scope) {
const instructionNode = getLastNodeFromPath9(scope.instructionPath);
const resolvedInputFragments = scope.resolvedInputs.flatMap((input) => {
const inputFragment = getInstructionInputDefaultFragment({
...scope,
input,
optionalAccountStrategy: parseOptionalAccountStrategy(instructionNode.optionalAccountStrategy)
});
if (!inputFragment.render) return [];
const camelName = camelCase6(input.name);
return [
inputFragment.mapRender(
(r) => isNode9(input, "instructionArgumentNode") ? `if (!args.${camelName}) {
${r}
}` : `if (!accounts.${camelName}.value) {
${r}
}`
)
];
});
if (resolvedInputFragments.length === 0) {
return fragment("");
}
return mergeFragments(
[fragment("// Resolve default values."), ...resolvedInputFragments],
(renders) => renders.join("\n")
);
}
// src/fragments/instructionInputType.ts
import {
camelCase as camelCase7,
getAllInstructionArguments,
isNode as isNode10,
parseDocs,
pascalCase as pascalCase4
} from "@codama/nodes";
import {
getLastNodeFromPath as getLastNodeFromPath10
} from "@codama/visitors-core";
function getInstructionInputTypeFragment(scope) {
const { instructionPath, useAsync, nameApi } = scope;
const instructionNode = getLastNodeFromPath10(instructionPath);
const instructionInputType = useAsync ? nameApi.instructionAsyncInputType(instructionNode.name) : nameApi.instructionSyncInputType(instructionNode.name);
const accountsFragment = getAccountsFragment(scope);
const [dataArgumentsFragment, customDataArgumentsFragment] = getDataArgumentsFragments(scope);
const extraArgumentsFragment = getExtraArgumentsFragment(scope);
const remainingAccountsFragment = getRemainingAccountsFragment(instructionNode);
return fragmentFromTemplate("instructionInputType.njk", {
accountsFragment,
customDataArgumentsFragment,
dataArgumentsFragment,
extraArgumentsFragment,
instruction: instructionNode,
instructionInputType,
remainingAccountsFragment
}).mergeImportsWith(
accountsFragment,
dataArgumentsFragment,
customDataArgumentsFragment,
extraArgumentsFragment,
remainingAccountsFragment
).addImports("solanaAddresses", ["type Address"]);
}
function getAccountsFragment(scope) {
const { instructionPath, resolvedInputs, useAsync, asyncResolvers } = scope;
const instructionNode = getLastNodeFromPath10(instructionPath);
const fragments = instructionNode.accounts.map((account) => {
const resolvedAccount = resolvedInputs.find(
(input) => input.kind === "instructionAccountNode" && input.name === account.name
);
const hasDefaultValue = !!resolvedAccount.defaultValue && !isNode10(resolvedAccount.defaultValue, ["identityValueNode", "payerValueNode"]) && (useAsync || !isAsyncDefaultValue(resolvedAccount.defaultValue, asyncResolvers));
const accountDocs = parseDocs(account.docs);
const docblock = accountDocs.length > 0 ? jsDocblock(accountDocs) : "";
const optionalSign = hasDefaultValue || resolvedAccount.isOptional ? "?" : "";
return getAccountTypeFragment2(resolvedAccount).mapRender(
(r) => `${docblock}${camelCase7(account.name)}${optionalSign}: ${r};`
);
});
return mergeFragments(fragments, (r) => r.join("\n"));
}
function getAccountTypeFragment2(account) {
const typeParam = `TAccount${pascalCase4(account.name)}`;
if (account.isPda && account.isSigner === false) {
return fragment(`ProgramDerivedAddress<${typeParam}>`).addImports("solanaAddresses", [
"type ProgramDerivedAddress"
]);
}
if (account.isPda && account.isSigner === "either") {
return fragment(`ProgramDerivedAddress<${typeParam}> | TransactionSigner<${typeParam}>`).addImports("solanaAddresses", ["type ProgramDerivedAddress"]).addImports("solanaSigners", ["type TransactionSigner"]);
}
if (account.isSigner === "either") {
return fragment(`Address<${typeParam}> | TransactionSigner<${typeParam}>`).addImports("solanaAddresses", ["type Address"]).addImports("solanaSigners", ["type TransactionSigner"]);
}
if (account.isSigner) {
return fragment(`TransactionSigner<${typeParam}>`).addImpor