You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

274 lines
7.1 KiB

4 years ago
  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. parser
  143. );
  144. if (!dep) return;
  145. dep.loc = expr.loc;
  146. dep.optional = !!parser.scope.inTry;
  147. parser.state.current.addDependency(dep);
  148. return true;
  149. }
  150. processArrayForRequestString(param) {
  151. if (param.isArray()) {
  152. const result = param.items.map(item =>
  153. this.processItemForRequestString(item)
  154. );
  155. if (result.every(Boolean)) return result.join(" ");
  156. } else if (param.isConstArray()) {
  157. return param.array.join(" ");
  158. }
  159. }
  160. processItemForRequestString(param) {
  161. if (param.isConditional()) {
  162. const result = param.options.map(item =>
  163. this.processItemForRequestString(item)
  164. );
  165. if (result.every(Boolean)) return result.join("|");
  166. } else if (param.isString()) {
  167. return param.string;
  168. }
  169. }
  170. processCallRequire(parser, expr) {
  171. let param;
  172. let dep;
  173. let result;
  174. const old = parser.state.current;
  175. if (expr.arguments.length >= 1) {
  176. param = parser.evaluateExpression(expr.arguments[0]);
  177. dep = this.newRequireDependenciesBlock(
  178. expr,
  179. param.range,
  180. expr.arguments.length > 1 ? expr.arguments[1].range : null,
  181. expr.arguments.length > 2 ? expr.arguments[2].range : null,
  182. parser.state.module,
  183. expr.loc,
  184. this.processArrayForRequestString(param)
  185. );
  186. parser.state.current = dep;
  187. }
  188. if (expr.arguments.length === 1) {
  189. parser.inScope([], () => {
  190. result = this.processArray(parser, expr, param);
  191. });
  192. parser.state.current = old;
  193. if (!result) return;
  194. parser.state.current.addBlock(dep);
  195. return true;
  196. }
  197. if (expr.arguments.length === 2 || expr.arguments.length === 3) {
  198. try {
  199. parser.inScope([], () => {
  200. result = this.processArray(parser, expr, param);
  201. });
  202. if (!result) {
  203. dep = new UnsupportedDependency("unsupported", expr.range);
  204. old.addDependency(dep);
  205. if (parser.state.module) {
  206. parser.state.module.errors.push(
  207. new UnsupportedFeatureWarning(
  208. parser.state.module,
  209. "Cannot statically analyse 'require(…, …)' in line " +
  210. expr.loc.start.line,
  211. expr.loc
  212. )
  213. );
  214. }
  215. dep = null;
  216. return true;
  217. }
  218. dep.functionBindThis = this.processFunctionArgument(
  219. parser,
  220. expr.arguments[1]
  221. );
  222. if (expr.arguments.length === 3) {
  223. dep.errorCallbackBindThis = this.processFunctionArgument(
  224. parser,
  225. expr.arguments[2]
  226. );
  227. }
  228. } finally {
  229. parser.state.current = old;
  230. if (dep) parser.state.current.addBlock(dep);
  231. }
  232. return true;
  233. }
  234. }
  235. newRequireDependenciesBlock(
  236. expr,
  237. arrayRange,
  238. functionRange,
  239. errorCallbackRange,
  240. module,
  241. loc,
  242. request
  243. ) {
  244. return new AMDRequireDependenciesBlock(
  245. expr,
  246. arrayRange,
  247. functionRange,
  248. errorCallbackRange,
  249. module,
  250. loc,
  251. request
  252. );
  253. }
  254. newRequireItemDependency(request, range) {
  255. return new AMDRequireItemDependency(request, range);
  256. }
  257. newRequireArrayDependency(depsArray, range) {
  258. return new AMDRequireArrayDependency(depsArray, range);
  259. }
  260. }
  261. module.exports = AMDRequireDependenciesBlockParserPlugin;