Skip to content

Commit eb1ea28

Browse files
feat(cosmogen): implement 3rd party generation root template (backport #4737) (#4740)
* feat(cosmogen): implement 3rd party generation root template (#4737) * feat(cosmogen): implement 3rd party generation * cl * hardcode module path * simplify * updates * lint * feat: Filter protos to module being processed * put test protos in correct folder * remove todo --------- Co-authored-by: “Clockwork” <[email protected]> (cherry picked from commit 842b3e9) # Conflicts: # ignite/pkg/cosmosbuf/buf.go # ignite/pkg/cosmosgen/generate_typescript_test.go * updates * cl --------- Co-authored-by: julienrbrt <[email protected]>
1 parent 0ecfe1a commit eb1ea28

File tree

42 files changed

+685
-52
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

42 files changed

+685
-52
lines changed

changelog.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
### Fixes
1010

1111
- [#4686](https://github.com/ignite/cli/pull/4686) Filter discovered protos to only messages.
12-
- [#4691](https://github.com/ignite/cli/pull/4691), [#4706](https://github.com/ignite/cli/pull/4706), [#4725](https://github.com/ignite/cli/pull/4725) Fix ts-client query template and solely Go template for `ts-client` generation.
12+
- [#4691](https://github.com/ignite/cli/pull/4691), [#4706](https://github.com/ignite/cli/pull/4706), [#4725](https://github.com/ignite/cli/pull/4725), [#4737](https://github.com/ignite/cli/pull/4737) Fix ts-client query template and solely Go template for `ts-client` generation.
1313

1414
## [`v28.10.0`](https://github.com/ignite/cli/releases/tag/v28.10.0)
1515

ignite/pkg/cosmosbuf/buf.go

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"context"
55
"fmt"
66
"path/filepath"
7+
"strings"
78

89
"github.com/gobwas/glob"
910
"golang.org/x/sync/errgroup"
@@ -67,6 +68,7 @@ type (
6768
fileByFile bool
6869
includeImports bool
6970
includeWKT bool
71+
moduleName string
7072
}
7173

7274
// GenOption configures code generation.
@@ -80,6 +82,7 @@ func newGenOptions() genOptions {
8082
fileByFile: false,
8183
includeWKT: false,
8284
includeImports: false,
85+
moduleName: "",
8386
}
8487
}
8588

@@ -115,6 +118,13 @@ func IncludeWKT() GenOption {
115118
}
116119
}
117120

121+
// WithModuleName sets the module name to filter protos for.
122+
func WithModuleName(value string) GenOption {
123+
return func(o *genOptions) {
124+
o.moduleName = value
125+
}
126+
}
127+
118128
// FileByFile runs the generate command for each proto file.
119129
func FileByFile() GenOption {
120130
return func(o *genOptions) {
@@ -197,9 +207,13 @@ func (b Buf) Generate(
197207
for _, apply := range options {
198208
apply(&opts)
199209
}
200-
210+
modulePath := protoPath
211+
if opts.moduleName != "" {
212+
path := append([]string{protoPath}, strings.Split(opts.moduleName, ".")...)
213+
modulePath = filepath.Join(path...)
214+
}
201215
// find all proto files into the path.
202-
foundFiles, err := xos.FindFilesExtension(protoPath, xos.ProtoFile)
216+
foundFiles, err := xos.FindFilesExtension(modulePath, xos.ProtoFile)
203217
if err != nil || len(foundFiles) == 0 {
204218
return err
205219
}

ignite/pkg/cosmosgen/generate_typescript.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,11 @@ func (g *generator) generateTS(ctx context.Context) error {
5959
return err
6060
}
6161

62+
// add third party modules to for the root template.
63+
for _, modules := range g.thirdModules {
64+
data.Modules = append(data.Modules, modules...)
65+
}
66+
6267
return tsg.generateRootTemplates(data)
6368
}
6469

@@ -132,6 +137,7 @@ func (g *tsGenerator) generateModuleTemplate(
132137
// All "cosmossdk.io" module packages must use SDK's
133138
// proto path which is where the proto files are stored.
134139
protoPath := filepath.Join(appPath, g.g.protoDir) // use module app path
140+
135141
if module.IsCosmosSDKPackage(appPath) {
136142
protoPath = filepath.Join(g.g.sdkDir, "proto")
137143
}
@@ -144,7 +150,7 @@ func (g *tsGenerator) generateModuleTemplate(
144150
g.g.tsTemplate(),
145151
cosmosbuf.ExcludeFiles("module.proto"),
146152
cosmosbuf.IncludeWKT(),
147-
// TODO: we should exclude folders that are irrelevant for the module.
153+
cosmosbuf.WithModuleName(m.Pkg.Name),
148154
); err != nil {
149155
return err
150156
}

ignite/pkg/cosmosgen/generate_typescript_test.go

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,10 @@ package cosmosgen
22

33
import (
44
"context"
5+
"fmt"
56
"os"
67
"path/filepath"
8+
"strings"
79
"testing"
810

911
"github.com/ettle/strcase"
@@ -39,16 +41,23 @@ func TestGenerateTypeScript(t *testing.T) {
3941
buf: buf,
4042
appModules: m,
4143
opts: &generateOptions{
42-
useCache: false,
44+
tsClientRootPath: tsClientDir,
45+
useCache: false,
4346
jsOut: func(m module.Module) string {
44-
return filepath.Join(tsClientDir, strcase.ToKebab(m.Name))
47+
return filepath.Join(tsClientDir, fmt.Sprintf("%s.%s.%s", "ignite", "planet", strcase.ToKebab(m.Name)))
4548
},
4649
},
4750
})
4851

4952
err = g.generateModuleTemplate(context.Background(), appDir, m[0])
5053
require.NoError(err, "failed to generate TypeScript files")
5154

55+
err = g.generateRootTemplates(generatePayload{
56+
Modules: m,
57+
PackageNS: strings.ReplaceAll(appDir, "/", "-"),
58+
})
59+
require.NoError(err)
60+
5261
// compare all generated files to golden files
5362
goldenDir := filepath.Join(testdataDir, "expected_files", "ts-client")
5463
_ = filepath.Walk(goldenDir, func(path string, info os.FileInfo, err error) error {
Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
/// <reference path="./types.d.ts" />
2+
import {
3+
GeneratedType,
4+
OfflineSigner,
5+
EncodeObject,
6+
Registry,
7+
} from "@cosmjs/proto-signing";
8+
import { SigningStargateClient, StdFee } from "@cosmjs/stargate";
9+
import { Env } from "./env";
10+
import { UnionToIntersection, Return, Constructor } from "./helpers";
11+
import { IgntModule } from "./modules";
12+
import { EventEmitter } from "events";
13+
import { ChainInfo } from "@keplr-wallet/types";
14+
15+
const defaultFee = {
16+
amount: [],
17+
gas: "200000",
18+
};
19+
20+
export class IgniteClient extends EventEmitter {
21+
static plugins: IgntModule[] = [];
22+
env: Env;
23+
signer?: OfflineSigner;
24+
registry: Array<[string, GeneratedType]> = [];
25+
static plugin<T extends IgntModule | IgntModule[]>(plugin: T) {
26+
const currentPlugins = this.plugins;
27+
28+
class AugmentedClient extends this {
29+
static plugins = currentPlugins.concat(plugin);
30+
}
31+
32+
if (Array.isArray(plugin)) {
33+
type Extension = UnionToIntersection<Return<T>['module']>
34+
return AugmentedClient as typeof IgniteClient & Constructor<Extension>;
35+
}
36+
37+
type Extension = Return<T>['module']
38+
return AugmentedClient as typeof IgniteClient & Constructor<Extension>;
39+
}
40+
41+
async signAndBroadcast(msgs: EncodeObject[], fee: StdFee, memo: string) {
42+
if (this.signer) {
43+
const { address } = (await this.signer.getAccounts())[0];
44+
const signingClient = await SigningStargateClient.connectWithSigner(this.env.rpcURL, this.signer, { registry: new Registry(this.registry) });
45+
return await signingClient.signAndBroadcast(address, msgs, fee ? fee : defaultFee, memo)
46+
} else {
47+
throw new Error(" Signer is not present.");
48+
}
49+
}
50+
51+
constructor(env: Env, signer?: OfflineSigner) {
52+
super();
53+
this.env = env;
54+
this.setMaxListeners(0);
55+
this.signer = signer;
56+
const classConstructor = this.constructor as typeof IgniteClient;
57+
classConstructor.plugins.forEach(plugin => {
58+
const pluginInstance = plugin(this);
59+
Object.assign(this, pluginInstance.module)
60+
if (this.registry) {
61+
this.registry = this.registry.concat(pluginInstance.registry)
62+
}
63+
});
64+
}
65+
useSigner(signer: OfflineSigner) {
66+
this.signer = signer;
67+
this.emit("signer-changed", this.signer);
68+
}
69+
removeSigner() {
70+
this.signer = undefined;
71+
this.emit("signer-changed", this.signer);
72+
}
73+
async useKeplr(keplrChainInfo: Partial<ChainInfo> = {}) {
74+
// Using queryClients directly because BaseClient has no knowledge of the modules at this stage
75+
try {
76+
const queryClient = (
77+
await import("./cosmos.base.tendermint.v1beta1/module")
78+
).queryClient;
79+
const bankQueryClient = (await import("./cosmos.bank.v1beta1/module"))
80+
.queryClient;
81+
const stakingQueryClient = (await import("./cosmos.staking.v1beta1/module")).queryClient;
82+
const stakingqc = stakingQueryClient({ addr: this.env.apiURL });
83+
const staking = await (await stakingqc.queryParams()).data;
84+
const qc = queryClient({ addr: this.env.apiURL });
85+
const node_info = await (await qc.serviceGetNodeInfo()).data;
86+
const chainId = node_info.default_node_info?.network ?? "";
87+
const chainName = chainId?.toUpperCase() + " Network";
88+
const bankqc = bankQueryClient({ addr: this.env.apiURL });
89+
const tokens = await (await bankqc.queryTotalSupply()).data;
90+
const addrPrefix = this.env.prefix ?? "cosmos";
91+
const rpc = this.env.rpcURL;
92+
const rest = this.env.apiURL;
93+
94+
let bip44 = {
95+
coinType: 118,
96+
};
97+
98+
let bech32Config = {
99+
bech32PrefixAccAddr: addrPrefix,
100+
bech32PrefixAccPub: addrPrefix + "pub",
101+
bech32PrefixValAddr: addrPrefix + "valoper",
102+
bech32PrefixValPub: addrPrefix + "valoperpub",
103+
bech32PrefixConsAddr: addrPrefix + "valcons",
104+
bech32PrefixConsPub: addrPrefix + "valconspub",
105+
};
106+
107+
let currencies =
108+
tokens.supply?.map((x) => {
109+
const y = {
110+
coinDenom: x.denom?.toUpperCase() ?? "",
111+
coinMinimalDenom: x.denom ?? "",
112+
coinDecimals: 0,
113+
};
114+
return y;
115+
}) ?? [];
116+
117+
let stakeCurrency = {
118+
coinDenom: staking.params?.bond_denom?.toUpperCase() ?? "",
119+
coinMinimalDenom: staking.params?.bond_denom ?? "",
120+
coinDecimals: 0,
121+
};
122+
123+
let feeCurrencies =
124+
tokens.supply?.map((x) => {
125+
const y = {
126+
coinDenom: x.denom?.toUpperCase() ?? "",
127+
coinMinimalDenom: x.denom ?? "",
128+
coinDecimals: 0,
129+
};
130+
return y;
131+
}) ?? [];
132+
133+
if (chainId) {
134+
const suggestOptions: ChainInfo = {
135+
chainId,
136+
chainName,
137+
rpc,
138+
rest,
139+
stakeCurrency,
140+
bip44,
141+
bech32Config,
142+
currencies,
143+
feeCurrencies,
144+
...keplrChainInfo,
145+
};
146+
await window.keplr.experimentalSuggestChain(suggestOptions);
147+
148+
window.keplr.defaultOptions = {
149+
sign: {
150+
preferNoSetFee: true,
151+
preferNoSetMemo: true,
152+
},
153+
};
154+
}
155+
await window.keplr.enable(chainId);
156+
this.signer = window.keplr.getOfflineSigner(chainId);
157+
this.emit("signer-changed", this.signer);
158+
} catch (e) {
159+
throw new Error(
160+
"Could not load tendermint, staking and bank modules. Please ensure your client loads them to use useKeplr()"
161+
);
162+
}
163+
}
164+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import { OfflineSigner } from "@cosmjs/proto-signing";
2+
3+
export interface Env {
4+
apiURL: string
5+
rpcURL: string
6+
prefix?: string
7+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
export type Constructor<T> = new (...args: any[]) => T;
2+
3+
export type AnyFunction = (...args: any) => any;
4+
5+
export type UnionToIntersection<Union> =
6+
(Union extends any
7+
? (argument: Union) => void
8+
: never
9+
) extends (argument: infer Intersection) => void
10+
? Intersection
11+
: never;
12+
13+
export type Return<T> =
14+
T extends AnyFunction
15+
? ReturnType<T>
16+
: T extends AnyFunction[]
17+
? UnionToIntersection<ReturnType<T[number]>>
18+
: never
19+
20+
21+
export const MissingWalletError = new Error("wallet is required");
22+
23+
export function getStructure(template) {
24+
let structure = { fields: [] as Array<unknown>}
25+
for (const [key, value] of Object.entries(template)) {
26+
let field: any = {}
27+
field.name = key
28+
field.type = typeof value
29+
structure.fields.push(field)
30+
}
31+
return structure
32+
}

ignite/pkg/cosmosgen/testdata/expected_files/ts-client/mars/index.ts renamed to ignite/pkg/cosmosgen/testdata/expected_files/ts-client/ignite.planet.mars/index.ts

File renamed without changes.

ignite/pkg/cosmosgen/testdata/expected_files/ts-client/mars/module.ts renamed to ignite/pkg/cosmosgen/testdata/expected_files/ts-client/ignite.planet.mars/module.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@ import { msgTypes } from './registry';
66
import { IgniteClient } from "../client"
77
import { MissingWalletError } from "../helpers"
88
import { Api } from "./rest";
9-
import { MsgMyMessageRequest } from "./types/planet/mars/mars";
10-
import { MsgBarRequest } from "./types/planet/mars/mars";
9+
import { MsgMyMessageRequest } from "./types/ignite/planet/mars/mars";
10+
import { MsgBarRequest } from "./types/ignite/planet/mars/mars";
1111

1212
import { AnotherType as typeAnotherType} from "./types"
1313

ignite/pkg/cosmosgen/testdata/testchain/ts-client/mars/registry.ts renamed to ignite/pkg/cosmosgen/testdata/expected_files/ts-client/ignite.planet.mars/registry.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { GeneratedType } from "@cosmjs/proto-signing";
2-
import { MsgMyMessageRequest } from "./types/planet/mars/mars";
3-
import { MsgBarRequest } from "./types/planet/mars/mars";
2+
import { MsgMyMessageRequest } from "./types/ignite/planet/mars/mars";
3+
import { MsgBarRequest } from "./types/ignite/planet/mars/mars";
44

55
const msgTypes: Array<[string, GeneratedType]> = [
66
["/ignite.planet.mars.MsgMyMessageRequest", MsgMyMessageRequest],

0 commit comments

Comments
 (0)