@codama/renderers-js 1.0.1 → 1.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. package/dist/index.node.cjs +110 -95
  2. package/dist/index.node.cjs.map +1 -1
  3. package/dist/index.node.mjs +112 -97
  4. package/dist/index.node.mjs.map +1 -1
  5. package/dist/types/fragments/accountFetchHelpers.d.ts +2 -1
  6. package/dist/types/fragments/accountFetchHelpers.d.ts.map +1 -1
  7. package/dist/types/fragments/accountPdaHelpers.d.ts +3 -3
  8. package/dist/types/fragments/accountPdaHelpers.d.ts.map +1 -1
  9. package/dist/types/fragments/accountSizeHelpers.d.ts +2 -1
  10. package/dist/types/fragments/accountSizeHelpers.d.ts.map +1 -1
  11. package/dist/types/fragments/accountType.d.ts +2 -1
  12. package/dist/types/fragments/accountType.d.ts.map +1 -1
  13. package/dist/types/fragments/instructionAccountTypeParam.d.ts +3 -4
  14. package/dist/types/fragments/instructionAccountTypeParam.d.ts.map +1 -1
  15. package/dist/types/fragments/instructionByteDelta.d.ts +2 -1
  16. package/dist/types/fragments/instructionByteDelta.d.ts.map +1 -1
  17. package/dist/types/fragments/instructionData.d.ts +2 -1
  18. package/dist/types/fragments/instructionData.d.ts.map +1 -1
  19. package/dist/types/fragments/instructionExtraArgs.d.ts +2 -1
  20. package/dist/types/fragments/instructionExtraArgs.d.ts.map +1 -1
  21. package/dist/types/fragments/instructionFunction.d.ts +3 -4
  22. package/dist/types/fragments/instructionFunction.d.ts.map +1 -1
  23. package/dist/types/fragments/instructionInputDefault.d.ts.map +1 -1
  24. package/dist/types/fragments/instructionInputResolved.d.ts +2 -2
  25. package/dist/types/fragments/instructionInputResolved.d.ts.map +1 -1
  26. package/dist/types/fragments/instructionInputType.d.ts +2 -2
  27. package/dist/types/fragments/instructionInputType.d.ts.map +1 -1
  28. package/dist/types/fragments/instructionParseFunction.d.ts +3 -3
  29. package/dist/types/fragments/instructionParseFunction.d.ts.map +1 -1
  30. package/dist/types/fragments/instructionRemainingAccounts.d.ts +2 -1
  31. package/dist/types/fragments/instructionRemainingAccounts.d.ts.map +1 -1
  32. package/dist/types/fragments/instructionType.d.ts +3 -3
  33. package/dist/types/fragments/instructionType.d.ts.map +1 -1
  34. package/dist/types/fragments/pdaFunction.d.ts +3 -3
  35. package/dist/types/fragments/pdaFunction.d.ts.map +1 -1
  36. package/dist/types/getRenderMapVisitor.d.ts.map +1 -1
  37. package/dist/types/getTypeManifestVisitor.d.ts +2 -5
  38. package/dist/types/getTypeManifestVisitor.d.ts.map +1 -1
  39. package/dist/types/renderVisitor.d.ts.map +1 -1
  40. package/package.json +7 -7
@@ -1,8 +1,8 @@
1
+ import { NodeStack, pipe, staticVisitor, extendVisitor, visit, findLastNodeFromPath, recordNodeStackVisitor, LinkableDictionary, getResolvedInstructionInputsVisitor, findProgramNodeFromPath, recordLinkablesOnFirstVisitVisitor, rootNodeVisitor, getLastNodeFromPath, deduplicateInstructionDependencies, findInstructionNodeFromPath } from '@codama/visitors-core';
1
2
  import { join, dirname } from 'node:path';
2
- import { REGISTERED_TYPE_NODE_KINDS, REGISTERED_VALUE_NODE_KINDS, resolveNestedTypeNode, isNode, camelCase, structTypeNode, structFieldTypeNode, isScalarEnum, structTypeNodeFromInstructionArgumentNodes, isNodeFilter, pascalCase, snakeCase, getAllInstructionsWithSubs, getAllPrograms, getAllPdas, getAllAccounts, getAllDefinedTypes, definedTypeLinkNode, definedTypeNode, isDataEnum, capitalize, kebabCase, titleCase, constantDiscriminatorNode, constantValueNodeFromBytes, constantValueNode, VALUE_NODES, accountValueNode, argumentValueNode, assertIsNode, getAllInstructionArguments } from '@codama/nodes';
3
- import { NodeStack, pipe, staticVisitor, extendVisitor, visit, recordNodeStackVisitor, LinkableDictionary, getResolvedInstructionInputsVisitor, recordLinkablesVisitor, rootNodeVisitor, deduplicateInstructionDependencies } from '@codama/visitors-core';
3
+ import { REGISTERED_TYPE_NODE_KINDS, REGISTERED_VALUE_NODE_KINDS, resolveNestedTypeNode, isNode, camelCase, structTypeNode, structFieldTypeNode, isScalarEnum, structTypeNodeFromInstructionArgumentNodes, isNodeFilter, pascalCase, snakeCase, definedTypeNode, getAllInstructionsWithSubs, getAllPrograms, getAllPdas, getAllAccounts, getAllDefinedTypes, definedTypeLinkNode, VALUE_NODES, isDataEnum, capitalize, kebabCase, titleCase, accountValueNode, argumentValueNode, constantDiscriminatorNode, constantValueNodeFromBytes, constantValueNode, assertIsNode, getAllInstructionArguments } from '@codama/nodes';
4
4
  import { getBase64Encoder, getBase58Encoder, getBase16Encoder, getUtf8Encoder, getBase64Decoder } from '@solana/codecs-strings';
5
- import { CodamaError, CODAMA_ERROR__UNEXPECTED_NODE_KIND, logWarn } from '@codama/errors';
5
+ import { logWarn, CodamaError, CODAMA_ERROR__UNEXPECTED_NODE_KIND } from '@codama/errors';
6
6
  import { fileURLToPath } from 'node:url';
7
7
  import nunjucks from 'nunjucks';
8
8
  import { RenderMap, deleteDirectory } from '@codama/renderers-core';
@@ -398,7 +398,8 @@ var Fragment = class _Fragment {
398
398
 
399
399
  // src/fragments/accountFetchHelpers.ts
400
400
  function getAccountFetchHelpersFragment(scope) {
401
- const { accountNode, typeManifest: typeManifest2, nameApi, customAccountData } = scope;
401
+ const { accountPath, typeManifest: typeManifest2, nameApi, customAccountData } = scope;
402
+ const accountNode = getLastNodeFromPath(accountPath);
402
403
  const hasCustomData = customAccountData.has(accountNode.name);
403
404
  const accountTypeFragment = hasCustomData ? typeManifest2.strictType.clone() : fragment(nameApi.dataType(accountNode.name));
404
405
  const decoderFunctionFragment = hasCustomData ? typeManifest2.decoder.clone() : fragment(`${nameApi.decoderFunction(accountNode.name)}()`);
@@ -425,8 +426,10 @@ function getAccountFetchHelpersFragment(scope) {
425
426
  ]);
426
427
  }
427
428
  function getAccountPdaHelpersFragment(scope) {
428
- const { accountNode, programNode, nameApi, linkables, customAccountData, typeManifest: typeManifest2 } = scope;
429
- const pdaNode = accountNode.pda ? linkables.get(accountNode.pda) : void 0;
429
+ const { accountPath, nameApi, linkables, customAccountData, typeManifest: typeManifest2 } = scope;
430
+ const accountNode = getLastNodeFromPath(accountPath);
431
+ const programNode = findProgramNodeFromPath(accountPath);
432
+ const pdaNode = accountNode.pda ? linkables.get([...accountPath, accountNode.pda]) : void 0;
430
433
  if (!pdaNode) {
431
434
  return fragment("");
432
435
  }
@@ -452,10 +455,9 @@ function getAccountPdaHelpersFragment(scope) {
452
455
  "type MaybeAccount"
453
456
  ]);
454
457
  }
455
-
456
- // src/fragments/accountSizeHelpers.ts
457
458
  function getAccountSizeHelpersFragment(scope) {
458
- const { accountNode, nameApi } = scope;
459
+ const { accountPath, nameApi } = scope;
460
+ const accountNode = getLastNodeFromPath(accountPath);
459
461
  if (accountNode.size == null) {
460
462
  return fragment("");
461
463
  }
@@ -535,7 +537,8 @@ function getTypeWithCodecFragment(scope) {
535
537
 
536
538
  // src/fragments/accountType.ts
537
539
  function getAccountTypeFragment(scope) {
538
- const { accountNode, typeManifest: typeManifest2, nameApi, customAccountData } = scope;
540
+ const { accountPath, typeManifest: typeManifest2, nameApi, customAccountData } = scope;
541
+ const accountNode = getLastNodeFromPath(accountPath);
539
542
  if (customAccountData.has(accountNode.name)) {
540
543
  return fragment("");
541
544
  }
@@ -606,7 +609,10 @@ function getInstructionAccountMetaFragment(instructionAccountNode) {
606
609
  return fragment(`ReadonlyAccount<${typeParam}>`).addImports("solanaInstructions", "type ReadonlyAccount");
607
610
  }
608
611
  function getInstructionAccountTypeParamFragment(scope) {
609
- const { instructionNode, instructionAccountNode, programNode, allowAccountMeta, linkables } = scope;
612
+ const { instructionAccountPath, allowAccountMeta, linkables } = scope;
613
+ const instructionAccountNode = getLastNodeFromPath(instructionAccountPath);
614
+ const instructionNode = findInstructionNodeFromPath(instructionAccountPath);
615
+ const programNode = findProgramNodeFromPath(instructionAccountPath);
610
616
  const typeParam = `TAccount${pascalCase(instructionAccountNode.name)}`;
611
617
  const accountMeta = allowAccountMeta ? " | IAccountMeta<string>" : "";
612
618
  const imports = new ImportMap();
@@ -624,7 +630,7 @@ function getDefaultAddress(defaultValue, programId, linkables) {
624
630
  case "publicKeyValueNode":
625
631
  return `"${defaultValue.publicKey}"`;
626
632
  case "programLinkNode":
627
- const programNode = linkables.get(defaultValue);
633
+ const programNode = linkables.get([defaultValue]);
628
634
  return programNode ? `"${programNode.publicKey}"` : "string";
629
635
  case "programIdValueNode":
630
636
  return `"${programId}"`;
@@ -633,7 +639,7 @@ function getDefaultAddress(defaultValue, programId, linkables) {
633
639
  }
634
640
  }
635
641
  function getInstructionByteDeltaFragment(scope) {
636
- const { byteDeltas } = scope.instructionNode;
642
+ const { byteDeltas } = getLastNodeFromPath(scope.instructionPath);
637
643
  const fragments = (byteDeltas ?? []).flatMap((r) => getByteDeltaFragment(r, scope));
638
644
  if (fragments.length === 0) return fragment("");
639
645
  return mergeFragments(
@@ -689,10 +695,9 @@ function getResolverValueNodeFragment(byteDelta, scope) {
689
695
  const functionName = scope.nameApi.resolverFunction(byteDelta.value.name);
690
696
  return fragment(`${awaitKeyword}${functionName}(resolverScope)`).addImports(scope.getImportFrom(byteDelta.value), functionName).addFeatures(["instruction:resolverScopeVariable"]);
691
697
  }
692
-
693
- // src/fragments/instructionData.ts
694
698
  function getInstructionDataFragment(scope) {
695
- const { instructionNode, dataArgsManifest, nameApi, customInstructionData } = scope;
699
+ const { instructionPath, dataArgsManifest, nameApi, customInstructionData } = scope;
700
+ const instructionNode = getLastNodeFromPath(instructionPath);
696
701
  if (instructionNode.arguments.length === 0 || customInstructionData.has(instructionNode.name)) {
697
702
  return fragment("");
698
703
  }
@@ -749,10 +754,9 @@ function getConstantFragment(scope) {
749
754
  (r) => r.join("\n\n")
750
755
  );
751
756
  }
752
-
753
- // src/fragments/instructionExtraArgs.ts
754
757
  function getInstructionExtraArgsFragment(scope) {
755
- const { instructionNode, extraArgsManifest, nameApi } = scope;
758
+ const { instructionPath, extraArgsManifest, nameApi } = scope;
759
+ const instructionNode = getLastNodeFromPath(instructionPath);
756
760
  if ((instructionNode.extraArguments ?? []).length === 0) {
757
761
  return fragment("");
758
762
  }
@@ -809,17 +813,16 @@ accounts.${inputName}.isWritable = ${isWritable ? "true" : "false"}`
809
813
  const pdaSeeds2 = defaultValue.pda.seeds.flatMap((seed) => {
810
814
  if (isNode(seed, "constantPdaSeedNode") && isNode(seed.value, "programIdValueNode")) {
811
815
  return [
812
- fragment(`getAddressEncoder().encode(${pdaProgram})`).mergeImportsWith(pdaProgram).addImports("solanaAddresses", "getAddressEncoder")
816
+ fragment(`getAddressEncoder().encode(${pdaProgram.render})`).mergeImportsWith(pdaProgram).addImports("solanaAddresses", "getAddressEncoder")
813
817
  ];
814
818
  }
815
819
  if (isNode(seed, "constantPdaSeedNode") && !isNode(seed.value, "programIdValueNode")) {
816
820
  const typeManifest2 = visit(seed.type, typeManifestVisitor);
817
821
  const valueManifest2 = visit(seed.value, typeManifestVisitor);
818
822
  return [
819
- fragment(`${typeManifest2.encoder}.encode(${valueManifest2.value})`).mergeImportsWith(
820
- typeManifest2.encoder,
821
- valueManifest2.value
822
- )
823
+ fragment(
824
+ `${typeManifest2.encoder.render}.encode(${valueManifest2.value.render})`
825
+ ).mergeImportsWith(typeManifest2.encoder, valueManifest2.value)
823
826
  ];
824
827
  }
825
828
  if (isNode(seed, "variablePdaSeedNode")) {
@@ -829,23 +832,22 @@ accounts.${inputName}.isWritable = ${isWritable ? "true" : "false"}`
829
832
  if (isNode(valueSeed, "accountValueNode")) {
830
833
  return [
831
834
  fragment(
832
- `${typeManifest2.encoder}.encode(expectAddress(accounts.${camelCase(valueSeed.name)}.value))`
835
+ `${typeManifest2.encoder.render}.encode(expectAddress(accounts.${camelCase(valueSeed.name)}.value))`
833
836
  ).mergeImportsWith(typeManifest2.encoder).addImports("shared", "expectAddress")
834
837
  ];
835
838
  }
836
839
  if (isNode(valueSeed, "argumentValueNode")) {
837
840
  return [
838
841
  fragment(
839
- `${typeManifest2.encoder}.encode(expectSome(args.${camelCase(valueSeed.name)}))`
842
+ `${typeManifest2.encoder.render}.encode(expectSome(args.${camelCase(valueSeed.name)}))`
840
843
  ).mergeImportsWith(typeManifest2.encoder).addImports("shared", "expectSome")
841
844
  ];
842
845
  }
843
846
  const valueManifest2 = visit(valueSeed, typeManifestVisitor);
844
847
  return [
845
- fragment(`${typeManifest2.encoder}.encode(${valueManifest2.value})`).mergeImportsWith(
846
- typeManifest2.encoder,
847
- valueManifest2.value
848
- )
848
+ fragment(
849
+ `${typeManifest2.encoder.render}.encode(${valueManifest2.value.render})`
850
+ ).mergeImportsWith(typeManifest2.encoder, valueManifest2.value)
849
851
  ];
850
852
  }
851
853
  return [];
@@ -974,11 +976,12 @@ function renderNestedInstructionDefault(scope) {
974
976
 
975
977
  // src/fragments/instructionInputResolved.ts
976
978
  function getInstructionInputResolvedFragment(scope) {
979
+ const instructionNode = getLastNodeFromPath(scope.instructionPath);
977
980
  const resolvedInputFragments = scope.resolvedInputs.flatMap((input) => {
978
981
  const inputFragment = getInstructionInputDefaultFragment({
979
982
  ...scope,
980
983
  input,
981
- optionalAccountStrategy: scope.instructionNode.optionalAccountStrategy
984
+ optionalAccountStrategy: instructionNode.optionalAccountStrategy
982
985
  });
983
986
  if (!inputFragment.render) return [];
984
987
  const camelName = camelCase(input.name);
@@ -1001,7 +1004,8 @@ ${r}
1001
1004
  );
1002
1005
  }
1003
1006
  function getInstructionInputTypeFragment(scope) {
1004
- const { instructionNode, useAsync, nameApi } = scope;
1007
+ const { instructionPath, useAsync, nameApi } = scope;
1008
+ const instructionNode = getLastNodeFromPath(instructionPath);
1005
1009
  const instructionInputType = useAsync ? nameApi.instructionAsyncInputType(instructionNode.name) : nameApi.instructionSyncInputType(instructionNode.name);
1006
1010
  const accountsFragment = getAccountsFragment(scope);
1007
1011
  const [dataArgumentsFragment, customDataArgumentsFragment] = getDataArgumentsFragments(scope);
@@ -1024,7 +1028,8 @@ function getInstructionInputTypeFragment(scope) {
1024
1028
  ).addImports("solanaAddresses", ["type Address"]);
1025
1029
  }
1026
1030
  function getAccountsFragment(scope) {
1027
- const { instructionNode, resolvedInputs, useAsync, asyncResolvers } = scope;
1031
+ const { instructionPath, resolvedInputs, useAsync, asyncResolvers } = scope;
1032
+ const instructionNode = getLastNodeFromPath(instructionPath);
1028
1033
  const fragments = instructionNode.accounts.map((account) => {
1029
1034
  const resolvedAccount = resolvedInputs.find(
1030
1035
  (input) => input.kind === "instructionAccountNode" && input.name === account.name
@@ -1057,7 +1062,8 @@ function getAccountTypeFragment2(account) {
1057
1062
  return fragment(`Address<${typeParam}>`).addImports("solanaAddresses", ["type Address"]);
1058
1063
  }
1059
1064
  function getDataArgumentsFragments(scope) {
1060
- const { instructionNode, nameApi } = scope;
1065
+ const { instructionPath, nameApi } = scope;
1066
+ const instructionNode = getLastNodeFromPath(instructionPath);
1061
1067
  const customData = scope.customInstructionData.get(instructionNode.name);
1062
1068
  if (customData) {
1063
1069
  return [
@@ -1074,7 +1080,8 @@ function getDataArgumentsFragments(scope) {
1074
1080
  return [mergeFragments(fragments, (r) => r.join("\n")), fragment("")];
1075
1081
  }
1076
1082
  function getExtraArgumentsFragment(scope) {
1077
- const { instructionNode, nameApi } = scope;
1083
+ const { instructionPath, nameApi } = scope;
1084
+ const instructionNode = getLastNodeFromPath(instructionPath);
1078
1085
  const instructionExtraName = nameApi.instructionExtraType(instructionNode.name);
1079
1086
  const extraArgsType = nameApi.dataArgsType(instructionExtraName);
1080
1087
  const fragments = (instructionNode.extraArguments ?? []).flatMap((arg) => {
@@ -1113,7 +1120,7 @@ function getRemainingAccountsFragment(instructionNode) {
1113
1120
  return mergeFragments(fragments, (r) => r.join("\n"));
1114
1121
  }
1115
1122
  function getInstructionRemainingAccountsFragment(scope) {
1116
- const { remainingAccounts } = scope.instructionNode;
1123
+ const { remainingAccounts } = getLastNodeFromPath(scope.instructionPath);
1117
1124
  const fragments = (remainingAccounts ?? []).flatMap((r) => getRemainingAccountsFragment2(r, scope));
1118
1125
  if (fragments.length === 0) return fragment("");
1119
1126
  return mergeFragments(
@@ -1136,7 +1143,7 @@ function getRemainingAccountsFragment2(remainingAccounts, scope) {
1136
1143
  return [remainingAccountsFragment];
1137
1144
  }
1138
1145
  function getArgumentValueNodeFragment2(remainingAccounts, scope) {
1139
- const { instructionNode } = scope;
1146
+ const instructionNode = getLastNodeFromPath(scope.instructionPath);
1140
1147
  assertIsNode(remainingAccounts.value, "argumentValueNode");
1141
1148
  const argumentName = camelCase(remainingAccounts.value.name);
1142
1149
  const isOptional = remainingAccounts.isOptional ?? false;
@@ -1179,8 +1186,7 @@ function getResolverValueNodeFragment2(remainingAccounts, scope) {
1179
1186
  function getInstructionFunctionFragment(scope) {
1180
1187
  const {
1181
1188
  useAsync,
1182
- instructionNode,
1183
- programNode,
1189
+ instructionPath,
1184
1190
  resolvedInputs,
1185
1191
  renamedArgs,
1186
1192
  dataArgsManifest,
@@ -1188,6 +1194,8 @@ function getInstructionFunctionFragment(scope) {
1188
1194
  nameApi,
1189
1195
  customInstructionData
1190
1196
  } = scope;
1197
+ const instructionNode = getLastNodeFromPath(instructionPath);
1198
+ const programNode = findProgramNodeFromPath(instructionPath);
1191
1199
  if (useAsync && !hasAsyncFunction(instructionNode, resolvedInputs, asyncResolvers)) {
1192
1200
  return fragment("");
1193
1201
  }
@@ -1289,7 +1297,8 @@ function getTypeParams(instructionNode, programAddressConstant) {
1289
1297
  return fragment(typeParams.filter((x) => !!x).join(", ")).mapRender((r) => `<${r}>`).addImports("generatedPrograms", [programAddressConstant]);
1290
1298
  }
1291
1299
  function getInstructionType(scope) {
1292
- const { instructionNode, nameApi } = scope;
1300
+ const { instructionPath, nameApi } = scope;
1301
+ const instructionNode = getLastNodeFromPath(instructionPath);
1293
1302
  const instructionTypeName = nameApi.instructionType(instructionNode.name);
1294
1303
  const programAddressFragment = fragment("TProgramAddress");
1295
1304
  const accountTypeParamsFragments = instructionNode.accounts.map((account) => {
@@ -1309,16 +1318,17 @@ function getInstructionType(scope) {
1309
1318
  ).mapRender((r) => `${instructionTypeName}<${r}>`);
1310
1319
  }
1311
1320
  function getInputTypeCall(scope) {
1312
- const { instructionNode, useAsync, nameApi } = scope;
1321
+ const { instructionPath, useAsync, nameApi } = scope;
1322
+ const instructionNode = getLastNodeFromPath(instructionPath);
1313
1323
  const inputTypeName = useAsync ? nameApi.instructionAsyncInputType(instructionNode.name) : nameApi.instructionSyncInputType(instructionNode.name);
1314
1324
  if (instructionNode.accounts.length === 0) return fragment(inputTypeName);
1315
1325
  const accountTypeParams = instructionNode.accounts.map((account) => `TAccount${pascalCase(account.name)}`).join(", ");
1316
1326
  return fragment(`${inputTypeName}<${accountTypeParams}>`);
1317
1327
  }
1318
-
1319
- // src/fragments/instructionParseFunction.ts
1320
1328
  function getInstructionParseFunctionFragment(scope) {
1321
- const { instructionNode, programNode, dataArgsManifest, nameApi, customInstructionData } = scope;
1329
+ const { instructionPath, dataArgsManifest, nameApi, customInstructionData } = scope;
1330
+ const instructionNode = getLastNodeFromPath(instructionPath);
1331
+ const programNode = findProgramNodeFromPath(instructionPath);
1322
1332
  const customData = customInstructionData.get(instructionNode.name);
1323
1333
  const hasAccounts = instructionNode.accounts.length > 0;
1324
1334
  const hasOptionalAccounts = instructionNode.accounts.some((account) => account.isOptional);
@@ -1347,7 +1357,9 @@ function getInstructionParseFunctionFragment(scope) {
1347
1357
  }).mergeImportsWith(dataTypeFragment).addImports("generatedPrograms", [programAddressConstant]).addImports("solanaInstructions", ["type IInstruction"]).addImports("solanaInstructions", hasAccounts ? ["type IInstructionWithAccounts", "type IAccountMeta"] : []).addImports("solanaInstructions", hasData ? ["type IInstructionWithData"] : []);
1348
1358
  }
1349
1359
  function getInstructionTypeFragment(scope) {
1350
- const { instructionNode, programNode, nameApi, customInstructionData } = scope;
1360
+ const { instructionPath, nameApi, customInstructionData } = scope;
1361
+ const instructionNode = getLastNodeFromPath(instructionPath);
1362
+ const programNode = findProgramNodeFromPath(instructionPath);
1351
1363
  const hasAccounts = instructionNode.accounts.length > 0;
1352
1364
  const customData = customInstructionData.get(instructionNode.name);
1353
1365
  const hasData = !!customData || instructionNode.arguments.length > 0;
@@ -1359,7 +1371,7 @@ function getInstructionTypeFragment(scope) {
1359
1371
  (account) => getInstructionAccountTypeParamFragment({
1360
1372
  ...scope,
1361
1373
  allowAccountMeta: true,
1362
- instructionAccountNode: account
1374
+ instructionAccountPath: [...instructionPath, account]
1363
1375
  })
1364
1376
  ),
1365
1377
  (renders) => renders.join(", ")
@@ -1395,7 +1407,9 @@ function getInstructionTypeFragment(scope) {
1395
1407
  return fragment2;
1396
1408
  }
1397
1409
  function getPdaFunctionFragment(scope) {
1398
- const { pdaNode, programNode, typeManifestVisitor, nameApi } = scope;
1410
+ const { pdaPath, typeManifestVisitor, nameApi } = scope;
1411
+ const pdaNode = getLastNodeFromPath(pdaPath);
1412
+ const programNode = findProgramNodeFromPath(pdaPath);
1399
1413
  const imports = new ImportMap();
1400
1414
  const seeds = pdaNode.seeds.map((seed) => {
1401
1415
  if (isNode(seed, "variablePdaSeedNode")) {
@@ -1614,8 +1628,8 @@ function mergeManifests(manifests, options = {}) {
1614
1628
  }
1615
1629
  function getTypeManifestVisitor(input) {
1616
1630
  const { nameApi, linkables, nonScalarEnums, customAccountData, customInstructionData, getImportFrom } = input;
1617
- const stack = new NodeStack();
1618
- let parentName = input.parentName ?? null;
1631
+ const stack = input.stack ?? new NodeStack();
1632
+ let parentName = null;
1619
1633
  return pipe(
1620
1634
  staticVisitor(
1621
1635
  () => ({
@@ -1626,14 +1640,16 @@ function getTypeManifestVisitor(input) {
1626
1640
  strictType: fragment(""),
1627
1641
  value: fragment("")
1628
1642
  }),
1629
- [
1630
- ...REGISTERED_TYPE_NODE_KINDS,
1631
- ...REGISTERED_VALUE_NODE_KINDS,
1632
- "definedTypeLinkNode",
1633
- "definedTypeNode",
1634
- "accountNode",
1635
- "instructionNode"
1636
- ]
1643
+ {
1644
+ keys: [
1645
+ ...REGISTERED_TYPE_NODE_KINDS,
1646
+ ...REGISTERED_VALUE_NODE_KINDS,
1647
+ "definedTypeLinkNode",
1648
+ "definedTypeNode",
1649
+ "accountNode",
1650
+ "instructionNode"
1651
+ ]
1652
+ }
1637
1653
  ),
1638
1654
  (visitor) => extendVisitor(visitor, {
1639
1655
  visitAccount(account, { self }) {
@@ -1878,7 +1894,7 @@ function getTypeManifestVisitor(input) {
1878
1894
  const enumName = nameApi.dataType(node.enum.name);
1879
1895
  const enumFunction = nameApi.discriminatedUnionFunction(node.enum.name);
1880
1896
  const importFrom = getImportFrom(node.enum);
1881
- const enumNode = linkables.get(node.enum)?.type;
1897
+ const enumNode = linkables.get([...stack.getPath(), node.enum])?.type;
1882
1898
  const isScalar = enumNode && isNode(enumNode, "enumTypeNode") ? isScalarEnum(enumNode) : !nonScalarEnums.includes(node.enum.name);
1883
1899
  if (!node.value && isScalar) {
1884
1900
  const variantName2 = nameApi.enumVariant(node.variant);
@@ -1902,19 +1918,19 @@ function getTypeManifestVisitor(input) {
1902
1918
  visitHiddenPrefixType(node, { self }) {
1903
1919
  const manifest = visit(node.type, self);
1904
1920
  const prefixes = node.prefix.map((c) => visit(c, self).value);
1905
- const prefixEncoders = fragment(prefixes.map((c) => `getConstantEncoder(${c})`).join(", ")).addImports("solanaCodecsCore", "getConstantEncoder").mergeImportsWith(...prefixes);
1906
- const prefixDecoders = fragment(prefixes.map((c) => `getConstantDecoder(${c})`).join(", ")).addImports("solanaCodecsCore", "getConstantDecoder").mergeImportsWith(...prefixes);
1907
- manifest.encoder.mapRender((r) => `getHiddenPrefixEncoder(${r}, [${prefixEncoders}])`).mergeImportsWith(prefixEncoders).addImports("solanaCodecsDataStructures", "getHiddenPrefixEncoder");
1908
- manifest.decoder.mapRender((r) => `getHiddenPrefixDecoder(${r}, [${prefixDecoders}])`).mergeImportsWith(prefixDecoders).addImports("solanaCodecsDataStructures", "getHiddenPrefixDecoder");
1921
+ const prefixEncoders = fragment(prefixes.map((c) => `getConstantEncoder(${c.render})`).join(", ")).addImports("solanaCodecsCore", "getConstantEncoder").mergeImportsWith(...prefixes);
1922
+ const prefixDecoders = fragment(prefixes.map((c) => `getConstantDecoder(${c.render})`).join(", ")).addImports("solanaCodecsCore", "getConstantDecoder").mergeImportsWith(...prefixes);
1923
+ manifest.encoder.mapRender((r) => `getHiddenPrefixEncoder(${r}, [${prefixEncoders.render}])`).mergeImportsWith(prefixEncoders).addImports("solanaCodecsDataStructures", "getHiddenPrefixEncoder");
1924
+ manifest.decoder.mapRender((r) => `getHiddenPrefixDecoder(${r}, [${prefixDecoders.render}])`).mergeImportsWith(prefixDecoders).addImports("solanaCodecsDataStructures", "getHiddenPrefixDecoder");
1909
1925
  return manifest;
1910
1926
  },
1911
1927
  visitHiddenSuffixType(node, { self }) {
1912
1928
  const manifest = visit(node.type, self);
1913
1929
  const suffixes = node.suffix.map((c) => visit(c, self).value);
1914
- const suffixEncoders = fragment(suffixes.map((c) => `getConstantEncoder(${c})`).join(", ")).addImports("solanaCodecsCore", "getConstantEncoder").mergeImportsWith(...suffixes);
1915
- const suffixDecoders = fragment(suffixes.map((c) => `getConstantDecoder(${c})`).join(", ")).addImports("solanaCodecsCore", "getConstantDecoder").mergeImportsWith(...suffixes);
1916
- manifest.encoder.mapRender((r) => `getHiddenSuffixEncoder(${r}, [${suffixEncoders}])`).mergeImportsWith(suffixEncoders).addImports("solanaCodecsDataStructures", "getHiddenSuffixEncoder");
1917
- manifest.decoder.mapRender((r) => `getHiddenSuffixDecoder(${r}, [${suffixDecoders}])`).mergeImportsWith(suffixDecoders).addImports("solanaCodecsDataStructures", "getHiddenSuffixDecoder");
1930
+ const suffixEncoders = fragment(suffixes.map((c) => `getConstantEncoder(${c.render})`).join(", ")).addImports("solanaCodecsCore", "getConstantEncoder").mergeImportsWith(...suffixes);
1931
+ const suffixDecoders = fragment(suffixes.map((c) => `getConstantDecoder(${c.render})`).join(", ")).addImports("solanaCodecsCore", "getConstantDecoder").mergeImportsWith(...suffixes);
1932
+ manifest.encoder.mapRender((r) => `getHiddenSuffixEncoder(${r}, [${suffixEncoders.render}])`).mergeImportsWith(suffixEncoders).addImports("solanaCodecsDataStructures", "getHiddenSuffixEncoder");
1933
+ manifest.decoder.mapRender((r) => `getHiddenSuffixDecoder(${r}, [${suffixDecoders.render}])`).mergeImportsWith(suffixDecoders).addImports("solanaCodecsDataStructures", "getHiddenSuffixDecoder");
1918
1934
  return manifest;
1919
1935
  },
1920
1936
  visitInstruction(instruction, { self }) {
@@ -2082,8 +2098,8 @@ function getTypeManifestVisitor(input) {
2082
2098
  visitSentinelType(node, { self }) {
2083
2099
  const manifest = visit(node.type, self);
2084
2100
  const sentinel = visit(node.sentinel, self).value;
2085
- manifest.encoder.mapRender((r) => `addEncoderSentinel(${r}, ${sentinel})`).mergeImportsWith(sentinel).addImports("solanaCodecsCore", "addEncoderSentinel");
2086
- manifest.decoder.mapRender((r) => `addDecoderSentinel(${r}, ${sentinel})`).mergeImportsWith(sentinel).addImports("solanaCodecsCore", "addDecoderSentinel");
2101
+ manifest.encoder.mapRender((r) => `addEncoderSentinel(${r}, ${sentinel.render})`).mergeImportsWith(sentinel).addImports("solanaCodecsCore", "addEncoderSentinel");
2102
+ manifest.decoder.mapRender((r) => `addDecoderSentinel(${r}, ${sentinel.render})`).mergeImportsWith(sentinel).addImports("solanaCodecsCore", "addDecoderSentinel");
2087
2103
  return manifest;
2088
2104
  },
2089
2105
  visitSetType(setType, { self }) {
@@ -2106,8 +2122,8 @@ function getTypeManifestVisitor(input) {
2106
2122
  visitSizePrefixType(node, { self }) {
2107
2123
  const manifest = visit(node.type, self);
2108
2124
  const prefix = visit(node.prefix, self);
2109
- manifest.encoder.mapRender((r) => `addEncoderSizePrefix(${r}, ${prefix.encoder})`).mergeImportsWith(prefix.encoder).addImports("solanaCodecsCore", "addEncoderSizePrefix");
2110
- manifest.decoder.mapRender((r) => `addDecoderSizePrefix(${r}, ${prefix.decoder})`).mergeImportsWith(prefix.decoder).addImports("solanaCodecsCore", "addDecoderSizePrefix");
2125
+ manifest.encoder.mapRender((r) => `addEncoderSizePrefix(${r}, ${prefix.encoder.render})`).mergeImportsWith(prefix.encoder).addImports("solanaCodecsCore", "addEncoderSizePrefix");
2126
+ manifest.decoder.mapRender((r) => `addDecoderSizePrefix(${r}, ${prefix.decoder.render})`).mergeImportsWith(prefix.decoder).addImports("solanaCodecsCore", "addDecoderSizePrefix");
2111
2127
  return manifest;
2112
2128
  },
2113
2129
  visitSolAmountType({ number }, { self }) {
@@ -2198,8 +2214,9 @@ ${jsDocblock(structFieldType.docs)}` : "";
2198
2214
  if (optionalFields.length === 0) {
2199
2215
  return mergedManifest;
2200
2216
  }
2201
- const instructionNode = stack.find("instructionNode");
2202
- const accountNode = stack.find("accountNode");
2217
+ const parentPath = stack.getPath();
2218
+ const instructionNode = findLastNodeFromPath(parentPath, "instructionNode");
2219
+ const accountNode = findLastNodeFromPath(parentPath, "accountNode");
2203
2220
  const discriminatorPrefix = instructionNode ? instructionNode.name : accountNode?.name;
2204
2221
  const discriminators = (instructionNode ? instructionNode.discriminators : accountNode?.discriminators) ?? [];
2205
2222
  const fieldDiscriminators = discriminators.filter(isNodeFilter("fieldDiscriminatorNode"));
@@ -2352,7 +2369,7 @@ var DEFAULT_NAME_TRANSFORMERS = {
2352
2369
  // src/getRenderMapVisitor.ts
2353
2370
  function getRenderMapVisitor(options = {}) {
2354
2371
  const linkables = new LinkableDictionary();
2355
- let program = null;
2372
+ const stack = new NodeStack();
2356
2373
  const nameTransformers = {
2357
2374
  ...DEFAULT_NAME_TRANSFORMERS,
2358
2375
  ...options.nameTransformers
@@ -2367,16 +2384,15 @@ function getRenderMapVisitor(options = {}) {
2367
2384
  const customAccountData = parseCustomDataOptions(options.customAccountData ?? [], "AccountData");
2368
2385
  const customInstructionData = parseCustomDataOptions(options.customInstructionData ?? [], "InstructionData");
2369
2386
  const getImportFrom = getImportFromFactory(options.linkOverrides ?? {}, customAccountData, customInstructionData);
2370
- const getTypeManifestVisitor2 = (parentName) => getTypeManifestVisitor({
2387
+ const typeManifestVisitor = getTypeManifestVisitor({
2371
2388
  customAccountData,
2372
2389
  customInstructionData,
2373
2390
  getImportFrom,
2374
2391
  linkables,
2375
2392
  nameApi,
2376
2393
  nonScalarEnums,
2377
- parentName
2394
+ stack
2378
2395
  });
2379
- const typeManifestVisitor = getTypeManifestVisitor2();
2380
2396
  const resolvedInstructionInputVisitor = getResolvedInstructionInputsVisitor();
2381
2397
  const globalScope = {
2382
2398
  asyncResolvers,
@@ -2393,19 +2409,18 @@ function getRenderMapVisitor(options = {}) {
2393
2409
  return render(join("pages", template), context, renderOptions);
2394
2410
  };
2395
2411
  return pipe(
2396
- staticVisitor(
2397
- () => new RenderMap(),
2398
- ["rootNode", "programNode", "pdaNode", "accountNode", "definedTypeNode", "instructionNode"]
2399
- ),
2412
+ staticVisitor(() => new RenderMap(), {
2413
+ keys: ["rootNode", "programNode", "pdaNode", "accountNode", "definedTypeNode", "instructionNode"]
2414
+ }),
2400
2415
  (v) => extendVisitor(v, {
2401
2416
  visitAccount(node) {
2402
- if (!program) {
2417
+ const accountPath = stack.getPath("accountNode");
2418
+ if (!findProgramNodeFromPath(accountPath)) {
2403
2419
  throw new Error("Account must be visited inside a program.");
2404
2420
  }
2405
2421
  const scope = {
2406
2422
  ...globalScope,
2407
- accountNode: node,
2408
- programNode: program,
2423
+ accountPath,
2409
2424
  typeManifest: visit(node, typeManifestVisitor)
2410
2425
  };
2411
2426
  const fields = resolveNestedTypeNode(node.data).fields;
@@ -2471,7 +2486,8 @@ function getRenderMapVisitor(options = {}) {
2471
2486
  );
2472
2487
  },
2473
2488
  visitInstruction(node) {
2474
- if (!program) {
2489
+ const instructionPath = stack.getPath("instructionNode");
2490
+ if (!findProgramNodeFromPath(instructionPath)) {
2475
2491
  throw new Error("Instruction must be visited inside a program.");
2476
2492
  }
2477
2493
  const instructionExtraName = nameApi.instructionExtraType(node.name);
@@ -2479,14 +2495,13 @@ function getRenderMapVisitor(options = {}) {
2479
2495
  ...globalScope,
2480
2496
  dataArgsManifest: visit(node, typeManifestVisitor),
2481
2497
  extraArgsManifest: visit(
2482
- structTypeNodeFromInstructionArgumentNodes(node.extraArguments ?? []),
2483
- getTypeManifestVisitor2({
2484
- loose: nameApi.dataArgsType(instructionExtraName),
2485
- strict: nameApi.dataType(instructionExtraName)
2486
- })
2498
+ definedTypeNode({
2499
+ name: instructionExtraName,
2500
+ type: structTypeNodeFromInstructionArgumentNodes(node.extraArguments ?? [])
2501
+ }),
2502
+ typeManifestVisitor
2487
2503
  ),
2488
- instructionNode: node,
2489
- programNode: program,
2504
+ instructionPath,
2490
2505
  renamedArgs: getRenamedArgsMap(node),
2491
2506
  resolvedInputs: visit(node, resolvedInstructionInputVisitor)
2492
2507
  };
@@ -2533,10 +2548,11 @@ function getRenderMapVisitor(options = {}) {
2533
2548
  );
2534
2549
  },
2535
2550
  visitPda(node) {
2536
- if (!program) {
2551
+ const pdaPath = stack.getPath("pdaNode");
2552
+ if (!findProgramNodeFromPath(pdaPath)) {
2537
2553
  throw new Error("Account must be visited inside a program.");
2538
2554
  }
2539
- const scope = { ...globalScope, pdaNode: node, programNode: program };
2555
+ const scope = { ...globalScope, pdaPath };
2540
2556
  const pdaFunctionFragment = getPdaFunctionFragment(scope);
2541
2557
  const imports = new ImportMap().mergeWith(pdaFunctionFragment);
2542
2558
  return new RenderMap().add(
@@ -2548,7 +2564,6 @@ function getRenderMapVisitor(options = {}) {
2548
2564
  );
2549
2565
  },
2550
2566
  visitProgram(node, { self }) {
2551
- program = node;
2552
2567
  const customDataDefinedType = [
2553
2568
  ...getDefinedTypeNodesToExtract(node.accounts, customAccountData),
2554
2569
  ...getDefinedTypeNodesToExtract(node.instructions, customInstructionData)
@@ -2578,11 +2593,10 @@ function getRenderMapVisitor(options = {}) {
2578
2593
  })
2579
2594
  );
2580
2595
  renderMap.mergeWith(
2581
- ...getAllInstructionsWithSubs(program, {
2596
+ ...getAllInstructionsWithSubs(node, {
2582
2597
  leavesOnly: !renderParentInstructions
2583
2598
  }).map((ix) => visit(ix, self))
2584
2599
  );
2585
- program = null;
2586
2600
  return renderMap;
2587
2601
  },
2588
2602
  visitRoot(node, { self }) {
@@ -2649,7 +2663,8 @@ function getRenderMapVisitor(options = {}) {
2649
2663
  return map.add("index.ts", render2("rootIndex.njk", ctx)).mergeWith(...getAllPrograms(node).map((p) => visit(p, self)));
2650
2664
  }
2651
2665
  }),
2652
- (v) => recordLinkablesVisitor(v, linkables)
2666
+ (v) => recordNodeStackVisitor(v, stack),
2667
+ (v) => recordLinkablesOnFirstVisitVisitor(v, linkables)
2653
2668
  );
2654
2669
  }
2655
2670
  function getRenamedArgsMap(instruction) {