Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.
 
 
 
 

335 строки
9.0 KiB

  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;