cytoscape
Version:
Graph theory (a.k.a. network) library for analysis and visualisation
131 lines (111 loc) • 4.07 kB
JavaScript
import fs from 'fs';
import path from 'path';
import process from 'process';
// Adjust the base directory to match your project layout:
const SRC_DIR = path.join(process.cwd(), 'test');
/**
* Recursively gather all .mjs files in the given directory
*/
function getAllMjsFiles(dir) {
let results = [];
const list = fs.readdirSync(dir, { withFileTypes: true });
for (const dirent of list) {
const fullPath = path.join(dir, dirent.name);
if (dirent.isDirectory()) {
// Recurse into subdirectories
results = results.concat(getAllMjsFiles(fullPath));
} else if (dirent.isFile() && fullPath.endsWith('.mjs')) {
results.push(fullPath);
}
}
return results;
}
/**
* Given an import path like '../../util', figure out if we should rewrite
* to '../../util.mjs' or '../../util/index.mjs', based on what is present in the file system.
*/
function resolveImport(rawImportPath, currentFileDir) {
// We only care about relative imports
if (!rawImportPath.startsWith('.')) {
// If it's not relative, leave it alone (e.g. 'react' or 'lodash')
return rawImportPath;
}
// The path on disk relative to the current file
const absoluteImportPath = path.resolve(currentFileDir, rawImportPath);
// 1. Check if `absoluteImportPath.mjs` exists
const candidateMjsFile = `${absoluteImportPath}.mjs`;
if (fs.existsSync(candidateMjsFile)) {
// Convert back to a relative path from the current file
return pathRelativeWinSafe(currentFileDir, candidateMjsFile);
}
// 2. Check if `absoluteImportPath/index.mjs` exists
const candidateIndexFile = path.join(absoluteImportPath, 'index.mjs');
if (fs.existsSync(candidateIndexFile)) {
return pathRelativeWinSafe(currentFileDir, candidateIndexFile);
}
// If neither .mjs nor index.mjs exist, leave it unchanged (or optionally throw an error)
return rawImportPath;
}
/**
* Convert absolute path back to a relative path (with forward slashes on all platforms).
* Because Node on Windows returns backslashes, which ESM imports won't like.
*/
function pathRelativeWinSafe(from, to) {
let relPath = path.relative(from, to);
// Replace backslashes with forward slashes
relPath = relPath.replace(/\\/g, '/');
// Ensure it starts with '.' or '..' if it isn’t already
if (!relPath.startsWith('.')) {
relPath = `./${relPath}`;
}
return relPath;
}
/**
* Perform the in-place rewrites for import statements in a single file.
*/
function rewriteImportsInFile(filePath) {
const fileDir = path.dirname(filePath);
let src = fs.readFileSync(filePath, 'utf8');
// Simple pattern capturing import statements of the form:
// import ... from '...';
// This will NOT catch every possible ESM shape (e.g., multiline). Adapt as needed.
const importRegex = /(\bimport\s+(?:[\s\S]+?)\s+from\s+['"])([^'"]+)(['"];)/g;
let changed = false;
src = src.replace(importRegex, (match, before, importPath, after) => {
const newImportPath = resolveImport(importPath, fileDir);
if (newImportPath !== importPath) {
changed = true;
return `${before}${newImportPath}${after}`;
}
return match;
});
// Optionally, handle require() if needed:
// const requireRegex = /(\brequire\s*\(\s*['"])([^'"]+)(['"]\s*\))/g;
// src = src.replace(requireRegex, (match, before, importPath, after) => {
// const newImportPath = resolveImport(importPath, fileDir);
// if (newImportPath !== importPath) {
// changed = true;
// return `${before}${newImportPath}${after}`;
// }
// return match;
// });
if (changed) {
fs.writeFileSync(filePath, src, 'utf8');
console.log(`Updated imports in: ${filePath}`);
}
}
/**
* Main routine:
* 1. Collect all .mjs files in src/
* 2. Rewrite their import statements
*/
function main() {
const allMjsFiles = getAllMjsFiles(SRC_DIR);
console.log(`Found ${allMjsFiles.length} .mjs files in ${SRC_DIR}.`);
for (const filePath of allMjsFiles) {
rewriteImportsInFile(filePath);
}
console.log('Done.');
}
main();