mirror of
https://github.com/sonr-io/sonr.git
synced 2026-08-03 01:41:44 +00:00
@@ -0,0 +1,199 @@
|
||||
// @ts-check
|
||||
|
||||
/**
|
||||
* This script generates the src/protobufs directory from the proto files in the
|
||||
* repos specified in `REPOS`. It uses `buf` to generate TS files from the proto
|
||||
* files, and then generates an `index.ts` file to re-export the generated code.
|
||||
*/
|
||||
|
||||
import { spawnSync } from "child_process";
|
||||
import degit from "degit";
|
||||
import { mkdirSync, readFileSync, rmSync, writeFileSync } from "fs";
|
||||
import { globSync } from "glob";
|
||||
import { capitalize } from "lodash-es";
|
||||
import { dirname, join } from "path";
|
||||
import { fileURLToPath } from "url";
|
||||
|
||||
/**
|
||||
* @typedef Repo
|
||||
* @type {object}
|
||||
* @property {string} repo - Git repo and branch to clone
|
||||
* @property {string[]} paths - Paths to proto files relative to the repo root
|
||||
*/
|
||||
|
||||
/**
|
||||
* TODO: Add more repos here when necessary.
|
||||
* @type {Repo[]}
|
||||
*/
|
||||
const REPOS = [
|
||||
// NOTE: cosmos-sdk is excluded because we use pre-generated cosmos proto files
|
||||
// to avoid issues with degit and version mismatches
|
||||
{
|
||||
repo: "cosmos/ibc-go#main",
|
||||
paths: ["proto"],
|
||||
},
|
||||
// Use local proto files for sonr instead of fetching from external repo
|
||||
// {
|
||||
// repo: "onsonr/sonr#main",
|
||||
// paths: ["proto"],
|
||||
// },
|
||||
{
|
||||
repo: "CosmWasm/wasmd#main",
|
||||
paths: ["proto"],
|
||||
},
|
||||
{
|
||||
repo: "osmosis-labs/osmosis#main",
|
||||
paths: ["proto"],
|
||||
},
|
||||
{
|
||||
repo: "evmos/ethermint#main",
|
||||
paths: ["proto"],
|
||||
},
|
||||
// Commented out babylon as it requires cosmos/staking which we don't generate
|
||||
// {
|
||||
// repo: "nomic-io/nomic#develop",
|
||||
// paths: ["src/babylon/proto"],
|
||||
// },
|
||||
];
|
||||
|
||||
const __dirname = dirname(fileURLToPath(import.meta.url));
|
||||
const PROTOBUFS_DIR = join(__dirname, "..", "src", "protobufs");
|
||||
const TMP_DIR = join(PROTOBUFS_DIR, ".tmp");
|
||||
/** Generates a unique dirname from `repo` to use in `TMP_DIR`. */
|
||||
const id = (/** @type {string} */ repo) => repo.replace(/[#/]/g, "-");
|
||||
|
||||
console.log("Initialising directories...");
|
||||
{
|
||||
// Don't delete the entire protobufs directory to preserve cosmos files
|
||||
// Only delete directories that will be regenerated
|
||||
rmSync(TMP_DIR, { recursive: true, force: true });
|
||||
mkdirSync(TMP_DIR);
|
||||
|
||||
// Ensure protobufs directory exists
|
||||
mkdirSync(PROTOBUFS_DIR, { recursive: true });
|
||||
|
||||
// Only clean up directories for repos we're regenerating
|
||||
const dirsToClean = [
|
||||
"ibc",
|
||||
"cosmwasm",
|
||||
"osmosis",
|
||||
"ethermint",
|
||||
"babylon", // Add babylon to clean list
|
||||
"did",
|
||||
"dwn",
|
||||
"svc",
|
||||
];
|
||||
for (const dir of dirsToClean) {
|
||||
const dirPath = join(PROTOBUFS_DIR, dir);
|
||||
rmSync(dirPath, { recursive: true, force: true });
|
||||
}
|
||||
}
|
||||
|
||||
console.log("Cloning required repos...");
|
||||
{
|
||||
await Promise.all(
|
||||
REPOS.map(({ repo }) => degit(repo).clone(join(TMP_DIR, id(repo))))
|
||||
);
|
||||
}
|
||||
|
||||
console.log("Generating TS files from proto files...");
|
||||
{
|
||||
for (const { repo, paths } of REPOS) {
|
||||
for (const path of paths) {
|
||||
spawnSync(
|
||||
"pnpm",
|
||||
[
|
||||
"buf",
|
||||
"generate",
|
||||
join(TMP_DIR, id(repo), path),
|
||||
"--output",
|
||||
join(
|
||||
PROTOBUFS_DIR,
|
||||
repo.startsWith("dymensionxyz") ? "dymension" : ""
|
||||
),
|
||||
],
|
||||
{
|
||||
cwd: process.cwd(),
|
||||
stdio: "inherit",
|
||||
}
|
||||
);
|
||||
}
|
||||
console.log(`✔️ [${repo}]`);
|
||||
}
|
||||
|
||||
// Generate from local Sonr proto files
|
||||
console.log("Generating TS files from local Sonr proto files...");
|
||||
const localProtoPath = join(__dirname, "..", "..", "..", "proto");
|
||||
spawnSync(
|
||||
"pnpm",
|
||||
["buf", "generate", localProtoPath, "--output", PROTOBUFS_DIR],
|
||||
{
|
||||
cwd: process.cwd(),
|
||||
stdio: "inherit",
|
||||
}
|
||||
);
|
||||
console.log(`✔️ [local sonr proto files]`);
|
||||
}
|
||||
|
||||
console.log("Generating src/index.ts file and renaming exports...");
|
||||
{
|
||||
const LAST_SEGMENT_REGEX = /[^/]+$/;
|
||||
const EXPORTED_NAME_REGEX = /^export \w+ (\w+) /gm;
|
||||
let contents =
|
||||
"/** This file is generated by gen-protobufs.mjs. Do not edit. */\n\n";
|
||||
/**
|
||||
* Builds the `src/proto/index.ts` file to re-export generated code.
|
||||
* A prefix is added to the exported names to avoid name collisions.
|
||||
* The prefix is the names of the directories in `proto` leading up
|
||||
* to the directory of the exported code, concatenated in PascalCase.
|
||||
* For example, if the exported code is in `proto/foo/bar/goo.ts`, the
|
||||
* prefix will be `FooBar`.
|
||||
* @param {string} dir
|
||||
*/
|
||||
function generateIndexExports(dir) {
|
||||
const files = globSync(join(dir, "*"));
|
||||
if (files.length === 0) {
|
||||
return;
|
||||
}
|
||||
const prefixName = dir
|
||||
.replace(PROTOBUFS_DIR + "/", "")
|
||||
.split("/")
|
||||
.map((name) =>
|
||||
// convert all names to PascalCase
|
||||
name.split(/[-_]/).map(capitalize).join("")
|
||||
)
|
||||
.join("");
|
||||
for (const file of files) {
|
||||
const fileName = file.match(LAST_SEGMENT_REGEX)?.[0];
|
||||
if (!fileName) {
|
||||
console.error("Could not find name for", file);
|
||||
continue;
|
||||
}
|
||||
if (!fileName.endsWith(".ts")) {
|
||||
continue;
|
||||
}
|
||||
const code = readFileSync(file, "utf8");
|
||||
contents += `export {\n`;
|
||||
for (const match of code.matchAll(EXPORTED_NAME_REGEX)) {
|
||||
const exportedName = match[1];
|
||||
contents += ` ${exportedName} as ${prefixName + exportedName},\n`;
|
||||
}
|
||||
const exportedFile = file
|
||||
.replace(PROTOBUFS_DIR + "/", "")
|
||||
.replace(".ts", ".js");
|
||||
contents += `} from "./${exportedFile}";\n`;
|
||||
}
|
||||
for (const file of files) {
|
||||
generateIndexExports(file);
|
||||
}
|
||||
}
|
||||
generateIndexExports(PROTOBUFS_DIR);
|
||||
writeFileSync(join(PROTOBUFS_DIR, "index.ts"), contents);
|
||||
}
|
||||
|
||||
console.log("Cleaning up...");
|
||||
{
|
||||
rmSync(TMP_DIR, { recursive: true, force: true });
|
||||
}
|
||||
|
||||
console.log("Proto generation completed successfully!");
|
||||
@@ -0,0 +1,53 @@
|
||||
import { writeFileSync } from "fs";
|
||||
import { compile } from "json-schema-to-typescript";
|
||||
import { dirname, join } from "path";
|
||||
import { fileURLToPath } from "url";
|
||||
|
||||
const __dirname = dirname(fileURLToPath(import.meta.url));
|
||||
|
||||
async function genChainRegistryChainInfo() {
|
||||
const tsName = "ChainRegistryChainInfo";
|
||||
const tsFile = tsName + ".ts";
|
||||
|
||||
console.log("Retrieving JSON schema...");
|
||||
const res = await fetch(
|
||||
"https://raw.githubusercontent.com/cosmos/chain-registry/master/chain.schema.json"
|
||||
);
|
||||
const schema = await res.json();
|
||||
schema.title = tsName;
|
||||
|
||||
console.log("Compiling JSON schema to TypeScript...");
|
||||
const types = await compile(schema, tsName, {
|
||||
// See: https://github.com/bcherny/json-schema-to-typescript?tab=readme-ov-file#options
|
||||
strictIndexSignatures: true,
|
||||
});
|
||||
|
||||
const target = join(__dirname, "..", "src", "registry", "types", tsFile);
|
||||
writeFileSync(target, types);
|
||||
console.log("Wrote types to", target);
|
||||
}
|
||||
|
||||
async function genChainRegistryAssetList() {
|
||||
const tsName = "ChainRegistryAssetList";
|
||||
const tsFile = tsName + ".ts";
|
||||
|
||||
console.log("Retrieving JSON schema...");
|
||||
const res = await fetch(
|
||||
"https://raw.githubusercontent.com/cosmos/chain-registry/master/assetlist.schema.json"
|
||||
);
|
||||
const schema = await res.json();
|
||||
schema.title = tsName;
|
||||
|
||||
console.log("Compiling JSON schema to TypeScript...");
|
||||
const types = await compile(schema, tsName, {
|
||||
// See: https://github.com/bcherny/json-schema-to-typescript?tab=readme-ov-file#options
|
||||
strictIndexSignatures: true,
|
||||
});
|
||||
|
||||
const target = join(__dirname, "..", "src", "registry", "types", tsFile);
|
||||
writeFileSync(target, types);
|
||||
console.log("Wrote types to", target);
|
||||
}
|
||||
|
||||
await genChainRegistryChainInfo();
|
||||
await genChainRegistryAssetList();
|
||||
Executable
+50
@@ -0,0 +1,50 @@
|
||||
#!/usr/bin/env node
|
||||
// @ts-check
|
||||
|
||||
/**
|
||||
* This is a custom plugin for `buf` that generates TS files from the services
|
||||
* defined in the proto files, and is referred to by the root `buf.gen.yaml`.
|
||||
* Files generated using this plugin contains the `_@sonr.io/es` suffix.
|
||||
*
|
||||
* Do not convert this to a TS file as it runs 4x slower!
|
||||
*/
|
||||
|
||||
import { createEcmaScriptPlugin, runNodeJs } from "@bufbuild/protoplugin";
|
||||
import {
|
||||
literalString,
|
||||
localName,
|
||||
makeJsDoc,
|
||||
} from "@bufbuild/protoplugin/ecmascript";
|
||||
|
||||
export function generateTs(schema) {
|
||||
for (const protoFile of schema.files) {
|
||||
const file = schema.generateFile(protoFile.name + "_cosmes.ts");
|
||||
file.preamble(protoFile);
|
||||
for (const service of protoFile.services) {
|
||||
generateService(schema, file, service);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function generateService(schema, f, service) {
|
||||
f.print("const TYPE_NAME = ", literalString(service.typeName), ";");
|
||||
f.print("");
|
||||
for (const method of service.methods) {
|
||||
f.print(makeJsDoc(method));
|
||||
f.print("export const ", localName(service), method.name, "Service = {");
|
||||
f.print(" typeName: TYPE_NAME,");
|
||||
f.print(" method: ", literalString(method.name), ",");
|
||||
f.print(" Request: ", method.input, ",");
|
||||
f.print(" Response: ", method.output, ",");
|
||||
f.print("} as const;");
|
||||
f.print("");
|
||||
}
|
||||
}
|
||||
|
||||
runNodeJs(
|
||||
createEcmaScriptPlugin({
|
||||
name: "protoc-gen-cosmes",
|
||||
version: "v0.0.1",
|
||||
generateTs,
|
||||
})
|
||||
);
|
||||
Reference in New Issue
Block a user