ethershell 0.1.1-alpha.15 → 0.1.1-beta.0

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.
@@ -0,0 +1,247 @@
1
+ /**
2
+ * @fileoverview TypeScript type generation from Solidity ABIs
3
+ * @description Generates type-safe TypeScript interfaces and classes
4
+ * from compiled Solidity contracts for use in TypeScript projects
5
+ * @module typeGenerator
6
+ */
7
+
8
+ import path from 'path';
9
+ import fs from 'fs';
10
+
11
+ /**
12
+ * Generate TypeScript types from contract ABI
13
+ * @param {string} contractName - Name of the contract
14
+ * @param {Array} abi - Contract ABI array
15
+ * @param {string} outputPath - Output directory for types
16
+ * @returns {string} Path to generated type file
17
+ */
18
+ export function generateContractTypes(contractName, abi, outputPath) {
19
+ try {
20
+ // Ensure output directory exists
21
+ if (!fs.existsSync(outputPath)) {
22
+ fs.mkdirSync(outputPath, { recursive: true });
23
+ }
24
+
25
+ // Generate TypeScript interfaces
26
+ const interfaces = generateInterfaces(contractName, abi);
27
+ const typePath = path.join(outputPath, `${contractName}.ts`);
28
+
29
+ fs.writeFileSync(typePath, interfaces);
30
+
31
+ return typePath;
32
+ } catch (error) {
33
+ console.error(`Error generating types for ${contractName}:`, error.message);
34
+ throw error;
35
+ }
36
+ }
37
+
38
+ /**
39
+ * Generate all TypeScript types from build artifacts
40
+ * @param {string} buildPath - Path to build directory with ABIs
41
+ * @param {string} typesOutputPath - Output directory for TypeScript types
42
+ * @returns {Array} Array of generated type file paths
43
+ */
44
+ export function generateAllTypes(buildPath, typesOutputPath = './src/types') {
45
+ try {
46
+ const abisPath = path.join(buildPath, 'abis');
47
+
48
+ if (!fs.existsSync(abisPath)) {
49
+ throw new Error(`ABIs directory not found at ${abisPath}`);
50
+ }
51
+
52
+ const abiFiles = fs.readdirSync(abisPath).filter(f => f.endsWith('.abi.json'));
53
+ const generatedFiles = [];
54
+
55
+ abiFiles.forEach(file => {
56
+ const contractName = file.replace('.abi.json', '');
57
+ const abiPath = path.join(abisPath, file);
58
+ const abi = JSON.parse(fs.readFileSync(abiPath, 'utf8'));
59
+
60
+ const typePath = generateContractTypes(contractName, abi, typesOutputPath);
61
+ generatedFiles.push(typePath);
62
+ });
63
+
64
+ // Generate index.ts for barrel export
65
+ generateIndexFile(typesOutputPath, abiFiles);
66
+
67
+ return generatedFiles;
68
+ } catch (error) {
69
+ console.error('Error generating types:', error.message);
70
+ throw error;
71
+ }
72
+ }
73
+
74
+ /**
75
+ * Generate TypeScript interface from ABI
76
+ * @private
77
+ */
78
+ function generateInterfaces(contractName, abi) {
79
+ const functions = abi.filter(item => item.type === 'function');
80
+ const events = abi.filter(item => item.type === 'event');
81
+ const structs = extractStructTypes(abi);
82
+
83
+ let typescript = `/**
84
+ * Auto-generated types for ${contractName} contract
85
+ * Generated from ABI
86
+ */
87
+
88
+ // ============= TYPES =============
89
+ ${generateStructTypes(structs)}
90
+
91
+ // ============= FUNCTION INPUTS =============
92
+ ${generateFunctionTypes(functions, 'input')}
93
+
94
+ // ============= FUNCTION OUTPUTS =============
95
+ ${generateFunctionTypes(functions, 'output')}
96
+
97
+ // ============= EVENT TYPES =============
98
+ ${generateEventTypes(events)}
99
+
100
+ // ============= CONTRACT INTERFACE =============
101
+ export interface I${contractName} {
102
+ ${generateContractMethods(functions)}
103
+ }
104
+
105
+ // ============= ABI EXPORT =============
106
+ export const ${contractName}ABI = ${JSON.stringify(abi, null, 2)} as const;
107
+ `;
108
+
109
+ return typescript;
110
+ }
111
+
112
+ /**
113
+ * Generate TypeScript types for function inputs/outputs
114
+ * @private
115
+ */
116
+ function generateFunctionTypes(functions, direction) {
117
+ const lines = [];
118
+
119
+ functions.forEach(func => {
120
+ const params = direction === 'input' ? func.inputs : func.outputs;
121
+ if (!params || params.length === 0) return;
122
+
123
+ const funcName = func.name;
124
+ const typeName = `${funcName.charAt(0).toUpperCase() + funcName.slice(1)}${direction === 'input' ? 'Params' : 'Result'}`;
125
+
126
+ lines.push(`export interface ${typeName} {`);
127
+ params.forEach((param, idx) => {
128
+ const name = param.name || `param${idx}`;
129
+ const type = solToTsType(param.type);
130
+ lines.push(` ${name}: ${type};`);
131
+ });
132
+ lines.push('}\n');
133
+ });
134
+
135
+ return lines.join('\n');
136
+ }
137
+
138
+ /**
139
+ * Generate TypeScript types for events
140
+ * @private
141
+ */
142
+ function generateEventTypes(events) {
143
+ const lines = [];
144
+
145
+ events.forEach(event => {
146
+ const typeName = `${event.name}Event`;
147
+ lines.push(`export interface ${typeName} {`);
148
+
149
+ event.inputs.forEach((input, idx) => {
150
+ const name = input.name || `param${idx}`;
151
+ const type = solToTsType(input.type);
152
+ const indexed = input.indexed ? ' // indexed' : '';
153
+ lines.push(` ${name}: ${type};${indexed}`);
154
+ });
155
+
156
+ lines.push('}\n');
157
+ });
158
+
159
+ return lines.join('\n');
160
+ }
161
+
162
+ /**
163
+ * Generate contract method signatures
164
+ * @private
165
+ */
166
+ function generateContractMethods(functions) {
167
+ const lines = [];
168
+
169
+ functions.forEach(func => {
170
+ const inputs = func.inputs.map(inp => {
171
+ const type = solToTsType(inp.type);
172
+ return `${inp.name || 'param'}: ${type}`;
173
+ }).join(', ');
174
+
175
+ let returnType = 'Promise<void>';
176
+ if (func.outputs && func.outputs.length > 0) {
177
+ if (func.outputs.length === 1) {
178
+ returnType = `Promise<${solToTsType(func.outputs[0].type)}>`;
179
+ } else {
180
+ returnType = `Promise<[${func.outputs.map(o => solToTsType(o.type)).join(', ')}]>`;
181
+ }
182
+ }
183
+
184
+ const stateMutability = func.stateMutability || 'nonpayable';
185
+ lines.push(` ${func.name}(${inputs}): ${returnType}; // ${stateMutability}`);
186
+ });
187
+
188
+ return lines.join('\n');
189
+ }
190
+
191
+ /**
192
+ * Convert Solidity type to TypeScript type
193
+ * @private
194
+ */
195
+ function solToTsType(solidityType) {
196
+ // Handle arrays
197
+ if (solidityType.endsWith(']')) {
198
+ const baseType = solidityType.replace(/\[\d*\]/g, '');
199
+ return `${solToTsType(baseType)}[]`;
200
+ }
201
+
202
+ // Handle base types
203
+ if (solidityType.startsWith('uint')) return 'bigint';
204
+ if (solidityType.startsWith('int')) return 'bigint';
205
+ if (solidityType.startsWith('bytes')) return 'string | Uint8Array';
206
+ if (solidityType === 'bool') return 'boolean';
207
+ if (solidityType === 'address') return 'string'; // EVM address as checksum string
208
+ if (solidityType === 'string') return 'string';
209
+
210
+ // Fallback for custom types
211
+ return 'any';
212
+ }
213
+
214
+ /**
215
+ * Extract struct types from ABI
216
+ * @private
217
+ */
218
+ function extractStructTypes(abi) {
219
+ // This would require more advanced parsing for tuple types
220
+ return [];
221
+ }
222
+
223
+ /**
224
+ * Generate struct type definitions
225
+ * @private
226
+ */
227
+ function generateStructTypes(structs) {
228
+ if (structs.length === 0) return '// No custom structs\n';
229
+
230
+ return structs.map(struct => `export interface ${struct.name} {\n // struct fields\n}\n`).join('\n');
231
+ }
232
+
233
+ /**
234
+ * Generate barrel export index.ts
235
+ * @private
236
+ */
237
+ function generateIndexFile(typesPath, abiFiles) {
238
+ const exports = abiFiles
239
+ .map(file => {
240
+ const name = file.replace('.abi.json', '');
241
+ return `export * from './${name}';`;
242
+ })
243
+ .join('\n');
244
+
245
+ const indexPath = path.join(typesPath, 'index.ts');
246
+ fs.writeFileSync(indexPath, `// Auto-generated barrel export\n${exports}\n`);
247
+ }