Source

lib/bindings/types.js

"use strict";

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.TypeGenerator = void 0;
var _stellarBase = require("@stellar/stellar-base");
var _utils = require("./utils");
/**
 * Interface for struct fields
 */

/**
 * Interface for union cases
 */

/**
 * Interface for enum cases
 */

/**
 * Generates TypeScript type definitions from Stellar contract specs
 */
class TypeGenerator {
  constructor(spec) {
    this.spec = spec;
  }

  /**
   * Generate all TypeScript type definitions
   */
  generate() {
    // Generate types for each entry in the spec
    const types = this.spec.entries.map(entry => this.generateEntry(entry)).filter(t => t).join("\n\n");
    // Generate imports for all types
    const imports = this.generateImports();
    return `${imports}

    ${types}
    `;
  }

  /**
   * Generate TypeScript for a single spec entry
   */
  generateEntry(entry) {
    switch (entry.switch()) {
      case _stellarBase.xdr.ScSpecEntryKind.scSpecEntryUdtStructV0():
        if ((0, _utils.isTupleStruct)(entry.udtStructV0())) {
          return this.generateTupleStruct(entry.udtStructV0());
        }
        return this.generateStruct(entry.udtStructV0());
      case _stellarBase.xdr.ScSpecEntryKind.scSpecEntryUdtUnionV0():
        return this.generateUnion(entry.udtUnionV0());
      case _stellarBase.xdr.ScSpecEntryKind.scSpecEntryUdtEnumV0():
        return this.generateEnum(entry.udtEnumV0());
      case _stellarBase.xdr.ScSpecEntryKind.scSpecEntryUdtErrorEnumV0():
        return this.generateErrorEnum(entry.udtErrorEnumV0());
      default:
        return null;
    }
  }
  generateImports() {
    const imports = (0, _utils.generateTypeImports)(this.spec.entries.flatMap(entry => {
      switch (entry.switch()) {
        case _stellarBase.xdr.ScSpecEntryKind.scSpecEntryUdtStructV0():
          return entry.udtStructV0().fields().map(field => field.type());
        case _stellarBase.xdr.ScSpecEntryKind.scSpecEntryUdtUnionV0():
          return entry.udtUnionV0().cases().flatMap(unionCase => {
            if (unionCase.switch() === _stellarBase.xdr.ScSpecUdtUnionCaseV0Kind.scSpecUdtUnionCaseTupleV0()) {
              return unionCase.tupleCase().type();
            }
            return [];
          });
        case _stellarBase.xdr.ScSpecEntryKind.scSpecEntryUdtEnumV0():
          // Enums do not have associated types
          return [];
        case _stellarBase.xdr.ScSpecEntryKind.scSpecEntryUdtErrorEnumV0():
          // Enums do not have associated types
          return [];
        default:
          return [];
      }
    }));
    return (0, _utils.formatImports)(imports, {
      includeTypeFileImports: false // Types file doesn't import from itself
    });
  }

  /**
   * Generate TypeScript interface for a struct
   */
  generateStruct(struct) {
    const name = (0, _utils.sanitizeIdentifier)(struct.name().toString());
    const doc = (0, _utils.formatJSDocComment)(struct.doc().toString() || `Struct: ${name}`, 0);
    const fields = struct.fields().map(field => {
      const fieldName = field.name().toString();
      const fieldType = (0, _utils.parseTypeFromTypeDef)(field.type());
      const fieldDoc = (0, _utils.formatJSDocComment)(field.doc().toString(), 2);
      return `${fieldDoc}  ${fieldName}: ${fieldType};`;
    }).join("\n");
    return `${doc}export interface ${name} {
${fields}
}`;
  }

  /**
   * Generate TypeScript union type
   */
  generateUnion(union) {
    const name = (0, _utils.sanitizeIdentifier)(union.name().toString());
    const doc = (0, _utils.formatJSDocComment)(union.doc().toString() || `Union: ${name}`, 0);
    const cases = union.cases().map(unionCase => this.generateUnionCase(unionCase));
    const caseTypes = cases.map(c => {
      if (c.types.length > 0) {
        return `${(0, _utils.formatJSDocComment)(c.doc, 2)}  { tag: "${c.name}"; values: readonly [${c.types.join(", ")}] }`;
      }
      return `${(0, _utils.formatJSDocComment)(c.doc, 2)}  { tag: "${c.name}"; values: void }`;
    }).join(" |\n");
    return `${doc} export type ${name} =
${caseTypes};`;
  }

  /**
   * Generate TypeScript enum
   */
  generateEnum(enumEntry) {
    const name = (0, _utils.sanitizeIdentifier)(enumEntry.name().toString());
    const doc = (0, _utils.formatJSDocComment)(enumEntry.doc().toString() || `Enum: ${name}`, 0);
    const members = enumEntry.cases().map(enumCase => {
      const caseName = enumCase.name().toString();
      const caseValue = enumCase.value();
      const caseDoc = enumCase.doc().toString() || `Enum Case: ${caseName}`;
      return `${(0, _utils.formatJSDocComment)(caseDoc, 2)}  ${caseName} = ${caseValue}`;
    }).join(",\n");
    return `${doc}export enum ${name} {
${members}
}`;
  }

  /**
   * Generate TypeScript error enum
   */
  generateErrorEnum(errorEnum) {
    const name = (0, _utils.sanitizeIdentifier)(errorEnum.name().toString());
    const doc = (0, _utils.formatJSDocComment)(errorEnum.doc().toString() || `Error Enum: ${name}`, 0);
    const cases = errorEnum.cases().map(enumCase => this.generateEnumCase(enumCase));
    const members = cases.map(c => {
      return `${(0, _utils.formatJSDocComment)(c.doc, 2)}  ${c.value} : { message: "${c.name}" }`;
    }).join(",\n");
    return `${doc}export const ${name} = {
${members}
}`;
  }

  /**
   * Generate union case
   */
  generateUnionCase(unionCase) {
    switch (unionCase.switch()) {
      case _stellarBase.xdr.ScSpecUdtUnionCaseV0Kind.scSpecUdtUnionCaseVoidV0():
        {
          const voidCase = unionCase.voidCase();
          return {
            doc: voidCase.doc().toString(),
            name: voidCase.name().toString(),
            types: []
          };
        }
      case _stellarBase.xdr.ScSpecUdtUnionCaseV0Kind.scSpecUdtUnionCaseTupleV0():
        {
          const tupleCase = unionCase.tupleCase();
          return {
            doc: tupleCase.doc().toString(),
            name: tupleCase.name().toString(),
            types: tupleCase.type().map(t => (0, _utils.parseTypeFromTypeDef)(t))
          };
        }
      default:
        throw new Error(`Unknown union case kind: ${unionCase.switch()}`);
    }
  }

  /**
   * Generate enum case
   */
  generateEnumCase(enumCase) {
    return {
      doc: enumCase.doc().toString(),
      name: enumCase.name().toString(),
      value: enumCase.value()
    };
  }
  generateTupleStruct(udtStruct) {
    const name = (0, _utils.sanitizeIdentifier)(udtStruct.name().toString());
    const doc = (0, _utils.formatJSDocComment)(udtStruct.doc().toString() || `Tuple Struct: ${name}`, 0);
    const types = udtStruct.fields().map(field => (0, _utils.parseTypeFromTypeDef)(field.type())).join(", ");
    return `${doc}export type ${name} = readonly [${types}];`;
  }
}
exports.TypeGenerator = TypeGenerator;