Advertisement
Guest User

Untitled

a guest
Dec 9th, 2016
57
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 4.62 KB | None | 0 0
  1. /**
  2. * This codemod expects 2 CLI arguments:
  3. * - packageDir: the path of the directory containing the package.json. It's used to detect whether a path points
  4. * to a dependency or an internal module.
  5. * - rootDirs: root directory paths separated by a comma if you have more than one root.
  6. * Let's say that you have two files:
  7. * - src/component.js
  8. * - src/index.js containing the import "import Component from 'component.js';"
  9. * To have the transformation successfully working you need to call jscodeshift with the "--rootDirs ./src" argument.
  10. */
  11.  
  12. const {existsSync} = require('fs');
  13. const {_builtinLibs} = require('repl'); // List of Node.js built in modules.
  14. const path = require('path');
  15.  
  16. const makeIsDependency = packageDir => {
  17. const {dependencies, devDependencies, peerDependencies} = require(path.resolve(packageDir, 'package.json'));
  18. const allDependencies = [..._builtinLibs, ...Object.keys(dependencies), ...Object.keys(devDependencies), ...Object.keys(peerDependencies)];
  19. return importedModulePath => allDependencies.some(name => (importedModulePath === name || importedModulePath.startsWith(`${name}/`)));
  20. };
  21.  
  22. const isRelative = importedModulePath => importedModulePath.startsWith('./') || importedModulePath.startsWith('../');
  23.  
  24. const makeGetDiskPathFromImportPath = rootDirs => {
  25. const importPathToDiskPath = {};
  26. return importedModulePath => {
  27. let diskPath = importPathToDiskPath[importedModulePath];
  28. if (diskPath) {
  29. return diskPath;
  30. }
  31. const importedModuleRoot = rootDirs.find(root => existsSync(path.join(root, importedModulePath)));
  32. if (importedModuleRoot) {
  33. diskPath = path.join(importedModuleRoot, importedModulePath);
  34. importPathToDiskPath[importedModulePath] = diskPath;
  35. return diskPath;
  36. }
  37. throw new Error(`Cannot find root for imported module ${importedModulePath}`);
  38. };
  39. };
  40.  
  41. const makeChangePathToRelativeIfNeeded = (currentModuleDirectoryPath, isDependency, rootDirs) => {
  42. const getDiskPathFromImportPath = makeGetDiskPathFromImportPath(rootDirs);
  43. return importedModulePath => {
  44. if (isRelative(importedModulePath) || isDependency(importedModulePath)) {
  45. return importedModulePath;
  46. }
  47.  
  48. const diskPath = getDiskPathFromImportPath(importedModulePath);
  49. const relativePath = path.relative(currentModuleDirectoryPath, diskPath).replace(/\\/g, '/');
  50. return relativePath.startsWith('../') ? relativePath : `./${relativePath}`;
  51. };
  52. };
  53.  
  54. const sortImportsAlphabetically = imports => {
  55. imports.sort((a, b) => a.path.localeCompare(b.path));
  56. };
  57.  
  58. const sortImportDeclarations = (importDeclarations, changePathToRelativeIfNeeded) => {
  59. let lastEndOfImportLine = undefined;
  60. const importGroups = [];
  61. importDeclarations.forEach(path => {
  62. const node = path.value;
  63.  
  64. const isFirstImport = lastEndOfImportLine === undefined;
  65. const isNewImportBlock = !isFirstImport && lastEndOfImportLine < (node.loc.start.line - 1);
  66. if (isFirstImport || isNewImportBlock) {
  67. importGroups.push([]);
  68. }
  69. lastEndOfImportLine = node.loc.end.line;
  70.  
  71. const currentImportPath = node.source.value;
  72. const newImportPath = changePathToRelativeIfNeeded(currentImportPath);
  73.  
  74. importGroups[importGroups.length - 1].push({
  75. path: newImportPath,
  76. specifiers: node.specifiers
  77. });
  78. });
  79. importGroups.forEach(sortImportsAlphabetically);
  80. const flattenedImports = [].concat.apply([], importGroups);
  81. return flattenedImports;
  82. };
  83.  
  84. const replaceBySortedImportDeclarations = (j, importDeclarations, sortedImportDeclarations) => {
  85. return importDeclarations
  86. .forEach((path, index) => {
  87. const newImport = sortedImportDeclarations[index];
  88. j(path).replaceWith(
  89. j.importDeclaration(newImport.specifiers, j.literal(newImport.path))
  90. );
  91. });
  92. };
  93.  
  94. module.exports = (fileInfo, api, options) => {
  95. const currentModuleDirectoryPath = path.dirname(path.resolve(fileInfo.path));
  96. const isDependency = makeIsDependency(options.packageDir);
  97. const rootDirs = options.rootDirs.split(',').map(rootPath => path.resolve(rootPath));
  98. const changePathToRelativeIfNeeded = makeChangePathToRelativeIfNeeded(currentModuleDirectoryPath, isDependency, rootDirs);
  99.  
  100. const j = api.jscodeshift;
  101. const root = j(fileInfo.source);
  102. const {comments} = root.find(j.Program).get('body', 0).node;
  103.  
  104. const importDeclarations = root.find(j.ImportDeclaration);
  105. const sortedImportDeclarations = sortImportDeclarations(importDeclarations, changePathToRelativeIfNeeded);
  106. replaceBySortedImportDeclarations(j, importDeclarations, sortedImportDeclarations);
  107.  
  108. root.get().node.comments = comments;
  109. return root.toSource({
  110. objectCurlySpacing: false,
  111. quote: 'single'
  112. });
  113. };
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement