MainFieldPlugin.js 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990
  1. /*
  2. MIT License http://www.opensource.org/licenses/mit-license.php
  3. Author Tobias Koppers @sokra
  4. */
  5. "use strict";
  6. const path = require("path");
  7. const DescriptionFileUtils = require("./DescriptionFileUtils");
  8. /** @typedef {import("./Resolver")} Resolver */
  9. /** @typedef {import("./Resolver").JsonObject} JsonObject */
  10. /** @typedef {import("./Resolver").ResolveRequest} ResolveRequest */
  11. /** @typedef {import("./Resolver").ResolveStepHook} ResolveStepHook */
  12. /** @typedef {{name: string|Array<string>, forceRelative: boolean}} MainFieldOptions */
  13. const alreadyTriedMainField = Symbol("alreadyTriedMainField");
  14. module.exports = class MainFieldPlugin {
  15. /**
  16. * @param {string | ResolveStepHook} source source
  17. * @param {MainFieldOptions} options options
  18. * @param {string | ResolveStepHook} target target
  19. */
  20. constructor(source, options, target) {
  21. this.source = source;
  22. this.options = options;
  23. this.target = target;
  24. }
  25. /**
  26. * @param {Resolver} resolver the resolver
  27. * @returns {void}
  28. */
  29. apply(resolver) {
  30. const target = resolver.ensureHook(this.target);
  31. resolver
  32. .getHook(this.source)
  33. .tapAsync("MainFieldPlugin", (request, resolveContext, callback) => {
  34. if (
  35. request.path !== request.descriptionFileRoot ||
  36. /** @type {ResolveRequest & { [alreadyTriedMainField]?: string }} */
  37. (request)[alreadyTriedMainField] === request.descriptionFilePath ||
  38. !request.descriptionFilePath
  39. )
  40. return callback();
  41. const filename = path.basename(request.descriptionFilePath);
  42. let mainModule =
  43. /** @type {string|null|undefined} */
  44. (
  45. DescriptionFileUtils.getField(
  46. /** @type {JsonObject} */ (request.descriptionFileData),
  47. this.options.name
  48. )
  49. );
  50. if (
  51. !mainModule ||
  52. typeof mainModule !== "string" ||
  53. mainModule === "." ||
  54. mainModule === "./"
  55. ) {
  56. return callback();
  57. }
  58. if (this.options.forceRelative && !/^\.\.?\//.test(mainModule))
  59. mainModule = "./" + mainModule;
  60. /** @type {ResolveRequest & { [alreadyTriedMainField]?: string }} */
  61. const obj = {
  62. ...request,
  63. request: mainModule,
  64. module: false,
  65. directory: mainModule.endsWith("/"),
  66. [alreadyTriedMainField]: request.descriptionFilePath
  67. };
  68. return resolver.doResolve(
  69. target,
  70. obj,
  71. "use " +
  72. mainModule +
  73. " from " +
  74. this.options.name +
  75. " in " +
  76. filename,
  77. resolveContext,
  78. callback
  79. );
  80. });
  81. }
  82. };