@codama/renderers-rust 1.2.6 → 1.2.8

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.
@@ -392,6 +392,10 @@ var render = (template, context, options) => {
392
392
  env.addFilter("kebabCase", kebabCase);
393
393
  env.addFilter("titleCase", titleCase);
394
394
  env.addFilter("rustDocblock", rustDocblock);
395
+ env.addFilter("hasTrait", (traits, ...traitNames) => {
396
+ if (typeof traits !== "string") return false;
397
+ return traitNames.some((traitName) => traits.includes(traitName));
398
+ });
395
399
  return env.render(template, context);
396
400
  };
397
401
 
@@ -501,14 +505,51 @@ function extractFullyQualifiedNames(traits, imports) {
501
505
  return trait.slice(index + 2);
502
506
  });
503
507
  }
508
+ function getSerdeFieldAttribute(serdeWith, node, userOptions = {}) {
509
+ assertIsNode(node, ["accountNode", "definedTypeNode", "instructionNode"]);
510
+ const options = { ...DEFAULT_TRAIT_OPTIONS, ...userOptions };
511
+ const nodeType = getNodeType(node);
512
+ if (nodeType === "alias") {
513
+ return "";
514
+ }
515
+ const sanitizedOverrides = Object.fromEntries(
516
+ Object.entries(options.overrides).map(([key, value]) => [camelCase3(key), value])
517
+ );
518
+ const nodeOverrides = sanitizedOverrides[node.name];
519
+ const allTraits = nodeOverrides === void 0 ? getDefaultTraits(nodeType, options) : nodeOverrides;
520
+ const hasSerdeSerialize = allTraits.some((t) => t === "serde::Serialize" || t === "Serialize");
521
+ const hasSerdeDeserialize = allTraits.some((t) => t === "serde::Deserialize" || t === "Deserialize");
522
+ if (!hasSerdeSerialize && !hasSerdeDeserialize) {
523
+ return "";
524
+ }
525
+ const partitionedTraits = partitionTraitsInFeatures(allTraits, options.featureFlags);
526
+ const featuredTraits = partitionedTraits[1];
527
+ let serdeFeatureName;
528
+ for (const [feature, traits] of Object.entries(featuredTraits)) {
529
+ if (traits.some(
530
+ (t) => t === "serde::Serialize" || t === "serde::Deserialize" || t === "Serialize" || t === "Deserialize"
531
+ )) {
532
+ serdeFeatureName = feature;
533
+ break;
534
+ }
535
+ }
536
+ if (serdeFeatureName) {
537
+ return `#[cfg_attr(feature = "${serdeFeatureName}", serde(with = "${serdeWith}"))]
538
+ `;
539
+ } else {
540
+ return `#[serde(with = "${serdeWith}")]
541
+ `;
542
+ }
543
+ }
504
544
 
505
545
  // src/getTypeManifestVisitor.ts
506
546
  function getTypeManifestVisitor(options) {
507
- const { getImportFrom, getTraitsFromNode: getTraitsFromNode2 } = options;
547
+ const { getImportFrom, getTraitsFromNode: getTraitsFromNode2, traitOptions } = options;
508
548
  let parentName = options.parentName ?? null;
509
549
  let nestedStruct = options.nestedStruct ?? false;
510
550
  let inlineStruct = false;
511
551
  let parentSize = null;
552
+ let parentNode = null;
512
553
  return pipe(
513
554
  mergeVisitor(
514
555
  () => ({ imports: new ImportMap(), nestedStructs: [], type: "" }),
@@ -521,10 +562,12 @@ function getTypeManifestVisitor(options) {
521
562
  (v) => extendVisitor(v, {
522
563
  visitAccount(account, { self }) {
523
564
  parentName = pascalCase3(account.name);
565
+ parentNode = account;
524
566
  const manifest = visit3(account.data, self);
525
567
  const traits = getTraitsFromNode2(account);
526
568
  manifest.imports.mergeWith(traits.imports);
527
569
  parentName = null;
570
+ parentNode = null;
528
571
  return {
529
572
  ...manifest,
530
573
  type: traits.render + manifest.type
@@ -599,10 +642,12 @@ function getTypeManifestVisitor(options) {
599
642
  },
600
643
  visitDefinedType(definedType, { self }) {
601
644
  parentName = pascalCase3(definedType.name);
645
+ parentNode = definedType;
602
646
  const manifest = visit3(definedType.type, self);
603
647
  const traits = getTraitsFromNode2(definedType);
604
648
  manifest.imports.mergeWith(traits.imports);
605
649
  parentName = null;
650
+ parentNode = null;
606
651
  const renderedType = isNode4(definedType.type, ["enumTypeNode", "structTypeNode"]) ? manifest.type : `pub type ${pascalCase3(definedType.name)} = ${manifest.type};`;
607
652
  return { ...manifest, type: `${traits.render}${renderedType}` };
608
653
  },
@@ -649,10 +694,18 @@ function getTypeManifestVisitor(options) {
649
694
  const childManifest = visit3(enumTupleVariantType.tuple, self);
650
695
  parentName = originalParentName;
651
696
  let derive = "";
652
- if (childManifest.type === "(Pubkey)") {
653
- derive = '#[cfg_attr(feature = "serde", serde(with = "serde_with::As::<serde_with::DisplayFromStr>"))]\n';
654
- } else if (childManifest.type === "(Vec<Pubkey>)") {
655
- derive = '#[cfg_attr(feature = "serde", serde(with = "serde_with::As::<Vec<serde_with::DisplayFromStr>>"))]\n';
697
+ if (parentNode && childManifest.type === "(Pubkey)") {
698
+ derive = getSerdeFieldAttribute(
699
+ "serde_with::As::<serde_with::DisplayFromStr>",
700
+ parentNode,
701
+ traitOptions
702
+ );
703
+ } else if (parentNode && childManifest.type === "(Vec<Pubkey>)") {
704
+ derive = getSerdeFieldAttribute(
705
+ "serde_with::As::<Vec<serde_with::DisplayFromStr>>",
706
+ parentNode,
707
+ traitOptions
708
+ );
656
709
  }
657
710
  return {
658
711
  ...childManifest,
@@ -799,14 +852,28 @@ ${variantNames}
799
852
  const docblock = rustDocblock(parseDocs(structFieldType.docs));
800
853
  const resolvedNestedType = resolveNestedTypeNode(structFieldType.type);
801
854
  let derive = "";
802
- if (fieldManifest.type === "Pubkey") {
803
- derive = '#[cfg_attr(feature = "serde", serde(with = "serde_with::As::<serde_with::DisplayFromStr>"))]\n';
804
- } else if (fieldManifest.type === "Vec<Pubkey>") {
805
- derive = '#[cfg_attr(feature = "serde", serde(with = "serde_with::As::<Vec<serde_with::DisplayFromStr>>"))]\n';
806
- } else if (isNode4(resolvedNestedType, "arrayTypeNode") && isNode4(resolvedNestedType.count, "fixedCountNode") && resolvedNestedType.count.value > 32) {
807
- derive = '#[cfg_attr(feature = "serde", serde(with = "serde_big_array::BigArray"))]\n';
808
- } else if (isNode4(resolvedNestedType, ["bytesTypeNode", "stringTypeNode"]) && isNode4(structFieldType.type, "fixedSizeTypeNode") && structFieldType.type.size > 32) {
809
- derive = '#[cfg_attr(feature = "serde", serde(with = "serde_with::As::<serde_with::Bytes>"))]\n';
855
+ if (parentNode) {
856
+ if (fieldManifest.type === "Pubkey") {
857
+ derive = getSerdeFieldAttribute(
858
+ "serde_with::As::<serde_with::DisplayFromStr>",
859
+ parentNode,
860
+ traitOptions
861
+ );
862
+ } else if (fieldManifest.type === "Vec<Pubkey>") {
863
+ derive = getSerdeFieldAttribute(
864
+ "serde_with::As::<Vec<serde_with::DisplayFromStr>>",
865
+ parentNode,
866
+ traitOptions
867
+ );
868
+ } else if (isNode4(resolvedNestedType, "arrayTypeNode") && isNode4(resolvedNestedType.count, "fixedCountNode") && resolvedNestedType.count.value > 32) {
869
+ derive = getSerdeFieldAttribute("serde_big_array::BigArray", parentNode, traitOptions);
870
+ } else if (isNode4(resolvedNestedType, ["bytesTypeNode", "stringTypeNode"]) && isNode4(structFieldType.type, "fixedSizeTypeNode") && structFieldType.type.size > 32) {
871
+ derive = getSerdeFieldAttribute(
872
+ "serde_with::As::<serde_with::Bytes>",
873
+ parentNode,
874
+ traitOptions
875
+ );
876
+ }
810
877
  }
811
878
  return {
812
879
  ...fieldManifest,
@@ -879,7 +946,11 @@ function getRenderMapVisitor(options = {}) {
879
946
  const dependencyMap = options.dependencyMap ?? {};
880
947
  const getImportFrom = getImportFromFactory(options.linkOverrides ?? {});
881
948
  const getTraitsFromNode2 = getTraitsFromNodeFactory(options.traitOptions);
882
- const typeManifestVisitor = getTypeManifestVisitor({ getImportFrom, getTraitsFromNode: getTraitsFromNode2 });
949
+ const typeManifestVisitor = getTypeManifestVisitor({
950
+ getImportFrom,
951
+ getTraitsFromNode: getTraitsFromNode2,
952
+ traitOptions: options.traitOptions
953
+ });
883
954
  const anchorTraits = options.anchorTraits ?? true;
884
955
  return pipe2(
885
956
  staticVisitor(() => createRenderMap(), {
@@ -921,9 +992,8 @@ function getRenderMapVisitor(options = {}) {
921
992
  if (hasVariableSeeds) {
922
993
  imports.mergeWith(seedsImports);
923
994
  }
924
- return createRenderMap(
925
- `accounts/${snakeCase4(node.name)}.rs`,
926
- render("accountsPage.njk", {
995
+ return createRenderMap(`accounts/${snakeCase4(node.name)}.rs`, {
996
+ content: render("accountsPage.njk", {
927
997
  account: node,
928
998
  anchorTraits,
929
999
  constantSeeds,
@@ -935,19 +1005,18 @@ function getRenderMapVisitor(options = {}) {
935
1005
  seeds,
936
1006
  typeManifest
937
1007
  })
938
- );
1008
+ });
939
1009
  },
940
1010
  visitDefinedType(node) {
941
1011
  const typeManifest = visit4(node, typeManifestVisitor);
942
1012
  const imports = new ImportMap().mergeWithManifest(typeManifest);
943
- return createRenderMap(
944
- `types/${snakeCase4(node.name)}.rs`,
945
- render("definedTypesPage.njk", {
1013
+ return createRenderMap(`types/${snakeCase4(node.name)}.rs`, {
1014
+ content: render("definedTypesPage.njk", {
946
1015
  definedType: node,
947
1016
  imports: imports.remove(`generatedTypes::${pascalCase4(node.name)}`).toString(dependencyMap),
948
1017
  typeManifest
949
1018
  })
950
- );
1019
+ });
951
1020
  },
952
1021
  visitInstruction(node) {
953
1022
  const imports = new ImportMap();
@@ -1008,9 +1077,8 @@ function getRenderMapVisitor(options = {}) {
1008
1077
  const typeManifest = visit4(struct, structVisitor);
1009
1078
  const dataTraits = getTraitsFromNode2(node);
1010
1079
  imports.mergeWith(dataTraits.imports);
1011
- return createRenderMap(
1012
- `instructions/${snakeCase4(node.name)}.rs`,
1013
- render("instructionsPage.njk", {
1080
+ return createRenderMap(`instructions/${snakeCase4(node.name)}.rs`, {
1081
+ content: render("instructionsPage.njk", {
1014
1082
  dataTraits: dataTraits.render,
1015
1083
  discriminatorConstants: discriminatorConstants.render,
1016
1084
  hasArgs,
@@ -1021,7 +1089,7 @@ function getRenderMapVisitor(options = {}) {
1021
1089
  program,
1022
1090
  typeManifest
1023
1091
  })
1024
- );
1092
+ });
1025
1093
  },
1026
1094
  visitProgram(node, { self }) {
1027
1095
  program = node;
@@ -1033,15 +1101,13 @@ function getRenderMapVisitor(options = {}) {
1033
1101
  }).map((ix) => visit4(ix, self))
1034
1102
  ]);
1035
1103
  if (node.errors.length > 0) {
1036
- renders = addToRenderMap(
1037
- renders,
1038
- `errors/${snakeCase4(node.name)}.rs`,
1039
- render("errorsPage.njk", {
1104
+ renders = addToRenderMap(renders, `errors/${snakeCase4(node.name)}.rs`, {
1105
+ content: render("errorsPage.njk", {
1040
1106
  errors: node.errors,
1041
1107
  imports: new ImportMap().toString(dependencyMap),
1042
1108
  program: node
1043
1109
  })
1044
- );
1110
+ });
1045
1111
  }
1046
1112
  program = null;
1047
1113
  return renders;
@@ -1064,13 +1130,13 @@ function getRenderMapVisitor(options = {}) {
1064
1130
  };
1065
1131
  return mergeRenderMaps([
1066
1132
  createRenderMap({
1067
- ["accounts/mod.rs"]: accountsToExport.length > 0 ? render("accountsMod.njk", ctx) : void 0,
1068
- ["errors/mod.rs"]: programsToExport.length > 0 ? render("errorsMod.njk", ctx) : void 0,
1069
- ["instructions/mod.rs"]: instructionsToExport.length > 0 ? render("instructionsMod.njk", ctx) : void 0,
1070
- ["mod.rs"]: render("rootMod.njk", ctx),
1071
- ["programs.rs"]: programsToExport.length > 0 ? render("programsMod.njk", ctx) : void 0,
1072
- ["shared.rs"]: accountsToExport.length > 0 ? render("sharedPage.njk", ctx) : void 0,
1073
- ["types/mod.rs"]: definedTypesToExport.length > 0 ? render("definedTypesMod.njk", ctx) : void 0
1133
+ ["accounts/mod.rs"]: accountsToExport.length > 0 ? { content: render("accountsMod.njk", ctx) } : void 0,
1134
+ ["errors/mod.rs"]: programsToExport.length > 0 ? { content: render("errorsMod.njk", ctx) } : void 0,
1135
+ ["instructions/mod.rs"]: instructionsToExport.length > 0 ? { content: render("instructionsMod.njk", ctx) } : void 0,
1136
+ ["mod.rs"]: { content: render("rootMod.njk", ctx) },
1137
+ ["programs.rs"]: programsToExport.length > 0 ? { content: render("programsMod.njk", ctx) } : void 0,
1138
+ ["shared.rs"]: accountsToExport.length > 0 ? { content: render("sharedPage.njk", ctx) } : void 0,
1139
+ ["types/mod.rs"]: definedTypesToExport.length > 0 ? { content: render("definedTypesMod.njk", ctx) } : void 0
1074
1140
  }),
1075
1141
  ...getAllPrograms(node).map((p) => visit4(p, self))
1076
1142
  ]);
@@ -1102,8 +1168,13 @@ function renderVisitor(path, options = {}) {
1102
1168
  visit5(root, writeRenderMapVisitor(getRenderMapVisitor(options), path));
1103
1169
  if (options.formatCode) {
1104
1170
  if (options.crateFolder) {
1105
- const toolchain = options.toolchain ?? "+stable";
1106
- runFormatter("cargo", [toolchain, "fmt", "--manifest-path", `${options.crateFolder}/Cargo.toml`]);
1171
+ const removeFalsy = (arg) => Boolean(arg);
1172
+ runFormatter(
1173
+ "cargo",
1174
+ [options.toolchain, "fmt", "--manifest-path", `${options.crateFolder}/Cargo.toml`].filter(
1175
+ removeFalsy
1176
+ )
1177
+ );
1107
1178
  } else {
1108
1179
  logWarn2("No crate folder specified, skipping formatting.");
1109
1180
  }