AMDDefineDependencyParserPlugin.js 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334
  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 AMDRequireContextDependency = require("./AMDRequireContextDependency");
  8. const ConstDependency = require("./ConstDependency");
  9. const AMDDefineDependency = require("./AMDDefineDependency");
  10. const AMDRequireArrayDependency = require("./AMDRequireArrayDependency");
  11. const LocalModuleDependency = require("./LocalModuleDependency");
  12. const ContextDependencyHelpers = require("./ContextDependencyHelpers");
  13. const LocalModulesHelpers = require("./LocalModulesHelpers");
  14. const isBoundFunctionExpression = expr => {
  15. if (expr.type !== "CallExpression") return false;
  16. if (expr.callee.type !== "MemberExpression") return false;
  17. if (expr.callee.computed) return false;
  18. if (expr.callee.object.type !== "FunctionExpression") return false;
  19. if (expr.callee.property.type !== "Identifier") return false;
  20. if (expr.callee.property.name !== "bind") return false;
  21. return true;
  22. };
  23. const isUnboundFunctionExpression = expr => {
  24. if (expr.type === "FunctionExpression") return true;
  25. if (expr.type === "ArrowFunctionExpression") return true;
  26. return false;
  27. };
  28. const isCallable = expr => {
  29. if (isUnboundFunctionExpression(expr)) return true;
  30. if (isBoundFunctionExpression(expr)) return true;
  31. return false;
  32. };
  33. class AMDDefineDependencyParserPlugin {
  34. constructor(options) {
  35. this.options = options;
  36. }
  37. apply(parser) {
  38. parser.hooks.call
  39. .for("define")
  40. .tap(
  41. "AMDDefineDependencyParserPlugin",
  42. this.processCallDefine.bind(this, parser)
  43. );
  44. }
  45. processArray(parser, expr, param, identifiers, namedModule) {
  46. if (param.isArray()) {
  47. param.items.forEach((param, idx) => {
  48. if (
  49. param.isString() &&
  50. ["require", "module", "exports"].includes(param.string)
  51. )
  52. identifiers[idx] = param.string;
  53. const result = this.processItem(parser, expr, param, namedModule);
  54. if (result === undefined) {
  55. this.processContext(parser, expr, param);
  56. }
  57. });
  58. return true;
  59. } else if (param.isConstArray()) {
  60. const deps = [];
  61. param.array.forEach((request, idx) => {
  62. let dep;
  63. let localModule;
  64. if (request === "require") {
  65. identifiers[idx] = request;
  66. dep = "__webpack_require__";
  67. } else if (["exports", "module"].includes(request)) {
  68. identifiers[idx] = request;
  69. dep = request;
  70. } else if (
  71. (localModule = LocalModulesHelpers.getLocalModule(
  72. parser.state,
  73. request
  74. ))
  75. ) {
  76. dep = new LocalModuleDependency(localModule, undefined, false);
  77. dep.loc = expr.loc;
  78. parser.state.current.addDependency(dep);
  79. } else {
  80. dep = this.newRequireItemDependency(request);
  81. dep.loc = expr.loc;
  82. dep.optional = !!parser.scope.inTry;
  83. parser.state.current.addDependency(dep);
  84. }
  85. deps.push(dep);
  86. });
  87. const dep = this.newRequireArrayDependency(deps, param.range);
  88. dep.loc = expr.loc;
  89. dep.optional = !!parser.scope.inTry;
  90. parser.state.current.addDependency(dep);
  91. return true;
  92. }
  93. }
  94. processItem(parser, expr, param, namedModule) {
  95. if (param.isConditional()) {
  96. param.options.forEach(param => {
  97. const result = this.processItem(parser, expr, param);
  98. if (result === undefined) {
  99. this.processContext(parser, expr, param);
  100. }
  101. });
  102. return true;
  103. } else if (param.isString()) {
  104. let dep, localModule;
  105. if (param.string === "require") {
  106. dep = new ConstDependency("__webpack_require__", param.range);
  107. } else if (["require", "exports", "module"].includes(param.string)) {
  108. dep = new ConstDependency(param.string, param.range);
  109. } else if (
  110. (localModule = LocalModulesHelpers.getLocalModule(
  111. parser.state,
  112. param.string,
  113. namedModule
  114. ))
  115. ) {
  116. dep = new LocalModuleDependency(localModule, param.range, false);
  117. } else {
  118. dep = this.newRequireItemDependency(param.string, param.range);
  119. }
  120. dep.loc = expr.loc;
  121. dep.optional = !!parser.scope.inTry;
  122. parser.state.current.addDependency(dep);
  123. return true;
  124. }
  125. }
  126. processContext(parser, expr, param) {
  127. const dep = ContextDependencyHelpers.create(
  128. AMDRequireContextDependency,
  129. param.range,
  130. param,
  131. expr,
  132. this.options
  133. );
  134. if (!dep) return;
  135. dep.loc = expr.loc;
  136. dep.optional = !!parser.scope.inTry;
  137. parser.state.current.addDependency(dep);
  138. return true;
  139. }
  140. processCallDefine(parser, expr) {
  141. let array, fn, obj, namedModule;
  142. switch (expr.arguments.length) {
  143. case 1:
  144. if (isCallable(expr.arguments[0])) {
  145. // define(f() {…})
  146. fn = expr.arguments[0];
  147. } else if (expr.arguments[0].type === "ObjectExpression") {
  148. // define({…})
  149. obj = expr.arguments[0];
  150. } else {
  151. // define(expr)
  152. // unclear if function or object
  153. obj = fn = expr.arguments[0];
  154. }
  155. break;
  156. case 2:
  157. if (expr.arguments[0].type === "Literal") {
  158. namedModule = expr.arguments[0].value;
  159. // define("…", …)
  160. if (isCallable(expr.arguments[1])) {
  161. // define("…", f() {…})
  162. fn = expr.arguments[1];
  163. } else if (expr.arguments[1].type === "ObjectExpression") {
  164. // define("…", {…})
  165. obj = expr.arguments[1];
  166. } else {
  167. // define("…", expr)
  168. // unclear if function or object
  169. obj = fn = expr.arguments[1];
  170. }
  171. } else {
  172. array = expr.arguments[0];
  173. if (isCallable(expr.arguments[1])) {
  174. // define([…], f() {})
  175. fn = expr.arguments[1];
  176. } else if (expr.arguments[1].type === "ObjectExpression") {
  177. // define([…], {…})
  178. obj = expr.arguments[1];
  179. } else {
  180. // define([…], expr)
  181. // unclear if function or object
  182. obj = fn = expr.arguments[1];
  183. }
  184. }
  185. break;
  186. case 3:
  187. // define("…", […], f() {…})
  188. namedModule = expr.arguments[0].value;
  189. array = expr.arguments[1];
  190. if (isCallable(expr.arguments[2])) {
  191. // define("…", […], f() {})
  192. fn = expr.arguments[2];
  193. } else if (expr.arguments[2].type === "ObjectExpression") {
  194. // define("…", […], {…})
  195. obj = expr.arguments[2];
  196. } else {
  197. // define("…", […], expr)
  198. // unclear if function or object
  199. obj = fn = expr.arguments[2];
  200. }
  201. break;
  202. default:
  203. return;
  204. }
  205. let fnParams = null;
  206. let fnParamsOffset = 0;
  207. if (fn) {
  208. if (isUnboundFunctionExpression(fn)) {
  209. fnParams = fn.params;
  210. } else if (isBoundFunctionExpression(fn)) {
  211. fnParams = fn.callee.object.params;
  212. fnParamsOffset = fn.arguments.length - 1;
  213. if (fnParamsOffset < 0) {
  214. fnParamsOffset = 0;
  215. }
  216. }
  217. }
  218. let fnRenames = parser.scope.renames.createChild();
  219. if (array) {
  220. const identifiers = {};
  221. const param = parser.evaluateExpression(array);
  222. const result = this.processArray(
  223. parser,
  224. expr,
  225. param,
  226. identifiers,
  227. namedModule
  228. );
  229. if (!result) return;
  230. if (fnParams) {
  231. fnParams = fnParams.slice(fnParamsOffset).filter((param, idx) => {
  232. if (identifiers[idx]) {
  233. fnRenames.set(param.name, identifiers[idx]);
  234. return false;
  235. }
  236. return true;
  237. });
  238. }
  239. } else {
  240. const identifiers = ["require", "exports", "module"];
  241. if (fnParams) {
  242. fnParams = fnParams.slice(fnParamsOffset).filter((param, idx) => {
  243. if (identifiers[idx]) {
  244. fnRenames.set(param.name, identifiers[idx]);
  245. return false;
  246. }
  247. return true;
  248. });
  249. }
  250. }
  251. let inTry;
  252. if (fn && isUnboundFunctionExpression(fn)) {
  253. inTry = parser.scope.inTry;
  254. parser.inScope(fnParams, () => {
  255. parser.scope.renames = fnRenames;
  256. parser.scope.inTry = inTry;
  257. if (fn.body.type === "BlockStatement") {
  258. parser.walkStatement(fn.body);
  259. } else {
  260. parser.walkExpression(fn.body);
  261. }
  262. });
  263. } else if (fn && isBoundFunctionExpression(fn)) {
  264. inTry = parser.scope.inTry;
  265. parser.inScope(
  266. fn.callee.object.params.filter(
  267. i => !["require", "module", "exports"].includes(i.name)
  268. ),
  269. () => {
  270. parser.scope.renames = fnRenames;
  271. parser.scope.inTry = inTry;
  272. if (fn.callee.object.body.type === "BlockStatement") {
  273. parser.walkStatement(fn.callee.object.body);
  274. } else {
  275. parser.walkExpression(fn.callee.object.body);
  276. }
  277. }
  278. );
  279. if (fn.arguments) {
  280. parser.walkExpressions(fn.arguments);
  281. }
  282. } else if (fn || obj) {
  283. parser.walkExpression(fn || obj);
  284. }
  285. const dep = this.newDefineDependency(
  286. expr.range,
  287. array ? array.range : null,
  288. fn ? fn.range : null,
  289. obj ? obj.range : null,
  290. namedModule ? namedModule : null
  291. );
  292. dep.loc = expr.loc;
  293. if (namedModule) {
  294. dep.localModule = LocalModulesHelpers.addLocalModule(
  295. parser.state,
  296. namedModule
  297. );
  298. }
  299. parser.state.current.addDependency(dep);
  300. return true;
  301. }
  302. newDefineDependency(
  303. range,
  304. arrayRange,
  305. functionRange,
  306. objectRange,
  307. namedModule
  308. ) {
  309. return new AMDDefineDependency(
  310. range,
  311. arrayRange,
  312. functionRange,
  313. objectRange,
  314. namedModule
  315. );
  316. }
  317. newRequireArrayDependency(depsArray, range) {
  318. return new AMDRequireArrayDependency(depsArray, range);
  319. }
  320. newRequireItemDependency(request, range) {
  321. return new AMDRequireItemDependency(request, range);
  322. }
  323. }
  324. module.exports = AMDDefineDependencyParserPlugin;