* Finds all import statements in content without using regex * @returns Array of {start, _end, path} objects for each import found
( content: string, )
| 88 | * @returns Array of {start, _end, path} objects for each import found |
| 89 | */ |
| 90 | function findImports( |
| 91 | content: string, |
| 92 | ): Array<{ start: number; _end: number; path: string }> { |
| 93 | const imports: Array<{ start: number; _end: number; path: string }> = []; |
| 94 | let i = 0; |
| 95 | const len = content.length; |
| 96 | |
| 97 | while (i < len) { |
| 98 | // Find next @ symbol |
| 99 | i = content.indexOf('@', i); |
| 100 | if (i === -1) break; |
| 101 | |
| 102 | // Check if it's a word boundary (not part of another word) |
| 103 | if (i > 0 && !isWhitespace(content[i - 1])) { |
| 104 | i++; |
| 105 | continue; |
| 106 | } |
| 107 | |
| 108 | // Find the end of the import path (whitespace or newline) |
| 109 | let j = i + 1; |
| 110 | while ( |
| 111 | j < len && |
| 112 | !isWhitespace(content[j]) && |
| 113 | content[j] !== '\n' && |
| 114 | content[j] !== '\r' |
| 115 | ) { |
| 116 | j++; |
| 117 | } |
| 118 | |
| 119 | // Extract the path (everything after @) |
| 120 | const importPath = content.slice(i + 1, j); |
| 121 | |
| 122 | // Basic validation (starts with ./ or / or letter) |
| 123 | if ( |
| 124 | importPath.length > 0 && |
| 125 | (importPath[0] === '.' || |
| 126 | importPath[0] === '/' || |
| 127 | isLetter(importPath[0])) |
| 128 | ) { |
| 129 | imports.push({ |
| 130 | start: i, |
| 131 | _end: j, |
| 132 | path: importPath, |
| 133 | }); |
| 134 | } |
| 135 | |
| 136 | i = j + 1; |
| 137 | } |
| 138 | |
| 139 | return imports; |
| 140 | } |
| 141 | |
| 142 | function isWhitespace(char: string): boolean { |
| 143 | return char === ' ' || char === '\t' || char === '\n' || char === '\r'; |
no test coverage detected