ContextDependencyHelpers.js 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. /*
  2. MIT License http://www.opensource.org/licenses/mit-license.php
  3. Author Tobias Koppers @sokra
  4. */
  5. "use strict";
  6. const ContextDependencyHelpers = exports;
  7. /**
  8. * Escapes regular expression metacharacters
  9. * @param {string} str String to quote
  10. * @returns {string} Escaped string
  11. */
  12. const quotemeta = str => {
  13. return str.replace(/[-[\]\\/{}()*+?.^$|]/g, "\\$&");
  14. };
  15. const splitContextFromPrefix = prefix => {
  16. const idx = prefix.lastIndexOf("/");
  17. let context = ".";
  18. if (idx >= 0) {
  19. context = prefix.substr(0, idx);
  20. prefix = `.${prefix.substr(idx)}`;
  21. }
  22. return {
  23. context,
  24. prefix
  25. };
  26. };
  27. const splitQueryFromPostfix = postfix => {
  28. const idx = postfix.indexOf("?");
  29. let query = "";
  30. if (idx >= 0) {
  31. query = postfix.substr(idx);
  32. postfix = postfix.substr(0, idx);
  33. }
  34. return {
  35. postfix,
  36. query
  37. };
  38. };
  39. ContextDependencyHelpers.create = (
  40. Dep,
  41. range,
  42. param,
  43. expr,
  44. options,
  45. contextOptions
  46. ) => {
  47. if (param.isTemplateString()) {
  48. let prefixRaw = param.quasis[0].string;
  49. let postfixRaw =
  50. param.quasis.length > 1
  51. ? param.quasis[param.quasis.length - 1].string
  52. : "";
  53. const prefixRange = [param.quasis[0].range[0], param.quasis[0].range[1]];
  54. const postfixRange =
  55. param.quasis.length > 1
  56. ? param.quasis[param.quasis.length - 1].range
  57. : "";
  58. const valueRange = param.range;
  59. const { context, prefix } = splitContextFromPrefix(prefixRaw);
  60. const { postfix, query } = splitQueryFromPostfix(postfixRaw);
  61. // If there are more than two quasis, maybe the generated RegExp can be more precise?
  62. const regExp = new RegExp(
  63. `^${quotemeta(prefix)}${options.wrappedContextRegExp.source}${quotemeta(
  64. postfix
  65. )}$`
  66. );
  67. const dep = new Dep(
  68. Object.assign(
  69. {
  70. request: context + query,
  71. recursive: options.wrappedContextRecursive,
  72. regExp,
  73. mode: "sync"
  74. },
  75. contextOptions
  76. ),
  77. range,
  78. valueRange
  79. );
  80. dep.loc = expr.loc;
  81. const replaces = [];
  82. if (prefixRange && prefix !== prefixRaw) {
  83. replaces.push({
  84. range: prefixRange,
  85. value: prefix
  86. });
  87. }
  88. if (postfixRange && postfix !== postfixRaw) {
  89. replaces.push({
  90. range: postfixRange,
  91. value: postfix
  92. });
  93. }
  94. dep.replaces = replaces;
  95. dep.critical =
  96. options.wrappedContextCritical &&
  97. "a part of the request of a dependency is an expression";
  98. return dep;
  99. } else if (
  100. param.isWrapped() &&
  101. ((param.prefix && param.prefix.isString()) ||
  102. (param.postfix && param.postfix.isString()))
  103. ) {
  104. let prefixRaw =
  105. param.prefix && param.prefix.isString() ? param.prefix.string : "";
  106. let postfixRaw =
  107. param.postfix && param.postfix.isString() ? param.postfix.string : "";
  108. const prefixRange =
  109. param.prefix && param.prefix.isString() ? param.prefix.range : null;
  110. const postfixRange =
  111. param.postfix && param.postfix.isString() ? param.postfix.range : null;
  112. const valueRange = param.range;
  113. const { context, prefix } = splitContextFromPrefix(prefixRaw);
  114. const { postfix, query } = splitQueryFromPostfix(postfixRaw);
  115. const regExp = new RegExp(
  116. `^${quotemeta(prefix)}${options.wrappedContextRegExp.source}${quotemeta(
  117. postfix
  118. )}$`
  119. );
  120. const dep = new Dep(
  121. Object.assign(
  122. {
  123. request: context + query,
  124. recursive: options.wrappedContextRecursive,
  125. regExp,
  126. mode: "sync"
  127. },
  128. contextOptions
  129. ),
  130. range,
  131. valueRange
  132. );
  133. dep.loc = expr.loc;
  134. const replaces = [];
  135. if (prefixRange && prefix !== prefixRaw) {
  136. replaces.push({
  137. range: prefixRange,
  138. value: JSON.stringify(prefix)
  139. });
  140. }
  141. if (postfixRange && postfix !== postfixRaw) {
  142. replaces.push({
  143. range: postfixRange,
  144. value: JSON.stringify(postfix)
  145. });
  146. }
  147. dep.replaces = replaces;
  148. dep.critical =
  149. options.wrappedContextCritical &&
  150. "a part of the request of a dependency is an expression";
  151. return dep;
  152. } else {
  153. const dep = new Dep(
  154. Object.assign(
  155. {
  156. request: options.exprContextRequest,
  157. recursive: options.exprContextRecursive,
  158. regExp: options.exprContextRegExp,
  159. mode: "sync"
  160. },
  161. contextOptions
  162. ),
  163. range,
  164. param.range
  165. );
  166. dep.loc = expr.loc;
  167. dep.critical =
  168. options.exprContextCritical &&
  169. "the request of a dependency is an expression";
  170. return dep;
  171. }
  172. };