@codama/renderers-js 1.0.0 → 1.1.0

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 (39) hide show
  1. package/dist/index.node.cjs +91 -75
  2. package/dist/index.node.cjs.map +1 -1
  3. package/dist/index.node.mjs +93 -77
  4. package/dist/index.node.mjs.map +1 -1
  5. package/dist/templates/fragments/instructionFunction.njk +1 -1
  6. package/dist/types/fragments/accountFetchHelpers.d.ts +2 -1
  7. package/dist/types/fragments/accountFetchHelpers.d.ts.map +1 -1
  8. package/dist/types/fragments/accountPdaHelpers.d.ts +3 -3
  9. package/dist/types/fragments/accountPdaHelpers.d.ts.map +1 -1
  10. package/dist/types/fragments/accountSizeHelpers.d.ts +2 -1
  11. package/dist/types/fragments/accountSizeHelpers.d.ts.map +1 -1
  12. package/dist/types/fragments/accountType.d.ts +2 -1
  13. package/dist/types/fragments/accountType.d.ts.map +1 -1
  14. package/dist/types/fragments/instructionAccountTypeParam.d.ts +3 -4
  15. package/dist/types/fragments/instructionAccountTypeParam.d.ts.map +1 -1
  16. package/dist/types/fragments/instructionByteDelta.d.ts +2 -1
  17. package/dist/types/fragments/instructionByteDelta.d.ts.map +1 -1
  18. package/dist/types/fragments/instructionData.d.ts +2 -1
  19. package/dist/types/fragments/instructionData.d.ts.map +1 -1
  20. package/dist/types/fragments/instructionExtraArgs.d.ts +2 -1
  21. package/dist/types/fragments/instructionExtraArgs.d.ts.map +1 -1
  22. package/dist/types/fragments/instructionFunction.d.ts +3 -4
  23. package/dist/types/fragments/instructionFunction.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/package.json +6 -6
@@ -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
  }
@@ -974,11 +978,12 @@ function renderNestedInstructionDefault(scope) {
974
978
 
975
979
  // src/fragments/instructionInputResolved.ts
976
980
  function getInstructionInputResolvedFragment(scope) {
981
+ const instructionNode = getLastNodeFromPath(scope.instructionPath);
977
982
  const resolvedInputFragments = scope.resolvedInputs.flatMap((input) => {
978
983
  const inputFragment = getInstructionInputDefaultFragment({
979
984
  ...scope,
980
985
  input,
981
- optionalAccountStrategy: scope.instructionNode.optionalAccountStrategy
986
+ optionalAccountStrategy: instructionNode.optionalAccountStrategy
982
987
  });
983
988
  if (!inputFragment.render) return [];
984
989
  const camelName = camelCase(input.name);
@@ -1001,7 +1006,8 @@ ${r}
1001
1006
  );
1002
1007
  }
1003
1008
  function getInstructionInputTypeFragment(scope) {
1004
- const { instructionNode, useAsync, nameApi } = scope;
1009
+ const { instructionPath, useAsync, nameApi } = scope;
1010
+ const instructionNode = getLastNodeFromPath(instructionPath);
1005
1011
  const instructionInputType = useAsync ? nameApi.instructionAsyncInputType(instructionNode.name) : nameApi.instructionSyncInputType(instructionNode.name);
1006
1012
  const accountsFragment = getAccountsFragment(scope);
1007
1013
  const [dataArgumentsFragment, customDataArgumentsFragment] = getDataArgumentsFragments(scope);
@@ -1024,7 +1030,8 @@ function getInstructionInputTypeFragment(scope) {
1024
1030
  ).addImports("solanaAddresses", ["type Address"]);
1025
1031
  }
1026
1032
  function getAccountsFragment(scope) {
1027
- const { instructionNode, resolvedInputs, useAsync, asyncResolvers } = scope;
1033
+ const { instructionPath, resolvedInputs, useAsync, asyncResolvers } = scope;
1034
+ const instructionNode = getLastNodeFromPath(instructionPath);
1028
1035
  const fragments = instructionNode.accounts.map((account) => {
1029
1036
  const resolvedAccount = resolvedInputs.find(
1030
1037
  (input) => input.kind === "instructionAccountNode" && input.name === account.name
@@ -1057,7 +1064,8 @@ function getAccountTypeFragment2(account) {
1057
1064
  return fragment(`Address<${typeParam}>`).addImports("solanaAddresses", ["type Address"]);
1058
1065
  }
1059
1066
  function getDataArgumentsFragments(scope) {
1060
- const { instructionNode, nameApi } = scope;
1067
+ const { instructionPath, nameApi } = scope;
1068
+ const instructionNode = getLastNodeFromPath(instructionPath);
1061
1069
  const customData = scope.customInstructionData.get(instructionNode.name);
1062
1070
  if (customData) {
1063
1071
  return [
@@ -1074,7 +1082,8 @@ function getDataArgumentsFragments(scope) {
1074
1082
  return [mergeFragments(fragments, (r) => r.join("\n")), fragment("")];
1075
1083
  }
1076
1084
  function getExtraArgumentsFragment(scope) {
1077
- const { instructionNode, nameApi } = scope;
1085
+ const { instructionPath, nameApi } = scope;
1086
+ const instructionNode = getLastNodeFromPath(instructionPath);
1078
1087
  const instructionExtraName = nameApi.instructionExtraType(instructionNode.name);
1079
1088
  const extraArgsType = nameApi.dataArgsType(instructionExtraName);
1080
1089
  const fragments = (instructionNode.extraArguments ?? []).flatMap((arg) => {
@@ -1113,7 +1122,7 @@ function getRemainingAccountsFragment(instructionNode) {
1113
1122
  return mergeFragments(fragments, (r) => r.join("\n"));
1114
1123
  }
1115
1124
  function getInstructionRemainingAccountsFragment(scope) {
1116
- const { remainingAccounts } = scope.instructionNode;
1125
+ const { remainingAccounts } = getLastNodeFromPath(scope.instructionPath);
1117
1126
  const fragments = (remainingAccounts ?? []).flatMap((r) => getRemainingAccountsFragment2(r, scope));
1118
1127
  if (fragments.length === 0) return fragment("");
1119
1128
  return mergeFragments(
@@ -1136,7 +1145,7 @@ function getRemainingAccountsFragment2(remainingAccounts, scope) {
1136
1145
  return [remainingAccountsFragment];
1137
1146
  }
1138
1147
  function getArgumentValueNodeFragment2(remainingAccounts, scope) {
1139
- const { instructionNode } = scope;
1148
+ const instructionNode = getLastNodeFromPath(scope.instructionPath);
1140
1149
  assertIsNode(remainingAccounts.value, "argumentValueNode");
1141
1150
  const argumentName = camelCase(remainingAccounts.value.name);
1142
1151
  const isOptional = remainingAccounts.isOptional ?? false;
@@ -1179,8 +1188,7 @@ function getResolverValueNodeFragment2(remainingAccounts, scope) {
1179
1188
  function getInstructionFunctionFragment(scope) {
1180
1189
  const {
1181
1190
  useAsync,
1182
- instructionNode,
1183
- programNode,
1191
+ instructionPath,
1184
1192
  resolvedInputs,
1185
1193
  renamedArgs,
1186
1194
  dataArgsManifest,
@@ -1188,6 +1196,8 @@ function getInstructionFunctionFragment(scope) {
1188
1196
  nameApi,
1189
1197
  customInstructionData
1190
1198
  } = scope;
1199
+ const instructionNode = getLastNodeFromPath(instructionPath);
1200
+ const programNode = findProgramNodeFromPath(instructionPath);
1191
1201
  if (useAsync && !hasAsyncFunction(instructionNode, resolvedInputs, asyncResolvers)) {
1192
1202
  return fragment("");
1193
1203
  }
@@ -1210,6 +1220,7 @@ function getInstructionFunctionFragment(scope) {
1210
1220
  ).length > 0;
1211
1221
  const hasRemainingAccountArgs = (instructionNode.remainingAccounts ?? []).filter(({ value }) => isNode(value, "argumentValueNode")).length > 0;
1212
1222
  const hasAnyArgs = hasDataArgs || hasExtraArgs || hasRemainingAccountArgs;
1223
+ const hasInput = hasAccounts || hasAnyArgs;
1213
1224
  const instructionDataName = nameApi.instructionDataType(instructionNode.name);
1214
1225
  const programAddressConstant = nameApi.programAddressConstant(programNode.name);
1215
1226
  const encoderFunction = customData ? dataArgsManifest.encoder.render : `${nameApi.encoderFunction(instructionDataName)}()`;
@@ -1253,6 +1264,7 @@ function getInstructionFunctionFragment(scope) {
1253
1264
  hasData,
1254
1265
  hasDataArgs,
1255
1266
  hasExtraArgs,
1267
+ hasInput,
1256
1268
  hasLegacyOptionalAccounts,
1257
1269
  hasRemainingAccounts,
1258
1270
  hasResolver,
@@ -1287,7 +1299,8 @@ function getTypeParams(instructionNode, programAddressConstant) {
1287
1299
  return fragment(typeParams.filter((x) => !!x).join(", ")).mapRender((r) => `<${r}>`).addImports("generatedPrograms", [programAddressConstant]);
1288
1300
  }
1289
1301
  function getInstructionType(scope) {
1290
- const { instructionNode, nameApi } = scope;
1302
+ const { instructionPath, nameApi } = scope;
1303
+ const instructionNode = getLastNodeFromPath(instructionPath);
1291
1304
  const instructionTypeName = nameApi.instructionType(instructionNode.name);
1292
1305
  const programAddressFragment = fragment("TProgramAddress");
1293
1306
  const accountTypeParamsFragments = instructionNode.accounts.map((account) => {
@@ -1307,24 +1320,22 @@ function getInstructionType(scope) {
1307
1320
  ).mapRender((r) => `${instructionTypeName}<${r}>`);
1308
1321
  }
1309
1322
  function getInputTypeCall(scope) {
1310
- const { instructionNode, useAsync, nameApi } = scope;
1323
+ const { instructionPath, useAsync, nameApi } = scope;
1324
+ const instructionNode = getLastNodeFromPath(instructionPath);
1311
1325
  const inputTypeName = useAsync ? nameApi.instructionAsyncInputType(instructionNode.name) : nameApi.instructionSyncInputType(instructionNode.name);
1312
1326
  if (instructionNode.accounts.length === 0) return fragment(inputTypeName);
1313
1327
  const accountTypeParams = instructionNode.accounts.map((account) => `TAccount${pascalCase(account.name)}`).join(", ");
1314
1328
  return fragment(`${inputTypeName}<${accountTypeParams}>`);
1315
1329
  }
1316
-
1317
- // src/fragments/instructionParseFunction.ts
1318
1330
  function getInstructionParseFunctionFragment(scope) {
1319
- const { instructionNode, programNode, dataArgsManifest, nameApi, customInstructionData } = scope;
1331
+ const { instructionPath, dataArgsManifest, nameApi, customInstructionData } = scope;
1332
+ const instructionNode = getLastNodeFromPath(instructionPath);
1333
+ const programNode = findProgramNodeFromPath(instructionPath);
1320
1334
  const customData = customInstructionData.get(instructionNode.name);
1321
1335
  const hasAccounts = instructionNode.accounts.length > 0;
1322
1336
  const hasOptionalAccounts = instructionNode.accounts.some((account) => account.isOptional);
1323
1337
  const minimumNumberOfAccounts = instructionNode.optionalAccountStrategy === "omitted" ? instructionNode.accounts.filter((account) => !account.isOptional).length : instructionNode.accounts.length;
1324
1338
  const hasData = !!customData || instructionNode.arguments.length > 0;
1325
- if (!hasAccounts && !hasData) {
1326
- return fragment("");
1327
- }
1328
1339
  const instructionDataName = nameApi.instructionDataType(instructionNode.name);
1329
1340
  const programAddressConstant = nameApi.programAddressConstant(programNode.name);
1330
1341
  const dataTypeFragment = fragment(
@@ -1348,7 +1359,9 @@ function getInstructionParseFunctionFragment(scope) {
1348
1359
  }).mergeImportsWith(dataTypeFragment).addImports("generatedPrograms", [programAddressConstant]).addImports("solanaInstructions", ["type IInstruction"]).addImports("solanaInstructions", hasAccounts ? ["type IInstructionWithAccounts", "type IAccountMeta"] : []).addImports("solanaInstructions", hasData ? ["type IInstructionWithData"] : []);
1349
1360
  }
1350
1361
  function getInstructionTypeFragment(scope) {
1351
- const { instructionNode, programNode, nameApi, customInstructionData } = scope;
1362
+ const { instructionPath, nameApi, customInstructionData } = scope;
1363
+ const instructionNode = getLastNodeFromPath(instructionPath);
1364
+ const programNode = findProgramNodeFromPath(instructionPath);
1352
1365
  const hasAccounts = instructionNode.accounts.length > 0;
1353
1366
  const customData = customInstructionData.get(instructionNode.name);
1354
1367
  const hasData = !!customData || instructionNode.arguments.length > 0;
@@ -1360,7 +1373,7 @@ function getInstructionTypeFragment(scope) {
1360
1373
  (account) => getInstructionAccountTypeParamFragment({
1361
1374
  ...scope,
1362
1375
  allowAccountMeta: true,
1363
- instructionAccountNode: account
1376
+ instructionAccountPath: [...instructionPath, account]
1364
1377
  })
1365
1378
  ),
1366
1379
  (renders) => renders.join(", ")
@@ -1396,7 +1409,9 @@ function getInstructionTypeFragment(scope) {
1396
1409
  return fragment2;
1397
1410
  }
1398
1411
  function getPdaFunctionFragment(scope) {
1399
- const { pdaNode, programNode, typeManifestVisitor, nameApi } = scope;
1412
+ const { pdaPath, typeManifestVisitor, nameApi } = scope;
1413
+ const pdaNode = getLastNodeFromPath(pdaPath);
1414
+ const programNode = findProgramNodeFromPath(pdaPath);
1400
1415
  const imports = new ImportMap();
1401
1416
  const seeds = pdaNode.seeds.map((seed) => {
1402
1417
  if (isNode(seed, "variablePdaSeedNode")) {
@@ -1615,8 +1630,8 @@ function mergeManifests(manifests, options = {}) {
1615
1630
  }
1616
1631
  function getTypeManifestVisitor(input) {
1617
1632
  const { nameApi, linkables, nonScalarEnums, customAccountData, customInstructionData, getImportFrom } = input;
1618
- const stack = new NodeStack();
1619
- let parentName = input.parentName ?? null;
1633
+ const stack = input.stack ?? new NodeStack();
1634
+ let parentName = null;
1620
1635
  return pipe(
1621
1636
  staticVisitor(
1622
1637
  () => ({
@@ -1627,14 +1642,16 @@ function getTypeManifestVisitor(input) {
1627
1642
  strictType: fragment(""),
1628
1643
  value: fragment("")
1629
1644
  }),
1630
- [
1631
- ...REGISTERED_TYPE_NODE_KINDS,
1632
- ...REGISTERED_VALUE_NODE_KINDS,
1633
- "definedTypeLinkNode",
1634
- "definedTypeNode",
1635
- "accountNode",
1636
- "instructionNode"
1637
- ]
1645
+ {
1646
+ keys: [
1647
+ ...REGISTERED_TYPE_NODE_KINDS,
1648
+ ...REGISTERED_VALUE_NODE_KINDS,
1649
+ "definedTypeLinkNode",
1650
+ "definedTypeNode",
1651
+ "accountNode",
1652
+ "instructionNode"
1653
+ ]
1654
+ }
1638
1655
  ),
1639
1656
  (visitor) => extendVisitor(visitor, {
1640
1657
  visitAccount(account, { self }) {
@@ -1879,7 +1896,7 @@ function getTypeManifestVisitor(input) {
1879
1896
  const enumName = nameApi.dataType(node.enum.name);
1880
1897
  const enumFunction = nameApi.discriminatedUnionFunction(node.enum.name);
1881
1898
  const importFrom = getImportFrom(node.enum);
1882
- const enumNode = linkables.get(node.enum)?.type;
1899
+ const enumNode = linkables.get([...stack.getPath(), node.enum])?.type;
1883
1900
  const isScalar = enumNode && isNode(enumNode, "enumTypeNode") ? isScalarEnum(enumNode) : !nonScalarEnums.includes(node.enum.name);
1884
1901
  if (!node.value && isScalar) {
1885
1902
  const variantName2 = nameApi.enumVariant(node.variant);
@@ -2199,8 +2216,9 @@ ${jsDocblock(structFieldType.docs)}` : "";
2199
2216
  if (optionalFields.length === 0) {
2200
2217
  return mergedManifest;
2201
2218
  }
2202
- const instructionNode = stack.find("instructionNode");
2203
- const accountNode = stack.find("accountNode");
2219
+ const parentPath = stack.getPath();
2220
+ const instructionNode = findLastNodeFromPath(parentPath, "instructionNode");
2221
+ const accountNode = findLastNodeFromPath(parentPath, "accountNode");
2204
2222
  const discriminatorPrefix = instructionNode ? instructionNode.name : accountNode?.name;
2205
2223
  const discriminators = (instructionNode ? instructionNode.discriminators : accountNode?.discriminators) ?? [];
2206
2224
  const fieldDiscriminators = discriminators.filter(isNodeFilter("fieldDiscriminatorNode"));
@@ -2353,7 +2371,7 @@ var DEFAULT_NAME_TRANSFORMERS = {
2353
2371
  // src/getRenderMapVisitor.ts
2354
2372
  function getRenderMapVisitor(options = {}) {
2355
2373
  const linkables = new LinkableDictionary();
2356
- let program = null;
2374
+ const stack = new NodeStack();
2357
2375
  const nameTransformers = {
2358
2376
  ...DEFAULT_NAME_TRANSFORMERS,
2359
2377
  ...options.nameTransformers
@@ -2368,16 +2386,15 @@ function getRenderMapVisitor(options = {}) {
2368
2386
  const customAccountData = parseCustomDataOptions(options.customAccountData ?? [], "AccountData");
2369
2387
  const customInstructionData = parseCustomDataOptions(options.customInstructionData ?? [], "InstructionData");
2370
2388
  const getImportFrom = getImportFromFactory(options.linkOverrides ?? {}, customAccountData, customInstructionData);
2371
- const getTypeManifestVisitor2 = (parentName) => getTypeManifestVisitor({
2389
+ const typeManifestVisitor = getTypeManifestVisitor({
2372
2390
  customAccountData,
2373
2391
  customInstructionData,
2374
2392
  getImportFrom,
2375
2393
  linkables,
2376
2394
  nameApi,
2377
2395
  nonScalarEnums,
2378
- parentName
2396
+ stack
2379
2397
  });
2380
- const typeManifestVisitor = getTypeManifestVisitor2();
2381
2398
  const resolvedInstructionInputVisitor = getResolvedInstructionInputsVisitor();
2382
2399
  const globalScope = {
2383
2400
  asyncResolvers,
@@ -2394,19 +2411,18 @@ function getRenderMapVisitor(options = {}) {
2394
2411
  return render(join("pages", template), context, renderOptions);
2395
2412
  };
2396
2413
  return pipe(
2397
- staticVisitor(
2398
- () => new RenderMap(),
2399
- ["rootNode", "programNode", "pdaNode", "accountNode", "definedTypeNode", "instructionNode"]
2400
- ),
2414
+ staticVisitor(() => new RenderMap(), {
2415
+ keys: ["rootNode", "programNode", "pdaNode", "accountNode", "definedTypeNode", "instructionNode"]
2416
+ }),
2401
2417
  (v) => extendVisitor(v, {
2402
2418
  visitAccount(node) {
2403
- if (!program) {
2419
+ const accountPath = stack.getPath("accountNode");
2420
+ if (!findProgramNodeFromPath(accountPath)) {
2404
2421
  throw new Error("Account must be visited inside a program.");
2405
2422
  }
2406
2423
  const scope = {
2407
2424
  ...globalScope,
2408
- accountNode: node,
2409
- programNode: program,
2425
+ accountPath,
2410
2426
  typeManifest: visit(node, typeManifestVisitor)
2411
2427
  };
2412
2428
  const fields = resolveNestedTypeNode(node.data).fields;
@@ -2472,7 +2488,8 @@ function getRenderMapVisitor(options = {}) {
2472
2488
  );
2473
2489
  },
2474
2490
  visitInstruction(node) {
2475
- if (!program) {
2491
+ const instructionPath = stack.getPath("instructionNode");
2492
+ if (!findProgramNodeFromPath(instructionPath)) {
2476
2493
  throw new Error("Instruction must be visited inside a program.");
2477
2494
  }
2478
2495
  const instructionExtraName = nameApi.instructionExtraType(node.name);
@@ -2480,14 +2497,13 @@ function getRenderMapVisitor(options = {}) {
2480
2497
  ...globalScope,
2481
2498
  dataArgsManifest: visit(node, typeManifestVisitor),
2482
2499
  extraArgsManifest: visit(
2483
- structTypeNodeFromInstructionArgumentNodes(node.extraArguments ?? []),
2484
- getTypeManifestVisitor2({
2485
- loose: nameApi.dataArgsType(instructionExtraName),
2486
- strict: nameApi.dataType(instructionExtraName)
2487
- })
2500
+ definedTypeNode({
2501
+ name: instructionExtraName,
2502
+ type: structTypeNodeFromInstructionArgumentNodes(node.extraArguments ?? [])
2503
+ }),
2504
+ typeManifestVisitor
2488
2505
  ),
2489
- instructionNode: node,
2490
- programNode: program,
2506
+ instructionPath,
2491
2507
  renamedArgs: getRenamedArgsMap(node),
2492
2508
  resolvedInputs: visit(node, resolvedInstructionInputVisitor)
2493
2509
  };
@@ -2534,10 +2550,11 @@ function getRenderMapVisitor(options = {}) {
2534
2550
  );
2535
2551
  },
2536
2552
  visitPda(node) {
2537
- if (!program) {
2553
+ const pdaPath = stack.getPath("pdaNode");
2554
+ if (!findProgramNodeFromPath(pdaPath)) {
2538
2555
  throw new Error("Account must be visited inside a program.");
2539
2556
  }
2540
- const scope = { ...globalScope, pdaNode: node, programNode: program };
2557
+ const scope = { ...globalScope, pdaPath };
2541
2558
  const pdaFunctionFragment = getPdaFunctionFragment(scope);
2542
2559
  const imports = new ImportMap().mergeWith(pdaFunctionFragment);
2543
2560
  return new RenderMap().add(
@@ -2549,7 +2566,6 @@ function getRenderMapVisitor(options = {}) {
2549
2566
  );
2550
2567
  },
2551
2568
  visitProgram(node, { self }) {
2552
- program = node;
2553
2569
  const customDataDefinedType = [
2554
2570
  ...getDefinedTypeNodesToExtract(node.accounts, customAccountData),
2555
2571
  ...getDefinedTypeNodesToExtract(node.instructions, customInstructionData)
@@ -2579,11 +2595,10 @@ function getRenderMapVisitor(options = {}) {
2579
2595
  })
2580
2596
  );
2581
2597
  renderMap.mergeWith(
2582
- ...getAllInstructionsWithSubs(program, {
2598
+ ...getAllInstructionsWithSubs(node, {
2583
2599
  leavesOnly: !renderParentInstructions
2584
2600
  }).map((ix) => visit(ix, self))
2585
2601
  );
2586
- program = null;
2587
2602
  return renderMap;
2588
2603
  },
2589
2604
  visitRoot(node, { self }) {
@@ -2650,7 +2665,8 @@ function getRenderMapVisitor(options = {}) {
2650
2665
  return map.add("index.ts", render2("rootIndex.njk", ctx)).mergeWith(...getAllPrograms(node).map((p) => visit(p, self)));
2651
2666
  }
2652
2667
  }),
2653
- (v) => recordLinkablesVisitor(v, linkables)
2668
+ (v) => recordNodeStackVisitor(v, stack),
2669
+ (v) => recordLinkablesOnFirstVisitVisitor(v, linkables)
2654
2670
  );
2655
2671
  }
2656
2672
  function getRenamedArgsMap(instruction) {