AMDRequireDependenciesBlockParserPlugin.js 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272
  1. /*
  2. MIT License http://www.opensource.org/licenses/mit-license.php
  3. Author Tobias Koppers @sokra
  4. */
  5. "use strict";
  6. const AMDRequireItemDependency = require("./AMDRequireItemDependency");
  7. const AMDRequireArrayDependency = require("./AMDRequireArrayDependency");
  8. const AMDRequireContextDependency = require("./AMDRequireContextDependency");
  9. const AMDRequireDependenciesBlock = require("./AMDRequireDependenciesBlock");
  10. const UnsupportedDependency = require("./UnsupportedDependency");
  11. const LocalModuleDependency = require("./LocalModuleDependency");
  12. const ContextDependencyHelpers = require("./ContextDependencyHelpers");
  13. const LocalModulesHelpers = require("./LocalModulesHelpers");
  14. const ConstDependency = require("./ConstDependency");
  15. const getFunctionExpression = require("./getFunctionExpression");
  16. const UnsupportedFeatureWarning = require("../UnsupportedFeatureWarning");
  17. class AMDRequireDependenciesBlockParserPlugin {
  18. constructor(options) {
  19. this.options = options;
  20. }
  21. processFunctionArgument(parser, expression) {
  22. let bindThis = true;
  23. const fnData = getFunctionExpression(expression);
  24. if (fnData) {
  25. parser.inScope(
  26. fnData.fn.params.filter(i => {
  27. return !["require", "module", "exports"].includes(i.name);
  28. }),
  29. () => {
  30. if (fnData.fn.body.type === "BlockStatement") {
  31. parser.walkStatement(fnData.fn.body);
  32. } else {
  33. parser.walkExpression(fnData.fn.body);
  34. }
  35. }
  36. );
  37. parser.walkExpressions(fnData.expressions);
  38. if (fnData.needThis === false) {
  39. bindThis = false;
  40. }
  41. } else {
  42. parser.walkExpression(expression);
  43. }
  44. return bindThis;
  45. }
  46. apply(parser) {
  47. parser.hooks.call
  48. .for("require")
  49. .tap(
  50. "AMDRequireDependenciesBlockParserPlugin",
  51. this.processCallRequire.bind(this, parser)
  52. );
  53. }
  54. processArray(parser, expr, param) {
  55. if (param.isArray()) {
  56. for (const p of param.items) {
  57. const result = this.processItem(parser, expr, p);
  58. if (result === undefined) {
  59. this.processContext(parser, expr, p);
  60. }
  61. }
  62. return true;
  63. } else if (param.isConstArray()) {
  64. const deps = [];
  65. for (const request of param.array) {
  66. let dep, localModule;
  67. if (request === "require") {
  68. dep = "__webpack_require__";
  69. } else if (["exports", "module"].includes(request)) {
  70. dep = request;
  71. } else if (
  72. (localModule = LocalModulesHelpers.getLocalModule(
  73. parser.state,
  74. request
  75. ))
  76. ) {
  77. dep = new LocalModuleDependency(localModule, undefined, false);
  78. dep.loc = expr.loc;
  79. parser.state.current.addDependency(dep);
  80. } else {
  81. dep = this.newRequireItemDependency(request);
  82. dep.loc = expr.loc;
  83. dep.optional = !!parser.scope.inTry;
  84. parser.state.current.addDependency(dep);
  85. }
  86. deps.push(dep);
  87. }
  88. const dep = this.newRequireArrayDependency(deps, param.range);
  89. dep.loc = expr.loc;
  90. dep.optional = !!parser.scope.inTry;
  91. parser.state.current.addDependency(dep);
  92. return true;
  93. }
  94. }
  95. processItem(parser, expr, param) {
  96. if (param.isConditional()) {
  97. for (const p of param.options) {
  98. const result = this.processItem(parser, expr, p);
  99. if (result === undefined) {
  100. this.processContext(parser, expr, p);
  101. }
  102. }
  103. return true;
  104. } else if (param.isString()) {
  105. let dep, localModule;
  106. if (param.string === "require") {
  107. dep = new ConstDependency("__webpack_require__", param.string);
  108. } else if (param.string === "module") {
  109. dep = new ConstDependency(
  110. parser.state.module.buildInfo.moduleArgument,
  111. param.range
  112. );
  113. } else if (param.string === "exports") {
  114. dep = new ConstDependency(
  115. parser.state.module.buildInfo.exportsArgument,
  116. param.range
  117. );
  118. } else if (
  119. (localModule = LocalModulesHelpers.getLocalModule(
  120. parser.state,
  121. param.string
  122. ))
  123. ) {
  124. dep = new LocalModuleDependency(localModule, param.range, false);
  125. } else {
  126. dep = this.newRequireItemDependency(param.string, param.range);
  127. }
  128. dep.loc = expr.loc;
  129. dep.optional = !!parser.scope.inTry;
  130. parser.state.current.addDependency(dep);
  131. return true;
  132. }
  133. }
  134. processContext(parser, expr, param) {
  135. const dep = ContextDependencyHelpers.create(
  136. AMDRequireContextDependency,
  137. param.range,
  138. param,
  139. expr,
  140. this.options
  141. );
  142. if (!dep) return;
  143. dep.loc = expr.loc;
  144. dep.optional = !!parser.scope.inTry;
  145. parser.state.current.addDependency(dep);
  146. return true;
  147. }
  148. processArrayForRequestString(param) {
  149. if (param.isArray()) {
  150. const result = param.items.map(item =>
  151. this.processItemForRequestString(item)
  152. );
  153. if (result.every(Boolean)) return result.join(" ");
  154. } else if (param.isConstArray()) {
  155. return param.array.join(" ");
  156. }
  157. }
  158. processItemForRequestString(param) {
  159. if (param.isConditional()) {
  160. const result = param.options.map(item =>
  161. this.processItemForRequestString(item)
  162. );
  163. if (result.every(Boolean)) return result.join("|");
  164. } else if (param.isString()) {
  165. return param.string;
  166. }
  167. }
  168. processCallRequire(parser, expr) {
  169. let param;
  170. let dep;
  171. let result;
  172. const old = parser.state.current;
  173. if (expr.arguments.length >= 1) {
  174. param = parser.evaluateExpression(expr.arguments[0]);
  175. dep = this.newRequireDependenciesBlock(
  176. expr,
  177. param.range,
  178. expr.arguments.length > 1 ? expr.arguments[1].range : null,
  179. expr.arguments.length > 2 ? expr.arguments[2].range : null,
  180. parser.state.module,
  181. expr.loc,
  182. this.processArrayForRequestString(param)
  183. );
  184. parser.state.current = dep;
  185. }
  186. if (expr.arguments.length === 1) {
  187. parser.inScope([], () => {
  188. result = this.processArray(parser, expr, param);
  189. });
  190. parser.state.current = old;
  191. if (!result) return;
  192. parser.state.current.addBlock(dep);
  193. return true;
  194. }
  195. if (expr.arguments.length === 2 || expr.arguments.length === 3) {
  196. try {
  197. parser.inScope([], () => {
  198. result = this.processArray(parser, expr, param);
  199. });
  200. if (!result) {
  201. dep = new UnsupportedDependency("unsupported", expr.range);
  202. old.addDependency(dep);
  203. if (parser.state.module) {
  204. parser.state.module.errors.push(
  205. new UnsupportedFeatureWarning(
  206. parser.state.module,
  207. "Cannot statically analyse 'require(…, …)' in line " +
  208. expr.loc.start.line,
  209. expr.loc
  210. )
  211. );
  212. }
  213. dep = null;
  214. return true;
  215. }
  216. dep.functionBindThis = this.processFunctionArgument(
  217. parser,
  218. expr.arguments[1]
  219. );
  220. if (expr.arguments.length === 3) {
  221. dep.errorCallbackBindThis = this.processFunctionArgument(
  222. parser,
  223. expr.arguments[2]
  224. );
  225. }
  226. } finally {
  227. parser.state.current = old;
  228. if (dep) parser.state.current.addBlock(dep);
  229. }
  230. return true;
  231. }
  232. }
  233. newRequireDependenciesBlock(
  234. expr,
  235. arrayRange,
  236. functionRange,
  237. errorCallbackRange,
  238. module,
  239. loc,
  240. request
  241. ) {
  242. return new AMDRequireDependenciesBlock(
  243. expr,
  244. arrayRange,
  245. functionRange,
  246. errorCallbackRange,
  247. module,
  248. loc,
  249. request
  250. );
  251. }
  252. newRequireItemDependency(request, range) {
  253. return new AMDRequireItemDependency(request, range);
  254. }
  255. newRequireArrayDependency(depsArray, range) {
  256. return new AMDRequireArrayDependency(depsArray, range);
  257. }
  258. }
  259. module.exports = AMDRequireDependenciesBlockParserPlugin;