AliasFieldPlugin.js 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105
  1. /*
  2. MIT License http://www.opensource.org/licenses/mit-license.php
  3. Author Tobias Koppers @sokra
  4. */
  5. "use strict";
  6. const DescriptionFileUtils = require("./DescriptionFileUtils");
  7. const getInnerRequest = require("./getInnerRequest");
  8. /** @typedef {import("./Resolver")} Resolver */
  9. /** @typedef {import("./Resolver").JsonPrimitive} JsonPrimitive */
  10. /** @typedef {import("./Resolver").ResolveRequest} ResolveRequest */
  11. /** @typedef {import("./Resolver").ResolveStepHook} ResolveStepHook */
  12. module.exports = class AliasFieldPlugin {
  13. /**
  14. * @param {string | ResolveStepHook} source source
  15. * @param {string | Array<string>} field field
  16. * @param {string | ResolveStepHook} target target
  17. */
  18. constructor(source, field, target) {
  19. this.source = source;
  20. this.field = field;
  21. this.target = target;
  22. }
  23. /**
  24. * @param {Resolver} resolver the resolver
  25. * @returns {void}
  26. */
  27. apply(resolver) {
  28. const target = resolver.ensureHook(this.target);
  29. resolver
  30. .getHook(this.source)
  31. .tapAsync("AliasFieldPlugin", (request, resolveContext, callback) => {
  32. if (!request.descriptionFileData) return callback();
  33. const innerRequest = getInnerRequest(resolver, request);
  34. if (!innerRequest) return callback();
  35. const fieldData = DescriptionFileUtils.getField(
  36. request.descriptionFileData,
  37. this.field,
  38. );
  39. if (fieldData === null || typeof fieldData !== "object") {
  40. if (resolveContext.log) {
  41. resolveContext.log(
  42. `Field '${
  43. this.field
  44. }' doesn't contain a valid alias configuration`,
  45. );
  46. }
  47. return callback();
  48. }
  49. /** @type {JsonPrimitive | undefined} */
  50. const data = Object.prototype.hasOwnProperty.call(
  51. fieldData,
  52. innerRequest,
  53. )
  54. ? /** @type {{[Key in string]: JsonPrimitive}} */ (fieldData)[
  55. innerRequest
  56. ]
  57. : innerRequest.startsWith("./")
  58. ? /** @type {{[Key in string]: JsonPrimitive}} */ (fieldData)[
  59. innerRequest.slice(2)
  60. ]
  61. : undefined;
  62. if (data === innerRequest) return callback();
  63. if (data === undefined) return callback();
  64. if (data === false) {
  65. /** @type {ResolveRequest} */
  66. const ignoreObj = {
  67. ...request,
  68. path: false,
  69. };
  70. if (typeof resolveContext.yield === "function") {
  71. resolveContext.yield(ignoreObj);
  72. return callback(null, null);
  73. }
  74. return callback(null, ignoreObj);
  75. }
  76. /** @type {ResolveRequest} */
  77. const obj = {
  78. ...request,
  79. path: /** @type {string} */ (request.descriptionFileRoot),
  80. request: /** @type {string} */ (data),
  81. fullySpecified: false,
  82. };
  83. resolver.doResolve(
  84. target,
  85. obj,
  86. `aliased from description file ${
  87. request.descriptionFilePath
  88. } with mapping '${innerRequest}' to '${/** @type {string} */ data}'`,
  89. resolveContext,
  90. (err, result) => {
  91. if (err) return callback(err);
  92. // Don't allow other aliasing or raw request
  93. if (result === undefined) return callback(null, null);
  94. callback(null, result);
  95. },
  96. );
  97. });
  98. }
  99. };