Source

lib/cli/util.js

"use strict";

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.createGenerator = createGenerator;
exports.deriveContractName = deriveContractName;
exports.generateAndWrite = generateAndWrite;
exports.logSourceInfo = logSourceInfo;
exports.writeBindings = writeBindings;
var fs = _interopRequireWildcard(require("fs/promises"));
var path = _interopRequireWildcard(require("path"));
var _generator = require("../bindings/generator");
var _bindings = require("../bindings");
var _server = require("../rpc/server");
function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
/**
 * Source information about where the contract was fetched from
 */

/**
 * Verify that the server is on the expected network
 */
async function verifyNetwork(server, expectedPassphrase) {
  const networkResponse = await server.getNetwork();
  if (networkResponse.passphrase !== expectedPassphrase) {
    throw new _bindings.WasmFetchError(`Network mismatch: expected "${expectedPassphrase}", got "${networkResponse.passphrase}"`);
  }
}

/**
 * Create a BindingGenerator from local file, network hash, or contract ID
 */
async function createGenerator(args) {
  // Validate exactly one source is provided
  const sources = [args.wasm, args.wasmHash, args.contractId].filter(Boolean);
  if (sources.length === 0) {
    throw new _bindings.WasmFetchError("Must provide one of: --wasm, --wasm-hash, or --contract-id");
  }
  if (sources.length > 1) {
    throw new _bindings.WasmFetchError("Must provide only one of: --wasm, --wasm-hash, or --contract-id");
  }

  // Local WASM file
  if (args.wasm) {
    const wasmBuffer = await fs.readFile(args.wasm);
    return {
      generator: _generator.BindingGenerator.fromWasm(wasmBuffer),
      source: {
        type: "file",
        path: args.wasm
      }
    };
  }

  // Network sources require RPC URL and network
  if (!args.rpcUrl) {
    throw new _bindings.WasmFetchError("--rpc-url is required when fetching from network");
  }
  if (!args.networkPassphrase) {
    throw new _bindings.WasmFetchError("--network is required when fetching from network");
  }
  const server = new _server.RpcServer(args.rpcUrl, args.serverOptions);
  await verifyNetwork(server, args.networkPassphrase);

  // WASM hash
  if (args.wasmHash) {
    return {
      generator: await _generator.BindingGenerator.fromWasmHash(args.wasmHash, server),
      source: {
        type: "wasm-hash",
        hash: args.wasmHash,
        rpcUrl: args.rpcUrl,
        network: args.networkPassphrase
      }
    };
  }
  if (args.contractId) {
    const generator = await _generator.BindingGenerator.fromContractId(args.contractId, server);
    return {
      generator,
      source: {
        type: "contract-id",
        contractId: args.contractId,
        rpcUrl: args.rpcUrl,
        network: args.networkPassphrase
      }
    };
  }
  throw new _bindings.WasmFetchError("Invalid arguments");
}

/**
 * Write generated bindings to disk
 */
async function writeBindings(outputDir, bindings, overwrite) {
  // Check if output directory exists
  try {
    const stat = await fs.stat(outputDir);
    if (stat.isFile()) {
      throw new Error(`Output path is a file: ${outputDir}`);
    }
    if (!overwrite) {
      throw new Error(`Directory exists (use --overwrite): ${outputDir}`);
    }
    await fs.rm(outputDir, {
      recursive: true,
      force: true
    });
  } catch (error) {
    if (error.code !== "ENOENT") throw error;
  }
  await fs.mkdir(path.join(outputDir, "src"), {
    recursive: true
  });
  const writes = [fs.writeFile(path.join(outputDir, "src/index.ts"), bindings.index), fs.writeFile(path.join(outputDir, "src/client.ts"), bindings.client), fs.writeFile(path.join(outputDir, ".gitignore"), bindings.gitignore), fs.writeFile(path.join(outputDir, "README.md"), bindings.readme), fs.writeFile(path.join(outputDir, "package.json"), bindings.packageJson), fs.writeFile(path.join(outputDir, "tsconfig.json"), bindings.tsConfig)];
  if (bindings.types.trim()) {
    writes.push(fs.writeFile(path.join(outputDir, "src/types.ts"), bindings.types));
  }
  await Promise.all(writes);
}
/**
 * Generate and write bindings to disk
 */
async function generateAndWrite(generator, options) {
  const {
    outputDir,
    overwrite = false,
    ...genOptions
  } = options;
  const bindings = generator.generate(genOptions);
  await writeBindings(outputDir, bindings, overwrite);
}

/**
 * Log source information
 */
function logSourceInfo(source) {
  console.log("\nSource:");
  switch (source.type) {
    case "file":
      console.log(`  Type: Local file`);
      console.log(`  Path: ${source.path}`);
      break;
    case "wasm-hash":
      console.log(`  Type: WASM hash`);
      console.log(`  Hash: ${source.hash}`);
      console.log(`  RPC: ${source.rpcUrl}`);
      console.log(`  Network: ${source.network}`);
      break;
    case "contract-id":
      console.log(`  Type: Contract ID`);
      console.log(`  Address: ${source.contractId}`);
      console.log(`  RPC: ${source.rpcUrl}`);
      console.log(`  Network: ${source.network}`);
      break;
  }
}

/**
 * Derive contract name from source path
 */
function deriveContractName(source) {
  if (source.type !== "file") return null;
  return path.basename(source.path, path.extname(source.path)).replace(/([a-z])([A-Z])/g, "$1-$2").replace(/_/g, "-").toLowerCase();
}