Skip to content

Commit cb6f571

Browse files
author
ci-bot
committed
fixes
1 parent bd3c646 commit cb6f571

File tree

1 file changed

+110
-7
lines changed

1 file changed

+110
-7
lines changed

libs/remix-solidity/src/compiler/dependency-resolver.ts

Lines changed: 110 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -206,27 +206,130 @@ export class DependencyResolver {
206206

207207
/**
208208
* Extract import statements from Solidity source code
209+
* Handles:
210+
* 1. Comments (single-line and multi-line)
211+
* 2. Multi-line imports
212+
* 3. All Solidity import syntaxes
213+
* 4. String literals (to avoid false matches)
209214
*/
210215
private extractImports(content: string): string[] {
211216
const imports: string[] = []
212217

213-
// Match: import "path/to/file.sol";
214-
// Match: import 'path/to/file.sol';
215-
// Match: import {Symbol} from "path/to/file.sol";
216-
// Match: import * as Name from "path/to/file.sol";
217-
const importRegex = /import\s+(?:{[^}]*}\s+from\s+)?(?:\*\s+as\s+\w+\s+from\s+)?["']([^"']+)["']/g
218+
// Step 1: Remove comments and string literals to avoid false matches
219+
const cleanedContent = this.removeCommentsAndStrings(content)
220+
221+
// Step 2: Extract imports from cleaned content
222+
// Solidity import patterns:
223+
// import "filename";
224+
// import 'filename';
225+
// import * as symbolName from "filename";
226+
// import { symbol1, symbol2 } from "filename";
227+
// import { symbol1 as alias1, symbol2 } from "filename";
228+
// import symbolName from "filename";
229+
// import "filename" as symbolName;
230+
231+
// Multi-line regex that handles whitespace and newlines
232+
const importRegex = /import\s+(?:(?:\*\s+as\s+\w+|{\s*[^}]*\s*}|\w+)\s+from\s+)?["']([^"']+)["'](?:\s+as\s+\w+)?/gms
218233

219234
let match
220-
while ((match = importRegex.exec(content)) !== null) {
221-
const importPath = match[1]
235+
while ((match = importRegex.exec(cleanedContent)) !== null) {
236+
const importPath = match[1]?.trim()
222237
if (importPath) {
223238
imports.push(importPath)
239+
this.log(`[DependencyResolver] 📄 Found import: ${importPath}`)
224240
}
225241
}
226242

227243
return imports
228244
}
229245

246+
/**
247+
* Remove comments and string literals from Solidity code to avoid false import matches
248+
* This prevents matching imports inside comments or string literals
249+
*/
250+
private removeCommentsAndStrings(content: string): string {
251+
let result = ''
252+
let i = 0
253+
let inString = false
254+
let stringChar = ''
255+
let inSingleLineComment = false
256+
let inMultiLineComment = false
257+
258+
while (i < content.length) {
259+
const char = content[i]
260+
const nextChar = i + 1 < content.length ? content[i + 1] : ''
261+
262+
// Handle multi-line comment start
263+
if (!inString && !inSingleLineComment && !inMultiLineComment && char === '/' && nextChar === '*') {
264+
inMultiLineComment = true
265+
result += ' ' // Replace with spaces to preserve positions
266+
i += 2
267+
continue
268+
}
269+
270+
// Handle multi-line comment end
271+
if (inMultiLineComment && char === '*' && nextChar === '/') {
272+
inMultiLineComment = false
273+
result += ' '
274+
i += 2
275+
continue
276+
}
277+
278+
// Handle single-line comment start
279+
if (!inString && !inMultiLineComment && char === '/' && nextChar === '/') {
280+
inSingleLineComment = true
281+
result += ' '
282+
i += 2
283+
continue
284+
}
285+
286+
// Handle end of line (ends single-line comment)
287+
if (inSingleLineComment && (char === '\n' || char === '\r')) {
288+
inSingleLineComment = false
289+
result += char // Keep newlines
290+
i++
291+
continue
292+
}
293+
294+
// Skip characters inside comments
295+
if (inSingleLineComment || inMultiLineComment) {
296+
result += char === '\n' || char === '\r' ? char : ' '
297+
i++
298+
continue
299+
}
300+
301+
// Handle string literals
302+
if (!inString && (char === '"' || char === "'")) {
303+
inString = true
304+
stringChar = char
305+
result += ' ' // Replace with space
306+
i++
307+
continue
308+
}
309+
310+
if (inString && char === stringChar && content[i - 1] !== '\\') {
311+
inString = false
312+
stringChar = ''
313+
result += ' '
314+
i++
315+
continue
316+
}
317+
318+
// Skip characters inside strings (except preserve structure)
319+
if (inString) {
320+
result += char === '\n' || char === '\r' ? char : ' '
321+
i++
322+
continue
323+
}
324+
325+
// Keep normal characters
326+
result += char
327+
i++
328+
}
329+
330+
return result
331+
}
332+
230333
/**
231334
* Extract package context from a file path
232335
* E.g., "@openzeppelin/contracts@4.8.0/token/ERC20/IERC20.sol" -> "@openzeppelin/contracts@4.8.0"

0 commit comments

Comments
 (0)