Recursively scan JS for static imports
({file, rootDir, scannedFiles, importList})
| 9 | |
| 10 | /** Recursively scan JS for static imports */ |
| 11 | function scanJS({file, rootDir, scannedFiles, importList}) { |
| 12 | try { |
| 13 | // 1. scan file for static imports |
| 14 | scannedFiles.add(file); // keep track of scanned files so we never redo work |
| 15 | importList.add(file); // make sure import is marked |
| 16 | if (isRemoteModule(file)) { |
| 17 | // don’t scan remote modules |
| 18 | return importList; |
| 19 | } |
| 20 | |
| 21 | let code = fs.readFileSync(file, 'utf-8'); |
| 22 | const [imports] = parse(code); |
| 23 | imports |
| 24 | .filter(({d}) => d === -1) // this is where we discard dynamic imports (> -1) and import.meta (-2) |
| 25 | .forEach(({s, e}) => { |
| 26 | const specifier = code.substring(s, e); |
| 27 | if (isRemoteModule(specifier)) { |
| 28 | importList.add(specifier); |
| 29 | scannedFiles.add(specifier); // don’t scan remote modules |
| 30 | } else { |
| 31 | importList.add( |
| 32 | specifier.startsWith('/') |
| 33 | ? path.join(rootDir, file) |
| 34 | : path.resolve(path.dirname(file), specifier), |
| 35 | ); |
| 36 | } |
| 37 | }); |
| 38 | |
| 39 | // 2. recursively scan imports not yet scanned |
| 40 | [...importList] |
| 41 | .filter((fileLoc) => !scannedFiles.has(fileLoc)) // prevent infinite loop |
| 42 | .forEach((fileLoc) => { |
| 43 | scanJS({file: fileLoc, rootDir, scannedFiles, importList}).forEach((newImport) => { |
| 44 | importList.add(newImport); |
| 45 | }); |
| 46 | }); |
| 47 | |
| 48 | return importList; |
| 49 | } catch (err) { |
| 50 | log(colors.yellow(` could not locate "${projectURL(file, rootDir)}"`), 'warn'); |
| 51 | return importList; |
| 52 | } |
| 53 | } |
| 54 | exports.scanJS = scanJS; |
no test coverage detected