1
1
//Simple parser for .sol files that finds libraries defined in the file and creates a wrapper
2
- // that converts all their internal functions to external functions so they can be tested
3
- // in forge unit tests.
2
+ // that converts all their internal functions to external functions so they can be externally
3
+ // called in forge unit tests.
4
+ //
5
+ //Forge supports vm.expectRevert even for internal functions, so this wrapper is primarily
6
+ // helpful for libraries like BytesParsing (the original motivation for this script) where
7
+ // you have a large family of similar functions to test and you don't want to write a separate
8
+ // test for each one. So, it really mostly is a workaround for Solidity's lack of support for
9
+ // generics.
10
+
11
+ //Regarding the implementation of this script:
4
12
//Instead of properly parsing the full AST, we make our task of finding and transforming the
5
13
// relevant bits easier by making some basic assumptions about code formatting that any sane
6
- // code should almost certainly adhere to regardless.
7
-
14
+ // code should almost certainly adhere to regardless, like closing braces of library definitions
15
+ // being on their own line with no leading whitespace, etc.
16
+ //
8
17
//Solidity language grammar:
9
18
// https://docs.soliditylang.org/en/latest/grammar.html
10
19
@@ -43,8 +52,22 @@ if (process.argv.length != 3) {
43
52
process . exit ( 1 ) ;
44
53
}
45
54
46
- const filename = process . argv [ 2 ] ;
47
- let fileCode = readFileSync ( "../src/" + filename + filename . endsWith ( ".sol" ) ? "" : ".sol" , "utf8" ) ;
55
+ //convenience for use with Makefile:
56
+ //If no .sol file ending is specified, this script will use Wormhole Solidity SDK defaults for
57
+ // the file paths, the SPDX license header, the pragma version, and the import statement.
58
+ const fullPath = ( ( ) => {
59
+ const filename = process . argv [ 2 ] ;
60
+ if ( filename . endsWith ( ".sol" ) )
61
+ return filename ;
62
+
63
+ console . log (
64
+ `// SPDX-License-Identifier: Apache 2\npragma solidity ^0.8.24;\n\n` +
65
+ `import "wormhole-sdk/${ filename } .sol";\n`
66
+ ) ;
67
+
68
+ return "../src/" + filename + ".sol" ;
69
+ } ) ( ) ;
70
+ let fileCode = readFileSync ( fullPath , "utf8" ) ;
48
71
49
72
//we first remove all comments so we can be sure that everything we're parsing is actual code
50
73
fileCode = removeComments ( fileCode ) ;
@@ -76,13 +99,13 @@ for (const libs of libMatches) {
76
99
const [ _ , funcName , funcParasRaw , modsRaw , close ] = funcs ;
77
100
if ( close == ';' )
78
101
continue ; //function pointer, not a function definition
79
-
102
+
80
103
if ( ! modsRaw . includes ( "internal" ) )
81
104
continue ; //not an internal function
82
105
83
106
const retParasRegex = / r e t u r n s \s * \( ( [ \s \S ] * ?) \) / ;
84
107
const retParasRaw = modsRaw . match ( retParasRegex ) ;
85
-
108
+
86
109
const collapseSpaceRegex = / \s \s + / g;
87
110
const paramsToArray = ( paramList : string ) =>
88
111
paramList . replace ( collapseSpaceRegex , ' ' ) . trim ( ) . split ( ',' ) . map ( param => {
@@ -100,12 +123,7 @@ for (const libs of libMatches) {
100
123
}
101
124
}
102
125
103
- console . log ( `// SPDX-License-Identifier: Apache 2
104
- pragma solidity ^0.8.24;
105
-
106
- //This file was auto-generated by libraryTestWrapper.ts
107
-
108
- import "wormhole-sdk/${ filename } .sol";` ) ;
126
+ console . log ( `// This file was auto-generated by wormhole-solidity-sdk gen/libraryTestWrapper.ts` ) ;
109
127
110
128
const pConcat = ( paras : string [ ] ) =>
111
129
( paras . length > 2 ? "\n " : "" ) +
@@ -121,7 +139,7 @@ const pNames = (paras: string[]) =>
121
139
122
140
for ( const [ libName , funcs ] of Object . entries ( libraries ) ) {
123
141
console . log ( `\ncontract ${ libName } TestWrapper {` ) ;
124
- const funcCode = [ ] ;
142
+ const funcCode = [ ] ;
125
143
for ( const func of funcs )
126
144
funcCode . push ( [
127
145
` function ${ func . name } (${ pConcat ( func . paras ) } ) external ${ func . stateMut } ` +
0 commit comments