Skip to content

Commit 4b2bb60

Browse files
authored
add remappings.txt support for foundry (intellij-solidity#331)
1 parent cd84374 commit 4b2bb60

File tree

10 files changed

+84
-7
lines changed

10 files changed

+84
-7
lines changed

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
*.ipr
66
*.iws
77
gen
8-
lib
8+
/lib
99
.sandbox
1010
.DS_Store
1111
/out/

src/main/kotlin/me/serce/solidity/lang/resolve/ref/SolImportPathReference.kt

Lines changed: 39 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -45,17 +45,50 @@ class SolImportPathReference(element: SolImportPathElement) : SolReferenceBase<S
4545
}
4646
}
4747

48-
// default lib located at: forge-std/Test.sol => lib/forge-std/src/Test.sol
49-
private fun findFoundryImportFile(file: VirtualFile, path: String): VirtualFile? {
48+
// apply foundry remappings to import path
49+
private fun applyRemappings(remappings: ArrayList<Pair<String,String>>, path: String):String {
50+
var output = path;
51+
remappings.forEach { (prefix, target) ->
52+
if (path.contains(prefix)) {
53+
output = path.replace(prefix, target)
54+
return output
55+
}
56+
}
57+
return output;
58+
}
59+
60+
private fun foundryDefaultFallback(file: VirtualFile, path: String): VirtualFile? {
5061
val count = Paths.get(path).nameCount;
51-
if (count < 2) {
62+
if (count<2) {
5263
return null;
5364
}
54-
val libName = Paths.get(path).subpath(0, 1).toString();
55-
val libFile = Paths.get(path).subpath(1, count).toString();
65+
val libName = Paths.get(path).subpath(0,1).toString();
66+
val libFile = Paths.get(path).subpath(1,count).toString();
5667
val test = file.findFileByRelativePath("lib/$libName/src/$libFile");
68+
return test;
69+
}
70+
71+
// default lib located at: forge-std/Test.sol => lib/forge-std/src/Test.sol
72+
private fun findFoundryImportFile(file: VirtualFile, path: String): VirtualFile? {
73+
val testRemappingFile = file.findFileByRelativePath("remappings.txt");
74+
val remappings = arrayListOf<Pair<String, String>>();
75+
if (testRemappingFile != null) {
76+
val mappingsContents = testRemappingFile.contentsToByteArray().toString(Charsets.UTF_8).split("[\r\n]+".toRegex());
77+
mappingsContents.forEach { mapping ->
78+
val splitMapping = mapping.split("=")
79+
if (splitMapping.size == 2) {
80+
remappings.add(Pair(splitMapping[0].trim(),splitMapping[1].trim()))
81+
}
82+
}
83+
}
84+
85+
val remappedPath = applyRemappings(remappings, path);
86+
val testRemappedPath = file.findFileByRelativePath(remappedPath);
87+
val testFoundryFallback = foundryDefaultFallback(file, path);
88+
5789
return when {
58-
test != null -> test
90+
testRemappedPath != null -> testRemappedPath
91+
testFoundryFallback != null -> testFoundryFallback
5992
file.parent != null -> findFoundryImportFile(file.parent, path)
6093
else -> null
6194
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package me.serce.solidity.lang.core.resolve
2+
3+
import me.serce.solidity.lang.psi.SolNamedElement
4+
5+
class SolImportResolveFoundryTest : SolResolveTestBase() {
6+
7+
fun testImportPathResolveFoundryRemappings() {
8+
val testcases = arrayListOf<Pair<String, String>>(
9+
Pair("lib/forge-std/src/Test.sol","contracts/ImportUsageFoundryStd.sol"),
10+
Pair("lib/solmate/src/tokens/ERC721.sol","contracts/ImportUsageFoundrySolmate.sol"),
11+
Pair("lib/openzeppelin-contracts/contracts/token/ERC20/ERC20.sol","contracts/ImportUsageFoundryOpenzeppelin.sol"),
12+
);
13+
testcases.forEach { (targetFile, contractFile) ->
14+
val file1 = myFixture.configureByFile(targetFile)
15+
myFixture.configureByFile("remappings.txt")
16+
myFixture.configureByFile(contractFile)
17+
val (refElement) = findElementAndDataInEditor<SolNamedElement>("^")
18+
val resolved = checkNotNull(refElement.reference?.resolve()) {
19+
"Failed to resolve ${refElement.text}"
20+
}
21+
assertEquals(file1.name, resolved.containingFile.name)
22+
}
23+
}
24+
25+
override fun getTestDataPath() = "src/test/resources/fixtures/importRemappings/"
26+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
import "@openzeppelin/token/ERC20/ERC20.sol";
2+
//^
3+
4+
contract ImportUsage {}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
import "@solmate/tokens/ERC721.sol";
2+
//^
3+
4+
contract ImportUsage {}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
import "forge-std/Test.sol";
2+
//^
3+
4+
contract ImportUsage {}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
contract Test {}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
contract ERC20 {}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
contract ERC721 {}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
@solmate/=lib/solmate/src/
2+
@openzeppelin/=lib/openzeppelin-contracts/contracts/
3+

0 commit comments

Comments
 (0)