ParsePlugin.js 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384
  1. /*
  2. MIT License http://www.opensource.org/licenses/mit-license.php
  3. Author Tobias Koppers @sokra
  4. */
  5. "use strict";
  6. /** @typedef {import("./Resolver")} Resolver */
  7. /** @typedef {import("./Resolver").ResolveRequest} ResolveRequest */
  8. /** @typedef {import("./Resolver").ResolveStepHook} ResolveStepHook */
  9. module.exports = class ParsePlugin {
  10. /**
  11. * @param {string | ResolveStepHook} source source
  12. * @param {Partial<ResolveRequest>} requestOptions request options
  13. * @param {string | ResolveStepHook} target target
  14. */
  15. constructor(source, requestOptions, target) {
  16. this.source = source;
  17. this.requestOptions = requestOptions;
  18. this.target = target;
  19. }
  20. /**
  21. * @param {Resolver} resolver the resolver
  22. * @returns {void}
  23. */
  24. apply(resolver) {
  25. const target = resolver.ensureHook(this.target);
  26. const { requestOptions } = this;
  27. resolver
  28. .getHook(this.source)
  29. .tapAsync("ParsePlugin", (request, resolveContext, callback) => {
  30. const parsed = resolver.parse(/** @type {string} */ (request.request));
  31. /** @type {ResolveRequest} */
  32. // Single spread + direct field assignment instead of
  33. // `{ ...request, ...parsed, ...requestOptions }` — avoids
  34. // two extra property enumerations on every resolve.
  35. // Keep in sync with Resolver.parse() output shape.
  36. const obj = { ...request };
  37. obj.request = parsed.request;
  38. obj.query = parsed.query || request.query || "";
  39. obj.fragment = parsed.fragment || request.fragment || "";
  40. obj.module = parsed.module;
  41. obj.directory = parsed.directory;
  42. obj.file = parsed.file;
  43. obj.internal = parsed.internal;
  44. Object.assign(obj, requestOptions);
  45. if (parsed && resolveContext.log) {
  46. if (parsed.module) resolveContext.log("Parsed request is a module");
  47. if (parsed.directory) {
  48. resolveContext.log("Parsed request is a directory");
  49. }
  50. }
  51. // There is an edge-case where a request with # can be a path or a fragment -> try both
  52. if (obj.request && !obj.query && obj.fragment) {
  53. const directory = obj.fragment.endsWith("/");
  54. /** @type {ResolveRequest} */
  55. const alternative = {
  56. ...obj,
  57. directory,
  58. request:
  59. obj.request +
  60. (obj.directory ? "/" : "") +
  61. (directory ? obj.fragment.slice(0, -1) : obj.fragment),
  62. fragment: "",
  63. };
  64. resolver.doResolve(
  65. target,
  66. alternative,
  67. null,
  68. resolveContext,
  69. (err, result) => {
  70. if (err) return callback(err);
  71. if (result) return callback(null, result);
  72. resolver.doResolve(target, obj, null, resolveContext, callback);
  73. },
  74. );
  75. return;
  76. }
  77. resolver.doResolve(target, obj, null, resolveContext, callback);
  78. });
  79. }
  80. };