@@ -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 = / i m p o r t \s + (?: { [ ^ } ] * } \s + f r o m \s + ) ? (?: \* \s + a s \s + \w + \s + f r o m \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 = / i m p o r t \s + (?: (?: \* \s + a s \s + \w + | { \s * [ ^ } ] * \s * } | \w + ) \s + f r o m \s + ) ? [ " ' ] ( [ ^ " ' ] + ) [ " ' ] (?: \s + a s \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