register.ts 2.5 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697
  1. import { createMatchPath } from "./match-path-sync";
  2. import { configLoader, ExplicitParams } from "./config-loader";
  3. import { options } from "./options";
  4. const noOp = (): void => void 0;
  5. function getCoreModules(
  6. builtinModules: string[] | undefined
  7. ): { [key: string]: boolean } {
  8. builtinModules = builtinModules || [
  9. "assert",
  10. "buffer",
  11. "child_process",
  12. "cluster",
  13. "crypto",
  14. "dgram",
  15. "dns",
  16. "domain",
  17. "events",
  18. "fs",
  19. "http",
  20. "https",
  21. "net",
  22. "os",
  23. "path",
  24. "punycode",
  25. "querystring",
  26. "readline",
  27. "stream",
  28. "string_decoder",
  29. "tls",
  30. "tty",
  31. "url",
  32. "util",
  33. "v8",
  34. "vm",
  35. "zlib",
  36. ];
  37. const coreModules: { [key: string]: boolean } = {};
  38. for (let module of builtinModules) {
  39. coreModules[module] = true;
  40. }
  41. return coreModules;
  42. }
  43. /**
  44. * Installs a custom module load function that can adhere to paths in tsconfig.
  45. * Returns a function to undo paths registration.
  46. */
  47. export function register(explicitParams: ExplicitParams): () => void {
  48. const configLoaderResult = configLoader({
  49. cwd: options.cwd,
  50. explicitParams,
  51. });
  52. if (configLoaderResult.resultType === "failed") {
  53. console.warn(
  54. `${configLoaderResult.message}. tsconfig-paths will be skipped`
  55. );
  56. return noOp;
  57. }
  58. const matchPath = createMatchPath(
  59. configLoaderResult.absoluteBaseUrl,
  60. configLoaderResult.paths,
  61. configLoaderResult.mainFields,
  62. configLoaderResult.addMatchAll
  63. );
  64. // Patch node's module loading
  65. // tslint:disable-next-line:no-require-imports variable-name
  66. const Module = require("module");
  67. const originalResolveFilename = Module._resolveFilename;
  68. const coreModules = getCoreModules(Module.builtinModules);
  69. // tslint:disable-next-line:no-any
  70. Module._resolveFilename = function (request: string, _parent: any): string {
  71. const isCoreModule = coreModules.hasOwnProperty(request);
  72. if (!isCoreModule) {
  73. const found = matchPath(request);
  74. if (found) {
  75. const modifiedArguments = [found, ...[].slice.call(arguments, 1)]; // Passes all arguments. Even those that is not specified above.
  76. // tslint:disable-next-line:no-invalid-this
  77. return originalResolveFilename.apply(this, modifiedArguments);
  78. }
  79. }
  80. // tslint:disable-next-line:no-invalid-this
  81. return originalResolveFilename.apply(this, arguments);
  82. };
  83. return () => {
  84. // Return node's module loading to original state.
  85. Module._resolveFilename = originalResolveFilename;
  86. };
  87. }