getDebugStringVisitor.ts 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111
  1. import { Node } from '@kinobi-so/nodes';
  2. import { interceptVisitor } from './interceptVisitor';
  3. import { mergeVisitor } from './mergeVisitor';
  4. import { pipe } from './pipe';
  5. import { Visitor } from './visitor';
  6. export function getDebugStringVisitor(options: { indent?: boolean; indentSeparator?: string } = {}): Visitor<string> {
  7. const indent = options.indent ?? false;
  8. const indentSeparator = options.indentSeparator ?? '| ';
  9. let stackLevel = -1;
  10. return pipe(
  11. mergeVisitor<string>(
  12. node => {
  13. const details = getNodeDetails(node).join('.');
  14. if (indent) {
  15. return `${indentSeparator.repeat(stackLevel)}${node.kind}${details ? ` [${details}]` : ''}`;
  16. }
  17. return `${node.kind}${details ? `[${details}]` : ''}`;
  18. },
  19. (node, values) => {
  20. const details = getNodeDetails(node).join('.');
  21. if (indent) {
  22. return [
  23. `${indentSeparator.repeat(stackLevel)}${node.kind}${details ? ` [${details}]` : ''}`,
  24. ...values,
  25. ].join('\n');
  26. }
  27. return `${node.kind}${details ? `[${details}]` : ''}(${values.join(', ')})`;
  28. },
  29. ),
  30. v =>
  31. interceptVisitor(v, (node, next) => {
  32. stackLevel += 1;
  33. const newNode = next(node);
  34. stackLevel -= 1;
  35. return newNode;
  36. }),
  37. );
  38. }
  39. function getNodeDetails(node: Node): string[] {
  40. switch (node.kind) {
  41. case 'programNode':
  42. return [node.name, node.publicKey];
  43. case 'instructionAccountNode':
  44. return [
  45. node.name,
  46. ...(node.isWritable ? ['writable'] : []),
  47. ...(node.isSigner === true ? ['signer'] : []),
  48. ...(node.isSigner === 'either' ? ['optionalSigner'] : []),
  49. ...(node.isOptional ? ['optional'] : []),
  50. ];
  51. case 'instructionRemainingAccountsNode':
  52. return [
  53. ...(node.isOptional ? ['optional'] : []),
  54. ...(node.isWritable ? ['writable'] : []),
  55. ...(node.isSigner === true ? ['signer'] : []),
  56. ...(node.isSigner === 'either' ? ['optionalSigner'] : []),
  57. ];
  58. case 'instructionByteDeltaNode':
  59. return [...(node.subtract ? ['subtract'] : []), ...(node.withHeader ? ['withHeader'] : [])];
  60. case 'errorNode':
  61. return [node.code.toString(), node.name];
  62. case 'programLinkNode':
  63. return [node.name];
  64. case 'pdaLinkNode':
  65. case 'accountLinkNode':
  66. case 'definedTypeLinkNode':
  67. return [...(node.program ? [node.program.name] : []), node.name];
  68. case 'numberTypeNode':
  69. return [node.format, ...(node.endian === 'be' ? ['bigEndian'] : [])];
  70. case 'amountTypeNode':
  71. return [node.decimals.toString(), ...(node.unit ? [node.unit] : [])];
  72. case 'stringTypeNode':
  73. return [node.encoding];
  74. case 'optionTypeNode':
  75. return node.fixed ? ['fixed'] : [];
  76. case 'fixedCountNode':
  77. return [node.value.toString()];
  78. case 'numberValueNode':
  79. return [node.number.toString()];
  80. case 'stringValueNode':
  81. return [node.string];
  82. case 'booleanValueNode':
  83. return [node.boolean ? 'true' : 'false'];
  84. case 'bytesValueNode':
  85. return [node.encoding, node.data];
  86. case 'publicKeyValueNode':
  87. return [...(node.identifier ? [`${node.identifier}`] : []), node.publicKey];
  88. case 'enumValueNode':
  89. return [node.variant];
  90. case 'resolverValueNode':
  91. return [node.name];
  92. case 'constantDiscriminatorNode':
  93. return [...(node.offset > 0 ? [`offset:${node.offset}`] : [])];
  94. case 'fieldDiscriminatorNode':
  95. return [node.name, ...(node.offset > 0 ? [`offset:${node.offset}`] : [])];
  96. case 'sizeDiscriminatorNode':
  97. return [node.size.toString()];
  98. case 'fixedSizeTypeNode':
  99. return [node.size.toString()];
  100. case 'preOffsetTypeNode':
  101. return [node.offset.toString(), node.strategy ?? 'relative'];
  102. case 'postOffsetTypeNode':
  103. return [node.offset.toString(), node.strategy ?? 'relative'];
  104. default:
  105. return 'name' in node ? [node.name] : [];
  106. }
  107. }