AliasFieldPlugin.js 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
  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 '${this.field}' doesn't contain a valid alias configuration`,
  43. );
  44. }
  45. return callback();
  46. }
  47. /** @type {JsonPrimitive | undefined} */
  48. const data = Object.prototype.hasOwnProperty.call(
  49. fieldData,
  50. innerRequest,
  51. )
  52. ? /** @type {{[Key in string]: JsonPrimitive}} */ (fieldData)[
  53. innerRequest
  54. ]
  55. : innerRequest.startsWith("./")
  56. ? /** @type {{[Key in string]: JsonPrimitive}} */ (fieldData)[
  57. innerRequest.slice(2)
  58. ]
  59. : undefined;
  60. if (data === innerRequest) return callback();
  61. if (data === undefined) return callback();
  62. if (data === false) {
  63. /** @type {ResolveRequest} */
  64. const ignoreObj = {
  65. ...request,
  66. path: false,
  67. };
  68. if (typeof resolveContext.yield === "function") {
  69. resolveContext.yield(ignoreObj);
  70. return callback(null, null);
  71. }
  72. return callback(null, ignoreObj);
  73. }
  74. /** @type {ResolveRequest} */
  75. const obj = {
  76. ...request,
  77. path: /** @type {string} */ (request.descriptionFileRoot),
  78. request: /** @type {string} */ (data),
  79. fullySpecified: false,
  80. };
  81. resolver.doResolve(
  82. target,
  83. obj,
  84. `aliased from description file ${
  85. request.descriptionFilePath
  86. } with mapping '${innerRequest}' to '${/** @type {string} */ data}'`,
  87. resolveContext,
  88. (err, result) => {
  89. if (err) return callback(err);
  90. // Don't allow other aliasing or raw request
  91. if (result === undefined) return callback(null, null);
  92. callback(null, result);
  93. },
  94. );
  95. });
  96. }
  97. };