Skip to content

Commit 3cba75e

Browse files
committed
add error and event extraction
1 parent 714e022 commit 3cba75e

File tree

2 files changed

+327
-155
lines changed

2 files changed

+327
-155
lines changed

etc/facadeBuilder/facadeBuilder.js

Lines changed: 180 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -36,20 +36,33 @@ var __generator = (this && this.__generator) || function (thisArg, body) {
3636
}
3737
};
3838
Object.defineProperty(exports, "__esModule", { value: true });
39-
var solidity_parser_antlr_1 = require("solidity-parser-antlr");
39+
var parser_1 = require("@solidity-parser/parser");
4040
var fs = require("fs-extra");
4141
var path = require("path");
4242
var yaml = require("js-yaml");
4343
var facadeConfigPath = './facade.yaml'; // Configuration file path
4444
var outputDir = './generated'; // Output directory for generated files
4545
function main() {
4646
return __awaiter(this, void 0, void 0, function () {
47-
var facadeConfig, _i, _a, facade, sourceDir, allFiles, _b, _c, facade, functionSignatures, _d, allFiles_1, file, fileName, content, ast, functions;
48-
return __generator(this, function (_e) {
49-
switch (_e.label) {
50-
case 0: return [4 /*yield*/, loadFacadeConfig()];
47+
var projectRoot, facadeConfigs, _i, facadeConfigs_1, facadeConfig, _a, _b, facade, _c, _d, facade, facadeObject, functionDir, interfaceDir, functionFiles, interfaceFiles, regex, _e, interfaceFiles_1, file, fileName, _f, functionFiles_1, file, fileName, content, ast;
48+
return __generator(this, function (_g) {
49+
switch (_g.label) {
50+
case 0:
51+
projectRoot = path.resolve(__dirname, '../../');
52+
process.chdir(projectRoot);
53+
// Ensure output directory exists
54+
return [4 /*yield*/, fs.ensureDir(path.resolve(outputDir))];
5155
case 1:
52-
facadeConfig = _e.sent();
56+
// Ensure output directory exists
57+
_g.sent();
58+
return [4 /*yield*/, loadFacadeConfig()];
59+
case 2:
60+
facadeConfigs = _g.sent();
61+
_i = 0, facadeConfigs_1 = facadeConfigs;
62+
_g.label = 3;
63+
case 3:
64+
if (!(_i < facadeConfigs_1.length)) return [3 /*break*/, 14];
65+
facadeConfig = facadeConfigs_1[_i];
5366
// Ensure required fields are present
5467
if (!facadeConfig.bundleName || !facadeConfig.bundleDirName) {
5568
console.error('Error: bundleName and bundleDirName are required in facade.yaml');
@@ -59,96 +72,115 @@ function main() {
5972
console.error('Error: At least one facade must be defined in facade.yaml');
6073
process.exit(1);
6174
}
62-
for (_i = 0, _a = facadeConfig.facades; _i < _a.length; _i++) {
63-
facade = _a[_i];
75+
for (_a = 0, _b = facadeConfig.facades; _a < _b.length; _a++) {
76+
facade = _b[_a];
6477
if (!facade.name) {
6578
console.error('Error: Each facade must have a name');
6679
process.exit(1);
6780
}
6881
}
69-
sourceDir = "./src/".concat(facadeConfig.bundleDirName, "/functions");
70-
return [4 /*yield*/, getSolidityFiles(sourceDir)];
71-
case 2:
72-
allFiles = _e.sent();
73-
// Ensure output directory exists
74-
return [4 /*yield*/, fs.ensureDir(outputDir)];
75-
case 3:
76-
// Ensure output directory exists
77-
_e.sent();
78-
_b = 0, _c = facadeConfig.facades;
79-
_e.label = 4;
82+
_c = 0, _d = facadeConfig.facades;
83+
_g.label = 4;
8084
case 4:
81-
if (!(_b < _c.length)) return [3 /*break*/, 11];
82-
facade = _c[_b];
83-
functionSignatures = [];
84-
_d = 0, allFiles_1 = allFiles;
85-
_e.label = 5;
85+
if (!(_c < _d.length)) return [3 /*break*/, 13];
86+
facade = _d[_c];
87+
facadeObject = {
88+
files: [],
89+
errors: [],
90+
events: [],
91+
functions: []
92+
};
93+
functionDir = "./src/".concat(facadeConfig.bundleDirName, "/functions");
94+
interfaceDir = "./src/".concat(facadeConfig.bundleDirName, "/interfaces");
95+
return [4 /*yield*/, getSolidityFiles(functionDir)];
8696
case 5:
87-
if (!(_d < allFiles_1.length)) return [3 /*break*/, 8];
88-
file = allFiles_1[_d];
97+
functionFiles = _g.sent();
98+
return [4 /*yield*/, getSolidityFiles(interfaceDir)];
99+
case 6:
100+
interfaceFiles = _g.sent();
101+
regex = /^(I)?.*(Errors|Events)\.sol$/;
102+
for (_e = 0, interfaceFiles_1 = interfaceFiles; _e < interfaceFiles_1.length; _e++) {
103+
file = interfaceFiles_1[_e];
104+
fileName = path.basename(file);
105+
if (regex.test(fileName)) {
106+
facadeObject.files.push({ name: fileName.replace(/\.sol$/, ""), origin: file.replace(/\\/g, '/') });
107+
}
108+
}
109+
_f = 0, functionFiles_1 = functionFiles;
110+
_g.label = 7;
111+
case 7:
112+
if (!(_f < functionFiles_1.length)) return [3 /*break*/, 10];
113+
file = functionFiles_1[_f];
89114
fileName = path.basename(file);
90115
// Exclude files based on facade configuration
91116
if (facade.excludeFileNames.includes(fileName)) {
92-
return [3 /*break*/, 7];
117+
return [3 /*break*/, 9];
93118
}
94119
return [4 /*yield*/, fs.readFile(file, 'utf8')];
95-
case 6:
96-
content = _e.sent();
120+
case 8:
121+
content = _g.sent();
97122
try {
98-
ast = (0, solidity_parser_antlr_1.parse)(content, { tolerant: true });
99-
functions = [];
100-
extractFunctions(ast, functions, fileName, facade);
101-
if (functions.length > 0) {
102-
functionSignatures.push.apply(functionSignatures, functions);
103-
}
123+
ast = (0, parser_1.parse)(content, { tolerant: true });
124+
// Extract functions from the AST
125+
traverseASTs(ast, facadeObject, fileName, facade);
104126
}
105127
catch (err) {
106128
console.error("Error parsing ".concat(file, ":"), err);
107129
}
108-
_e.label = 7;
109-
case 7:
110-
_d++;
111-
return [3 /*break*/, 5];
112-
case 8:
113-
// Generate facade contract
114-
return [4 /*yield*/, generateFacadeContract(functionSignatures, facade, facadeConfig)];
130+
_g.label = 9;
115131
case 9:
116-
// Generate facade contract
117-
_e.sent();
118-
_e.label = 10;
132+
_f++;
133+
return [3 /*break*/, 7];
119134
case 10:
120-
_b++;
135+
console.log(facadeObject);
136+
// Generate facade contract
137+
return [4 /*yield*/, generateFacadeContract(facadeObject, facade, facadeConfig)];
138+
case 11:
139+
// Generate facade contract
140+
_g.sent();
141+
_g.label = 12;
142+
case 12:
143+
_c++;
121144
return [3 /*break*/, 4];
122-
case 11: return [2 /*return*/];
145+
case 13:
146+
_i++;
147+
return [3 /*break*/, 3];
148+
case 14: return [2 /*return*/];
123149
}
124150
});
125151
});
126152
}
127153
function loadFacadeConfig() {
128154
return __awaiter(this, void 0, void 0, function () {
129-
var configContent, configRaw, _i, _a, facade, config, err_1;
130-
return __generator(this, function (_b) {
131-
switch (_b.label) {
155+
var configContent, configRaws, _i, configRaws_1, configRaw, _a, _b, facade, config, err_1;
156+
return __generator(this, function (_c) {
157+
switch (_c.label) {
132158
case 0:
133-
_b.trys.push([0, 2, , 3]);
159+
_c.trys.push([0, 2, , 3]);
134160
return [4 /*yield*/, fs.readFile(facadeConfigPath, 'utf8')];
135161
case 1:
136-
configContent = _b.sent();
137-
configRaw = yaml.load(configContent);
138-
// Ensure excludeFileNames and excludeFunctionNames are arrays
139-
for (_i = 0, _a = configRaw.facades; _i < _a.length; _i++) {
140-
facade = _a[_i];
141-
if (!facade.excludeFileNames) {
142-
facade.excludeFileNames = [];
162+
configContent = _c.sent();
163+
configRaws = yaml.load(configContent);
164+
for (_i = 0, configRaws_1 = configRaws; _i < configRaws_1.length; _i++) {
165+
configRaw = configRaws_1[_i];
166+
if (!configRaw.bundleDirName) {
167+
configRaw.bundleDirName = configRaw.bundleName;
143168
}
144-
if (!facade.excludeFunctionNames) {
145-
facade.excludeFunctionNames = [];
169+
// Ensure excludeFileNames and excludeFunctionNames are arrays
170+
for (_a = 0, _b = configRaw.facades; _a < _b.length; _a++) {
171+
facade = _b[_a];
172+
if (!facade.excludeFileNames) {
173+
facade.excludeFileNames = [];
174+
}
175+
if (!facade.excludeFunctionNames) {
176+
facade.excludeFunctionNames = [];
177+
}
146178
}
147179
}
148-
config = configRaw;
180+
config = configRaws;
149181
return [2 /*return*/, config];
150182
case 2:
151-
err_1 = _b.sent();
183+
err_1 = _c.sent();
152184
console.error("Could not load facade configuration from ".concat(facadeConfigPath, "."));
153185
process.exit(1);
154186
return [3 /*break*/, 3];
@@ -195,48 +227,77 @@ function getSolidityFiles(dir) {
195227
});
196228
});
197229
}
198-
function extractFunctions(ast, functions, origin, facade) {
230+
function traverseASTs(ast, facadeObjects, origin, facade) {
199231
if (ast.type === 'FunctionDefinition' && ast.isConstructor === false) {
200-
// Skip functions based on the criteria
201-
if (!ast.name || // Skip unnamed functions (constructor, fallback, receive)
202-
ast.visibility === 'internal' ||
203-
ast.name.startsWith('_') ||
204-
ast.name.startsWith('test') ||
205-
ast.name === 'setUp' ||
206-
facade.excludeFunctionNames.includes(ast.name)) {
207-
return;
208-
}
209-
var func = {
210-
name: ast.name,
211-
visibility: ast.visibility || 'default',
212-
stateMutability: ast.stateMutability || '',
213-
parameters: ast.parameters
214-
.map(function (param) { return getParameter(param); })
215-
.join(', '),
216-
returnParameters: ast.returnParameters
217-
? ast.returnParameters
218-
.map(function (param) { return getParameter(param); })
219-
.join(', ')
220-
: '',
221-
origin: origin, // Set the origin to the file name
222-
};
223-
// Add to functions array
224-
functions.push(func);
232+
extractFunctions(ast, facadeObjects.functions, origin, facade);
225233
}
226234
else if (ast.type === 'ContractDefinition') {
227235
// Traverse contract sub-nodes
228236
for (var _i = 0, _a = ast.subNodes; _i < _a.length; _i++) {
229237
var subNode = _a[_i];
230-
extractFunctions(subNode, functions, origin, facade);
238+
traverseASTs(subNode, facadeObjects, origin, facade);
231239
}
232240
}
233241
else if (ast.type === 'SourceUnit') {
234242
// Traverse source unit nodes
235243
for (var _b = 0, _c = ast.children; _b < _c.length; _b++) {
236244
var child = _c[_b];
237-
extractFunctions(child, functions, origin, facade);
245+
traverseASTs(child, facadeObjects, origin, facade);
238246
}
239247
}
248+
else if (ast.type === 'CustomErrorDefinition') {
249+
extractErrors(ast, facadeObjects.errors, origin);
250+
}
251+
else if (ast.type === 'EventDefinition') {
252+
extractEvents(ast, facadeObjects.events, origin);
253+
}
254+
}
255+
function extractErrors(ast, errors, origin) {
256+
var error = {
257+
name: ast.name,
258+
parameters: ast.parameters
259+
.map(function (param) { return getParameter(param); })
260+
.join(', '),
261+
origin: origin
262+
};
263+
errors.push(error);
264+
}
265+
function extractEvents(ast, events, origin) {
266+
var event = {
267+
name: ast.name,
268+
parameters: ast.parameters
269+
.map(function (param) { return getParameter(param); })
270+
.join(', '),
271+
origin: origin
272+
};
273+
events.push(event);
274+
}
275+
function extractFunctions(ast, functions, origin, facade) {
276+
// Skip functions based on the criteria
277+
if (!ast.name || // Skip unnamed functions (constructor, fallback, receive)
278+
ast.name.startsWith('test') ||
279+
ast.name === 'setUp' ||
280+
ast.visibility === 'private' ||
281+
ast.visibility === 'internal' ||
282+
facade.excludeFunctionNames.includes(ast.name)) {
283+
return;
284+
}
285+
var func = {
286+
name: ast.name,
287+
visibility: ast.visibility || 'default',
288+
stateMutability: ast.stateMutability || '',
289+
parameters: ast.parameters
290+
.map(function (param) { return getParameter(param); })
291+
.join(', '),
292+
returnParameters: ast.returnParameters
293+
? ast.returnParameters
294+
.map(function (param) { return getParameter(param); })
295+
.join(', ')
296+
: '',
297+
origin: origin, // Set the origin to the file name
298+
};
299+
// Add to functions array
300+
functions.push(func);
240301
}
241302
function getParameter(param) {
242303
var typeName = getTypeName(param.typeName);
@@ -265,30 +326,51 @@ function getTypeName(typeName) {
265326
return 'unknown';
266327
}
267328
}
268-
function generateFacadeContract(functionSignatures, facade, config) {
329+
function generateFacadeContract(objects, facade, config) {
269330
return __awaiter(this, void 0, void 0, function () {
270-
var facadeFilePath, code, _i, functionSignatures_1, func;
271-
return __generator(this, function (_a) {
272-
switch (_a.label) {
331+
var facadeFilePath, code, _i, _a, file, _b, _c, error, _d, _e, event_1, _f, _g, func;
332+
return __generator(this, function (_h) {
333+
switch (_h.label) {
273334
case 0:
274335
facadeFilePath = path.join(outputDir, "".concat(facade.name, ".sol"));
275-
code = "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.24;\n\nimport {Schema} from \"src/".concat(config.bundleDirName, "/storage/Schema.sol\";\nimport {I").concat(config.bundleName, "Events} from \"src/").concat(config.bundleDirName, "/interfaces/I").concat(config.bundleName, "Events.sol\";\nimport {I").concat(config.bundleName, "Errors} from \"src/").concat(config.bundleDirName, "/interfaces/I").concat(config.bundleName, "Errors.sol\";\n\ncontract ").concat(facade.name, " is Schema, I").concat(config.bundleName, "Events, I").concat(config.bundleName, "Errors {\n");
276-
for (_i = 0, functionSignatures_1 = functionSignatures; _i < functionSignatures_1.length; _i++) {
277-
func = functionSignatures_1[_i];
336+
code = "\n// SPDX-License-Identifier: MIT\npragma solidity ^0.8.24;\n\nimport {Schema} from \"src/".concat(config.bundleDirName, "/storage/Schema.sol\";\n");
337+
for (_i = 0, _a = objects.files; _i < _a.length; _i++) {
338+
file = _a[_i];
339+
code += "import {".concat(file.name, "} from \"").concat(file.origin, "\";\n");
340+
}
341+
code += "\ncontract ".concat(facade.name, " is Schema, ").concat(objects.files.map(function (file) { return file.name; }).join(', '), " {\n");
342+
for (_b = 0, _c = objects.errors; _b < _c.length; _b++) {
343+
error = _c[_b];
344+
code += generateError(error);
345+
}
346+
code += "\n";
347+
for (_d = 0, _e = objects.events; _d < _e.length; _d++) {
348+
event_1 = _e[_d];
349+
code += generateEvent(event_1);
350+
}
351+
code += "\n";
352+
for (_f = 0, _g = objects.functions; _f < _g.length; _f++) {
353+
func = _g[_f];
278354
code += generateFunctionSignature(func);
279355
}
280356
code += "}\n";
281357
// Write the facade contract to the output file
282358
return [4 /*yield*/, fs.writeFile(facadeFilePath, code)];
283359
case 1:
284360
// Write the facade contract to the output file
285-
_a.sent();
361+
_h.sent();
286362
console.log("Facade contract generated at ".concat(facadeFilePath));
287363
return [2 /*return*/];
288364
}
289365
});
290366
});
291367
}
368+
function generateError(error) {
369+
return " error ".concat(error.name, "(").concat(error.parameters, ");\n");
370+
}
371+
function generateEvent(event) {
372+
return " event ".concat(event.name, "(").concat(event.parameters, ");\n");
373+
}
292374
function generateFunctionSignature(func) {
293375
var visibility = func.visibility !== 'default' ? func.visibility : 'public';
294376
var stateMutability = func.stateMutability

0 commit comments

Comments
 (0)