@codama/renderers-rust 1.1.0 → 1.1.2

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.
@@ -76,13 +76,13 @@ import {
76
76
  getAllDefinedTypes,
77
77
  getAllInstructionsWithSubs,
78
78
  getAllPrograms,
79
- isNode as isNode4,
80
- isNodeFilter,
79
+ isNode as isNode5,
80
+ isNodeFilter as isNodeFilter2,
81
81
  pascalCase as pascalCase4,
82
82
  resolveNestedTypeNode as resolveNestedTypeNode2,
83
- snakeCase as snakeCase3,
83
+ snakeCase as snakeCase4,
84
84
  structTypeNodeFromInstructionArgumentNodes,
85
- VALUE_NODES
85
+ VALUE_NODES as VALUE_NODES2
86
86
  } from "@codama/nodes";
87
87
  import { RenderMap } from "@codama/renderers-core";
88
88
  import {
@@ -93,7 +93,7 @@ import {
93
93
  recordLinkablesOnFirstVisitVisitor,
94
94
  recordNodeStackVisitor,
95
95
  staticVisitor,
96
- visit as visit3
96
+ visit as visit4
97
97
  } from "@codama/visitors-core";
98
98
 
99
99
  // src/getTypeManifestVisitor.ts
@@ -102,17 +102,17 @@ import {
102
102
  arrayTypeNode,
103
103
  definedTypeNode,
104
104
  fixedCountNode,
105
- isNode as isNode2,
105
+ isNode as isNode4,
106
106
  numberTypeNode,
107
107
  parseDocs,
108
- pascalCase as pascalCase2,
108
+ pascalCase as pascalCase3,
109
109
  prefixedCountNode,
110
110
  REGISTERED_TYPE_NODE_KINDS,
111
111
  remainderCountNode,
112
112
  resolveNestedTypeNode,
113
- snakeCase as snakeCase2
113
+ snakeCase as snakeCase3
114
114
  } from "@codama/nodes";
115
- import { extendVisitor, mergeVisitor, pipe, visit } from "@codama/visitors-core";
115
+ import { extendVisitor, mergeVisitor, pipe, visit as visit3 } from "@codama/visitors-core";
116
116
 
117
117
  // src/utils/codecs.ts
118
118
  import { getBase16Encoder, getBase58Encoder, getBase64Encoder, getUtf8Encoder } from "@solana/codecs-strings";
@@ -130,6 +130,204 @@ function getBytesFromBytesValueNode(node) {
130
130
  }
131
131
  }
132
132
 
133
+ // src/utils/discriminatorConstant.ts
134
+ import {
135
+ camelCase,
136
+ isNode as isNode2,
137
+ isNodeFilter,
138
+ snakeCase,
139
+ VALUE_NODES
140
+ } from "@codama/nodes";
141
+ import { visit as visit2 } from "@codama/visitors-core";
142
+
143
+ // src/renderValueNodeVisitor.ts
144
+ import {
145
+ arrayValueNode,
146
+ bytesValueNode,
147
+ isNode,
148
+ numberValueNode,
149
+ pascalCase
150
+ } from "@codama/nodes";
151
+ import { visit } from "@codama/visitors-core";
152
+ function renderValueNode(value, getImportFrom, useStr = false) {
153
+ return visit(value, renderValueNodeVisitor(getImportFrom, useStr));
154
+ }
155
+ function renderValueNodeVisitor(getImportFrom, useStr = false) {
156
+ return {
157
+ visitArrayValue(node) {
158
+ const list = node.items.map((v) => visit(v, this));
159
+ return {
160
+ imports: new ImportMap().mergeWith(...list.map((c) => c.imports)),
161
+ render: `[${list.map((c) => c.render).join(", ")}]`
162
+ };
163
+ },
164
+ visitBooleanValue(node) {
165
+ return {
166
+ imports: new ImportMap(),
167
+ render: JSON.stringify(node.boolean)
168
+ };
169
+ },
170
+ visitBytesValue(node) {
171
+ const bytes = getBytesFromBytesValueNode(node);
172
+ const numbers = Array.from(bytes).map(numberValueNode);
173
+ return visit(arrayValueNode(numbers), this);
174
+ },
175
+ visitConstantValue(node) {
176
+ if (isNode(node.value, "bytesValueNode")) {
177
+ return visit(node.value, this);
178
+ }
179
+ if (isNode(node.type, "stringTypeNode") && isNode(node.value, "stringValueNode")) {
180
+ return visit(bytesValueNode(node.type.encoding, node.value.string), this);
181
+ }
182
+ if (isNode(node.type, "numberTypeNode") && isNode(node.value, "numberValueNode")) {
183
+ const numberManifest = visit(node.value, this);
184
+ const { format, endian } = node.type;
185
+ const byteFunction = endian === "le" ? "to_le_bytes" : "to_be_bytes";
186
+ numberManifest.render = `${numberManifest.render}${format}.${byteFunction}()`;
187
+ return numberManifest;
188
+ }
189
+ throw new Error("Unsupported constant value type.");
190
+ },
191
+ visitEnumValue(node) {
192
+ const imports = new ImportMap();
193
+ const enumName = pascalCase(node.enum.name);
194
+ const variantName = pascalCase(node.variant);
195
+ const importFrom = getImportFrom(node.enum);
196
+ imports.add(`${importFrom}::${enumName}`);
197
+ if (!node.value) {
198
+ return { imports, render: `${enumName}::${variantName}` };
199
+ }
200
+ const enumValue = visit(node.value, this);
201
+ const fields = enumValue.render;
202
+ return {
203
+ imports: imports.mergeWith(enumValue.imports),
204
+ render: `${enumName}::${variantName} ${fields}`
205
+ };
206
+ },
207
+ visitMapEntryValue(node) {
208
+ const mapKey = visit(node.key, this);
209
+ const mapValue = visit(node.value, this);
210
+ return {
211
+ imports: mapKey.imports.mergeWith(mapValue.imports),
212
+ render: `[${mapKey.render}, ${mapValue.render}]`
213
+ };
214
+ },
215
+ visitMapValue(node) {
216
+ const map = node.entries.map((entry) => visit(entry, this));
217
+ const imports = new ImportMap().add("std::collection::HashMap");
218
+ return {
219
+ imports: imports.mergeWith(...map.map((c) => c.imports)),
220
+ render: `HashMap::from([${map.map((c) => c.render).join(", ")}])`
221
+ };
222
+ },
223
+ visitNoneValue() {
224
+ return {
225
+ imports: new ImportMap(),
226
+ render: "None"
227
+ };
228
+ },
229
+ visitNumberValue(node) {
230
+ return {
231
+ imports: new ImportMap(),
232
+ render: node.number.toString()
233
+ };
234
+ },
235
+ visitPublicKeyValue(node) {
236
+ return {
237
+ imports: new ImportMap().add("solana_pubkey"),
238
+ render: `pubkey!("${node.publicKey}")`
239
+ };
240
+ },
241
+ visitSetValue(node) {
242
+ const set = node.items.map((v) => visit(v, this));
243
+ const imports = new ImportMap().add("std::collection::HashSet");
244
+ return {
245
+ imports: imports.mergeWith(...set.map((c) => c.imports)),
246
+ render: `HashSet::from([${set.map((c) => c.render).join(", ")}])`
247
+ };
248
+ },
249
+ visitSomeValue(node) {
250
+ const child = visit(node.value, this);
251
+ return {
252
+ ...child,
253
+ render: `Some(${child.render})`
254
+ };
255
+ },
256
+ visitStringValue(node) {
257
+ return {
258
+ imports: new ImportMap(),
259
+ render: useStr ? `${JSON.stringify(node.string)}` : `String::from(${JSON.stringify(node.string)})`
260
+ };
261
+ },
262
+ visitStructFieldValue(node) {
263
+ const structValue = visit(node.value, this);
264
+ return {
265
+ imports: structValue.imports,
266
+ render: `${node.name}: ${structValue.render}`
267
+ };
268
+ },
269
+ visitStructValue(node) {
270
+ const struct = node.fields.map((field) => visit(field, this));
271
+ return {
272
+ imports: new ImportMap().mergeWith(...struct.map((c) => c.imports)),
273
+ render: `{ ${struct.map((c) => c.render).join(", ")} }`
274
+ };
275
+ },
276
+ visitTupleValue(node) {
277
+ const tuple = node.items.map((v) => visit(v, this));
278
+ return {
279
+ imports: new ImportMap().mergeWith(...tuple.map((c) => c.imports)),
280
+ render: `(${tuple.map((c) => c.render).join(", ")})`
281
+ };
282
+ }
283
+ };
284
+ }
285
+
286
+ // src/utils/discriminatorConstant.ts
287
+ function mergeFragments(fragments, merge) {
288
+ const imports = fragments.reduce((acc, frag) => acc.mergeWith(frag.imports), new ImportMap());
289
+ const render2 = merge(fragments.map((frag) => frag.render));
290
+ return { imports, render: render2 };
291
+ }
292
+ function getDiscriminatorConstants(scope) {
293
+ const fragments = scope.discriminatorNodes.map((node) => getDiscriminatorConstant(node, scope)).filter(Boolean);
294
+ return mergeFragments(fragments, (r) => r.join("\n\n"));
295
+ }
296
+ function getDiscriminatorConstant(discriminatorNode, scope) {
297
+ switch (discriminatorNode.kind) {
298
+ case "constantDiscriminatorNode":
299
+ return getConstantDiscriminatorConstant(discriminatorNode, scope);
300
+ case "fieldDiscriminatorNode":
301
+ return getFieldDiscriminatorConstant(discriminatorNode, scope);
302
+ default:
303
+ return null;
304
+ }
305
+ }
306
+ function getConstantDiscriminatorConstant(discriminatorNode, scope) {
307
+ const { discriminatorNodes, getImportFrom, prefix, typeManifestVisitor } = scope;
308
+ const index = discriminatorNodes.filter(isNodeFilter("constantDiscriminatorNode")).indexOf(discriminatorNode);
309
+ const suffix = index <= 0 ? "" : `_${index + 1}`;
310
+ const name = camelCase(`${prefix}_discriminator${suffix}`);
311
+ const typeManifest = visit2(discriminatorNode.constant.type, typeManifestVisitor);
312
+ const value = renderValueNode(discriminatorNode.constant.value, getImportFrom);
313
+ return getConstant(name, typeManifest, value);
314
+ }
315
+ function getFieldDiscriminatorConstant(discriminatorNode, scope) {
316
+ const { fields, prefix, getImportFrom, typeManifestVisitor } = scope;
317
+ const field = fields.find((f) => f.name === discriminatorNode.name);
318
+ if (!field || !field.defaultValue || !isNode2(field.defaultValue, VALUE_NODES)) {
319
+ return null;
320
+ }
321
+ const name = camelCase(`${prefix}_${discriminatorNode.name}`);
322
+ const typeManifest = visit2(field.type, typeManifestVisitor);
323
+ const value = renderValueNode(field.defaultValue, getImportFrom);
324
+ return getConstant(name, typeManifest, value);
325
+ }
326
+ function getConstant(name, typeManifest, value) {
327
+ const type = { imports: typeManifest.imports, render: typeManifest.type };
328
+ return mergeFragments([type, value], ([t, v]) => `pub const ${snakeCase(name).toUpperCase()}: ${t} = ${v};`);
329
+ }
330
+
133
331
  // src/utils/linkOverrides.ts
134
332
  import { CODAMA_ERROR__UNEXPECTED_NODE_KIND, CodamaError } from "@codama/errors";
135
333
  function getImportFromFactory(overrides) {
@@ -176,7 +374,7 @@ function getImportFromFactory(overrides) {
176
374
  // src/utils/render.ts
177
375
  import { dirname as pathDirname, join } from "path";
178
376
  import { fileURLToPath } from "url";
179
- import { camelCase, kebabCase, pascalCase, snakeCase, titleCase } from "@codama/nodes";
377
+ import { camelCase as camelCase2, kebabCase, pascalCase as pascalCase2, snakeCase as snakeCase2, titleCase } from "@codama/nodes";
180
378
  import nunjucks from "nunjucks";
181
379
  function rustDocblock(docs) {
182
380
  if (docs.length <= 0) return "";
@@ -188,9 +386,9 @@ var render = (template, context, options) => {
188
386
  const dirname = true ? pathDirname(fileURLToPath(import.meta.url)) : __dirname;
189
387
  const templates = false ? join(dirname, "..", "..", "public", "templates") : join(dirname, "templates");
190
388
  const env = nunjucks.configure(templates, { autoescape: false, trimBlocks: true, ...options });
191
- env.addFilter("pascalCase", pascalCase);
192
- env.addFilter("camelCase", camelCase);
193
- env.addFilter("snakeCase", snakeCase);
389
+ env.addFilter("pascalCase", pascalCase2);
390
+ env.addFilter("camelCase", camelCase2);
391
+ env.addFilter("snakeCase", snakeCase2);
194
392
  env.addFilter("kebabCase", kebabCase);
195
393
  env.addFilter("titleCase", titleCase);
196
394
  env.addFilter("rustDocblock", rustDocblock);
@@ -200,8 +398,8 @@ var render = (template, context, options) => {
200
398
  // src/utils/traitOptions.ts
201
399
  import {
202
400
  assertIsNode,
203
- camelCase as camelCase2,
204
- isNode,
401
+ camelCase as camelCase3,
402
+ isNode as isNode3,
205
403
  isScalarEnum
206
404
  } from "@codama/nodes";
207
405
  var DEFAULT_TRAIT_OPTIONS = {
@@ -233,7 +431,7 @@ function getTraitsFromNode(node, userOptions = {}) {
233
431
  return { imports: new ImportMap(), render: "" };
234
432
  }
235
433
  const sanitizedOverrides = Object.fromEntries(
236
- Object.entries(options.overrides).map(([key, value]) => [camelCase2(key), value])
434
+ Object.entries(options.overrides).map(([key, value]) => [camelCase3(key), value])
237
435
  );
238
436
  const nodeOverrides = sanitizedOverrides[node.name];
239
437
  const allTraits = nodeOverrides === void 0 ? getDefaultTraits(nodeType, options) : nodeOverrides;
@@ -255,9 +453,9 @@ function getTraitsFromNode(node, userOptions = {}) {
255
453
  return { imports, render: traitLines.join("") };
256
454
  }
257
455
  function getNodeType(node) {
258
- if (isNode(node, ["accountNode", "instructionNode"])) return "struct";
259
- if (isNode(node.type, "structTypeNode")) return "struct";
260
- if (isNode(node.type, "enumTypeNode")) {
456
+ if (isNode3(node, ["accountNode", "instructionNode"])) return "struct";
457
+ if (isNode3(node.type, "structTypeNode")) return "struct";
458
+ if (isNode3(node.type, "enumTypeNode")) {
261
459
  return isScalarEnum(node.type) ? "scalarEnum" : "dataEnum";
262
460
  }
263
461
  return "alias";
@@ -322,8 +520,8 @@ function getTypeManifestVisitor(options) {
322
520
  ),
323
521
  (v) => extendVisitor(v, {
324
522
  visitAccount(account, { self }) {
325
- parentName = pascalCase2(account.name);
326
- const manifest = visit(account.data, self);
523
+ parentName = pascalCase3(account.name);
524
+ const manifest = visit3(account.data, self);
327
525
  const traits = getTraitsFromNode2(account);
328
526
  manifest.imports.mergeWith(traits.imports);
329
527
  parentName = null;
@@ -333,14 +531,14 @@ function getTypeManifestVisitor(options) {
333
531
  };
334
532
  },
335
533
  visitArrayType(arrayType, { self }) {
336
- const childManifest = visit(arrayType.item, self);
337
- if (isNode2(arrayType.count, "fixedCountNode")) {
534
+ const childManifest = visit3(arrayType.item, self);
535
+ if (isNode4(arrayType.count, "fixedCountNode")) {
338
536
  return {
339
537
  ...childManifest,
340
538
  type: `[${childManifest.type}; ${arrayType.count.value}]`
341
539
  };
342
540
  }
343
- if (isNode2(arrayType.count, "remainderCountNode")) {
541
+ if (isNode4(arrayType.count, "remainderCountNode")) {
344
542
  childManifest.imports.add("kaigan::types::RemainderVec");
345
543
  return {
346
544
  ...childManifest,
@@ -397,19 +595,19 @@ function getTypeManifestVisitor(options) {
397
595
  arraySize = prefixedCountNode(parentSize);
398
596
  }
399
597
  const arrayType = arrayTypeNode(numberTypeNode("u8"), arraySize);
400
- return visit(arrayType, self);
598
+ return visit3(arrayType, self);
401
599
  },
402
600
  visitDefinedType(definedType, { self }) {
403
- parentName = pascalCase2(definedType.name);
404
- const manifest = visit(definedType.type, self);
601
+ parentName = pascalCase3(definedType.name);
602
+ const manifest = visit3(definedType.type, self);
405
603
  const traits = getTraitsFromNode2(definedType);
406
604
  manifest.imports.mergeWith(traits.imports);
407
605
  parentName = null;
408
- const renderedType = isNode2(definedType.type, ["enumTypeNode", "structTypeNode"]) ? manifest.type : `pub type ${pascalCase2(definedType.name)} = ${manifest.type};`;
606
+ const renderedType = isNode4(definedType.type, ["enumTypeNode", "structTypeNode"]) ? manifest.type : `pub type ${pascalCase3(definedType.name)} = ${manifest.type};`;
409
607
  return { ...manifest, type: `${traits.render}${renderedType}` };
410
608
  },
411
609
  visitDefinedTypeLink(node) {
412
- const pascalCaseDefinedType = pascalCase2(node.name);
610
+ const pascalCaseDefinedType = pascalCase3(node.name);
413
611
  const importFrom = getImportFrom(node);
414
612
  return {
415
613
  imports: new ImportMap().add(`${importFrom}::${pascalCaseDefinedType}`),
@@ -418,7 +616,7 @@ function getTypeManifestVisitor(options) {
418
616
  };
419
617
  },
420
618
  visitEnumEmptyVariantType(enumEmptyVariantType) {
421
- const name = pascalCase2(enumEmptyVariantType.name);
619
+ const name = pascalCase3(enumEmptyVariantType.name);
422
620
  return {
423
621
  imports: new ImportMap(),
424
622
  nestedStructs: [],
@@ -426,14 +624,14 @@ function getTypeManifestVisitor(options) {
426
624
  };
427
625
  },
428
626
  visitEnumStructVariantType(enumStructVariantType, { self }) {
429
- const name = pascalCase2(enumStructVariantType.name);
627
+ const name = pascalCase3(enumStructVariantType.name);
430
628
  const originalParentName = parentName;
431
629
  if (!originalParentName) {
432
630
  throw new Error("Enum struct variant type must have a parent name.");
433
631
  }
434
632
  inlineStruct = true;
435
- parentName = pascalCase2(originalParentName) + name;
436
- const typeManifest = visit(enumStructVariantType.struct, self);
633
+ parentName = pascalCase3(originalParentName) + name;
634
+ const typeManifest = visit3(enumStructVariantType.struct, self);
437
635
  inlineStruct = false;
438
636
  parentName = originalParentName;
439
637
  return {
@@ -442,13 +640,13 @@ function getTypeManifestVisitor(options) {
442
640
  };
443
641
  },
444
642
  visitEnumTupleVariantType(enumTupleVariantType, { self }) {
445
- const name = pascalCase2(enumTupleVariantType.name);
643
+ const name = pascalCase3(enumTupleVariantType.name);
446
644
  const originalParentName = parentName;
447
645
  if (!originalParentName) {
448
646
  throw new Error("Enum struct variant type must have a parent name.");
449
647
  }
450
- parentName = pascalCase2(originalParentName) + name;
451
- const childManifest = visit(enumTupleVariantType.tuple, self);
648
+ parentName = pascalCase3(originalParentName) + name;
649
+ const childManifest = visit3(enumTupleVariantType.tuple, self);
452
650
  parentName = originalParentName;
453
651
  let derive = "";
454
652
  if (childManifest.type === "(Pubkey)") {
@@ -466,25 +664,25 @@ function getTypeManifestVisitor(options) {
466
664
  if (!originalParentName) {
467
665
  throw new Error("Enum type must have a parent name.");
468
666
  }
469
- const variants = enumType.variants.map((variant) => visit(variant, self));
667
+ const variants = enumType.variants.map((variant) => visit3(variant, self));
470
668
  const variantNames = variants.map((variant) => variant.type).join("\n");
471
669
  const mergedManifest = mergeManifests(variants);
472
670
  return {
473
671
  ...mergedManifest,
474
- type: `pub enum ${pascalCase2(originalParentName)} {
672
+ type: `pub enum ${pascalCase3(originalParentName)} {
475
673
  ${variantNames}
476
674
  }`
477
675
  };
478
676
  },
479
677
  visitFixedSizeType(fixedSizeType, { self }) {
480
678
  parentSize = fixedSizeType.size;
481
- const manifest = visit(fixedSizeType.type, self);
679
+ const manifest = visit3(fixedSizeType.type, self);
482
680
  parentSize = null;
483
681
  return manifest;
484
682
  },
485
683
  visitMapType(mapType, { self }) {
486
- const key = visit(mapType.key, self);
487
- const value = visit(mapType.value, self);
684
+ const key = visit3(mapType.key, self);
685
+ const value = visit3(mapType.value, self);
488
686
  const mergedManifest = mergeManifests([key, value]);
489
687
  mergedManifest.imports.add("std::collections::HashMap");
490
688
  return {
@@ -510,7 +708,7 @@ ${variantNames}
510
708
  };
511
709
  },
512
710
  visitOptionType(optionType, { self }) {
513
- const childManifest = visit(optionType.item, self);
711
+ const childManifest = visit3(optionType.item, self);
514
712
  const optionPrefix = resolveNestedTypeNode(optionType.prefix);
515
713
  if (optionPrefix.format === "u8" && optionPrefix.endian === "le") {
516
714
  return {
@@ -531,7 +729,7 @@ ${variantNames}
531
729
  throw new CodamaError2(CODAMA_ERROR__RENDERERS__UNSUPPORTED_NODE, { kind: node.kind, node });
532
730
  },
533
731
  visitSetType(setType, { self }) {
534
- const childManifest = visit(setType.item, self);
732
+ const childManifest = visit3(setType.item, self);
535
733
  childManifest.imports.add("std::collections::HashSet");
536
734
  return {
537
735
  ...childManifest,
@@ -540,7 +738,7 @@ ${variantNames}
540
738
  },
541
739
  visitSizePrefixType(sizePrefixType, { self }) {
542
740
  parentSize = resolveNestedTypeNode(sizePrefixType.prefix);
543
- const manifest = visit(sizePrefixType.type, self);
741
+ const manifest = visit3(sizePrefixType.type, self);
544
742
  parentSize = null;
545
743
  return manifest;
546
744
  },
@@ -559,7 +757,7 @@ ${variantNames}
559
757
  type: `[u8; ${parentSize}]`
560
758
  };
561
759
  }
562
- if (isNode2(parentSize, "numberTypeNode") && parentSize.endian === "le") {
760
+ if (isNode4(parentSize, "numberTypeNode") && parentSize.endian === "le") {
563
761
  switch (parentSize.format) {
564
762
  case "u32":
565
763
  return {
@@ -590,14 +788,14 @@ ${variantNames}
590
788
  if (!originalParentName) {
591
789
  throw new Error("Struct field type must have a parent name.");
592
790
  }
593
- parentName = pascalCase2(originalParentName) + pascalCase2(structFieldType.name);
791
+ parentName = pascalCase3(originalParentName) + pascalCase3(structFieldType.name);
594
792
  nestedStruct = true;
595
793
  inlineStruct = false;
596
- const fieldManifest = visit(structFieldType.type, self);
794
+ const fieldManifest = visit3(structFieldType.type, self);
597
795
  parentName = originalParentName;
598
796
  inlineStruct = originalInlineStruct;
599
797
  nestedStruct = originalNestedStruct;
600
- const fieldName = snakeCase2(structFieldType.name);
798
+ const fieldName = snakeCase3(structFieldType.name);
601
799
  const docblock = rustDocblock(parseDocs(structFieldType.docs));
602
800
  const resolvedNestedType = resolveNestedTypeNode(structFieldType.type);
603
801
  let derive = "";
@@ -605,9 +803,9 @@ ${variantNames}
605
803
  derive = '#[cfg_attr(feature = "serde", serde(with = "serde_with::As::<serde_with::DisplayFromStr>"))]\n';
606
804
  } else if (fieldManifest.type === "Vec<Pubkey>") {
607
805
  derive = '#[cfg_attr(feature = "serde", serde(with = "serde_with::As::<Vec<serde_with::DisplayFromStr>>"))]\n';
608
- } else if (isNode2(resolvedNestedType, "arrayTypeNode") && isNode2(resolvedNestedType.count, "fixedCountNode") && resolvedNestedType.count.value > 32) {
806
+ } else if (isNode4(resolvedNestedType, "arrayTypeNode") && isNode4(resolvedNestedType.count, "fixedCountNode") && resolvedNestedType.count.value > 32) {
609
807
  derive = '#[cfg_attr(feature = "serde", serde(with = "serde_big_array::BigArray"))]\n';
610
- } else if (isNode2(resolvedNestedType, ["bytesTypeNode", "stringTypeNode"]) && isNode2(structFieldType.type, "fixedSizeTypeNode") && structFieldType.type.size > 32) {
808
+ } else if (isNode4(resolvedNestedType, ["bytesTypeNode", "stringTypeNode"]) && isNode4(structFieldType.type, "fixedSizeTypeNode") && structFieldType.type.size > 32) {
611
809
  derive = '#[cfg_attr(feature = "serde", serde(with = "serde_with::As::<serde_with::Bytes>"))]\n';
612
810
  }
613
811
  return {
@@ -620,7 +818,7 @@ ${variantNames}
620
818
  if (!originalParentName) {
621
819
  throw new Error("Struct type must have a parent name.");
622
820
  }
623
- const fields = structType.fields.map((field) => visit(field, self));
821
+ const fields = structType.fields.map((field) => visit3(field, self));
624
822
  const fieldTypes = fields.map((field) => field.type).join("\n");
625
823
  const mergedManifest = mergeManifests(fields);
626
824
  if (nestedStruct) {
@@ -632,11 +830,11 @@ ${variantNames}
632
830
  ...mergedManifest,
633
831
  nestedStructs: [
634
832
  ...mergedManifest.nestedStructs,
635
- `${nestedTraits.render}pub struct ${pascalCase2(originalParentName)} {
833
+ `${nestedTraits.render}pub struct ${pascalCase3(originalParentName)} {
636
834
  ${fieldTypes}
637
835
  }`
638
836
  ],
639
- type: pascalCase2(originalParentName)
837
+ type: pascalCase3(originalParentName)
640
838
  };
641
839
  }
642
840
  if (inlineStruct) {
@@ -646,13 +844,13 @@ ${fieldTypes}
646
844
  }
647
845
  return {
648
846
  ...mergedManifest,
649
- type: `pub struct ${pascalCase2(originalParentName)} {
847
+ type: `pub struct ${pascalCase3(originalParentName)} {
650
848
  ${fieldTypes}
651
849
  }`
652
850
  };
653
851
  },
654
852
  visitTupleType(tupleType, { self }) {
655
- const items = tupleType.items.map((item) => visit(item, self));
853
+ const items = tupleType.items.map((item) => visit3(item, self));
656
854
  const mergedManifest = mergeManifests(items);
657
855
  return {
658
856
  ...mergedManifest,
@@ -672,149 +870,6 @@ function mergeManifests(manifests) {
672
870
  };
673
871
  }
674
872
 
675
- // src/renderValueNodeVisitor.ts
676
- import {
677
- arrayValueNode,
678
- bytesValueNode,
679
- isNode as isNode3,
680
- numberValueNode,
681
- pascalCase as pascalCase3
682
- } from "@codama/nodes";
683
- import { visit as visit2 } from "@codama/visitors-core";
684
- function renderValueNode(value, getImportFrom, useStr = false) {
685
- return visit2(value, renderValueNodeVisitor(getImportFrom, useStr));
686
- }
687
- function renderValueNodeVisitor(getImportFrom, useStr = false) {
688
- return {
689
- visitArrayValue(node) {
690
- const list = node.items.map((v) => visit2(v, this));
691
- return {
692
- imports: new ImportMap().mergeWith(...list.map((c) => c.imports)),
693
- render: `[${list.map((c) => c.render).join(", ")}]`
694
- };
695
- },
696
- visitBooleanValue(node) {
697
- return {
698
- imports: new ImportMap(),
699
- render: JSON.stringify(node.boolean)
700
- };
701
- },
702
- visitBytesValue(node) {
703
- const bytes = getBytesFromBytesValueNode(node);
704
- const numbers = Array.from(bytes).map(numberValueNode);
705
- return visit2(arrayValueNode(numbers), this);
706
- },
707
- visitConstantValue(node) {
708
- if (isNode3(node.value, "bytesValueNode")) {
709
- return visit2(node.value, this);
710
- }
711
- if (isNode3(node.type, "stringTypeNode") && isNode3(node.value, "stringValueNode")) {
712
- return visit2(bytesValueNode(node.type.encoding, node.value.string), this);
713
- }
714
- if (isNode3(node.type, "numberTypeNode") && isNode3(node.value, "numberValueNode")) {
715
- const numberManifest = visit2(node.value, this);
716
- const { format, endian } = node.type;
717
- const byteFunction = endian === "le" ? "to_le_bytes" : "to_be_bytes";
718
- numberManifest.render = `${numberManifest.render}${format}.${byteFunction}()`;
719
- return numberManifest;
720
- }
721
- throw new Error("Unsupported constant value type.");
722
- },
723
- visitEnumValue(node) {
724
- const imports = new ImportMap();
725
- const enumName = pascalCase3(node.enum.name);
726
- const variantName = pascalCase3(node.variant);
727
- const importFrom = getImportFrom(node.enum);
728
- imports.add(`${importFrom}::${enumName}`);
729
- if (!node.value) {
730
- return { imports, render: `${enumName}::${variantName}` };
731
- }
732
- const enumValue = visit2(node.value, this);
733
- const fields = enumValue.render;
734
- return {
735
- imports: imports.mergeWith(enumValue.imports),
736
- render: `${enumName}::${variantName} ${fields}`
737
- };
738
- },
739
- visitMapEntryValue(node) {
740
- const mapKey = visit2(node.key, this);
741
- const mapValue = visit2(node.value, this);
742
- return {
743
- imports: mapKey.imports.mergeWith(mapValue.imports),
744
- render: `[${mapKey.render}, ${mapValue.render}]`
745
- };
746
- },
747
- visitMapValue(node) {
748
- const map = node.entries.map((entry) => visit2(entry, this));
749
- const imports = new ImportMap().add("std::collection::HashMap");
750
- return {
751
- imports: imports.mergeWith(...map.map((c) => c.imports)),
752
- render: `HashMap::from([${map.map((c) => c.render).join(", ")}])`
753
- };
754
- },
755
- visitNoneValue() {
756
- return {
757
- imports: new ImportMap(),
758
- render: "None"
759
- };
760
- },
761
- visitNumberValue(node) {
762
- return {
763
- imports: new ImportMap(),
764
- render: node.number.toString()
765
- };
766
- },
767
- visitPublicKeyValue(node) {
768
- return {
769
- imports: new ImportMap().add("solana_pubkey"),
770
- render: `pubkey!("${node.publicKey}")`
771
- };
772
- },
773
- visitSetValue(node) {
774
- const set = node.items.map((v) => visit2(v, this));
775
- const imports = new ImportMap().add("std::collection::HashSet");
776
- return {
777
- imports: imports.mergeWith(...set.map((c) => c.imports)),
778
- render: `HashSet::from([${set.map((c) => c.render).join(", ")}])`
779
- };
780
- },
781
- visitSomeValue(node) {
782
- const child = visit2(node.value, this);
783
- return {
784
- ...child,
785
- render: `Some(${child.render})`
786
- };
787
- },
788
- visitStringValue(node) {
789
- return {
790
- imports: new ImportMap(),
791
- render: useStr ? `${JSON.stringify(node.string)}` : `String::from(${JSON.stringify(node.string)})`
792
- };
793
- },
794
- visitStructFieldValue(node) {
795
- const structValue = visit2(node.value, this);
796
- return {
797
- imports: structValue.imports,
798
- render: `${node.name}: ${structValue.render}`
799
- };
800
- },
801
- visitStructValue(node) {
802
- const struct = node.fields.map((field) => visit2(field, this));
803
- return {
804
- imports: new ImportMap().mergeWith(...struct.map((c) => c.imports)),
805
- render: `{ ${struct.map((c) => c.render).join(", ")} }`
806
- };
807
- },
808
- visitTupleValue(node) {
809
- const tuple = node.items.map((v) => visit2(v, this));
810
- return {
811
- imports: new ImportMap().mergeWith(...tuple.map((c) => c.imports)),
812
- render: `(${tuple.map((c) => c.render).join(", ")})`
813
- };
814
- }
815
- };
816
- }
817
-
818
873
  // src/getRenderMapVisitor.ts
819
874
  function getRenderMapVisitor(options = {}) {
820
875
  const linkables = new LinkableDictionary();
@@ -832,40 +887,49 @@ function getRenderMapVisitor(options = {}) {
832
887
  }),
833
888
  (v) => extendVisitor2(v, {
834
889
  visitAccount(node) {
835
- const typeManifest = visit3(node, typeManifestVisitor);
890
+ const typeManifest = visit4(node, typeManifestVisitor);
891
+ const fields = resolveNestedTypeNode2(node.data).fields;
892
+ const discriminatorConstants = getDiscriminatorConstants({
893
+ discriminatorNodes: node.discriminators ?? [],
894
+ fields,
895
+ getImportFrom,
896
+ prefix: node.name,
897
+ typeManifestVisitor
898
+ });
836
899
  const seedsImports = new ImportMap();
837
900
  const pda = node.pda ? linkables.get([...stack.getPath(), node.pda]) : void 0;
838
901
  const pdaSeeds = pda?.seeds ?? [];
839
902
  const seeds = pdaSeeds.map((seed) => {
840
- if (isNode4(seed, "variablePdaSeedNode")) {
841
- const seedManifest2 = visit3(seed.type, typeManifestVisitor);
903
+ if (isNode5(seed, "variablePdaSeedNode")) {
904
+ const seedManifest2 = visit4(seed.type, typeManifestVisitor);
842
905
  seedsImports.mergeWith(seedManifest2.imports);
843
906
  const resolvedType2 = resolveNestedTypeNode2(seed.type);
844
907
  return { ...seed, resolvedType: resolvedType2, typeManifest: seedManifest2 };
845
908
  }
846
- if (isNode4(seed.value, "programIdValueNode")) {
909
+ if (isNode5(seed.value, "programIdValueNode")) {
847
910
  return seed;
848
911
  }
849
- const seedManifest = visit3(seed.type, typeManifestVisitor);
912
+ const seedManifest = visit4(seed.type, typeManifestVisitor);
850
913
  const valueManifest = renderValueNode(seed.value, getImportFrom, true);
851
914
  seedsImports.mergeWith(valueManifest.imports);
852
915
  const resolvedType = resolveNestedTypeNode2(seed.type);
853
916
  return { ...seed, resolvedType, typeManifest: seedManifest, valueManifest };
854
917
  });
855
- const hasVariableSeeds = pdaSeeds.filter(isNodeFilter("variablePdaSeedNode")).length > 0;
856
- const constantSeeds = seeds.filter(isNodeFilter("constantPdaSeedNode")).filter((seed) => !isNode4(seed.value, "programIdValueNode"));
918
+ const hasVariableSeeds = pdaSeeds.filter(isNodeFilter2("variablePdaSeedNode")).length > 0;
919
+ const constantSeeds = seeds.filter(isNodeFilter2("constantPdaSeedNode")).filter((seed) => !isNode5(seed.value, "programIdValueNode"));
857
920
  const { imports } = typeManifest;
858
921
  if (hasVariableSeeds) {
859
922
  imports.mergeWith(seedsImports);
860
923
  }
861
924
  return new RenderMap().add(
862
- `accounts/${snakeCase3(node.name)}.rs`,
925
+ `accounts/${snakeCase4(node.name)}.rs`,
863
926
  render("accountsPage.njk", {
864
927
  account: node,
865
928
  anchorTraits,
866
929
  constantSeeds,
930
+ discriminatorConstants: discriminatorConstants.render,
867
931
  hasVariableSeeds,
868
- imports: imports.remove(`generatedAccounts::${pascalCase4(node.name)}`).toString(dependencyMap),
932
+ imports: imports.mergeWith(discriminatorConstants.imports).remove(`generatedAccounts::${pascalCase4(node.name)}`).toString(dependencyMap),
869
933
  pda,
870
934
  program,
871
935
  seeds,
@@ -874,10 +938,10 @@ function getRenderMapVisitor(options = {}) {
874
938
  );
875
939
  },
876
940
  visitDefinedType(node) {
877
- const typeManifest = visit3(node, typeManifestVisitor);
941
+ const typeManifest = visit4(node, typeManifestVisitor);
878
942
  const imports = new ImportMap().mergeWithManifest(typeManifest);
879
943
  return new RenderMap().add(
880
- `types/${snakeCase3(node.name)}.rs`,
944
+ `types/${snakeCase4(node.name)}.rs`,
881
945
  render("definedTypesPage.njk", {
882
946
  definedType: node,
883
947
  imports: imports.remove(`generatedTypes::${pascalCase4(node.name)}`).toString(dependencyMap),
@@ -893,6 +957,13 @@ function getRenderMapVisitor(options = {}) {
893
957
  `[Rust] Accounts and args of instruction [${node.name}] have the following conflicting attributes [${accountsAndArgsConflicts.join(", ")}]. Thus, the conflicting arguments will be suffixed with "_arg". You may want to rename the conflicting attributes.`
894
958
  );
895
959
  }
960
+ const discriminatorConstants = getDiscriminatorConstants({
961
+ discriminatorNodes: node.discriminators ?? [],
962
+ fields: node.arguments,
963
+ getImportFrom,
964
+ prefix: node.name,
965
+ typeManifestVisitor
966
+ });
896
967
  const instructionArgs = [];
897
968
  let hasArgs = false;
898
969
  let hasOptional = false;
@@ -903,10 +974,10 @@ function getRenderMapVisitor(options = {}) {
903
974
  nestedStruct: true,
904
975
  parentName: `${pascalCase4(node.name)}InstructionData`
905
976
  });
906
- const manifest = visit3(argument.type, argumentVisitor);
977
+ const manifest = visit4(argument.type, argumentVisitor);
907
978
  imports.mergeWith(manifest.imports);
908
- const innerOptionType = isNode4(argument.type, "optionTypeNode") ? manifest.type.slice("Option<".length, -1) : null;
909
- const hasDefaultValue = !!argument.defaultValue && isNode4(argument.defaultValue, VALUE_NODES);
979
+ const innerOptionType = isNode5(argument.type, "optionTypeNode") ? manifest.type.slice("Option<".length, -1) : null;
980
+ const hasDefaultValue = !!argument.defaultValue && isNode5(argument.defaultValue, VALUE_NODES2);
910
981
  let renderValue = null;
911
982
  if (hasDefaultValue) {
912
983
  const { imports: argImports, render: value } = renderValueNode(
@@ -934,16 +1005,17 @@ function getRenderMapVisitor(options = {}) {
934
1005
  getTraitsFromNode: getTraitsFromNode2,
935
1006
  parentName: `${pascalCase4(node.name)}InstructionData`
936
1007
  });
937
- const typeManifest = visit3(struct, structVisitor);
1008
+ const typeManifest = visit4(struct, structVisitor);
938
1009
  const dataTraits = getTraitsFromNode2(node);
939
1010
  imports.mergeWith(dataTraits.imports);
940
1011
  return new RenderMap().add(
941
- `instructions/${snakeCase3(node.name)}.rs`,
1012
+ `instructions/${snakeCase4(node.name)}.rs`,
942
1013
  render("instructionsPage.njk", {
943
1014
  dataTraits: dataTraits.render,
1015
+ discriminatorConstants: discriminatorConstants.render,
944
1016
  hasArgs,
945
1017
  hasOptional,
946
- imports: imports.remove(`generatedInstructions::${pascalCase4(node.name)}`).toString(dependencyMap),
1018
+ imports: imports.mergeWith(discriminatorConstants.imports).remove(`generatedInstructions::${pascalCase4(node.name)}`).toString(dependencyMap),
947
1019
  instruction: node,
948
1020
  instructionArgs,
949
1021
  program,
@@ -953,14 +1025,14 @@ function getRenderMapVisitor(options = {}) {
953
1025
  },
954
1026
  visitProgram(node, { self }) {
955
1027
  program = node;
956
- const renderMap = new RenderMap().mergeWith(...node.accounts.map((account) => visit3(account, self))).mergeWith(...node.definedTypes.map((type) => visit3(type, self))).mergeWith(
1028
+ const renderMap = new RenderMap().mergeWith(...node.accounts.map((account) => visit4(account, self))).mergeWith(...node.definedTypes.map((type) => visit4(type, self))).mergeWith(
957
1029
  ...getAllInstructionsWithSubs(node, {
958
1030
  leavesOnly: !renderParentInstructions
959
- }).map((ix) => visit3(ix, self))
1031
+ }).map((ix) => visit4(ix, self))
960
1032
  );
961
1033
  if (node.errors.length > 0) {
962
1034
  renderMap.add(
963
- `errors/${snakeCase3(node.name)}.rs`,
1035
+ `errors/${snakeCase4(node.name)}.rs`,
964
1036
  render("errorsPage.njk", {
965
1037
  errors: node.errors,
966
1038
  imports: new ImportMap().toString(dependencyMap),
@@ -1006,7 +1078,7 @@ function getRenderMapVisitor(options = {}) {
1006
1078
  if (definedTypesToExport.length > 0) {
1007
1079
  map.add("types/mod.rs", render("definedTypesMod.njk", ctx));
1008
1080
  }
1009
- return map.add("mod.rs", render("rootMod.njk", ctx)).mergeWith(...getAllPrograms(node).map((p) => visit3(p, self)));
1081
+ return map.add("mod.rs", render("rootMod.njk", ctx)).mergeWith(...getAllPrograms(node).map((p) => visit4(p, self)));
1010
1082
  }
1011
1083
  }),
1012
1084
  (v) => recordNodeStackVisitor(v, stack),
@@ -1025,14 +1097,14 @@ function getConflictsForInstructionAccountsAndArgs(instruction) {
1025
1097
  // src/renderVisitor.ts
1026
1098
  import { logError, logWarn as logWarn2 } from "@codama/errors";
1027
1099
  import { deleteDirectory, writeRenderMapVisitor } from "@codama/renderers-core";
1028
- import { rootNodeVisitor, visit as visit4 } from "@codama/visitors-core";
1100
+ import { rootNodeVisitor, visit as visit5 } from "@codama/visitors-core";
1029
1101
  import { spawnSync } from "child_process";
1030
1102
  function renderVisitor(path, options = {}) {
1031
1103
  return rootNodeVisitor((root) => {
1032
1104
  if (options.deleteFolderBeforeRendering ?? true) {
1033
1105
  deleteDirectory(path);
1034
1106
  }
1035
- visit4(root, writeRenderMapVisitor(getRenderMapVisitor(options), path));
1107
+ visit5(root, writeRenderMapVisitor(getRenderMapVisitor(options), path));
1036
1108
  if (options.formatCode) {
1037
1109
  if (options.crateFolder) {
1038
1110
  const toolchain = options.toolchain ?? "+stable";