@hyperweb/telescope 1.17.2 → 1.17.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -6,311 +6,398 @@ import { makeAliasNameWithPackageAtEnd } from "@cosmology/utils";
6
6
  /**
7
7
  * Gets the aliased function name if it's duplicated across multiple files
8
8
  */
9
- function getAliasedFunctionName(builder: TelescopeBuilder, functionName: string, packageName: string): string {
10
- const duplicatedHelperFuncs = builder.store.getHelperFuncsInMultipleFiles();
11
- const isDuplicated = duplicatedHelperFuncs.includes(functionName);
12
-
13
- if (isDuplicated) {
14
- const serialNumber = builder.store.getAndIncTypeSerialNumber(functionName);
15
- if (serialNumber > 0) {
16
- return makeAliasNameWithPackageAtEnd({ package: packageName, name: functionName });
17
- }
18
- }
9
+ function getAliasedFunctionName(
10
+ builder: TelescopeBuilder,
11
+ functionName: string,
12
+ packageName: string
13
+ ): string {
14
+ const duplicatedHelperFuncs = builder.store.getHelperFuncsInMultipleFiles();
15
+ const isDuplicated = duplicatedHelperFuncs.includes(functionName);
16
+
17
+ if (isDuplicated) {
18
+ return makeAliasNameWithPackageAtEnd({
19
+ package: packageName,
20
+ name: functionName,
21
+ });
22
+ }
19
23
 
20
- return functionName;
24
+ return functionName;
21
25
  }
22
26
 
23
27
  /**
24
28
  * Cleans up comments by removing lint directives and technical annotations
25
29
  */
26
30
  function cleanComment(comment: string): string {
27
- if (!comment) return comment;
28
-
29
- // Remove lint directives and technical annotations
30
- const cleanedComment = comment
31
- // Remove buf:lint:ignore directives
32
- .replace(/buf:lint:ignore\s+[A-Z_]+/gi, '')
33
- // Remove other common lint directives
34
- .replace(/lint:ignore[:\s]+[A-Z_]+/gi, '')
35
- // Remove protolint directives
36
- .replace(/protolint:disable[:\s]+[A-Z_]+/gi, '')
37
- // Remove eslint directives
38
- .replace(/eslint-disable[:\s-]+[a-z-]+/gi, '')
39
- // Remove multiple consecutive spaces
40
- .replace(/\s+/g, ' ')
41
- // Remove leading/trailing whitespace
42
- .trim();
43
-
44
- return cleanedComment;
31
+ if (!comment) return comment;
32
+
33
+ // Remove lint directives and technical annotations
34
+ const cleanedComment = comment
35
+ // Remove buf:lint:ignore directives
36
+ .replace(/buf:lint:ignore\s+[A-Z_]+/gi, "")
37
+ // Remove other common lint directives
38
+ .replace(/lint:ignore[:\s]+[A-Z_]+/gi, "")
39
+ // Remove protolint directives
40
+ .replace(/protolint:disable[:\s]+[A-Z_]+/gi, "")
41
+ // Remove eslint directives
42
+ .replace(/eslint-disable[:\s-]+[a-z-]+/gi, "")
43
+ // Remove multiple consecutive spaces
44
+ .replace(/\s+/g, " ")
45
+ // Remove leading/trailing whitespace
46
+ .trim();
47
+
48
+ return cleanedComment;
45
49
  }
46
50
 
47
51
  /**
48
52
  * Gets the project name from the output path
49
53
  */
50
54
  function getProjectName(outPath: string): string {
51
- return basename(outPath);
55
+ return basename(outPath);
52
56
  }
53
57
 
54
58
  /**
55
59
  * Gets the appropriate import path for a function, considering bundle exports
56
60
  */
57
- function getImportPath(builder: TelescopeBuilder, functionName: string, packageName: string, projectName: string, sourceFilename?: string): string {
58
- const duplicatedHelperFuncs = builder.store.getHelperFuncsInMultipleFiles();
59
- const isDuplicated = duplicatedHelperFuncs.includes(functionName);
60
-
61
- // If the function is duplicated (and thus potentially aliased), it should be available in the bundle
62
- if (isDuplicated) {
63
- // Check the aliased function name to see if it would be different
64
- const aliasedName = getAliasedFunctionName(builder, functionName, packageName);
65
- if (aliasedName !== functionName) {
66
- // Extract the top-level package name (e.g., 'akash' from 'akash.audit.v1beta2')
67
- const topLevelPackage = packageName.split('.')[0];
68
-
69
- // Function is aliased and should be available in bundle
70
- return `${projectName}/${topLevelPackage}/bundle`;
71
- }
72
- }
61
+ function getImportPath(
62
+ builder: TelescopeBuilder,
63
+ functionName: string,
64
+ packageName: string,
65
+ projectName: string,
66
+ sourceFilename?: string
67
+ ): string {
68
+ const duplicatedHelperFuncs = builder.store.getHelperFuncsInMultipleFiles();
69
+ const isDuplicated = duplicatedHelperFuncs.includes(functionName);
70
+
71
+ // If the function is duplicated (and thus potentially aliased), it should be available in the bundle
72
+ if (isDuplicated) {
73
+ // Check the aliased function name to see if it would be different
74
+ const aliasedName = getAliasedFunctionName(
75
+ builder,
76
+ functionName,
77
+ packageName
78
+ );
79
+ if (aliasedName !== functionName) {
80
+ // Extract the top-level package name (e.g., 'akash' from 'akash.audit.v1beta2')
81
+ const topLevelPackage = packageName.split(".")[0];
73
82
 
74
- // If we have source filename info, use the full file path
75
- // This handles all functions with specific file locations
76
- if (sourceFilename) {
77
- // Remove .ts extension and convert to proper import path
78
- const filePath = sourceFilename.replace(/\.ts$/, '');
79
- return `${projectName}/${filePath}`;
83
+ // Function is aliased and should be available in bundle
84
+ return `${projectName}/${topLevelPackage}/bundle`;
80
85
  }
81
-
82
- // Fallback: import from the specific package path
83
- return `${projectName}/${packageName.replace(/\./g, '/')}`;
86
+ }
87
+
88
+ // If we have source filename info, use the full file path
89
+ // This handles all functions with specific file locations
90
+ if (sourceFilename) {
91
+ // Remove .ts extension and convert to proper import path
92
+ const filePath = sourceFilename.replace(/\.ts$/, "");
93
+ return `${projectName}/${filePath}`;
94
+ }
95
+
96
+ // Fallback: import from the specific package path
97
+ return `${projectName}/${packageName.replace(/\./g, "/")}`;
84
98
  }
85
99
 
86
100
  /**
87
101
  * Gets all types for a package by looking at export objects and filtering out extended forms
88
102
  */
89
- function getTypesForPackage(builder: TelescopeBuilder, packageName: string): Array<{ name: string, sourceFile: string }> {
90
- const types: Array<{ name: string, sourceFile: string }> = [];
91
-
92
- // Get all contexts for this package
93
- const packageContexts = builder.contexts.filter(ctx => ctx.ref.proto.package === packageName);
94
-
95
- packageContexts.forEach(context => {
96
- // Get types from this context
97
- const contextTypes = context.types.filter(type => !type.isNested);
98
-
99
- contextTypes.forEach(typeInfo => {
100
- const typeName = typeInfo.name;
101
- // Filter out extended forms (these are created during code generation but not in the types array)
102
- if (!typeName.endsWith('ProtoMsg') &&
103
- !typeName.endsWith('Amino') &&
104
- !typeName.endsWith('AminoMsg') &&
105
- !typeName.endsWith('Encoded') &&
106
- !typeName.endsWith('SDKType')) {
107
-
108
- // Get the actual source file from the store mapping
109
- const typeFiles = builder.store.getTypeFilesMapping(typeName);
110
- let sourceFile: string;
111
-
112
- if (typeFiles && typeFiles.length > 0) {
113
- // Use the first (or most relevant) file where this type is defined
114
- sourceFile = typeFiles[0];
115
- } else {
116
- // Fallback to context ref filename if not in mapping
117
- sourceFile = context.ref.filename.replace(/\.proto$/, '.ts');
118
- }
119
-
120
- types.push({
121
- name: typeName,
122
- sourceFile
123
- });
124
- }
103
+ function getTypesForPackage(
104
+ builder: TelescopeBuilder,
105
+ packageName: string
106
+ ): Array<{ name: string; sourceFile: string }> {
107
+ const types: Array<{ name: string; sourceFile: string }> = [];
108
+
109
+ // Get all contexts for this package
110
+ const packageContexts = builder.contexts.filter(
111
+ (ctx) => ctx.ref.proto.package === packageName
112
+ );
113
+
114
+ packageContexts.forEach((context) => {
115
+ // Get types from this context
116
+ const contextTypes = context.types.filter((type) => !type.isNested);
117
+
118
+ contextTypes.forEach((typeInfo) => {
119
+ const typeName = typeInfo.name;
120
+ // Filter out extended forms (these are created during code generation but not in the types array)
121
+ if (
122
+ !typeName.endsWith("ProtoMsg") &&
123
+ !typeName.endsWith("Amino") &&
124
+ !typeName.endsWith("AminoMsg") &&
125
+ !typeName.endsWith("Encoded") &&
126
+ !typeName.endsWith("SDKType")
127
+ ) {
128
+ // Get the actual source file from the store mapping
129
+ const typeFiles = builder.store.getTypeFilesMapping(typeName);
130
+ let sourceFile: string;
131
+
132
+ if (typeFiles && typeFiles.length > 0) {
133
+ // Use the first (or most relevant) file where this type is defined
134
+ sourceFile = typeFiles[0];
135
+ } else {
136
+ // Fallback to context ref filename if not in mapping
137
+ sourceFile = context.ref.filename.replace(/\.proto$/, ".ts");
138
+ }
139
+
140
+ types.push({
141
+ name: typeName,
142
+ sourceFile,
125
143
  });
144
+ }
126
145
  });
146
+ });
127
147
 
128
- // Remove duplicates and sort
129
- const uniqueTypes = types.filter((type, index, self) =>
130
- index === self.findIndex(t => t.name === type.name)
131
- );
148
+ // Remove duplicates and sort
149
+ const uniqueTypes = types.filter(
150
+ (type, index, self) => index === self.findIndex((t) => t.name === type.name)
151
+ );
132
152
 
133
- return uniqueTypes.sort((a, b) => a.name.localeCompare(b.name));
153
+ return uniqueTypes.sort((a, b) => a.name.localeCompare(b.name));
134
154
  }
135
155
 
136
156
  export const plugin = (builder: TelescopeBuilder) => {
137
- if (!builder.options?.readme?.enabled && !builder.options?.mcpServer?.enabled) {
138
- return;
139
- }
140
-
141
- const readmePath = join(builder.outPath, "README.md");
142
- const projectName = getProjectName(builder.outPath);
143
-
144
- // Get function mappings from builder
145
- const functionMappings = builder.getFunctionMappings();
146
-
147
- // Generate package documentation
148
- let packageDocs = "";
149
-
150
- Object.keys(functionMappings).sort().forEach(packageName => {
151
- const packageServices = functionMappings[packageName];
152
-
153
- // Check if package has any methods before adding it
154
- const hasQueryMethods = packageServices.Query && Object.keys(packageServices.Query).length > 0;
155
- const hasMsgMethods = packageServices.Msg && Object.keys(packageServices.Msg).length > 0;
156
-
157
- if (!hasQueryMethods && !hasMsgMethods) {
158
- return; // Skip empty packages
159
- }
160
-
161
- packageDocs += `## ${packageName}\n\n`;
162
-
163
- // Types section
164
- const types = getTypesForPackage(builder, packageName);
165
- if (types && types.length > 0) {
166
- packageDocs += `### Types\n\n`;
167
- packageDocs += `| Type | Name | Source |\n`;
168
- packageDocs += `| --- | --- | --- |\n`;
169
- types.forEach(type => {
170
- packageDocs += `| Type | \`${type.name}\` | [View source ↗](${type.sourceFile}) |\n`;
171
- });
172
- packageDocs += '\n';
173
- }
174
-
175
- // Query section
176
- if (packageServices.Query) {
177
- packageDocs += `### Query Methods\n\n`;
178
- const queryMethods = Object.keys(packageServices.Query);
179
- queryMethods.forEach((methodName, index) => {
180
- const method = packageServices.Query[methodName];
181
-
182
- // Get the aliased function name using the same logic as bundler
183
- const aliasedFunctionName = getAliasedFunctionName(builder, method.functionName, packageName);
184
- const aliasedHookName = getAliasedFunctionName(builder, method.hookName, packageName);
185
-
186
- packageDocs += `**${methodName}**\n\n`;
187
-
188
- // Add comment directly after title (if exists)
189
- if (method.comment) {
190
- packageDocs += `${cleanComment(method.comment)}\n\n`;
191
- }
192
-
193
- // Add import code block
194
- const functionImportPath = getImportPath(builder, method.functionName, packageName, projectName, method.sourceFilename);
195
- const hookImportPath = method.hookName ? getImportPath(builder, method.hookName, packageName, projectName, method.hookSourceFilename) : functionImportPath;
196
-
197
- packageDocs += `\`\`\`ts\n`;
198
- packageDocs += `import { ${aliasedFunctionName} } from '${functionImportPath}'\n`;
199
- if (method.hookName && aliasedHookName !== aliasedFunctionName) {
200
- packageDocs += `import { ${aliasedHookName} } from '${hookImportPath}'\n`;
201
- }
202
- packageDocs += `\`\`\`\n\n`;
203
-
204
- // Add function details in organized format
205
- packageDocs += `| Field | Value | Source |\n`;
206
- packageDocs += `| --- | --- | --- |\n`;
207
-
208
- // Function source
209
- const functionSourcePath = method.sourceFilename || `${packageName.replace(/\./g, '/')}/query.rpc.func.ts`;
210
- packageDocs += `| Function | \`${aliasedFunctionName}\` | [View source ↗](${functionSourcePath}) |\n`;
211
-
212
- // Hook source (React)
213
- if (method.hookName && aliasedHookName !== aliasedFunctionName) {
214
- const hookSourcePath = method.hookSourceFilename || `${packageName.replace(/\./g, '/')}/query.rpc.react.ts`;
215
- packageDocs += `| Hook | \`${aliasedHookName}\` | [View source ↗](${hookSourcePath}) |\n`;
216
- }
217
-
218
- // Request type source
219
- if (method.requestType) {
220
- const requestSourcePath = method.typeSourceFilename || `${packageName.replace(/\./g, '/')}/query.ts`;
221
- packageDocs += `| Request | \`${method.requestType}\` | [View source ↗](${requestSourcePath}) |\n`;
222
- }
223
-
224
- // Response type source
225
- if (method.responseType) {
226
- const responseSourcePath = method.typeSourceFilename || `${packageName.replace(/\./g, '/')}/query.ts`;
227
- packageDocs += `| Response | \`${method.responseType}\` | [View source ↗](${responseSourcePath}) |\n`;
228
- }
229
-
230
- // Add spacing between methods (but not after the last one)
231
- if (index < queryMethods.length - 1) {
232
- packageDocs += '\n---\n\n';
233
- } else {
234
- packageDocs += '\n';
235
- }
236
- });
237
- }
238
-
239
- // Transaction section
240
- if (packageServices.Msg) {
241
- packageDocs += `### Transaction Methods\n\n`;
242
- const msgMethods = Object.keys(packageServices.Msg);
243
- msgMethods.forEach((methodName, index) => {
244
- const method = packageServices.Msg[methodName];
245
-
246
- // Get the aliased function name using the same logic as bundler
247
- const aliasedFunctionName = getAliasedFunctionName(builder, method.functionName, packageName);
248
- const aliasedHookName = getAliasedFunctionName(builder, method.hookName, packageName);
249
-
250
- packageDocs += `**${methodName}**\n\n`;
251
-
252
- // Add comment directly after title (if exists)
253
- if (method.comment) {
254
- packageDocs += `${cleanComment(method.comment)}\n\n`;
255
- }
256
-
257
- // Add import code block
258
- const functionImportPath = getImportPath(builder, method.functionName, packageName, projectName, method.sourceFilename);
259
- const hookImportPath = method.hookName ? getImportPath(builder, method.hookName, packageName, projectName, method.hookSourceFilename) : functionImportPath;
260
-
261
- packageDocs += `\`\`\`ts\n`;
262
- packageDocs += `import { ${aliasedFunctionName} } from '${functionImportPath}'\n`;
263
- if (method.hookName && aliasedHookName !== aliasedFunctionName) {
264
- packageDocs += `import { ${aliasedHookName} } from '${hookImportPath}'\n`;
265
- }
266
- packageDocs += `\`\`\`\n\n`;
267
-
268
- // Add function details in organized format
269
- packageDocs += `| Field | Value | Source |\n`;
270
- packageDocs += `| --- | --- | --- |\n`;
271
-
272
- // Function source
273
- const functionSourcePath = method.sourceFilename || `${packageName.replace(/\./g, '/')}/tx.rpc.func.ts`;
274
- packageDocs += `| Function | \`${aliasedFunctionName}\` | [View source ↗](${functionSourcePath}) |\n`;
275
-
276
- // Hook source (React)
277
- if (method.hookName && aliasedHookName !== aliasedFunctionName) {
278
- const hookSourcePath = method.hookSourceFilename || `${packageName.replace(/\./g, '/')}/tx.rpc.react.ts`;
279
- packageDocs += `| Hook | \`${aliasedHookName}\` | [View source ↗](${hookSourcePath}) |\n`;
280
- }
281
-
282
- // Request type source
283
- if (method.requestType) {
284
- const requestSourcePath = method.typeSourceFilename || `${packageName.replace(/\./g, '/')}/tx.ts`;
285
- packageDocs += `| Request | \`${method.requestType}\` | [View source ↗](${requestSourcePath}) |\n`;
286
- }
287
-
288
- // Response type source
289
- if (method.responseType) {
290
- const responseSourcePath = method.typeSourceFilename || `${packageName.replace(/\./g, '/')}/tx.ts`;
291
- packageDocs += `| Response | \`${method.responseType}\` | [View source ↗](${responseSourcePath}) |\n`;
292
- }
293
-
294
- // Add spacing between methods (but not after the last one)
295
- if (index < msgMethods.length - 1) {
296
- packageDocs += '\n---\n\n';
297
- } else {
298
- packageDocs += '\n';
299
- }
300
- });
301
- }
157
+ if (
158
+ !builder.options?.readme?.enabled &&
159
+ !builder.options?.mcpServer?.enabled
160
+ ) {
161
+ return;
162
+ }
163
+
164
+ const readmePath = join(builder.outPath, "README.md");
165
+ const projectName = getProjectName(builder.outPath);
166
+
167
+ // Get function mappings from builder
168
+ const functionMappings = builder.getFunctionMappings();
169
+
170
+ // Generate package documentation
171
+ let packageDocs = "";
172
+
173
+ Object.keys(functionMappings)
174
+ .sort()
175
+ .forEach((packageName) => {
176
+ const packageServices = functionMappings[packageName];
177
+
178
+ // Check if package has any methods before adding it
179
+ const hasQueryMethods =
180
+ packageServices.Query && Object.keys(packageServices.Query).length > 0;
181
+ const hasMsgMethods =
182
+ packageServices.Msg && Object.keys(packageServices.Msg).length > 0;
183
+
184
+ if (!hasQueryMethods && !hasMsgMethods) {
185
+ return; // Skip empty packages
186
+ }
187
+
188
+ packageDocs += `## ${packageName}\n\n`;
189
+
190
+ // Types section
191
+ const types = getTypesForPackage(builder, packageName);
192
+ if (types && types.length > 0) {
193
+ packageDocs += `### Types\n\n`;
194
+ packageDocs += `| Type | Name | Source |\n`;
195
+ packageDocs += `| --- | --- | --- |\n`;
196
+ types.forEach((type) => {
197
+ packageDocs += `| Type | \`${type.name}\` | [View source ↗](${type.sourceFile}) |\n`;
198
+ });
199
+ packageDocs += "\n";
200
+ }
201
+
202
+ // Query section
203
+ if (packageServices.Query) {
204
+ packageDocs += `### Query Methods\n\n`;
205
+ const queryMethods = Object.keys(packageServices.Query);
206
+ queryMethods.forEach((methodName, index) => {
207
+ const method = packageServices.Query[methodName];
208
+
209
+ // Get the aliased function name using the same logic as bundler
210
+ const aliasedFunctionName = getAliasedFunctionName(
211
+ builder,
212
+ method.functionName,
213
+ packageName
214
+ );
215
+ const aliasedHookName = getAliasedFunctionName(
216
+ builder,
217
+ method.hookName,
218
+ packageName
219
+ );
220
+
221
+ packageDocs += `**${methodName}**\n\n`;
222
+
223
+ // Add comment directly after title (if exists)
224
+ if (method.comment) {
225
+ packageDocs += `${cleanComment(method.comment)}\n\n`;
226
+ }
227
+
228
+ // Add import code block
229
+ const functionImportPath = getImportPath(
230
+ builder,
231
+ method.functionName,
232
+ packageName,
233
+ projectName,
234
+ method.sourceFilename
235
+ );
236
+ const hookImportPath = method.hookName
237
+ ? getImportPath(
238
+ builder,
239
+ method.hookName,
240
+ packageName,
241
+ projectName,
242
+ method.hookSourceFilename
243
+ )
244
+ : functionImportPath;
245
+
246
+ packageDocs += `\`\`\`ts\n`;
247
+ packageDocs += `import { ${aliasedFunctionName} } from '${functionImportPath}'\n`;
248
+ if (method.hookName && aliasedHookName !== aliasedFunctionName) {
249
+ packageDocs += `import { ${aliasedHookName} } from '${hookImportPath}'\n`;
250
+ }
251
+ packageDocs += `\`\`\`\n\n`;
252
+
253
+ // Add function details in organized format
254
+ packageDocs += `| Field | Value | Source |\n`;
255
+ packageDocs += `| --- | --- | --- |\n`;
256
+
257
+ // Function source
258
+ const functionSourcePath =
259
+ method.sourceFilename ||
260
+ `${packageName.replace(/\./g, "/")}/query.rpc.func.ts`;
261
+ packageDocs += `| Function | \`${aliasedFunctionName}\` | [View source ↗](${functionSourcePath}) |\n`;
262
+
263
+ // Hook source (React)
264
+ if (method.hookName && aliasedHookName !== aliasedFunctionName) {
265
+ const hookSourcePath =
266
+ method.hookSourceFilename ||
267
+ `${packageName.replace(/\./g, "/")}/query.rpc.react.ts`;
268
+ packageDocs += `| Hook | \`${aliasedHookName}\` | [View source ↗](${hookSourcePath}) |\n`;
269
+ }
270
+
271
+ // Request type source
272
+ if (method.requestType) {
273
+ const requestSourcePath =
274
+ method.typeSourceFilename ||
275
+ `${packageName.replace(/\./g, "/")}/query.ts`;
276
+ packageDocs += `| Request | \`${method.requestType}\` | [View source ↗](${requestSourcePath}) |\n`;
277
+ }
278
+
279
+ // Response type source
280
+ if (method.responseType) {
281
+ const responseSourcePath =
282
+ method.typeSourceFilename ||
283
+ `${packageName.replace(/\./g, "/")}/query.ts`;
284
+ packageDocs += `| Response | \`${method.responseType}\` | [View source ↗](${responseSourcePath}) |\n`;
285
+ }
286
+
287
+ // Add spacing between methods (but not after the last one)
288
+ if (index < queryMethods.length - 1) {
289
+ packageDocs += "\n---\n\n";
290
+ } else {
291
+ packageDocs += "\n";
292
+ }
293
+ });
294
+ }
295
+
296
+ // Transaction section
297
+ if (packageServices.Msg) {
298
+ packageDocs += `### Transaction Methods\n\n`;
299
+ const msgMethods = Object.keys(packageServices.Msg);
300
+ msgMethods.forEach((methodName, index) => {
301
+ const method = packageServices.Msg[methodName];
302
+
303
+ // Get the aliased function name using the same logic as bundler
304
+ const aliasedFunctionName = getAliasedFunctionName(
305
+ builder,
306
+ method.functionName,
307
+ packageName
308
+ );
309
+ const aliasedHookName = getAliasedFunctionName(
310
+ builder,
311
+ method.hookName,
312
+ packageName
313
+ );
314
+
315
+ packageDocs += `**${methodName}**\n\n`;
316
+
317
+ // Add comment directly after title (if exists)
318
+ if (method.comment) {
319
+ packageDocs += `${cleanComment(method.comment)}\n\n`;
320
+ }
321
+
322
+ // Add import code block
323
+ const functionImportPath = getImportPath(
324
+ builder,
325
+ method.functionName,
326
+ packageName,
327
+ projectName,
328
+ method.sourceFilename
329
+ );
330
+ const hookImportPath = method.hookName
331
+ ? getImportPath(
332
+ builder,
333
+ method.hookName,
334
+ packageName,
335
+ projectName,
336
+ method.hookSourceFilename
337
+ )
338
+ : functionImportPath;
339
+
340
+ packageDocs += `\`\`\`ts\n`;
341
+ packageDocs += `import { ${aliasedFunctionName} } from '${functionImportPath}'\n`;
342
+ if (method.hookName && aliasedHookName !== aliasedFunctionName) {
343
+ packageDocs += `import { ${aliasedHookName} } from '${hookImportPath}'\n`;
344
+ }
345
+ packageDocs += `\`\`\`\n\n`;
346
+
347
+ // Add function details in organized format
348
+ packageDocs += `| Field | Value | Source |\n`;
349
+ packageDocs += `| --- | --- | --- |\n`;
350
+
351
+ // Function source
352
+ const functionSourcePath =
353
+ method.sourceFilename ||
354
+ `${packageName.replace(/\./g, "/")}/tx.rpc.func.ts`;
355
+ packageDocs += `| Function | \`${aliasedFunctionName}\` | [View source ↗](${functionSourcePath}) |\n`;
356
+
357
+ // Hook source (React)
358
+ if (method.hookName && aliasedHookName !== aliasedFunctionName) {
359
+ const hookSourcePath =
360
+ method.hookSourceFilename ||
361
+ `${packageName.replace(/\./g, "/")}/tx.rpc.react.ts`;
362
+ packageDocs += `| Hook | \`${aliasedHookName}\` | [View source ↗](${hookSourcePath}) |\n`;
363
+ }
364
+
365
+ // Request type source
366
+ if (method.requestType) {
367
+ const requestSourcePath =
368
+ method.typeSourceFilename ||
369
+ `${packageName.replace(/\./g, "/")}/tx.ts`;
370
+ packageDocs += `| Request | \`${method.requestType}\` | [View source ↗](${requestSourcePath}) |\n`;
371
+ }
372
+
373
+ // Response type source
374
+ if (method.responseType) {
375
+ const responseSourcePath =
376
+ method.typeSourceFilename ||
377
+ `${packageName.replace(/\./g, "/")}/tx.ts`;
378
+ packageDocs += `| Response | \`${method.responseType}\` | [View source ↗](${responseSourcePath}) |\n`;
379
+ }
380
+
381
+ // Add spacing between methods (but not after the last one)
382
+ if (index < msgMethods.length - 1) {
383
+ packageDocs += "\n---\n\n";
384
+ } else {
385
+ packageDocs += "\n";
386
+ }
387
+ });
388
+ }
302
389
 
303
- // Add spacing between packages
304
- packageDocs += '\n';
390
+ // Add spacing between packages
391
+ packageDocs += "\n";
305
392
  });
306
393
 
307
- const readmeContent = `# Package Documentation
394
+ const readmeContent = `# Package Documentation
308
395
  ${packageDocs}`;
309
396
 
310
- writeContentToFile(
311
- builder.outPath,
312
- builder.options,
313
- readmeContent,
314
- readmePath
315
- );
316
- };
397
+ writeContentToFile(
398
+ builder.outPath,
399
+ builder.options,
400
+ readmeContent,
401
+ readmePath
402
+ );
403
+ };