update-imports.mjs 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131
  1. #!/usr/bin/env node
  2. import fs from 'fs';
  3. import path from 'path';
  4. import process from 'process';
  5. // Adjust the base directory to match your project layout:
  6. const SRC_DIR = path.join(process.cwd(), 'test');
  7. /**
  8. * Recursively gather all .mjs files in the given directory
  9. */
  10. function getAllMjsFiles(dir) {
  11. let results = [];
  12. const list = fs.readdirSync(dir, { withFileTypes: true });
  13. for (const dirent of list) {
  14. const fullPath = path.join(dir, dirent.name);
  15. if (dirent.isDirectory()) {
  16. // Recurse into subdirectories
  17. results = results.concat(getAllMjsFiles(fullPath));
  18. } else if (dirent.isFile() && fullPath.endsWith('.mjs')) {
  19. results.push(fullPath);
  20. }
  21. }
  22. return results;
  23. }
  24. /**
  25. * Given an import path like '../../util', figure out if we should rewrite
  26. * to '../../util.mjs' or '../../util/index.mjs', based on what is present in the file system.
  27. */
  28. function resolveImport(rawImportPath, currentFileDir) {
  29. // We only care about relative imports
  30. if (!rawImportPath.startsWith('.')) {
  31. // If it's not relative, leave it alone (e.g. 'react' or 'lodash')
  32. return rawImportPath;
  33. }
  34. // The path on disk relative to the current file
  35. const absoluteImportPath = path.resolve(currentFileDir, rawImportPath);
  36. // 1. Check if `absoluteImportPath.mjs` exists
  37. const candidateMjsFile = `${absoluteImportPath}.mjs`;
  38. if (fs.existsSync(candidateMjsFile)) {
  39. // Convert back to a relative path from the current file
  40. return pathRelativeWinSafe(currentFileDir, candidateMjsFile);
  41. }
  42. // 2. Check if `absoluteImportPath/index.mjs` exists
  43. const candidateIndexFile = path.join(absoluteImportPath, 'index.mjs');
  44. if (fs.existsSync(candidateIndexFile)) {
  45. return pathRelativeWinSafe(currentFileDir, candidateIndexFile);
  46. }
  47. // If neither .mjs nor index.mjs exist, leave it unchanged (or optionally throw an error)
  48. return rawImportPath;
  49. }
  50. /**
  51. * Convert absolute path back to a relative path (with forward slashes on all platforms).
  52. * Because Node on Windows returns backslashes, which ESM imports won't like.
  53. */
  54. function pathRelativeWinSafe(from, to) {
  55. let relPath = path.relative(from, to);
  56. // Replace backslashes with forward slashes
  57. relPath = relPath.replace(/\\/g, '/');
  58. // Ensure it starts with '.' or '..' if it isn’t already
  59. if (!relPath.startsWith('.')) {
  60. relPath = `./${relPath}`;
  61. }
  62. return relPath;
  63. }
  64. /**
  65. * Perform the in-place rewrites for import statements in a single file.
  66. */
  67. function rewriteImportsInFile(filePath) {
  68. const fileDir = path.dirname(filePath);
  69. let src = fs.readFileSync(filePath, 'utf8');
  70. // Simple pattern capturing import statements of the form:
  71. // import ... from '...';
  72. // This will NOT catch every possible ESM shape (e.g., multiline). Adapt as needed.
  73. const importRegex = /(\bimport\s+(?:[\s\S]+?)\s+from\s+['"])([^'"]+)(['"];)/g;
  74. let changed = false;
  75. src = src.replace(importRegex, (match, before, importPath, after) => {
  76. const newImportPath = resolveImport(importPath, fileDir);
  77. if (newImportPath !== importPath) {
  78. changed = true;
  79. return `${before}${newImportPath}${after}`;
  80. }
  81. return match;
  82. });
  83. // Optionally, handle require() if needed:
  84. // const requireRegex = /(\brequire\s*\(\s*['"])([^'"]+)(['"]\s*\))/g;
  85. // src = src.replace(requireRegex, (match, before, importPath, after) => {
  86. // const newImportPath = resolveImport(importPath, fileDir);
  87. // if (newImportPath !== importPath) {
  88. // changed = true;
  89. // return `${before}${newImportPath}${after}`;
  90. // }
  91. // return match;
  92. // });
  93. if (changed) {
  94. fs.writeFileSync(filePath, src, 'utf8');
  95. console.log(`Updated imports in: ${filePath}`);
  96. }
  97. }
  98. /**
  99. * Main routine:
  100. * 1. Collect all .mjs files in src/
  101. * 2. Rewrite their import statements
  102. */
  103. function main() {
  104. const allMjsFiles = getAllMjsFiles(SRC_DIR);
  105. console.log(`Found ${allMjsFiles.length} .mjs files in ${SRC_DIR}.`);
  106. for (const filePath of allMjsFiles) {
  107. rewriteImportsInFile(filePath);
  108. }
  109. console.log('Done.');
  110. }
  111. main();